Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

JavaScript Internationalization with Intl

Learn the ECMAScript Internationalization API: locale negotiation, number and date formatting, comparison, lists, plural rules, relative time, locale identifiers, display names, segmentation, formatter parts, and capability detection.

Levels: Advanced ~60 min read

Advanced

Interactive Runnable example
Edit

Ready to run.

Quick check

What is Intl.NumberFormat responsible for?

const value=1234567.89; const formatted=new Intl.NumberFormat("en-US").format(value); console.log(formatted); document.querySelector("#output").textContent=formatted;
Interactive Runnable example
Edit

Ready to run.

Quick check

Which option selects currency formatting?

const formatted=new Intl.NumberFormat("en-US",{style:"currency",currency:"USD"}).format(1234.5); console.log(formatted); document.querySelector("#output").textContent=formatted;
Interactive Runnable example
Edit

Ready to run.

Quick check

What does percent style do?

const formatted=new Intl.NumberFormat("en-US",{style:"percent"}).format(0.256); console.log(formatted); document.querySelector("#output").textContent=formatted;
Interactive Runnable example
Edit

Ready to run.

Quick check

Why is timeZone specified here?

const date=new Date("2026-09-27T12:30:00Z"); const formatted=new Intl.DateTimeFormat("en-US",{dateStyle:"medium",timeZone:"UTC"}).format(date); console.log(formatted); document.querySelector("#output").textContent=formatted;
Interactive Runnable example
Edit

Ready to run.

Quick check

What does Collator provide?

const collator=new Intl.Collator("en",{sensitivity:"base"}); const result=collator.compare("resume","résumé"); console.log(result); document.querySelector("#output").textContent=String(result);
Interactive Runnable example
Edit

Ready to run.

Quick check

What does ListFormat solve?

const formatted=new Intl.ListFormat("en",{style:"long",type:"conjunction"}).format(["HTML","CSS","JavaScript"]); console.log(formatted); document.querySelector("#output").textContent=formatted;
Interactive Runnable example
Edit

Ready to run.

Quick check

What does PluralRules.select return?

const rules=new Intl.PluralRules("en"); const categories=[1,2,5].map(n=>rules.select(n)); console.log(categories); document.querySelector("#output").textContent=categories.join(", ");
Interactive Runnable example
Edit

Ready to run.

Quick check

What is RelativeTimeFormat for?

const formatted=new Intl.RelativeTimeFormat("en",{numeric:"auto"}).format(-1,"day"); console.log(formatted); document.querySelector("#output").textContent=formatted;
Interactive Runnable example
Edit

Ready to run.

Quick check

What does Intl.Locale represent?

const locale=new Intl.Locale("ar-EG"); const result={baseName:locale.baseName,language:locale.language,region:locale.region}; console.log(result); document.querySelector("#output").textContent=JSON.stringify(result);
Interactive Runnable example
Edit

Ready to run.

Quick check

What does supportedLocalesOf report?

const requested=["fr-FR","xx-XX"]; const supported=Intl.NumberFormat.supportedLocalesOf(requested); console.log(supported); document.querySelector("#output").textContent=JSON.stringify(supported);
Interactive Runnable example
Edit

Ready to run.

Quick check

Why use formatToParts?

const parts=new Intl.NumberFormat("en-US",{style:"currency",currency:"USD"}).formatToParts(1234.5); console.log(parts); document.querySelector("#output").textContent=parts.map(p=>p.type+":"+p.value).join(" | ");
Interactive Runnable example
Edit

Ready to run.

Quick check

What does resolvedOptions provide?

const formatter=new Intl.NumberFormat("de-DE",{style:"currency",currency:"EUR"}); const options=formatter.resolvedOptions(); console.log(options); document.querySelector("#output").textContent=JSON.stringify({locale:options.locale,numberingSystem:options.numberingSystem,currency:options.currency});
Interactive Runnable example
Edit

Ready to run.

Quick check

What does DisplayNames do here?

const formatter=new Intl.DisplayNames("en",{type:"language"}); const result=formatter.of("fr"); console.log(result); document.querySelector("#output").textContent=result;
Interactive Runnable example
Edit

Ready to run.

Quick check

What does Segmenter provide?

