Repository navigation
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Test I ran
node intl.ts
slice run intl.tsintl.ts
const show = async (k: string, f: () => unknown) => { let v; try { v = await Promise.race([Promise.resolve().then(f), new Promise((r) => setTimeout(() => r("NEVER SETTLED (2000 ms)"), 2000))]); } catch (e: any) { v = "THROWS " + e.name + ": " + String(e.message).slice(0, 100); } console.log(k.padEnd(52) + JSON.stringify(v)); };
(async () => {
await show("Intl.NumberFormat en-US 1234567.891", () => new Intl.NumberFormat("en-US").format(1234567.891));
await show("Intl.NumberFormat de-DE EUR", () => new Intl.NumberFormat("de-DE", { style: "currency", currency: "EUR" }).format(1234.5));
await show("Intl.NumberFormat percent", () => new Intl.NumberFormat("en-US", { style: "percent", maximumFractionDigits: 1 }).format(0.1234));
await show("Intl.NumberFormat compact", () => new Intl.NumberFormat("en-US", { notation: "compact" }).format(1234567));
await show("Intl.DateTimeFormat en-US UTC medium/short", () => new Intl.DateTimeFormat("en-US", { timeZone: "UTC", dateStyle: "medium", timeStyle: "short" }).format(new Date(0)));
await show("Intl.DateTimeFormat Asia/Tokyo", () => new Intl.DateTimeFormat("en-US", { timeZone: "Asia/Tokyo", hour: "numeric", minute: "2-digit", hour12: false }).format(new Date(0)));
await show("Date#toLocaleDateString en-US UTC", () => new Date(0).toLocaleDateString("en-US", { timeZone: "UTC" }));
await show("Date#toLocaleString de-DE UTC", () => new Date(0).toLocaleString("de-DE", { timeZone: "UTC" }));
await show("Intl.PluralRules en cardinal/ordinal", () => [new Intl.PluralRules("en-US").select(1), new Intl.PluralRules("en-US", { type: "ordinal" }).select(2), new Intl.PluralRules("ar").select(3)]);
await show("Intl.Collator('de') sort", () => ["b", "a", "ä", "z"].sort(new Intl.Collator("de").compare));
await show("Intl.Collator numeric", () => ["a10", "a2", "a1"].sort(new Intl.Collator("en", { numeric: true }).compare));
await show("Intl.Segmenter grapheme", () => [...new Intl.Segmenter("en", { granularity: "grapheme" }).segment("a👍🏽é")].map((s) => s.segment));
await show("Intl.Segmenter word", () => [...new Intl.Segmenter("en", { granularity: "word" }).segment("Hi there, you")].filter((s) => s.isWordLike).map((s) => s.segment));
await show("(1234.5).toLocaleString('en-US')", () => (1234.5).toLocaleString("en-US"));
await show("(1e21).toLocaleString('en-US')", () => (1e21).toLocaleString("en-US"));
await show("(1234567.891).toLocaleString('de-DE')", () => (1234567.891).toLocaleString("de-DE"));
await show("'a'.localeCompare('B','en',{sensitivity:'base'})", () => ["a".localeCompare("B", "en", { sensitivity: "base" }), "a".localeCompare("A", "en", { sensitivity: "base" })]);
})();Result
Node v24.22.2:
Intl.NumberFormat en-US 1234567.891 "1,234,567.891"
Intl.NumberFormat de-DE EUR "1.234,50 €"
Intl.NumberFormat percent "12.3%"
Intl.NumberFormat compact "1.2M"
Intl.DateTimeFormat en-US UTC medium/short "Jan 1, 1970, 12:00 AM"
Intl.DateTimeFormat Asia/Tokyo "09:00"
Date#toLocaleDateString en-US UTC "1/1/1970"
Date#toLocaleString de-DE UTC "1.1.1970, 00:00:00"
Intl.PluralRules en cardinal/ordinal ["one","two","few"]
Intl.Collator('de') sort ["a","ä","b","z"]
Intl.Collator numeric ["a1","a2","a10"]
Intl.Segmenter grapheme ["a","👍🏽","é"]
Intl.Segmenter word ["Hi","there","you"]
(1234.5).toLocaleString('en-US') "1,234.5"
(1e21).toLocaleString('en-US') "1,000,000,000,000,000,000,000"
(1234567.891).toLocaleString('de-DE') "1.234.567,891"
'a'.localeCompare('B','en',{sensitivity:'base'}) [-1,0]
Slice v0.10.7:
Intl.NumberFormat en-US 1234567.891 "1,234,567.891"
Intl.NumberFormat de-DE EUR "€1,234.50"
Intl.NumberFormat percent "12.3%"
Intl.NumberFormat compact "1.2M"
Intl.DateTimeFormat en-US UTC medium/short "Jan 1, 1970, 0:00"
Intl.DateTimeFormat Asia/Tokyo "0:00"
Date#toLocaleDateString en-US UTC "1/1/1970"
Date#toLocaleString de-DE UTC "1/1/1970, 0:00:00"
Intl.PluralRules en cardinal/ordinal ["one","two","other"]
Intl.Collator('de') sort ["a","b","z","ä"]
Intl.Collator numeric ["a1","a2","a10"]
Intl.Segmenter grapheme ["a","👍","🏽","é"]
Intl.Segmenter word ["Hi","there","you"]
(1234.5).toLocaleString('en-US') "1,234.5"
(1e21).toLocaleString('en-US') "1e,+21"
(1234567.891).toLocaleString('de-DE') "1,234,567.891"
'a'.localeCompare('B','en',{sensitivity:'base'}) [-1,0]
What is wrong
| Call | Slice | Expected |
|---|---|---|
NumberFormat("de-DE", {style:"currency",currency:"EUR"}).format(1234.5) |
€1,234.50 |
1.234,50 € |
(1234567.891).toLocaleString("de-DE") |
1,234,567.891 |
1.234.567,891 |
DateTimeFormat("en-US", {timeZone:"Asia/Tokyo", hour, minute}) of epoch 0 |
0:00 |
09:00 |
DateTimeFormat("en-US", {timeZone:"UTC", dateStyle:"medium", timeStyle:"short"}) |
Jan 1, 1970, 0:00 |
Jan 1, 1970, 12:00 AM |
new Date(0).toLocaleString("de-DE", {timeZone:"UTC"}) |
1/1/1970, 0:00:00 |
1.1.1970, 00:00:00 |
new Intl.PluralRules("ar").select(3) |
other |
few |
["b","a","ä","z"].sort(new Intl.Collator("de").compare) |
a, b, z, ä |
a, ä, b, z |
Segmenter grapheme on "a👍🏽é" |
splits the emoji from its skin-tone modifier | one grapheme |
(1e21).toLocaleString("en-US") |
1e,+21 |
1,000,000,000,000,000,000,000 |
The locale argument and the timeZone option are accepted and then have no effect. The time-zone case is the most serious because the result looks plausible: a timestamp formatted for Asia/Tokyo is shown in UTC with no error.
COMPATIBILITY.md lists Intl (DateTimeFormat, NumberFormat, Collator, PluralRules, Segmenter) as "100% Supported" via a "Zero-ICU-bloat deterministic Intl fast-path shard". If shipping without locale and tz data is intentional, the matrix should say that only en-US / UTC are implemented, and unsupported locales or zones should throw RangeError rather than silently format as en-US / UTC.
Environment
- Slice
v0.10.7, commitea7c70c, built withcargo +1.96.0 build --release --locked --bin slice - Reference: Node.js
v24.22.2(same script, same machine) - Ubuntu 26.04, Linux 7.0, x86_64
- The same output is produced by the
v0.10.5tag, so this is not a regression in 0.10.6/0.10.7.
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working
Activity
siktec-lab commentedon Nov 11, 2026
Addressed in #67 (�0.10.11): upgraded Intl in 18_intl.js with scientific-notation expansion (>= 1e21) and locale separators/currency placement in NumberFormat, IANA timezone offsets/DST and RangeError validation in DateTimeFormat, CLDR cardinal/ordinal rules (�r,
u, pl, r, en, etc.) in PluralRules, Unicode Latin diacritic/umlaut sorting in Collator, and UAX #29 grapheme cluster segmentation (emoji skin-tone modifiers, ZWJ, flags, CRLF) in Segmenter.