The Locale module provides support for number and date formatting. A large number of languages and locales are supported out of the box and the locale framework is extensible.
Extending the supported locales is a (relatively) simple matter of defining
an Object with the relevant properties. Although there are a large number of
properties, the locale system has a simple inheritance mechanism so that you
only have to fill in the properties that differ from the base
locale.
The templates directory has a file called locale_template.js that you can adapt for your own purposes. The example is a self-executing function but if you don't need to define aliases or compute anything as part of the locale definition, this can be a simple list of properties.
Locales should be identified using BCP 47 tags which take the form
<LANGUAGE>-<SCRIPT>-<COUNTRY>
Only the language tag is necessary for most locales; the other parts are specializations for a particular country. For example, "sr" is the tag for Serbian in the default Cyrillic script. "sr-Latn" is the tag for Serbian using the Latin alphabet while "sr-Latn-ME" is the tag for Serbian using the Latin alphabet in Montenegro. See RFC 5646 for more details on language tags and the relevant IANA documentation for the correct language codes.
The UsefulJS core defines a default locale ("def") that is the base of all
other locales. If your locale derives from the default locale (via its base
property) then you only have to define properties that differ from the default
locale. If the base
is something other than "def", then you only need to
define properties that differ from the base locale AND the def locale. Inheritance
can be any number of levels deep. For example, the ar-TZ (Tunisia) locale has
the following inheritance:
ar-TZ -> ar-DZ (Algeria) -> ar-MA (Morocco) -> ar-AE (United Arab Emirates) -> ar (Arabic) -> def (Default)
Property | Type | Meaning | Purpose | Notes | Default |
---|---|---|---|---|---|
n | String | Name | Displayable, localized name | - | English |
base | String | Parent locale | The base locale for inheritance purposes | - | null |
ndigits | String | Numeric digits | The default digits used for representing numbers | See UsefulJS.Number | latn |
ds | String | Decimal separator | The character that separates the integer component of a number from the decimal part | - | . |
gs | String | Numeric group separator | The character that separates groups when a number is formatted for readability | - | , |
gc | Array | Group counts | How many digits are in each group of the number. | Most locales use a count of 3 as in 10,000,000; in Indian locales this would be 1,00,00,000 which makes the gc value [3,2] | [3] |
nn | String | Negative number pattern | The template used for rendering negative numbers | "%1" is replaced with the formatted absolute value | -%1 |
cc | String | Currency code | The ISO 4217 currency code | This is a locale-neutral currency representation; codes are listed here. | EUR |
cu | Object | Currency units | Localized currency symbols | This maps three-letter currency codes to currency symbols; for example,
{ USD : "US$", AUD : "$" } .
| - |
cf | Array | Currency formats | The templates used for rendering positive and negative currency values | '$' is replaced with the currency code or symbol; "%1" is replaced with the formatted absolute value | |
pc | Array | Percentage codes | The templates used for rendering positive and negative percent values | "%1" is replaced with the formatted absolute value | |
ddigits | String | Date digits | The default digits used for representing dates | See UsefulJS.Date | latn |
mc | Array | Compact months | Short forms of month names | Some locales do not have a compact form for month names; use
null . |
["Jan", ... "Dec"] |
mf | Array | Full months | Long forms of month names | - | ["January", ... "December"] |
mn | Array | Nominative month names | Month names in the nominative case | Some languages distinguish between, e.g. "18 September" and "September 2015", using genitive case for the former and nominative for the latter. When this is the case use the genitive forms in mf and the nominative forms in mn. | null |
da | Array | Abbreviated day names | Shortest forms of day names | These are the day codes that are returned by the UsefulJS.Date
cal function. If this not meaningful in the locale,
use null . |
["Su", ... "Sa"] |
dc | Array | Compact day names | Short forms of day names | Some locales do not have a compact form for day names; use
null . |
["Sun", ... "Sat"] |
df | Array | Full day names | Long forms of day names | Values should always start at the equivalent of Sunday | ["Sunday", ... "Saturday"] |
um | Array | Uppercase meridiem names | Local equivalent of AM/PM | 12 hour clock is not meaningful in all locales | ["AM", "PM"] |
lm | Array | Lowercase meridiem names | Local equivalent of am/pm | - | ["am", "pm"] |
hd | Array | Hour divisions | The starting hours of each division of the day | Some locales may divide the hours of the day into more than two divisions | [0, 12] |
hour12 | Boolean | 12 hour clock flag | Default value of the hour12 format property when using the Intl API | Set to true if the locale uses 12 hour clock by default | false |
sc | Object | Strftime codes | Macros for strftime | Some strftime codes (such as %c) are expanded to a sequence of other strftime codes. Macros that may need to be defined are: %c (date and time), %x (date), %X (time) and %r (time with am/pm). | { "%c" : "%a %d %b %Y %X", %x" : "%d/%m/%Y", "%X" : "%T", "%r" : "%I:%M:%S %p" } |
dfmt | Object | Date format strings | strftime sequences for formatting dates using the Intl API | See below. | See below |
tfmt | Object | Time format strings | strftime sequences for formatting times using the Intl API | See below. | See below |
datetime | String | Date and time template | The template used to combine the format strings used for rendering the date and the time | "{d}" is replaced with the date format string while "{t}" is replaced with the time format string. | {d} {t} |
dateera | String | Date and era template | The template used to combine the format string used for rendering the date and the era | "{d}" is replaced with the date format string. | {d} %! |
time12 | String | Twelve hour clock template | The template used to combine the format string used for rendering the time and am/pm | "{t}" is replaced with the time format string. | {t} %p |
timetz | String | Time + timezone template | The template used to combine the format string used for rendering the time and the timezone | "{t}" is replaced with the time format string. | {t} GMT%z |
fd | Number | First day of the week | 0-based value of the first day of the week where 0 corresponds to Sunday and 6 corresponds to Saturday | - | 1 |
calendar | String | Default calendar | The name of the default calendar for the locale. | See UsefulJS.Date | gregory |
<CALENDAR NAME> | Object | Calendar property overrides | Allow overriding of selected calendar properties | For example, to override the strings used for AD and BC, add a gregory
property whose value is { era : ["<AD equivalent>", "<BC equivalent>"] } |
null |
When using the Intl-compatible API to format dates, rather than specifying a
format string, you specify the properties that you'd like the output to have.
Sensible property combinations result in sensible output via the format strings
in the dfmt
and tfmt
Objects in the Locale definition.
The keys use the characters 't', 'n' and '-' where 't' represents a text field,
'n' represents a numeric field and '-' represents an absent field. Rather than
having to specify all possible combinations, you only need to specify a sensible
subset and only when they differ from the base locale. dfmt keys are four characters
representing weekday, year, month and day while tfmt keys are three characters
representing hours, minutes and seconds. The following table lists the sensible
combinations, together with their values in the def locale and example output.
Key | Meaning | Format String | Example |
---|---|---|---|
dfmt | |||
tntn | Weekday, year, month, day | %A, %e %B %Y | Saturday, 19 September 2015 |
tnnn | Weekday, year, month, day | %A, %e/%N/%Y | Saturday, 19/9/2015 |
-ntn | Year, month, day | %e %B %Y | 19 September 2015 |
-nnn | Year, month, day | %e/%N/%Y | 19/9/2015 |
-nt- | Year, month | %B %Y | September 2015 |
-nn- | Year, month | %N/%Y | 9/2015 |
--tn | Month, day | %e %B | 19 September |
--nn | Month, day | %e/%N | 19/9 |
tfmt | |||
nnn | Hours, minutes, seconds | %k:%M:%S | 2:05:24 |
nn- | Hours, minutes | %k:%M | 13:27 |
This read/write value is the fallback locale when no locales are specified when constructing a format object. It is initialized with information obtained from the browser which, depending on the browser, may or may not reflect a user's preference. To illustrate, assuming that the library sets "en" (US English) as the current locale:
(new UsefulJS.Date.Format()).format(new Date()); // 9/19/2015 UsefulJS.Locale.current = "fr"; (new UsefulJS.Date.Format()).format(new Date()); // 19/9/2015
If the browser supports Object.defineProperty
, the current
property is accessed through a getter and setter which will raise a TypeError if you attempt
to set a silly value. If you set an unsupported locale, a sensible fallback will be
used. To illustrate:
UsefulJS.current = null; // throws TypeError UsefulJS.current = "zz"; UsefulJS.current // "en" UsefulJS.current = "zh-Hant-CN"; UsefulJS.current // "zh"
If the browser does not support Object.defineProperty
, you can
set silly values which will make bad things happen. So don't!
The UsefulJS.Locale functions are called by the numeric and date formatting code but they are public functions that your own applications may call.
Sets aliases for a defined locale (two or more arguments) or resolves an alias (single argument).
UsefulJS.Locale.alias(loc[, alias1, alias2 ...])
loc
Stringalias1, alias2, ...
StringReturns: String. The resolved locale (single-argument only)
Aliasing is required when the lookup algorithm would give the wrong answer. For example, the locale ID for Taiwan is "zh-Hant-TW" meaning Chinese, written in Han traditional script as used in Taiwan. If we were to lookup "zh-TW" (Chinese as used in Taiwan), the lookup algorithm would resolve "zh" which is mainland Chinese. If, however, we record "zh-TW" as an alias for "zh-Hant-TW", the lookup for "zh-TW" gives the correct answer.
// Set an alias UsefulJS.Locale.alias("zh-Hant-TW", "zh-TW"); // Resolve an alias var resolved = UsefulJS.Locale.alias("zh-TW"); // zh-Hant-TW
Obtains best match for the requested locales from the supported locales.
UsefulJS.Locale.lookup(locales)
locales
ArrayReturns: Array. Two items, the best match locale and any unicode extension requested for that locale.
For ease of processing the selected code is split into the BCP 47 part and
any unicode extension requested. The algorithm returns the first "acceptable"
result, falling back to the default locale if no acceptable results can be
obtained. Unassisted, the algorithm may not select the best match,
however. For example, if the input is ["en-MY", "en-GB", "en-US"]
,
the returned locale will be "en", since "en-MY" is not a supported locale.
However, for a Malaysian audience, "en-GB" would produce better output. The solution
is to alias "en-GB" to "en-MY".
UsefulJS.Locale.lookup(["ja-JP-u-nu-fullwidth", "zh-Hant"]); // ["ja", "u-nu-fullwidth"] UsefulJS.Locale.alias("en-GB", "en-MY"); UsefulJS.Locale.lookup(["en-MY", "en-GB", "en"]); // ["en-GB", ""]
Gets the locale options for the named locale.
UsefulJS.Locale.options(loc)
loc
StringReturns: Object. The resolved locale options
Although the locale Objects are properties of UsefulJS.Locale accessing
them directly is unlikely to return the right thing because of the inheritance
system which means that a whole bunch of properties are likely to be missing.
Getting the Objects through the options
method both resolves the
input locale and the inherited properties. This method is primarily designed
to be called to do the initial property resolution for the dateOptions
and numericOptions
methods so the returned value is not 100% useful.
Gets the fully resolved locale options required for date formatting.
UsefulJS.Locale.dateOptions(loc[, fmtOptions])
loc
StringfmtOptions
ObjectReturns: Object. The resolved locale options
Unlike the options
method, this call does return an Object with
everything resolved that needs to be resolved, taking into account the requested
numbering and calendar.
Gets the fully resolved locale options required for number formatting.
UsefulJS.Locale.numericOptions(loc[, fmtOptions])
loc
StringfmtOptions
ObjectReturns: Object. The resolved locale options
Unlike the options
method, this call does return an Object with
everything resolved that needs to be resolved, taking into account the requested
numbering.
Returns items from an input array that are supported in the sense that they
do not force a fallback to the current
locale.
UsefulJS.Locale.supportedLocalesOf(locales)
locales
ArrayReturns: Array. Filtered items from the input array.
Returns the list of locales that are actually supported.
UsefulJS.Locale.getSupported()
Returns: Array. Directly supported locale codes.
Returns the supported numbering systems.
UsefulJS.Locale.numberSystems()
Returns: Array. Supported numbering system names.
These values go into the -nu-
part of the unicode extension.
Returns the supported calendars.
UsefulJS.Locale.calendars()
Returns: Array. Supported calendar names.
These values go into the -ca-
part of the unicode extension.