const segmenter=new Intl.Segmenter("en",{granularity:"word"}); const segments=[...segmenter.segment("Foxipa teaches JavaScript")].map(x=>x.segment); console.log(segments); document.querySelector("#output").textContent=segments.join(" | ");
Interactive Runnable example
Edit

Ready to run.

Quick check

What should code do when a newer Intl service is unavailable?

const output=document.querySelector("#output"); if(typeof Intl.DurationFormat!=="function"){output.textContent="Intl.DurationFormat is not available in this runtime.";}else{const f=new Intl.DurationFormat("en",{style:"long"}); const result=f.format({hours:2,minutes:30}); console.log(result); output.textContent=result;}
Interactive Runnable example
Edit

Ready to run.

Quick check

Why reuse a formatter instance?

const formatter=new Intl.NumberFormat("en-US",{maximumFractionDigits:2}); const values=[12.3,4567.89,0.125]; const results=values.map(formatter.format,formatter); console.log(results); document.querySelector("#output").textContent=results.join(" | ");

The Intl model

ECMA-402 defines the ECMAScript Internationalization API as a family of locale-sensitive services. Intl services do not translate arbitrary application prose for you; they format, compare, segment, or expose localized representations according to standardized locale identifiers and service-specific options. The actual locale data is implementation-provided within the specification constraints, so exact punctuation, symbols, names, and wording can vary by locale and runtime.

Locale negotiation is part of the API

Most Intl constructors accept a locale or locale list plus options. The implementation resolves the requested locales against supported locale data. Use supportedLocalesOf when you need to test support explicitly, and resolvedOptions when you need to inspect the effective configuration.

Formatting is presentation, not data mutation

Intl.NumberFormat and Intl.DateTimeFormat return strings for presentation. They do not change the underlying Number or Date value. Prefer keeping application data in its semantic form and formatting it at the presentation boundary.

Use parts when markup or semantics matter

formatToParts lets applications inspect typed pieces of a localized result. This is useful when a UI needs to style, annotate, or otherwise structure portions of a formatted value without hard-coding locale-specific punctuation or ordering.

Authoring rules

Prefer Intl services over hand-written locale rules. Do not assume comma/period conventions, month names, plural categories, list punctuation, or word boundaries are universal. Keep locale-sensitive presentation at the boundary, preserve the original data, reuse formatter instances when appropriate, and feature-detect services whose availability may vary across runtimes.

Complete the ECMA-402 service surface

The core Intl constructors are only part of the API. ECMA-402 also provides locale canonicalization and capability discovery, range formatting, richer formatter options, plural ranges, locale metadata, and structured formatter output. These belong to the Intl lesson because they are part of the same internationalization service model. This section focuses on observable API behavior rather than reproducing the specification algorithms.

Interactive Runnable example
Edit

Ready to run.

Quick check

What does Intl.getCanonicalLocales return?

const result=Intl.getCanonicalLocales(["EN-us","fr-fr"]); console.log(result); document.querySelector("#output").textContent=result.join(" | ");
Interactive Runnable example
Edit

Ready to run.

Quick check

What is Intl.supportedValuesOf for?

const keys=["calendar","currency","timeZone","numberingSystem","language"]; const result=Object.fromEntries(keys.map(k=>[k,Intl.supportedValuesOf(k).slice(0,4)])); console.log(result); document.querySelector("#output").textContent=JSON.stringify(result);
Interactive Runnable example
Edit

Ready to run.

Quick check

What does DateTimeFormat.formatRange do?

const f=new Intl.DateTimeFormat("en-US",{dateStyle:"medium",timeZone:"UTC"}); const result=f.formatRange(new Date("2026-09-27T00:00:00Z"),new Date("2026-09-30T00:00:00Z")); console.log(result); document.querySelector("#output").textContent=result;
Interactive Runnable example
Edit

Ready to run.

Quick check

Why use formatRangeToParts?

const f=new Intl.DateTimeFormat("en-US",{dateStyle:"medium",timeZone:"UTC"}); const parts=f.formatRangeToParts(new Date("2026-09-27T00:00:00Z"),new Date("2026-09-30T00:00:00Z")); console.log(parts); document.querySelector("#output").textContent=parts.map(p=>`${p.type}:${p.value}`).join(" | ");
Interactive Runnable example
Edit

