tc39 / proposal-intl-numberformat-v3 Goto Github PK
View Code? Open in Web Editor NEWAdditional features for Intl.NumberFormat to solve key pain points.
License: MIT License
Additional features for Intl.NumberFormat to solve key pain points.
License: MIT License
The spec currently states that the rounding increment should be applied at the point at which rounding is applied. This works fine for fraction digit rounding:
new Intl.NumberFormat("en", {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
roundingIncrement: 5
}).format(1.03);
// => "1.05"
However, for significant digits rounding, the behavior could be surprising:
const nf = new Intl.NumberFormat("en", {
minimumSignificantDigits: 2,
maximumSignificantDigits: 2,
roundingIncrement: 5
});
nf.format(130); // 150
nf.format(13); // 15
nf.format(1.3); // 1.5
Also, ICU does not support rounding increment combined with significant digits.
I suggest that we throw an exception when roundingIncrement
is used in combination with anything that requires significant digits. We can always remove the exception later.
As of #28, the README is up to date with the latest consensus. The spec needs to be updated to reflect this.
Since InitializePluralRules calls SetNumberFormatDigitOptions it is possible RoundingType in the return value contains morePrecision or lessPrecision
Change
[[RoundingType]] is one of the values fractionDigits or significantDigits, indicating which rounding strategy to use, as discussed in .
to
[[RoundingType]] is one of the values fractionDigits<del> or significantDigits</del><ins>, significantDigits, morePrecision, or lessPrecision</ins>, indicating which rounding strategy to use, as discussed in .
I would like to schedule a meeting to discuss some of the details involving significant digits rounding in Intl.NumberFormat as highlighted in #8. Please fill out the following Doodle if interested. I would like to schedule this for next week. If you are not available next week, please let me know and we can put it the following week instead.
https://doodle.com/poll/zbf68rcw6k9ztre9?utm_source=poll&utm_medium=link
Table 3: Resolved Options of NumberFormat Instances
I think you need to add <ins> to the following rows
Internal Slot | Property |
---|---|
[[RoundingMode]] | "roundingMode" |
[[RoundingIncrement]] | "roundingIncrement" |
[[TrailingZeroDisplay]] | "trailingZeroDisplay" |
From https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-setnfdigitoptions:
If ( not hasSd and notation is not "compact" ) or roundingPriority is not "auto", set needFd to true; else, set needFd to false.
As mentioned in the other ECMA-402 PR, we need to explicitly compare against boolean values. And also parenthesised expressions aren't ECMASpeak syntax. Two possible alternatives are either using ", or if" to separate the two conditions:
If hasSd is false and notation is not "compact", or if roundingPriority is not "auto", set needFd to true; else, set needFd to false.
Or to use separate if-clauses:
If hasSd is false and notation is not "compact", set needFd to true.
Else if roundingPriority is not "auto", set needFd to true.
Else, set needFd to false.
What should we call the "min2"
option for useGrouping? (context: #3)
"min2"
(keep it as proposed)"minimum2"
(suggested by @FrankYFTang)"partial"
(suggested by @sffc)The arguments are formatted a bit strangely -- it makes it seem like this is conditional on four arguments, not that the four arguments are required. In addition, we are not specifying the types here, as we do normally for AOs. We might want to make the prose more specific (it is a bit hand wavy right now). Finally, Doesnβt specify what it is returning.
A question from @ryzokuken: Why does PluralRulesSelectRange not have a ToParts?
The Temporal proposal uses a nice stylesheet for their Markdown.
https://github.com/tc39/proposal-temporal/blob/main/docs/buildDocs.js
It would be nice to use something similar here. Is there a way to avoid duplicating the buildDocs.js code?
From @FrankYFTang:
is that true, with your change
passing
Symbol(12)
[]
{}
as input to format(), formatToParts() or formatRange()
will throw TypeError
let nf = new Intl.NumberFormat("en", {style: "unit", unit: "day"})
nf.format(3.4)
> "3.4 days"
nf.formatToParts(3.4)
>0: {type: "integer", value: "3"}
1: {type: "decimal", value: "."}
2: {type: "fraction", value: "4"}
3: {type: "literal", value: " "}
4: {type: "unit", value: "days"}
let rf = new Intl.RelativeTimeFormat("en")
rf.format(3.4, "day")
> "in 3.4 days"
rf.formatToParts(3.4, "day")
> 0: {type: "literal", value: "in "}
1: {type: "integer", value: "3", unit: "day"}
2: {type: "decimal", value: ".", unit: "day"}
3: {type: "fraction", value: "4", unit: "day"}
4: {type: "literal", value: " days"}
Notice the output from the Intl.RelativeTimeFormat has the unit: "day" in the integer/decimal/fraction
Should we also make the Intl.NumberFormat to output that ?
I think we should change the spec in NumberFormat v3 to make Intl.NumberFormat output
nf.formatToParts(3.4)
>0: {type: "integer", value: "3", unit: "day"}
1: {type: "decimal", value: ".", unit: "day"}
2: {type: "fraction", value: "4", unit: "day"}
3: {type: "literal", value: " "}
4: {type: "unit", value: "days"}
There is a second issue of the 4: {type: "literal", value: " days"} from the Intl.RelativeTimeFormat, which I think we should discuss in a ECMA402 issue.
ICU has the following options:
"halfUp"
(default)"halfEven"
"halfDown"
"ceiling"
"floor"
"up"
"down"
Chart: http://userguide.icu-project.org/formatparse/numbers/rounding-modes
Do we want to include all those in Intl.NumberFormat? How would we pick a subset?
ResolvePluralRange ( pluralRules, n ) should be 3 arguments instead of 2
and should be ResolvePluralRange ( pluralRules, x, y )
https://tc39.es/proposal-intl-numberformat-v3/out/pluralrules/diff.html#sec-resolvepluralrange
Currently, https://tc39.es/proposal-intl-numberformat-v3/out/negotiation/diff.html#sec-getoption
(notice the section ID should be changed from #sec-getoption to #sec-getstringorbooleanoption for GetStringOrBooleanOption instead of the one for the GetOption)
have
1.2.12 GetStringOrBooleanOption ( options, property, values, trueValue, fallback )
The abstract operation GetStringOrBooleanOption extracts the value of the property named
property from the provided options object. If the value is undefined, the operation returns
fallback. If the value is true, the operation returns trueValue. If the value is falsy,
the operation returns false. Otherwise, the operation converts the value to a String,
checks whether it is one of a List of allowed values (which must not be undefined),
and returns the stringified value.
I suggest we change it to the following to make it more generalized:
1.2.12 GetStringOrBooleanOption ( options, property, values, ^falseValue,^ trueValue, fallback )
The abstract operation GetStringOrBooleanOption extracts the value of the property named
property from the provided options object. If the value is undefined, the operation returns
fallback. If the value is true, the operation returns trueValue. If the value is false,
the operation returns ^falseValue^. Otherwise, the operation converts the value to a String,
checks whether it is one of a List of allowed values (which must not be undefined),
and returns the stringified value.
Current limit is 20.
Jeff Walden found a typo:
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-initializenumberformat step 24 should be "trailingZeroDisplay" (no initial cap)
Use-case:
I'd like to round negative values but I don't want -0
to be formatted into a string with "minus" sign i.e. I prefer "0"
instead of "-0"
For example:
const formatter = new Intl.NumberFormat("en", {
maximumFractionDigits: 1
});
console.log(formatter.format(-0.03));
// Returns: -0
// Desired result: 0
The proposed spec for signDisplay
supports these options: auto
, always
, never
and exceptZero
. But, none of them seem to produce the output desired for the use-case above - without compromising on something else.
exceptZero
comes close, but in addition to removing the minus sign from -0
, it also adds a plus sign to positive numbers (as expected) which is not desired for the use-case above.
var formatter = new Intl.NumberFormat("en", {
maximumFractionDigits: 1,
signDisplay: "exceptZero"
});
console.log(formatter.format(-0.03));
// Returns the desired result: 0 π
// but...
console.log(formatter.format(123));
// Returns: +123 π
// Desired result: 123
I found this table containing examples of signDisplay
options here: https://github.com/tc39/proposal-unified-intl-numberformat/blob/master/README.md#iii-sign-display. I was hoping to find an option that would produce -1 | 0 | 0 | 1 | NaN
, but such an option does not seem to exist.
Am I missing something? What is the recommendation for handling the use-case above?
Thank you.
Please fix the diff version of
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-initializenumberformat
The green/pink highlight looks missed a lot of changes from https://tc39.es/ecma402/ and is now very confusing to figure out which part is the change. Please compare with https://tc39.es/ecma402/ and highlight it correctly.
Currently, Number.prototype.toFixed
cannot specify a different rounding mode, and hope that it can be taken into consideration in this proposal since that it has brought out different kinds of rounding modes in JavaScript.
(1.02).toFixed(1); // => "1.0"
(1.05).toFixed(1); // => "1.1" round by default
// If we can specify types:
(1.05).toFixed(1, 'floor'); // => "1.0"
(1.02).toFixed(1, 'ceiling'); // => "1.1"
The main use case that's interesting for scale
is when you have a BigInt of a small unit, like currency micros, and you want to divide it by some constant when formatting.
This raises the question: perhaps, since the scale is assumed to be more related to the number than the formatter settings, that scale
should go into the format method. For example:
const nf = new Intl.NumberFormat("fr-FR", {
style: "currency",
currency: "EUR",
});
const micros = 1000000n;
// Version 1:
nf.format(micros, { scale: -6 });
// Version 2:
nf.format({
number: micros,
scale: -6
});
What should happen here?
const nf = new Intl.NumberFormat("en", {
signDisplay: "always"
});
console.log(nf.formatRange(50, 70));
console.log(nf.formatRange(50, 50));
Options:
Description | 50 - 70 | 50 - 50 |
---|---|---|
Always obey signDisplay | +50β70 | +50 |
Obey on identity fallback | 50β70 | +50 |
Ignore | 50β70 | 50 |
CLDR does not clearly specify this case.
If we picked the second option (obey only on identity fallback), it would work nicely with #6 and #10, to let you toggle back and forth between the two main options for identityFallback.
Should ResolvePluralRange
perform the same range checks as PartitionNumberRangePattern
(steps 1-4)?
Number ranges have their own rules for plural selection. CLDR has this data. Consider exposing it in JavaScript via PluralRules.prototype.selectRange().
Right now, this proposal specifies that undefined
aliases to "auto"
.
Does this also include "compact"
notation, considering ICU defaults it to "min2"
for compact notation so that true
equates to 'min2"
for compact notation in the current Intl.NumberFormat?
In http://userguide.icu-project.org/formatparse/numbers/rounding-modes
We see how each roundingMode return for some sample number
But in JavaScript we have -0 in additional to 0 :
What should -0 return when roundingMode: "up"? Should it be 0 or -1?
What should -0 return when roundingMode: "floor"? Should it be 0 or -1?
ICU4J has a number of settings for range formatting:
collapse
Sets the aggressiveness of "collapsing" fields across the range separator. Possible values:
- ALL: "3-5K miles"
- UNIT: "3K - 5K miles"
- NONE: "3K miles - 5K miles"
- AUTO: usually UNIT or NONE, depending on the locale and formatter settings
The default value is AUTO.
identityFallback
Sets the behavior when the two sides of the range are the same. This could happen if the same two numbers are passed to the formatRange function, or if different numbers are passed to the function but they become the same after rounding rules are applied. Possible values:
- SINGLE_VALUE: "5 miles"
- APPROXIMATELY_OR_SINGLE_VALUE: "~5 miles" or "5 miles", depending on whether the number was the same before rounding was applied
- APPROXIMATELY: "~5 miles"
- RANGE: "5-5 miles" (with collapse=UNIT)
The default value is APPROXIMATELY.
Do we want to add those options to ECMA-402, or just stick with the defaults?
From @FrankYFTang:
I think this is a bug in your current spec
nf.formatRange(500, 1/0); // "3ββ"
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-partitionnumberrangepattern
1.1.21 PartitionNumberRangePattern ( numberFormat, x, y )
...
If x is a non-finite Number or y is is a non-finite Number, throw a RangeError exception.
Should it be an "and" here? and there is a double "is" (editorial issue)
In the prose describing CollapseNumberRange, the last line is:
The algorithm is implementation dependent, but it must not introduce ambiguity: the resulting string after modification should be unique for all pairs x and y.
It should instead be
The algorithm is implementation dependent, but it must not introduce ambiguity: the resulting list after modification should be unique for all pairs x and y.
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-collapsenumberrange
From #7: It's interesting to see the case conventions of halfEven
instead of half-even
. This matches our recent decisions. Unfortunately, now we're getting into an area where this convention potentially "infects" or conflicts with the other convention, where it would be half-even
: I was hoping that Decimal would use rounding modes that match Intl. Do we want to extend the camelCase string convention here?
Add new styles to format numbers with "ordinal" or "spell-out". Like in iOS:
https://developer.apple.com/documentation/foundation/numberformatter/style/ordinal
CLDR contains such data for locales.
From @FrankYFTang:
Also in the README.md it said
Ranges to infinity are supported, but if either value is NaN, an error is thrown. (#12)
nf.formatRange(500, 0/0); // RangeError
But I have a hard time figuring out where in the spec to throw the NaN now.
I don't think ToIntlMathematicalValue will throw if the value is NaN right?
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-partitionnumberrangepattern
If x is a non-finite Number or y is is a non-finite Number, throw a RangeError exception.
What is the definition of "non-finite Number" ?
Is NaN a "non-finite Number" ? I cannot tell
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-partitionnumberpattern
surely won't throw if NaN because
If x is NaN, then
Let n be an implementation- and locale-dependent (ILD) String value indicating the NaN value.
@waldemarhorwat, @erights, and @msaboff have at various times raised questions about the rounding modes and how they apply to this proposal. The intent is that all rounding modes take place in decimal space, after we compute the "shortest string" form of the IEEE double. I'm opening this issue to make sure we specify this clearly in the spec.
I think we should probably forbid NaN and Infinity from taking part in a number range format. What would be your expected behavior in these cases?
new Intl.NumberFormat().formatRange(10, NaN);
new Intl.NumberFormat().formatRange(10, Infinity);
The first case makes no sense. The second case could be an interesting application of the "greater than" pattern, but that's not yet supported in ICU.
For now, better to throw a RangeError. We can remove that restriction later if we ever needed to.
As currently written, ToIntlMathematicalValue
accepts non-decimal number strings like for example "0x10"
, via StringNumericLiteral -> StrNumericLiteral -> NonDecimalIntegerLiteral
. Is this intentional? The explainer only mentions decimals, so I just want to make sure supporting non-decimal number strings is expected.
We need to add a row of roundingPriority to https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#table-numberformat-resolvedoptions-properties
Internal Slot | Property |
---|---|
[[RoundingPriority]] | "roundingPriority" |
in Table 3: Resolved Options of NumberFormat Instances
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-setnfdigitoptions
I suggest we change
15. If hasSd or roundingPriority is not "auto", set needSd to true; else, set needSd to false.
to
15. If hasSd is true or roundingPriority is not "auto", then set needSd to true; else, set needSd to false.
I suggest we change
16. If ( not hasSd and notation is not "compact" ) or roundingPriority is not "auto", set needFd to true; else, set needFd to false.
to
16. set needFd to false.
17. If hasSd is false and notation is not "compact", then set needFd to true.
18. if roundingPriority is not "auto", then set needFd to true.
I think we should throw RangeError when either of the inputs to formatRange() is negative.
new Intl.NumberFormat().formatRange(-5, -3); // RangeError
CLDR's number range data is very limited and does not cover this case in a cohesive way. Better to forbid it, and we can add it later if we need to.
Number::toString(-0)
is "0"
, see Number::toString.
FormatNumericToString
doesn't pass [[RoundingIncrement]]
to ToRawPrecision
resp. ToRawFixed
.
roundingIncrement
takes an integer that is either 10^n or 5x10^n, where n is an integer >= 0.
What should the type of roundingIncrement
be? I was thinking Number, since most other numeric options in Intl are Number. But maybe we want BigInt or the new Intl numerical value we are using in the .format() function.
https://tc39.es/proposal-intl-numberformat-v3/out/numberformat/diff.html#sec-initializenumberformat
Let trailingZeroDisplay be ? GetOption(options, "TrailingZeroDisplay", "string", Β« "auto", "stripIfInteger" Β», "stripIfInteger").
should be
Let trailingZeroDisplay be ? GetOption(options, "trailingZeroDisplay", "string", Β« "auto", "stripIfInteger" Β», "stripIfInteger").
also, is it intentional to switch the default to "stripIfInteger"? I cannot find the discussion of such change in #8 nor in https://github.com/tc39/proposal-intl-numberformat-v3
From https://github.com/tc39/proposal-intl-numberformat-v3#rounding-priority:
This resolution algorithm applies separately between the maximum digits settings and the minimum digits settings. So, for example, suppose you had
{ minimumFractionDigits: 2, minimumSignificantDigits: 2 }
Consider the input number "1". minimumFractionDigits wants to retain trailing zeros up to the hundredths place, producing "1.00", whereas minimumSignificantDigits wants to retain only as many as are required to render two significant digits, producing "1.0". We again have a conflict, and the conflict is resolved in the same way.
ICU doesn't support this conflict resolution. From https://unicode-org.github.io/icu-docs/apidoc/released/icu4c/unumberformatter_8h.html#ae481df8b480671a6affec8af37491dd5:
Conflicting minimum fraction and significant digits are always resolved in the direction that results in more trailing zeros.
And the spec seems to follow ICU's behaviour, because the minimum digits aren't taken into account for [[RoundingMagnitude]].
I have a puzzle which has perplexed me.
Below, I list real-life use cases for how users want to round their numbers in Intl.NumberFormat. I am trying to figure out some set of options that is capable of expressing these various different rounding strategies.
Input | Style 1 | Style 2 | Style 3 |
---|---|---|---|
1,234,000 | 1234K | 1234K | 1234K |
123,400 | 123K | 123K | 123K |
12,340 | 12K | 12K | 12.3K |
1,234 | 1.2K | 1.2K | 1.23K |
1,034 | 1K | 1.0K | 1.03K |
.1034 | .1 | .10 | .103 |
.1234 | .12 | .12 | .123 |
Style 1 could be expressed as minFrac=0, maxFrac=0, and minSig=2, and when minSig is in conflict with maxFrac, minSig wins, except that we strip trailing zeros. In other words, we could make Style 1 be expressed as:
{
minimumFractionDigits: 0,
maximumFractionDigits: 0,
minimumSignificantDigits: 2
}
However, this approach is not capable of expressing Style 2.
We could have an option like "applyFractionGreaterThanIntDigits", which would mean to use minFrac/maxFrac when there are a certain number of integer digits, and minSig/maxSig when there are fewer. This is not a very pretty option, but it is capable of expressing all three styles:
Option | Style 1 | Style 2 | Style 3 |
---|---|---|---|
minimumFractionDigits | 0 | 0 | 0 |
maximumFractionDigits | 0 | 0 | 0 |
minimumSignificantDigits | 1 | 2 | 1 |
maximumSignificantDigits | 2 | 2 | 3 |
applyFractionGreaterThanIntDigits | 2 | 2 | 3 |
Input | Style 1 | Style 2 | Style 3 | Style 4 |
---|---|---|---|---|
1 | $1.00 | $1 | $1.00 | $1.00 |
1.01 | $1.01 | $1.01 | $1.00 | $1.00 |
1.04 | $1.04 | $1.04 | $1.05 | $1.00 |
1.12 | $1.12 | $1.12 | $1.10 | $1.10 |
A simple boolean option "stripFractionWhenEmpty" would solve Style 2.
A simple boolean option "nickelRounding" would solve Style 3.
Note that minFrac already serves absolutely no purpose other than retaining trailing zeros.
Given that minFrac is really only about retaining trailing zeros, for Style 4, we could let minFrac be greater than maxFrac, but it is weird for a minimum to be greater than a maximum.
Since a lot of the problems in this section, as well as Style 2 in the previous section, involve various different ways of treating trailing zeros, maybe we could introduce a "trailingZeroStyle" option, an enum with several different options that encompass all of the use cases.
Input | Style 1 | Style 2 |
---|---|---|
60 | 50 yards | 50 yards |
220 | 200 yards | 200 yards |
450 | 450 yards | 450 yards |
490 | 500 yards | 500 yards |
530 | 550 yards | 500 yards |
590 | 600 yards | 600 yards |
Style 1 can be represented by a variant of nickelRounding. We could name the option nickelRoundingMagnitude, and if set, it would override fraction and significant rounding. Alternatively, we could allow minFrac/maxFrac to be less than zero, in which case they express the power of 10 at which you round.
Style 2 involves a cutoff. If we can't figure out how to support it, we could declare it out of scope.
Maybe we should throw the minFrac/maxFrac stuff out the door (keep it for backwards compatibility), and devise a whole new way of thinking about rounding strategies.
The type of useGrouping used to be a boolean but this proposal change it to accept true, false, "min2", "auto", "always".
How should we set the resolvedOptions().useGrouping?
The proposal currently includes the following 4 grouping strategies, based on the list from ICU:
"never"
(false
): do not display grouping separators."min2"
: display grouping separators when there are at least 2 digits in a group; for example, "1000" (first group too small) and "10,000" (now there are at least 2 digits in that group)."auto"
(default): display grouping separators based on the locale preference, which may also be dependent on the currency. Most locales prefer to use grouping separators."always"
(true
): display grouping separators even if the locale prefers otherwise.@jswalden asked if there could be additional options added. Could you clarify?
In
Line 15 should be infallible, that is: Return ! CollapseNumberRange(result).
Given https://unicode-org.atlassian.net/browse/CLDR-11431, the following is how we could add the approximately pattern to Intl.NumberFormat:
new Intl.NumberFormat({
signDisplay: "approximately"
});
Expected outputs:
Input | en-US result with signDisplay: "approximately" |
---|---|
5 | ~5 |
0 | ~0 |
-0 | -0 |
-5 | -5 |
Alternatively, we could throw RangeError on the negative numbers, since the behavior with them is not well-defined in CLDR.
Related: #6
See tc39/ecma402#128
From @FrankYFTang:
https://github.com/tc39/proposal-intl-numberformat-v3#formatrange-ecma-402-393
const nf = new Intl.NumberFormat("en-US", {
style: "currency",
currency: "EUR",
maximumFractionDigits: 0,
});
nf.formatRangeToParts(3, 5);
/*
[
{type: "currency", value: "β¬", source: "startRange"}
{type: "integer", value: "3", source: "startRange"}
{type: "literal", value: "β", source: "shared"}
{type: "integer", value: "5", source: "endRange"}
]
*/
so nf.formatRange(3,5)
should give us "β¬3 β 5"
but in my prototype now, I got "β¬3 β β¬5" and
nf.formatRangeToParts(3, 5)
return
[{type: "currency", value: "β¬", source: "startRange"},
{type: "integer", value: "3", source: "startRange"},
{type: "literal", value: " β ", source: "shared"},
{type: "currency", value: "β¬", source: "endRange"},
{type: "integer", value: "5", source: "endRange"}]
Any idea what I need to do to make ICU return "β¬3 β 5" instead?
Also, if it return "β¬3 β 5", then the formatRangeToPart should use "shared" for "β¬" instead, as
[
{type: "currency", value: "β¬", source: "shared"}
{type: "integer", value: "3", source: "startRange"}
{type: "literal", value: "β", source: "shared"}
{type: "integer", value: "5", source: "endRange"}
]
right?
Suggestion to add a paragraph such as the following to the README:
In ECMA-402, we receive dozens of feature requests each year. When forming this proposal, the author (Shane F. Carr) considered every feature request relating to Intl.NumberFormat and put them up against the following criteria:
- The feature must have multiple stakeholders.
- The feature must have robust prior art, e.g., in CLDR, ICU, or Unicode.
- The feature must be difficult to implement in user land (such as a locale data dependency).
All parts of this proposal meet that bar, and furthermore, the author's intent is that all Intl.NumberFormat feature requests meeting that bar are part of this proposal.
@zbraniecki SGTY?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
π Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. πππ
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google β€οΈ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.