Introduction
This specification's source can be found at https://github.com/tc39/ecma402.
The ECMAScript 2027 Internationalization API Specification (ECMA-402 14th Edition), provides key language sensitive functionality as a complement to ECMA-262. Its functionality has been selected from that of well-established internationalization APIs such as those of the Internationalization Components for Unicode (ICU) library (https://unicode-org.github.io/icu-docs/), of the .NET framework, or of the Java platform.
The 1st Edition API was developed by an ad-hoc group established by Ecma TC39 in September 2010 based on a proposal by Nebojša Ćirić and Jungshik Shin.
The 2nd Edition API was adopted by the General Assembly of June 2015, as a complement to the ECMAScript 6th Edition.
The 3rd Edition API was the first edition released under Ecma TC39's new yearly release cadence and open development process. A plain-text source document was built from the ECMA-402 source document to serve as the base for further development entirely on GitHub. Over the year of this standard's development, dozens of pull requests and issues were filed representing several of bug fixes, editorial fixes and other improvements. Additionally, numerous software tools were developed to aid in this effort including Ecmarkup, Ecmarkdown, and Grammarkdown.
Dozens of individuals representing many organizations have made very significant contributions within Ecma TC39 to the development of this edition and to the prior editions. In addition, a vibrant community has emerged supporting TC39's ECMAScript efforts. This community has reviewed numerous drafts, filed dozens of bug reports, performed implementation experiments, contributed test suites, and educated the world-wide developer community about ECMAScript Internationalization. Unfortunately, it is impossible to identify and acknowledge every person and organization who has contributed to this effort.
Norbert Lindenberg
ECMA-402, 1st Edition Project Editor
Rick Waldron
ECMA-402, 2nd Edition Project Editor
Caridy Patiño
ECMA-402, 3rd, 4th and 5th Editions Project Editor
Caridy Patiño, Daniel Ehrenberg, Leo Balter
ECMA-402, 6th Edition Project Editors
Leo Balter, Valerie Young, Isaac Durazo
ECMA-402, 7th Edition Project Editors
Leo Balter, Richard Gibson
ECMA-402, 8th Edition Project Editors
Leo Balter, Richard Gibson, Ujjwal Sharma
ECMA-402, 9th Edition Project Editors
Richard Gibson, Ujjwal Sharma
ECMA-402, 10th Edition Project Editors
Richard Gibson, Ujjwal Sharma
ECMA-402, 11th Edition Project Editors
Ben Allen, Richard Gibson, Ujjwal Sharma
ECMA-402, 12th Edition Project Editors
Ben Allen, Richard Gibson, Ujjwal Sharma
ECMA-402, 13th Edition Project Editors
Ben Allen, Richard Gibson, Ujjwal Sharma
ECMA-402, 14th Edition Project Editors
4 Overview
This section is non-normative.
4.1 Internationalization, Localization, and Globalization
Internationalization of software means designing it such that it supports or can be easily adapted to support the needs of users speaking different languages and having different cultural expectations, and enables worldwide communication between them. Localization then is the actual adaptation to a specific language and culture. Globalization of software is commonly understood to be the combination of internationalization and localization. Globalization starts at the lowest level by using a text representation that supports all languages in the world, and using standard identifiers to identify languages, countries, time zones, and other relevant parameters. It continues with using a user interface language and data presentation that the user understands, and finally often requires product-specific adaptations to the user's language, culture, and environment.
ECMA-262 lays the foundation by using Unicode for text representation and by providing a few language-sensitive functions, but gives applications little control over the behaviour of these functions. This specification builds on that foundation by providing a set of customizable language-sensitive functionality. The API is useful even for applications that themselves are not internationalized, as even applications targeting only one language and one region need to properly support that one language and region. However, the API also enables applications that support multiple languages and regions, even concurrently, as may be needed in server environments.
4.2 API Overview
This specification is designed to complement ECMA-262 by providing key language-sensitive functionality, and can be added to an implementation thereof in whole or in part. This specification introduces new language values observable to ECMAScript code (such as the value of a [[FallbackSymbol]] internal slot and the set of values transitively reachable from %Intl% by property access), and also refines the definition of some functions specified in ECMA-262 (as described below). Neither category prohibits behaviour that is otherwise permitted for values and interfaces defined in ECMA-262, in order to support adoption of this specification by any implementation.
This specification provides several key pieces of language-sensitive functionality that are required in most applications: locale selection and inspection, string comparison (collation) and case conversion, pluralization rules, text segmentation, and formatting of numbers, absolute and relative dates and times, durations, and lists. While ECMA-262 provides functions for this basic functionality (on Array.prototype: toLocaleString; on String.prototype: localeCompare, toLocaleLowerCase, toLocaleUpperCase; on Number.prototype: toLocaleString; on Date.prototype: toLocaleString, toLocaleDateString, and toLocaleTimeString), their actual behaviour is left largely implemenation-defined. This specification provides additional functionality, control over the language and over details of the behaviour to be used, and a more complete specification of required functionality.
Applications can use the API in two ways:
-
Directly, by using a service constructor to construct an object, specifying a list of preferred languages and options to configure its behaviour. The object provides a main function (
compare, select, format, etc.), which can be called repeatedly. It also provides a resolvedOptions function, which the application can use to find out the exact configuration of the object.
-
Indirectly, by using the functions of ECMA-262 mentioned above. The collation and formatting functions are respecified in this specification to accept the same arguments as the Collator, NumberFormat, and DateTimeFormat constructors and produce the same results as their compare or format methods. The case conversion functions are respecified to accept a list of preferred languages.
The Intl object is used to package all functionality defined in this specification in order to avoid name collisions.
NoteWhile the API includes a variety of formatters, it does not provide any parsing facilities. This is intentional, has been discussed extensively, and concluded after weighing in all the benefits and drawbacks of including said functionality. See the discussion on the
issue tracker.
4.3 API Conventions
Every Intl constructor should behave as if defined by a class, throwing a TypeError exception when called as a function (without NewTarget). For backwards compatibility with past editions, this does not apply to %Intl.Collator%, %Intl.DateTimeFormat%, or %Intl.NumberFormat%, each of which construct and return a new object when called as a function.
Note
In ECMA 402 v1, Intl
constructors supported a mode of operation where calling them with an existing object as a receiver would add relevant internal slots to the receiver, effectively transforming it into an instance of the class. In ECMA 402 v2, this capability was removed, to avoid adding internal slots to existing objects. In ECMA 402 v3, the capability was re-added as "normative optional" in a mode which chains the underlying Intl instance on any object, when the
constructor is called. See
Issue 57 for details.
4.4 Implementation Dependencies
Due to the nature of internationalization, this specification has to leave several details implementation dependent:
-
The set of locales that an implementation supports with adequate localizations: Linguists have described thousands of human languages, with the IANA Language Subtag Registry containing over 7000 primary language subtags (used as the base for locale identifiers). Even large locale data collections, such as the Common Locale Data Repository, cover only a tiny subset of all languages and their regional or dialectical variations. Implementations targeting resource-constrained devices may have to further reduce the subset.
-
The exact form of localizations such as format patterns: In many cases locale-dependent conventions are not standardized, so different forms may exist side by side, or they vary over time. Different internationalization libraries may have implemented different forms, without any of them being actually wrong. In order to allow this API to be implemented on top of existing libraries, such variations have to be permitted.
-
Subsets of Unicode: Some operations, such as collation, operate on strings that can include characters from the entire Unicode character set. However, both the Unicode Standard and the ECMAScript standard allow implementations to limit their functionality to subsets of the Unicode character set. In addition, locale conventions typically don't specify the desired behaviour for the entire Unicode character set, but only for those characters that are relevant for the locale. While the Unicode Collation Algorithm combines a default collation order for the entire Unicode character set with the ability to tailor for local conventions, subsets and tailorings still result in differences in behaviour.
In browser implementations the initial set of locales, currencies, calendars, numbering systems, and other enumerable items visible to a particular origin must be the same for all users sharing the same user agent string (engine and platform version). Furthermore, dynamic changes to these sets must not result in users becoming distinguishable from each other. This constraint is imposed to reduce the fingerprinting risk inherent in internationalization, and may be relaxed in future revisions. As a result of this constraint, the first time a browser implementation that allows on-demand locale installation receives a request from a particular origin that could require installing a new locale, it must not reveal whether or not that locale is already installed.
Throughout this specification, implementation- and locale-dependent behaviour is referred to as ILD, and implementation-, locale-, and numbering system-dependent behaviour is referred to as ILND.
4.4.1 Compatibility across implementations
ECMA 402 describes the schema of the data used by its functions. The
data contained inside is implementation-dependent, and expected to
change over time and vary between implementations. The variation is
visible by programmers, and it is possible to construct programs which
will depend on a particular output. However, this specification
attempts to describe reasonable constraints which will allow
well-written programs to function across implementations.
Implementations are encouraged to continue their efforts to harmonize
linguistic data.
6 Identification of Locales, Currencies, Time Zones, Measurement Units, Numbering Systems, Collations, and Calendars
This clause describes the String values used in this specification to identify locales, currencies, time zones, measurement units, numbering systems, collations, calendars, and pattern strings.
6.1 Case Sensitivity and Case Mapping
The String values used to identify locales, currencies, scripts, and time zones are interpreted in an ASCII-case-insensitive manner, treating the code units 0x0041 through 0x005A (corresponding to Unicode characters LATIN CAPITAL LETTER A through LATIN CAPITAL LETTER Z) as equivalent to the corresponding code units 0x0061 through 0x007A (corresponding to Unicode characters LATIN SMALL LETTER A through LATIN SMALL LETTER Z), both inclusive. No other case folding equivalences are applied.
Note
For example, "ß" (U+00DF) must not match or be mapped to "SS" (U+0053, U+0053). "ı" (U+0131) must not match or be mapped to "I" (U+0049).
The ASCII-uppercase of a String value string is the String value derived from string by replacing each occurrence of an ASCII lowercase letter code unit (0x0061 through 0x007A, inclusive) with the corresponding ASCII uppercase letter code unit (0x0041 through 0x005A, inclusive) while preserving all other code units.
The ASCII-lowercase of a String value string is the String value derived from string by replacing each occurrence of an ASCII uppercase letter code unit (0x0041 through 0x005A, inclusive) with the corresponding ASCII lowercase letter code unit (0x0061 through 0x007A, inclusive) while preserving all other code units.
A String value A is an ASCII-case-insensitive match for String value B if the ASCII-uppercase of A is exactly the same sequence of code units as the ASCII-uppercase of B. A sequence of Unicode code points A is an ASCII-case-insensitive match for B if B is an ASCII-case-insensitive match for CodePointsToString(A).
6.2 Language Tags
This specification identifies locales using Unicode BCP 47 locale identifiers as defined by Unicode Technical Standard #35 Part 1 Core, Section 3.3 BCP 47 Conformance, and its algorithms refer to Unicode locale nonterminals defined in the grammars of Section 3 Unicode Language and Locale Identifiers.
Each such identifier can also be referred to as a language tag, and is in fact a valid language tag as that term is used in BCP 47.
A locale identifier in canonical form as specified in Unicode Technical Standard #35 Part 1 Core, Section 3.2.1 Canonical Unicode Locale Identifiers is referred to as a "Unicode canonicalized locale identifier".
Locale identifiers consist of case-insensitive Unicode Basic Latin alphanumeric subtags separated by "-" (U+002D HYPHEN-MINUS) characters, with single-character subtags referred to as "singleton subtags".
Unicode Technical Standard #35 Part 1 Core, Section 3.6 Unicode BCP 47 U Extension subtag sequences are used extensively, and the term "Unicode locale extension sequence" describes the longest substring of a language tag that can be matched by the unicode_locale_extensions Unicode locale nonterminal and is not part of a "-x-…" private use subtag sequence. It starts with "-u-" and includes all immediately following subtags that are not singleton subtags, along with their preceding "-" separators. For example, the Unicode locale extension sequence of "en-US-u-fw-mon-x-u-ex-foobar" is "-u-fw-mon".
All well-formed language tags are appropriate for use with the APIs defined by this specification, but implementations are not required to use Unicode Common Locale Data Repository (CLDR) data for validating them; the set of locales and thus language tags that an implementation supports with adequate localizations is implementation-defined. Intl constructors map requested language tags to locales supported by their respective implementations.
6.2.1 IsWellFormedLanguageTag ( locale )
The abstract operation IsWellFormedLanguageTag takes argument locale (a String) and returns a Boolean. It determines whether locale is a well-formed language tag conforming with the well-formedness constraints of a unicode_bcp47_locale_id. It does not consider whether locale conveys any meaningful semantics, nor does it differentiate between aliased subtags and their preferred replacement subtags or require canonical casing or subtag ordering. It performs the following steps when called:
- Let lowerLocale be the ASCII-lowercase of locale.
- If lowerLocale cannot be matched by the
unicode_locale_id Unicode locale nonterminal, return false. - If lowerLocale uses any of the backwards compatibility syntax described in Unicode Technical Standard #35 Part 1 Core, Section 3.3 BCP 47 Conformance, return false.
- Let baseName be GetLocaleBaseName(lowerLocale).
- Let variants be GetLocaleVariants(baseName).
- If variants is not undefined, then
- If variants contains any duplicate subtags, return false.
- Let extensions be the suffix of lowerLocale following baseName.
- NOTE: A "-x-…" private use subtag sequence matched by the
pu_extensions Unicode locale nonterminal must be ignored, but an isolated final "x" subtag with no following content does not affect any of the below checks. - Let puIndex be StringIndexOf(extensions, "-x-", 0).
- If puIndex is not not-found, set extensions to the substring of extensions from 0 to puIndex.
- If extensions is not the empty String, then
- If extensions contains any duplicate singleton subtags, return false.
- Let transformExtension be the longest substring of extensions matched by the
transformed_extensions Unicode locale nonterminal. If there is no such substring, return true. - Assert: The substring of transformExtension from 0 to 3 is "-t-".
- Let tPrefix be the substring of transformExtension from 3.
- Let tlang be the longest prefix of tPrefix matched by the
tlang Unicode locale nonterminal. If there is no such prefix, return true. - Let tlangVariants be GetLocaleVariants(tlang).
- If tlangVariants is not undefined, then
- If tlangVariants contains any duplicate subtags, return false.
- Return true.
6.2.2 CanonicalizeUnicodeLocaleId ( locale )
The abstract operation CanonicalizeUnicodeLocaleId takes argument locale (a language tag) and returns a Unicode canonicalized locale identifier. It returns the canonical and case-regularized form of locale. It performs the following steps when called:
- Let localeId be the String value resulting from performing the Processing LocaleIds algorithm to transform locale to canonical form per Unicode Technical Standard #35 Part 1 Core, Annex C LocaleId Canonicalization.
- If localeId contains a substring that is a Unicode locale extension sequence, then
- Let extension be the String value consisting of the substring of the Unicode locale extension sequence within localeId.
- Let newExtension be "-u".
- Let components be UnicodeExtensionComponents(extension).
- For each element attr of components.[[Attributes]], do
- Set newExtension to the string-concatenation of newExtension, "-", and attr.
- For each Record { [[Key]], [[Value]] } keyword of components.[[Keywords]], do
- Set newExtension to the string-concatenation of newExtension, "-", and keyword.[[Key]].
- If keyword.[[Value]] is not the empty String, then
- Set newExtension to the string-concatenation of newExtension, "-", and keyword.[[Value]].
- Assert: newExtension is not "-u".
- Set localeId to a copy of localeId in which the first appearance of substring extension has been replaced with newExtension.
- Return localeId.
Note
Step
2 ensures that a
Unicode locale extension sequence in the returned
language tag contains:
- only the first instance of any attribute duplicated in the input, and
- only the first keyword for a given key in the input.
6.2.3 DefaultLocale ( )
The implementation-defined abstract operation DefaultLocale takes no arguments and returns a Unicode canonicalized locale identifier. The returned String value represents the well-formed (6.2.1) and canonicalized (6.2.2) language tag for the host environment's current locale. It must not contain a Unicode locale extension sequence.
Note
The returned value is is a potential fingerprinting vector. In browser environments, it should match
navigator.language to avoid providing any additional distinguishing information.
6.3 Currency Codes
This specification identifies currencies using 3-letter currency codes as defined by ISO 4217. Their canonical form is uppercase.
All well-formed 3-letter ISO 4217 currency codes are allowed. However, the set of combinations of currency code and language tag for which localized currency symbols are available is implementation dependent. Where a localized currency symbol is not available, the ISO 4217 currency code is used for formatting.
6.3.1 IsWellFormedCurrencyCode ( currency )
The abstract operation IsWellFormedCurrencyCode takes argument currency (a String) and returns a Boolean. It verifies that the currency argument represents a well-formed 3-letter ISO 4217 currency code. It performs the following steps when called:
- If the length of currency is not 3, return false.
- Let normalized be the ASCII-uppercase of currency.
- If normalized contains any code unit outside of 0x0041 through 0x005A (corresponding to Unicode characters LATIN CAPITAL LETTER A through LATIN CAPITAL LETTER Z), return false.
- Return true.
6.4 AvailableCanonicalCurrencies ( )
The implementation-defined abstract operation AvailableCanonicalCurrencies takes no arguments and returns a List of Strings. The returned List is sorted according to lexicographic code unit order, and contains unique, well-formed, and upper case canonicalized 3-letter ISO 4217 currency codes, identifying the currencies for which the implementation provides the functionality of Intl.DisplayNames and Intl.NumberFormat objects.
6.5 Use of the IANA Time Zone Database
Implementations that adopt this specification must be time zone aware: they must use the IANA Time Zone Database https://www.iana.org/time-zones/ to supply available named time zone identifiers and data used in ECMAScript calculations and formatting.
This section defines how the IANA Time Zone Database should be used by time zone aware implementations.
No String may be an available named time zone identifier unless it is a Zone name or a Link name in the IANA Time Zone Database.
Available named time zone identifiers returned by ECMAScript built-in objects must use the casing found in the IANA Time Zone Database.
Each Zone in the IANA Time Zone Database must be a primary time zone identifier and each Link name in the IANA Time Zone Database must be a non-primary time zone identifier that resolves to its corresponding Zone name, with the following exceptions implemented in AvailableNamedTimeZoneIdentifiers:
-
For historical reasons, "UTC" must be a primary time zone identifier.
"Etc/UTC", "Etc/GMT", and "GMT", as well as all Link names that resolve to any of them, must be non-primary time identifiers that resolve to "UTC".
-
Any Link name that is present in the “TZ” column of file
zone.tab must be a primary time zone identifier.
For example, both "Europe/Prague" and "Europe/Bratislava" must be primary time zone identifiers.
This requirement guarantees at least one primary time zone identifier for each ISO 3166-1 Alpha-2 country code, and ensures that future changes to time zone rules of one country will not affect ECMAScript programs that use another country's time zone(s), unless those countries' territorial boundaries have also changed.
-
Any Link name that is not listed in the “TZ” column of file
zone.tab and that represents a geographical area entirely contained within the territory of a single ISO 3166-1 Alpha-2 country code must resolve to a primary identifier that also represents a geographical area entirely contained within the territory of the same country code.
For example, "Atlantic/Jan_Mayen" must resolve to "Arctic/Longyearbyen".
Note
The IANA Time Zone Database offers build options that affect which available named time zone identifiers are primary.
The default build options merge different countries' time zones, for example "Atlantic/Reykjavik" is built as a Link to the Zone "Africa/Abidjan".
Geographically and politically distinct locations are likely to introduce divergent time zone rules in a future version of the IANA Time Zone Database.
The exceptions above serve to mitigate these future-compatibility issues.
The Unicode Common Locale Data Repository (CLDR) implements most of the exceptions above when determining which available named time zone identifiers are primary or non-primary.
Although use of CLDR data is recommended for consistency between implementations, it is not required.
Non-CLDR-based implementations can still use CLDR's identifier data in timezone.xml.
Implementations may also build the IANA Time Zone Database directly, for example by using build options such as PACKRATDATA=backzone PACKRATLIST=zone.tab and performing any post-processing needed to ensure compliance with the requirements above.
The IANA Time Zone Database is typically updated between five and ten times per year.
These updates may add new Zone or Link names, may change Zones to Links, and may change the UTC offsets and transitions associated with any Zone.
Implementations are recommended to include updates to the IANA Time Zone Database as soon as possible.
Such prompt action ensures that ECMAScript programs can accurately perform time-zone-sensitive calculations and can use newly-added available named time zone identifiers supplied by external input or the host environment.
Although the IANA Time Zone Database maintainers strive for stability, in rare cases (averaging less than once per year) a Zone may be replaced by a new Zone.
For example, in 2022 "Europe/Kiev" was deprecated to a Link resolving to a new "Europe/Kyiv" Zone.
The deprecated Link is called a renamed time zone identifier and the newly-added Zone is called a replacement time zone identifier.
To reduce disruption from these infrequent changes, implementations should initially add each replacement time zone identifier as a non-primary time zone identifier that resolves to the existing renamed time zone identifier.
This allows ECMAScript programs to recognize both identifiers, but also reduces the chance that an ECMAScript program will send the replacement time zone identifier to another system that does not yet recognize it.
After a rename waiting period, implementations should promote the new Zone to a primary time zone identifier while simultaneously demoting the renamed time zone identifier to non-primary.
To provide ample time for other systems to be updated, the recommended rename waiting period is two years.
However, it does not need to be either exact or dynamic.
Instead, implementations should make the replacement time zone identifier primary after the waiting period as part of their normal release process for updating time zone data.
A waiting period should only apply when a new Zone is added to replace an existing Zone.
If an existing Zone and Link are swapped, then no renaming has happened and no waiting period is necessary.
If implementations revise time zone information during the lifetime of an agent, then it is required that the list of available named time zone identifiers, the primary time zone identifier associated with any available named time zone identifier, and the UTC offsets and transitions associated with any available named time zone identifier, be consistent with results previously observed by that agent.
Due to the complexity of supporting this requirement, it is recommended that implementations maintain a fully consistent copy of the IANA Time Zone Database for the lifetime of each agent.
This section complements but does not supersede 21.4.1.19.
6.5.1 AvailableNamedTimeZoneIdentifiers ( )
The implementation-defined abstract operation AvailableNamedTimeZoneIdentifiers takes no arguments and returns a List of Time Zone Identifier Records.
Its result describes all available named time zone identifiers in this implementation, as well as the primary time zone identifier corresponding to each available named time zone identifier.
The List is ordered according to the [[Identifier]] field of each Time Zone Identifier Record.
This definition supersedes the definition provided in 21.4.1.23.
- Let identifiers be a List containing the String value of each Zone or Link name in the IANA Time Zone Database.
- Assert: No element of identifiers is an ASCII-case-insensitive match for any other element.
- Sort identifiers according to lexicographic code unit order.
- Let result be a new empty List.
- For each element identifier of identifiers, do
- Let primary be identifier.
- If identifier is a Link name in the IANA Time Zone Database and identifier is not present in the “TZ” column of
zone.tab of the IANA Time Zone Database, then- Let zone be the Zone name that identifier resolves to, according to the rules for resolving Link names in the IANA Time Zone Database.
- If zone starts with "Etc/", then
- Set primary to zone.
- Else,
- Let identifierCountryCode be the ISO 3166-1 Alpha-2 country code whose territory contains the geographical area corresponding to identifier.
- Let zoneCountryCode be the ISO 3166-1 Alpha-2 country code whose territory contains the geographical area corresponding to zone.
- If identifierCountryCode is zoneCountryCode, then
- Set primary to zone.
- Else,
- Let countryCodeLineCount be the number of lines in file
zone.tab of the IANA Time Zone Database where the “