Ready to run.

Quick check

What does notation:"compact" control?

const f=new Intl.NumberFormat("en-US",{notation:"compact",maximumFractionDigits:1}); const result=f.format(1234567); console.log(result); document.querySelector("#output").textContent=result;
Interactive Runnable example
Edit

Ready to run.

Quick check

Which NumberFormat options select unit formatting?

const f=new Intl.NumberFormat("en-US",{style:"unit",unit:"kilometer-per-hour",unitDisplay:"long"}); const result=f.format(88); console.log(result); document.querySelector("#output").textContent=result;
Interactive Runnable example
Edit

Ready to run.

Quick check

What is roundingMode responsible for?

const f=new Intl.NumberFormat("en-US",{maximumFractionDigits:0,roundingMode:"halfExpand"}); const result=f.format(2.5); console.log(result); document.querySelector("#output").textContent=result;
Interactive Runnable example
Edit

Ready to run.

Quick check

What do NumberFormat range methods provide?

const f=new Intl.NumberFormat("en-US"); const result=f.formatRange(1200,1500); const parts=f.formatRangeToParts(1200,1500); console.log(result,parts); document.querySelector("#output").textContent=result+"\n"+parts.map(p=>p.type+":"+p.value).join(" | ");
Interactive Runnable example
Edit

Ready to run.

Quick check

How does PluralRules.selectRange differ from select?

const rules=new Intl.PluralRules("en"); const result=rules.selectRange(1,2); console.log(result); document.querySelector("#output").textContent=result;
Interactive Runnable example
Edit

Ready to run.

Quick check

Why use RelativeTimeFormat.formatToParts?

const f=new Intl.RelativeTimeFormat("en",{numeric:"always"}); const parts=f.formatToParts(-3,"day"); console.log(parts); document.querySelector("#output").textContent=parts.map(p=>p.type+":"+p.value).join(" | ");
Interactive Runnable example
Edit

Ready to run.

Quick check

What does DurationFormat.formatToParts provide?

const f=new Intl.DurationFormat("en",{style:"long"}); if(typeof f.formatToParts!=="function"){document.querySelector("#output").textContent="formatToParts unavailable";}else{const parts=f.formatToParts({hours:2,minutes:30}); console.log(parts); document.querySelector("#output").textContent=parts.map(p=>p.type+":"+p.value).join(" | ");}
Interactive Runnable example
Edit

Ready to run.

Quick check

What does Intl.Locale provide?

const locale=new Intl.Locale("en-US"); const result={base:locale.baseName,language:locale.language,region:locale.region,calendar:locale.calendar,numberingSystem:locale.numberingSystem}; console.log(result); document.querySelector("#output").textContent=JSON.stringify(result);
Interactive Runnable example
Edit

Ready to run.

Quick check

What do maximize() and minimize() do?

const locale=new Intl.Locale("en-Latn"); const result={max:locale.maximize().toString(),min:locale.minimize().toString()}; console.log(result); document.querySelector("#output").textContent=JSON.stringify(result);
Interactive Runnable example
Edit

Ready to run.

Quick check

Why use Locale getter methods such as getCalendars()?

const locale=new Intl.Locale("en-US"); const result={calendars:locale.getCalendars(),collations:locale.getCollations(),hourCycles:locale.getHourCycles(),numberingSystems:locale.getNumberingSystems()}; console.log(result); document.querySelector("#output").textContent=JSON.stringify(result);
Interactive Runnable example
Edit

Ready to run.

Quick check

What does Segmenter.resolvedOptions() tell you?

const segmenter=new Intl.Segmenter("en",{granularity:"word"}); const options=segmenter.resolvedOptions(); console.log(options); document.querySelector("#output").textContent=JSON.stringify(options);

What remains implementation-dependent

ECMA-402 specifies API behavior but intentionally permits variation in supported locales, localized data, and some locale-dependent presentation details. Code should therefore depend on the API contract and feature detection, not on one machine’s exact punctuation, month names, numbering data, or locale inventory.

Was this page helpful?

Mark this learning resource complete to track your learning progress.