Every user-visible date now goes through web/src/lib/datetime.ts, driven by three settings (Settings > General > Locale): - Language & region: automatic, or any of the 618 locales CLDR has data for, each named in its own language and script (web/src/lib/locales.ts, generated by probing Intl over the subtag space). - Date format: automatic (locale order), 22.11.2025, 22/11/2025, 11/22/2025, or ISO 8601 2025-11-22. - Time format: automatic (locale), 24-hour, or 12-hour. Automatic takes the locale Stalwart has for the account, read best-effort at login via x:Account/get (urn:stalwart:jmap) and passed to the client in the session; servers without the capability, or that deny sysAccountGet to a regular user, fall back to the browser locale. POSIX forms are normalised (de_DE.UTF-8 -> de-DE) and script modifiers kept (sr_RS@latin -> sr-Latn-RS, uz_UZ@cyrillic -> uz-Cyrl-UZ), while dialect/variant/currency modifiers are dropped and a script the locale already implies is not appended. Numerals follow the locale (22.11.2025 renders as Arabic-Indic digits under ar-EG); ISO 8601 is the exception and pins date and clock to Latin digits so one line never mixes digit systems. Rewired: message list and headers, quoted reply headers, calendar (titles, weekday and hour gutters, mini calendar, agenda, popovers, invite cards, free/busy), contacts, files, sessions. No raw toLocale*String date calls are left in web/src. Native <input type="datetime-local"> pickers always follow the browser locale and cannot be restyled by a page, so the out-of-office fields echo the entered instant in the chosen format underneath. Also: month-grid day labels no longer wrap when they hold a date, and the mock server serves x:Account/get (MOCK_LOCALE, default en_US). Closes #1
89 lines
6.3 KiB
TypeScript
89 lines
6.3 KiB
TypeScript
/**
|
|
* Every locale ICU/CLDR has real data for — generated by probing
|
|
* `Intl.DateTimeFormat(tag).resolvedOptions()` over the language, script and
|
|
* region subtag space and keeping the tags the resolver does not fold into a
|
|
* parent. Script variants appear only where they differ from the region's
|
|
* default script (so `sr-RS` and `sr-Latn-RS` are both listed, but
|
|
* `sr-Cyrl-RS` — the same thing as `sr-RS` — is not).
|
|
*/
|
|
export const LOCALE_TAGS: readonly string[] = [
|
|
"af-NA", "af-ZA", "agq-CM", "ak-GH", "am-ET", "ar-AE", "ar-BH", "ar-DJ",
|
|
"ar-DZ", "ar-EG", "ar-EH", "ar-ER", "ar-IL", "ar-IQ", "ar-JO", "ar-KM",
|
|
"ar-KW", "ar-LB", "ar-LY", "ar-MA", "ar-MR", "ar-OM", "ar-PS", "ar-QA",
|
|
"ar-SA", "ar-SD", "ar-SO", "ar-SS", "ar-SY", "ar-TD", "ar-TN", "ar-YE",
|
|
"ars", "as-IN", "asa-TZ", "ast-ES", "az-AZ", "az-Cyrl-AZ", "ba-RU", "bas-CM",
|
|
"be-BY", "bem-ZM", "bez-TZ", "bg-BG", "bgc-IN", "bho-IN", "blo-BJ", "bm-ML",
|
|
"bn-BD", "bn-IN", "bo-CN", "bo-IN", "br-FR", "brx-IN", "bs-BA", "bs-Cyrl-BA",
|
|
"bua-RU", "ca-AD", "ca-ES", "ca-FR", "ca-IT", "ccp-BD", "ccp-IN", "ce-RU",
|
|
"ceb-PH", "cgg-UG", "chr-US", "ckb-IQ", "ckb-IR", "cs-CZ", "csw-CA", "cv-RU",
|
|
"cy-GB", "da-DK", "da-GL", "dav-KE", "de-AT", "de-BE", "de-CH", "de-DE",
|
|
"de-IT", "de-LI", "de-LU", "dje-NE", "doi-IN", "dsb-DE", "dua-CM", "dyo-SN",
|
|
"dz-BT", "ebu-KE", "ee-GH", "ee-TG", "el-CY", "el-GR", "en-AE", "en-AG",
|
|
"en-AI", "en-AS", "en-AT", "en-AU", "en-BB", "en-BE", "en-BI", "en-BM",
|
|
"en-BS", "en-BW", "en-BZ", "en-CA", "en-CC", "en-CH", "en-CK", "en-CM",
|
|
"en-CX", "en-CY", "en-CZ", "en-DE", "en-DG", "en-DK", "en-DM", "en-EE",
|
|
"en-ER", "en-ES", "en-FI", "en-FJ", "en-FK", "en-FM", "en-FR", "en-GB",
|
|
"en-GD", "en-GE", "en-GG", "en-GH", "en-GI", "en-GM", "en-GS", "en-GU",
|
|
"en-GY", "en-HK", "en-HU", "en-ID", "en-IE", "en-IL", "en-IM", "en-IN",
|
|
"en-IO", "en-IT", "en-JE", "en-JM", "en-JP", "en-KE", "en-KI", "en-KN",
|
|
"en-KY", "en-LC", "en-LR", "en-LS", "en-LT", "en-LV", "en-MG", "en-MH",
|
|
"en-MO", "en-MP", "en-MS", "en-MT", "en-MU", "en-MV", "en-MW", "en-MY",
|
|
"en-NA", "en-NF", "en-NG", "en-NL", "en-NO", "en-NR", "en-NU", "en-NZ",
|
|
"en-PG", "en-PH", "en-PK", "en-PL", "en-PN", "en-PR", "en-PT", "en-PW",
|
|
"en-RO", "en-RW", "en-SB", "en-SC", "en-SD", "en-SE", "en-SG", "en-SH",
|
|
"en-SI", "en-SK", "en-SL", "en-SS", "en-SX", "en-SZ", "en-TC", "en-TK",
|
|
"en-TO", "en-TT", "en-TV", "en-TZ", "en-UA", "en-UG", "en-UM", "en-US",
|
|
"en-VC", "en-VG", "en-VI", "en-VU", "en-WS", "en-ZA", "en-ZM", "en-ZW",
|
|
"eo", "es-AR", "es-BO", "es-BR", "es-BZ", "es-CL", "es-CO", "es-CR",
|
|
"es-CU", "es-DO", "es-EA", "es-EC", "es-ES", "es-GQ", "es-GT", "es-HN",
|
|
"es-IC", "es-MX", "es-NI", "es-PA", "es-PE", "es-PH", "es-PR", "es-PY",
|
|
"es-SV", "es-US", "es-UY", "es-VE", "et-EE", "eu-ES", "ewo-CM", "fa-AF",
|
|
"fa-IR", "ff-Adlm-BF", "ff-Adlm-CM", "ff-Adlm-GH", "ff-Adlm-GM", "ff-Adlm-GN", "ff-Adlm-GW", "ff-Adlm-LR",
|
|
"ff-Adlm-MR", "ff-Adlm-NE", "ff-Adlm-NG", "ff-Adlm-SL", "ff-Adlm-SN", "ff-BF", "ff-CM", "ff-GH",
|
|
"ff-GM", "ff-GN", "ff-GW", "ff-LR", "ff-MR", "ff-NE", "ff-NG", "ff-SL",
|
|
"ff-SN", "fi-FI", "fil-PH", "fo-DK", "fo-FO", "fr-BE", "fr-BF", "fr-BI",
|
|
"fr-BJ", "fr-BL", "fr-CA", "fr-CD", "fr-CF", "fr-CG", "fr-CH", "fr-CI",
|
|
"fr-CM", "fr-DJ", "fr-DZ", "fr-FR", "fr-GA", "fr-GF", "fr-GN", "fr-GP",
|
|
"fr-GQ", "fr-HT", "fr-KM", "fr-LU", "fr-MA", "fr-MC", "fr-MF", "fr-MG",
|
|
"fr-ML", "fr-MQ", "fr-MR", "fr-MU", "fr-NC", "fr-NE", "fr-PF", "fr-PM",
|
|
"fr-RE", "fr-RW", "fr-SC", "fr-SN", "fr-SY", "fr-TD", "fr-TG", "fr-TN",
|
|
"fr-VU", "fr-WF", "fr-YT", "fur-IT", "fy-NL", "ga-GB", "ga-IE", "gaa-GH",
|
|
"gd-GB", "gl-ES", "gsw-CH", "gsw-FR", "gsw-LI", "gu-IN", "guz-KE", "gv-IM",
|
|
"ha-GH", "ha-NE", "ha-NG", "haw-US", "he-IL", "hi-IN", "hi-Latn-IN", "hr-BA",
|
|
"hr-HR", "hsb-DE", "hu-HU", "hy-AM", "ia", "id-ID", "ie-EE", "ig-NG",
|
|
"ii-CN", "is-IS", "it-CH", "it-IT", "it-SM", "it-VA", "ja-JP", "jgo-CM",
|
|
"jmc-TZ", "jv-ID", "ka-GE", "kab-DZ", "kam-KE", "kde-TZ", "kea-CV", "kgp-BR",
|
|
"khq-ML", "ki-KE", "kk-CN", "kk-KZ", "kkj-CM", "kl-GL", "kln-KE", "km-KH",
|
|
"kn-IN", "ko-CN", "ko-KP", "ko-KR", "kok-IN", "kok-Latn-IN", "ks-Deva-IN", "ks-IN",
|
|
"ksb-TZ", "ksf-CM", "ksh-DE", "ku-IQ", "ku-Latn-IQ", "ku-SY", "ku-TR", "kw-GB",
|
|
"kxv-Deva-IN", "kxv-IN", "kxv-Orya-IN", "kxv-Telu-IN", "ky-KG", "lag-TZ", "lb-LU", "lg-UG",
|
|
"lij-IT", "lkt-US", "lmo-IT", "ln-AO", "ln-CD", "ln-CF", "ln-CG", "lo-LA",
|
|
"lrc-IQ", "lrc-IR", "lt-LT", "lu-CD", "luo-KE", "luy-KE", "lv-LV", "mai-IN",
|
|
"mas-KE", "mas-TZ", "mer-KE", "mfe-MU", "mg-MG", "mgh-MZ", "mgo-CM", "mi-NZ",
|
|
"mk-MK", "ml-IN", "mn-MN", "mni-IN", "mr-IN", "ms-BN", "ms-ID", "ms-MY",
|
|
"ms-SG", "mt-MT", "mua-CM", "my-MM", "mzn-IR", "naq-NA", "nb", "nd-ZW",
|
|
"nds-DE", "nds-NL", "ne-IN", "ne-NP", "nl-AW", "nl-BE", "nl-BQ", "nl-CW",
|
|
"nl-NL", "nl-SR", "nl-SX", "nmg-CM", "nn-NO", "nnh-CM", "no-NO", "nqo-GN",
|
|
"nso-ZA", "nus-SS", "nyn-UG", "oc-ES", "oc-FR", "om-ET", "om-KE", "or-IN",
|
|
"os-GE", "os-RU", "pa-IN", "pa-PK", "pcm-NG", "pl-PL", "pms-IT", "prg-PL",
|
|
"ps-AF", "ps-PK", "pt-AO", "pt-BR", "pt-CH", "pt-CV", "pt-GQ", "pt-GW",
|
|
"pt-LU", "pt-MO", "pt-MZ", "pt-PT", "pt-ST", "pt-TL", "qu-BO", "qu-EC",
|
|
"qu-PE", "raj-IN", "rm-CH", "rn-BI", "ro-MD", "ro-RO", "rof-TZ", "ru-BY",
|
|
"ru-KG", "ru-KZ", "ru-MD", "ru-RU", "ru-UA", "rw-RW", "rwk-TZ", "sa-IN",
|
|
"sah-RU", "saq-KE", "sat-IN", "sbp-TZ", "sc-IT", "scn-IT", "sd-IN", "sd-PK",
|
|
"se-FI", "se-NO", "se-SE", "seh-MZ", "ses-ML", "sg-CF", "shi-Latn-MA", "shi-MA",
|
|
"shn-MM", "shn-TH", "si-LK", "sk-SK", "sl-SI", "smn-FI", "sn-ZW", "so-DJ",
|
|
"so-ET", "so-KE", "so-SO", "sq-AL", "sq-MK", "sq-XK", "sr-BA", "sr-Cyrl-ME",
|
|
"sr-Latn-BA", "sr-Latn-RS", "sr-Latn-XK", "sr-ME", "sr-RS", "sr-XK", "st-LS", "st-ZA",
|
|
"su-ID", "sv-AX", "sv-FI", "sv-SE", "sw-CD", "sw-KE", "sw-TZ", "sw-UG",
|
|
"syr-IQ", "syr-SY", "szl-PL", "ta-IN", "ta-LK", "ta-MY", "ta-SG", "te-IN",
|
|
"teo-KE", "teo-UG", "tg-TJ", "th-TH", "ti-ER", "ti-ET", "tk-TM", "tn-BW",
|
|
"tn-ZA", "to-TO", "tok", "tr-CY", "tr-TR", "tt-RU", "twq-NE", "tyv-RU",
|
|
"tzm-MA", "ug-CN", "uk-UA", "ur-IN", "ur-PK", "uz-AF", "uz-Cyrl-UZ", "uz-UZ",
|
|
"vai-LR", "vai-Latn-LR", "vec-IT", "vi-VN", "vmw-MZ", "vun-TZ", "wae-CH", "wo-SN",
|
|
"xh-ZA", "xnr-IN", "xog-UG", "yav-CM", "yi-UA", "yo-BJ", "yo-NG", "yrl-BR",
|
|
"yrl-CO", "yrl-VE", "yue-CN", "yue-HK", "yue-Hant-CN", "yue-MO", "za-CN", "zgh-MA",
|
|
"zh-CN", "zh-HK", "zh-Hans-HK", "zh-Hans-MO", "zh-Hant-MY", "zh-MO", "zh-MY", "zh-SG",
|
|
"zh-TW", "zu-ZA",
|
|
];
|