Comments (26)
is/are can also:
KEY: FilesReady
Source: "{0, plural, =1 {# file} other {# files}} {0, plural, =1 {is} other {are}} ready"
Result:
NUM:0 -> 0 files are ready
NUM:1 -> 1 file is ready
NUM:2 -> 2 files are ready
NUM:3 -> 3 files are ready
NUM:4 -> 4 files are ready
NUM:5 -> 5 files are ready
NUM:6 -> 6 files are ready
NUM:7 -> 7 files are ready
NUM:8 -> 8 files are ready
NUM:9 -> 9 files are ready
NUM:10 -> 10 files are ready
Test regex101 online work
from files.
This has low priority comparing to other urgent issues but definitely worth trying and if someone gonna make a PR for this we are happy to help.
Personally, I try to find a compromise between speed, compatibility and simplicity. Personally, I am creating my own new project and trying to implement this feature.
In addition, I try to contribute to extensions in community projects.
Thus, in my personal development, I only share the main points of progress so that a working prototype already exists when It start development.
from files.
We can also start with a couple strings as a test and see how it goes.
from files.
MessageFormat #15323 (comment)
I recommend using the MessageFormat solution, I'm trying it out, and it's versatile and can handle text formats like '{0}' or '{num}'
Alternatively, I could help with testing and deployment
from files.
Sample of personal use
StringExtensions.cs
// Copyright (c) 2024 Laštůvka Lukáš
// Licensed under the Apache-2.0 license. See the LICENSE.
using System.Text.RegularExpressions;
namespace ProjectName.Extensions;
public static partial class StringExtensions
{
// Default resource manager
private static readonly ResourceManager _resourceManager = new("ProjectName.Strings.Resources", typeof(Program).Assembly);
// Default pattern for plural strings
private const string _regexPattern = @"\{\s*(?'index'\d+)\s*,\s*plural\s*,\s*=\s*(?'num'\d+)\s*\{\s*(?'std'[^{]+)\s*\}\s*(?:(one|few|many|other)\s*\{\s*([^{}]+)\s*\})?\s*(?:(one|few|many|other)\s*\{\s*([^{}]+)\s*\})?\s*(?:(one|few|many|other)\s*\{\s*([^{}]+)\s*\})?\s*(?:(one|few|many|other)\s*\{\s*([^{}]+)\s*\})?\s*\}";
// Default string to replace with amount
private const string _replaceString = "#";
// Default regex object for pattern
[GeneratedRegex(_regexPattern, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace)]
private static partial Regex ResourceRegex();
private static readonly Regex _regex = ResourceRegex();
/// <summary>
/// Tests if a resource with the specified key exists in the resource manager with the specified culture.
/// </summary>
/// <param name="resKey">The key of the resource to look for.</param>
/// <param name="culture">The culture to use when looking for the resource.</param>
/// <param name="value">The value of the resource, if it exists.</param>
/// <returns>True if the resource exists, false otherwise.</returns>
private static bool ExistsLocalizedResource(this string resKey, CultureInfo culture, out string value)
{
try
{
var keyValue = _resourceManager.GetResourceSet(culture, true, true)?.GetString(resKey);
if (keyValue != null)
{
value = keyValue;
return true;
}
}
catch { }
value = string.Empty;
return false;
}
/// <summary>
/// Gets the plural category for the specified number.
/// </summary>
/// <param name="amount">The number for which to get the plural category.</param>
/// <returns>The plural category for the specified number.</returns>
private static string GetPluralCategory(int amount)
{
if (amount == 1)
{
return "one";
}
else if (amount % 10 >= 2 && amount % 10 <= 4 && (amount % 100 < 10 || amount % 100 >= 20))
{
return "few";
}
else if ((amount % 10 == 0 || (amount % 10 >= 5 && amount % 10 <= 9) || (amount % 100 >= 11 && amount % 100 <= 19)))
{
return "many";
}
else
{
return "other";
}
}
/// <summary>
/// Tests if a resource with the specified key exists in the resource manager with the current UI culture.
/// </summary>
/// <param name="resKey">The key of the resource to look for.</param>
/// <returns>True if the resource exists, false otherwise.</returns>
public static bool ExistsLocalizedResource(this string resKey) => ExistsLocalizedResource(resKey, CultureInfo.CurrentUICulture, out var _);
/// <summary>
/// Gets the localized string for the specified resource key from the resource manager with the specified culture.
/// </summary>
/// <param name="resKey">The key of the resource to look for.</param>
/// <param name="culture">The culture to use when looking for the resource.</param>
/// <returns>The localized string for the resource, or the resource key if the resource could not be found.</returns>
public static string GetLocalizedResource(this string resKey, CultureInfo culture) => ExistsLocalizedResource(resKey, culture, out string value) ? value : resKey;
/// <summary>
/// Gets the localized string for the specified resource key from the resource manager with the current UI culture.
/// </summary>
/// <param name="resKey">The key of the resource to look for.</param>
/// <returns>The localized string for the resource, or the resource key if the resource could not be found.</returns>
public static string GetLocalizedResource(this string resKey) => GetLocalizedResource(resKey, CultureInfo.CurrentUICulture);
/// <summary>
/// Gets the plural localized resource for the specified resource key and culture, using the specified amounts.
/// </summary>
/// <param name="resKey">The key of the resource to look for.</param>
/// <param name="culture">The culture to use when looking for the resource.</param>
/// <param name="amounts">The amounts to use for pluralization.</param>
/// <returns>The pluralized localized resource for the specified key and culture.</returns>
public static string GetPluralLocalizedResource(this string resKey, CultureInfo culture, params int[] amounts)
{
var res = GetLocalizedResource(resKey, culture);
var matches = _regex.Matches(res);
if (matches.Count == 0)
{
return res;
}
foreach (var match in matches.Cast<Match>())
{
var index = int.Parse(match.Groups["index"].Value);
var num = int.Parse(match.Groups["num"].Value);
if (amounts[index] == num)
{
var std = match.Groups["std"].Value;
res = res.ReplaceFirst(match.Groups[0].Value, std.ReplaceFirst(_replaceString, amounts[index].ToString()));
continue;
}
for (int i = 1; i < match.Groups.Count; i += 2)
{
var groupName = match.Groups[i].Value;
var groupText = match.Groups[i + 1].Value;
if (groupName == GetPluralCategory(amounts[index]) || groupName == "other")
{
res = res.ReplaceFirst(match.Groups[0].Value, groupText.ReplaceFirst(_replaceString, amounts[index].ToString()).TrimEnd());
break;
}
}
}
return res;
}
/// <summary>
/// Gets the plural localized resource for the specified resource key and culture, using the specified amounts with the current UI culture.
/// </summary>
/// <param name="resKey">The key of the resource to look for.</param>
/// <param name="amounts">The amounts to use for pluralization.</param>
/// <returns>The pluralized localized resource for the specified key and culture.</returns>
public static string GetPluralLocalizedResource(this string resKey, params int[] amounts) => GetPluralLocalizedResource(resKey, CultureInfo.CurrentUICulture, amounts);
/// <summary>
/// Replaces the first occurrence of a specified string with another specified string in a given string.
/// </summary>
/// <param name="str">The given string.</param>
/// <param name="oldValue">The string to be replaced.</param>
/// <param name="newValue">The new string to replace the old string.</param>
/// <returns>A string that is identical to the given string except that the first occurrence of oldValue is replaced with newValue.</returns>
public static string ReplaceFirst(this string str, string oldValue, string newValue)
{
int position = str.IndexOf(oldValue);
if (position < 0)
{
return str;
}
str = string.Concat(str.AsSpan(0, position), newValue, str.AsSpan(position + oldValue.Length));
return str;
}
}
Example using in code
// Copyright (c) 2024 Laštůvka Lukáš
// Licensed under the Apache-2.0 license. See the LICENSE.
// Test New Version
CultureInfo.CurrentUICulture = new("en-US");
string[] testStrings = ["CreateShortcutDescription", "UnpinFolderFromSidebarDescription"];
foreach (string testString in testStrings)
{
Console.WriteLine($"KEY: {testString}");
Console.WriteLine($"Source: \"{testString.GetLocalizedResource()}\"");
Console.WriteLine($"\nResult:\n");
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($"NUM:{i}\t->\t{testString.GetPluralLocalizedResource(i)}");
}
Console.WriteLine();
}
string[] testStrings2 = ["ConflictingItemsDialogSubtitleMultipleConflictsMultipleNonConflicts", "CopyItemsDialogSubtitleMultiple"];
foreach (string testString in testStrings2)
{
Console.WriteLine($"KEY: {testString}");
Console.WriteLine($"Source: \"{testString.GetLocalizedResource()}\"");
Console.WriteLine($"\nResult:\n");
for (int i = 0; i <= 10; i++)
{
Console.WriteLine($"NUM:{i}\t->\t{testString.GetPluralLocalizedResource(i,0)}");
}
Console.WriteLine();
}
Console.ReadKey();
from files.
Testing on real data
-
For compatibility reasons, I created a new version that handles multivalued text better.
-
I have made a demonstration of the possibilities and implementation
-
Test New Version RegExr online work
-
Test New Version regex101 online work
Samples
Sample A
KEY: CreateShortcutDescription
Source: "Create new {0, plural, =1 {shortcut} other {shortcuts}} to selected {0, plural, =1 {item} other {items}}"
Result:
NUM:1 -> Create new shortcut to selected item
NUM:2 -> Create new shortcuts to selected items
NUM:3 -> Create new shortcuts to selected items
NUM:4 -> Create new shortcuts to selected items
NUM:5 -> Create new shortcuts to selected items
NUM:6 -> Create new shortcuts to selected items
NUM:7 -> Create new shortcuts to selected items
NUM:8 -> Create new shortcuts to selected items
NUM:9 -> Create new shortcuts to selected items
NUM:10 -> Create new shortcuts to selected items
Sample B
KEY: UnpinFolderFromSidebarDescription
Source: "Unpin {0, plural, =1 {folder} other {folders}} from Sidebar"
Result:
NUM:1 -> Unpin folder from Sidebar
NUM:2 -> Unpin folders from Sidebar
NUM:3 -> Unpin folders from Sidebar
NUM:4 -> Unpin folders from Sidebar
NUM:5 -> Unpin folders from Sidebar
NUM:6 -> Unpin folders from Sidebar
NUM:7 -> Unpin folders from Sidebar
NUM:8 -> Unpin folders from Sidebar
NUM:9 -> Unpin folders from Sidebar
NUM:10 -> Unpin folders from Sidebar
Sample C
KEY: ConflictingItemsDialogSubtitleMultipleConflictsMultipleNonConflicts
Source: "There are {0, plural, =0 {no conflicting file names} one {# conflicting file name} other {# conflicting file names}}, and {1, plural, =0 {zero outgoing items} one {# outgoing item} other {# outgoing items}}."
Result:
NUM:0 -> There are no conflicting file names, and zero outgoing items.
NUM:1 -> There are 1 conflicting file name, and zero outgoing items.
NUM:2 -> There are 2 conflicting file names, and zero outgoing items.
NUM:3 -> There are 3 conflicting file names, and zero outgoing items.
NUM:4 -> There are 4 conflicting file names, and zero outgoing items.
NUM:5 -> There are 5 conflicting file names, and zero outgoing items.
NUM:6 -> There are 6 conflicting file names, and zero outgoing items.
NUM:7 -> There are 7 conflicting file names, and zero outgoing items.
NUM:8 -> There are 8 conflicting file names, and zero outgoing items.
NUM:9 -> There are 9 conflicting file names, and zero outgoing items.
NUM:10 -> There are 10 conflicting file names, and zero outgoing items.
Sample D
KEY: CopyItemsDialogSubtitleMultiple
Source: "{0, plural, =1 {# item} other {# items}} will be copied"
Result:
NUM:0 -> 0 items will be copied
NUM:1 -> 1 item will be copied
NUM:2 -> 2 items will be copied
NUM:3 -> 3 items will be copied
NUM:4 -> 4 items will be copied
NUM:5 -> 5 items will be copied
NUM:6 -> 6 items will be copied
NUM:7 -> 7 items will be copied
NUM:8 -> 8 items will be copied
NUM:9 -> 9 items will be copied
NUM:10 -> 10 items will be copied
from files.
@Jay-o-Way do you have any input?
from files.
Hm, looks sweet! But not really my expertise... Would be nice as a nuget package? 😉
One detail: I see it doesn't work for the "is/are" words.
There are 1 conflicting file name
from files.
MessageFormat
- I tried the existing nuget package "MessageFormat"
- Public repo MessageFormatter for .NET
Install NuGet
Install-Package MessageFormat
Demo code
// Copyright (c) 2024 Laštůvka Lukáš
// Licensed under the Apache-2.0 license. See the LICENSE.
// Test With MessageFormat
using Jeffijoe.MessageFormat;
CultureInfo.CurrentUICulture = new("en-US");
var mf = new MessageFormatter(useCache: true, locale: CultureInfo.CurrentUICulture.Name);
string[] testStrings = ["CreateShortcutDescription", "UnpinFolderFromSidebarDescription"];
foreach (string testString in testStrings)
{
Console.WriteLine($"KEY: {testString}");
Console.WriteLine($"Source: \"{testString.GetLocalizedResource()}\"");
Console.WriteLine($"\nResult:\n");
for (int i = 1; i <= 10; i++)
{
Console.WriteLine($"NUM:{i}\t->\t{mf.FormatMessage(testString.GetLocalizedResource(), new Dictionary<string, object?> { { "0", i } })}");
}
Console.WriteLine();
}
string[] testStrings2 = ["ConflictingItemsDialogSubtitleMultipleConflictsMultipleNonConflicts", "CopyItemsDialogSubtitleMultiple", "FilesReady"];
foreach (string testString in testStrings2)
{
Console.WriteLine($"KEY: {testString}");
Console.WriteLine($"Source: \"{testString.GetLocalizedResource()}\"");
Console.WriteLine($"\nResult:\n");
for (int i = 0; i <= 10; i++)
{
Console.WriteLine($"NUM:{i}\t->\t{mf.FormatMessage(testString.GetLocalizedResource(), new Dictionary<string, object?> { { "0", i },{ "1", 0} })}");
}
Console.WriteLine();
}
Console.ReadKey();
Results
KEY: CreateShortcutDescription
Source: "Create new {0, plural, =1 {shortcut} other {shortcuts}} to selected {0, plural, =1 {item} other {items}}"
Result:
NUM:1 -> Create new shortcut to selected item
NUM:2 -> Create new shortcuts to selected items
NUM:3 -> Create new shortcuts to selected items
NUM:4 -> Create new shortcuts to selected items
NUM:5 -> Create new shortcuts to selected items
NUM:6 -> Create new shortcuts to selected items
NUM:7 -> Create new shortcuts to selected items
NUM:8 -> Create new shortcuts to selected items
NUM:9 -> Create new shortcuts to selected items
NUM:10 -> Create new shortcuts to selected items
KEY: UnpinFolderFromSidebarDescription
Source: "Unpin {0, plural, =1 {folder} other {folders}} from Sidebar"
Result:
NUM:1 -> Unpin folder from Sidebar
NUM:2 -> Unpin folders from Sidebar
NUM:3 -> Unpin folders from Sidebar
NUM:4 -> Unpin folders from Sidebar
NUM:5 -> Unpin folders from Sidebar
NUM:6 -> Unpin folders from Sidebar
NUM:7 -> Unpin folders from Sidebar
NUM:8 -> Unpin folders from Sidebar
NUM:9 -> Unpin folders from Sidebar
NUM:10 -> Unpin folders from Sidebar
KEY: ConflictingItemsDialogSubtitleMultipleConflictsMultipleNonConflicts
Source: "There are {0, plural, =0 {no conflicting file names} one {# conflicting file name} other {# conflicting file names}}, and {1, plural, =0 {zero outgoing items} one {# outgoing item} other {# outgoing items}}."
Result:
NUM:0 -> There are no conflicting file names, and zero outgoing items.
NUM:1 -> There are 1 conflicting file name, and zero outgoing items.
NUM:2 -> There are 2 conflicting file names, and zero outgoing items.
NUM:3 -> There are 3 conflicting file names, and zero outgoing items.
NUM:4 -> There are 4 conflicting file names, and zero outgoing items.
NUM:5 -> There are 5 conflicting file names, and zero outgoing items.
NUM:6 -> There are 6 conflicting file names, and zero outgoing items.
NUM:7 -> There are 7 conflicting file names, and zero outgoing items.
NUM:8 -> There are 8 conflicting file names, and zero outgoing items.
NUM:9 -> There are 9 conflicting file names, and zero outgoing items.
NUM:10 -> There are 10 conflicting file names, and zero outgoing items.
KEY: CopyItemsDialogSubtitleMultiple
Source: "{0, plural, =1 {# item} other {# items}} will be copied"
Result:
NUM:0 -> 0 items will be copied
NUM:1 -> 1 item will be copied
NUM:2 -> 2 items will be copied
NUM:3 -> 3 items will be copied
NUM:4 -> 4 items will be copied
NUM:5 -> 5 items will be copied
NUM:6 -> 6 items will be copied
NUM:7 -> 7 items will be copied
NUM:8 -> 8 items will be copied
NUM:9 -> 9 items will be copied
NUM:10 -> 10 items will be copied
KEY: FilesReady
Source: "{0, plural, one {# file} other {# files}} {0, plural, =1 {is} other {are}} ready"
Result:
NUM:0 -> 0 files are ready
NUM:1 -> 1 file is ready
NUM:2 -> 2 files are ready
NUM:3 -> 3 files are ready
NUM:4 -> 4 files are ready
NUM:5 -> 5 files are ready
NUM:6 -> 6 files are ready
NUM:7 -> 7 files are ready
NUM:8 -> 8 files are ready
NUM:9 -> 9 files are ready
NUM:10 -> 10 files are ready
from files.
This has low priority comparing to other urgent issues but definitely worth trying and if someone gonna make a PR for this we are happy to help.
from files.
The main question about this implementation is if it will cause confusion. This is something we need translators to provide input on as they are the ones putting the time and effort into localizing Files.
from files.
@XTorLukas do you want to open a PR using this method for a couple strings so we can get a feel for it?
from files.
@yaira2 why not, let's see if the translators know their stuff
from files.
I don't think we need string extension for this as Crowdin seems to support ICU message syntax.
The issue that should be fixed here is to have this syntax in en-US resources.
I'll open an issue for this and list up all strings that have to be inflected.
Btw, it looks like XCode has a brilliant feature for this type of thing called Grammatical Agreement: you can put ^[item](inflect: true)
for singular and plural, ^[them].(agreeWithConcept: true)
to match with other pronounce in other sentences and (agreeWithArgument)
to match with other words in the same sentence, for dependency agreement. Looks nice but Crowdin will do instead.
from files.
@0x5bfa we already agreed to try this approach but if you have a simpler solution, please share the details here so we can track in one place.
from files.
@XTorLukas already posted it as a first solution to this, as a second solution to this they suggested to have an extension class. This issue is too crowded to list up.
from files.
Picked some up.
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 387 to 410 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 429 to 440 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 450 to 452 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 471 to 476 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1236 to 1244 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1248 to 1256 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1260 to 1277 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1290 to 1295 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1383 to 1388 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1626 to 1628 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2376 to 2405 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2412 to 2423 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2445 to 2459 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2472 to 2480 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2493 to 2516 in af0ab75
from files.
@0x5bfa can you open a PR for one of them and we can see how it goes (the Status Bar is a good one to start with)?
I'd like to keep this issue open as a backup plan.
from files.
@0x5bfa is already busy with other tasks so if you can help that would be great!
from files.
@yaira2 But I don't know the syntax of your code yet, so if a foundation is established, I could start helping.
from files.
Each area is different but I think we can start with the Status Bar.
from files.
I wrote a prototype of a possible implementation and tested this part for my region where more than two possible values are used:
<data name="ItemSelected.Text" xml:space="preserve">
<value>položka vybrána</value>
</data>
<data name="ItemsSelected.Text" xml:space="preserve">
<value>položky vybrány</value>
</data>
Change to only one pluralKey with prefix p
<data name="pItemsSelected.Text" xml:space="preserve">
<value>{0, plural, one {# položka vybrána} few {# položky vybrány} other {# položek vybráno}}</value>
</data>
Maybe I'll create a PR for my solution
from files.
Looks good to me
from files.
Looks absolutely great. We can reduce a number of string resources.
from files.
I'll start working on finding all the text strings that will need to be reworked. I won't be opening any more PRs, just in the private branch for now, or if necessary I'll create a PR as a draft
I'll start with these: #15323 (comment)
Picked some up.
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 387 to 410 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 429 to 440 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 450 to 452 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 471 to 476 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1236 to 1244 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1248 to 1256 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1260 to 1277 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1290 to 1295 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1383 to 1388 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 1626 to 1628 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2376 to 2405 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2412 to 2423 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2445 to 2459 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2472 to 2480 in af0ab75
Files/src/Files.App/Strings/en-US/Resources.resw
Lines 2493 to 2516 in af0ab75
from files.
Merging with #15503
from files.
Related Issues (20)
- Files UI isn't used when Windows prompts you to open a file HOT 2
- Can't download v3.7.7 HOT 1
- QuickLook stopped opening previews in Files HOT 1
- Adjusting Highlight Color for Selected Items HOT 1
- Recycle Bin shown as Shell:RecycleBinFolder HOT 3
- I want a font selection feature. HOT 14
- Option to Expand to Open Folder in Files App (Like in Windows Explorer) HOT 1
- Double Clicking Folders does not open in Files HOT 3
- Developer performance - Console window integration HOT 5
- Developer Tools - IDE Integration HOT 1
- Bug: Files crashes with memory error when browsing files with file preview enabled HOT 3
- Can't open files set to open with UWP app
- Keep acrylic effects even when unfocused HOT 6
- Multiple issues: Pinned folders & Forced shutdown HOT 2
- Set naam when adding a file or folder from toolbar in Dutch language HOT 3
- Context menu "More options" missing items HOT 5
- Feature: Integrate file details into the Columns layout HOT 1
- Adding a auto-hide function HOT 1
- Tag can contain other Tags HOT 1
- Feature: Reduce minimum window height HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from files.