mirror of
https://github.com/bulwarkmail/native.git
synced 2026-10-31 00:06:17 +00:00
fix: load only the active language's calendar date locale
`src/lib/calendar-locale.ts` imported its 27 date-fns locales from the `date-fns/locale` barrel, which re-exports all of date-fns' ~100 locales. Metro bundled every one of them and evaluated them at startup through the calendar screens. Each locale is now required from its own `date-fns/locale/<code>` module the first time `getDateFnsLocale()` asks for it; en-US stays a static import as the fallback. A test checks that every UI language still maps to the right date-fns locale. Measured with `npx expo export --platform android`: - modules in the bundle: 2,469 -> 2,114 (date-fns locale modules: 531 -> 170, 1,213 KB -> 358 KB unminified) - Hermes bundle: 8.19 MB -> 7.61 MB - modules evaluated at startup: 2,038 -> 1,516 (date-fns locale modules: 531 -> 10, i.e. only en-US)
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import { SUPPORTED_LOCALES } from '../../i18n';
|
||||
import { getDateFnsLocale } from '../calendar-locale';
|
||||
|
||||
// date-fns names a few locales differently from the UI language codes.
|
||||
const EXPECTED_CODE: Record<string, string> = {
|
||||
en: 'en-US',
|
||||
fa: 'fa-IR',
|
||||
zh: 'zh-CN',
|
||||
'zh-TW': 'zh-TW',
|
||||
};
|
||||
|
||||
describe('getDateFnsLocale', () => {
|
||||
it('loads the matching date-fns locale for every UI language', () => {
|
||||
for (const { code } of SUPPORTED_LOCALES) {
|
||||
const locale = getDateFnsLocale(code);
|
||||
expect(locale.code, code).toBe(EXPECTED_CODE[code] ?? code);
|
||||
expect(typeof locale.localize?.month, code).toBe('function');
|
||||
// Loaded once, then served from the cache.
|
||||
expect(getDateFnsLocale(code)).toBe(locale);
|
||||
}
|
||||
});
|
||||
|
||||
it('falls back to en-US for unknown or missing codes', () => {
|
||||
expect(getDateFnsLocale('xx').code).toBe('en-US');
|
||||
expect(getDateFnsLocale('toString').code).toBe('en-US');
|
||||
expect(getDateFnsLocale(null).code).toBe('en-US');
|
||||
expect(getDateFnsLocale(undefined).code).toBe('en-US');
|
||||
});
|
||||
});
|
||||
@@ -1,19 +1,56 @@
|
||||
import type { Locale } from 'date-fns';
|
||||
import {
|
||||
ar, ca, cs, da, de, enUS, es, faIR, fr, he, hu, it, ja, ko, lv, mn, nb, nl, pl, pt, ro, ru, sk, tr, uk, zhCN, zhTW,
|
||||
} from 'date-fns/locale';
|
||||
import { enUS } from 'date-fns/locale/en-US';
|
||||
import { useLocaleStore } from '../stores/locale-store';
|
||||
import type { LocaleCode } from '../i18n';
|
||||
|
||||
// date-fns locale for each UI language so month/day names, "EEE, MMM d"
|
||||
// headers and the like render in the user's language (the webmail localizes
|
||||
// them through next-intl / useFormatEventDate).
|
||||
const DATE_FNS_LOCALES: Record<LocaleCode, Locale> = {
|
||||
en: enUS, ar, ca, cs, da, de, es, fa: faIR, fr, he, hu, it, nl, nb, pl, pt, ro, ru, sk, tr, uk, ja, ko, mn, zh: zhCN, 'zh-TW': zhTW, lv,
|
||||
//
|
||||
// Each locale is required from its own module on first use: importing from
|
||||
// the `date-fns/locale` barrel bundled and evaluated all ~100 date-fns
|
||||
// locales at startup. The require paths must stay string literals for Metro
|
||||
// to bundle them.
|
||||
const DATE_FNS_LOCALE_LOADERS: Record<LocaleCode, () => Locale> = {
|
||||
en: () => enUS,
|
||||
ar: () => require('date-fns/locale/ar').ar,
|
||||
ca: () => require('date-fns/locale/ca').ca,
|
||||
cs: () => require('date-fns/locale/cs').cs,
|
||||
da: () => require('date-fns/locale/da').da,
|
||||
de: () => require('date-fns/locale/de').de,
|
||||
es: () => require('date-fns/locale/es').es,
|
||||
fa: () => require('date-fns/locale/fa-IR').faIR,
|
||||
fr: () => require('date-fns/locale/fr').fr,
|
||||
he: () => require('date-fns/locale/he').he,
|
||||
hu: () => require('date-fns/locale/hu').hu,
|
||||
it: () => require('date-fns/locale/it').it,
|
||||
ja: () => require('date-fns/locale/ja').ja,
|
||||
ko: () => require('date-fns/locale/ko').ko,
|
||||
lv: () => require('date-fns/locale/lv').lv,
|
||||
mn: () => require('date-fns/locale/mn').mn,
|
||||
nb: () => require('date-fns/locale/nb').nb,
|
||||
nl: () => require('date-fns/locale/nl').nl,
|
||||
pl: () => require('date-fns/locale/pl').pl,
|
||||
pt: () => require('date-fns/locale/pt').pt,
|
||||
ro: () => require('date-fns/locale/ro').ro,
|
||||
ru: () => require('date-fns/locale/ru').ru,
|
||||
sk: () => require('date-fns/locale/sk').sk,
|
||||
tr: () => require('date-fns/locale/tr').tr,
|
||||
uk: () => require('date-fns/locale/uk').uk,
|
||||
zh: () => require('date-fns/locale/zh-CN').zhCN,
|
||||
'zh-TW': () => require('date-fns/locale/zh-TW').zhTW,
|
||||
};
|
||||
|
||||
const loaded = new Map<string, Locale>();
|
||||
|
||||
export function getDateFnsLocale(code: LocaleCode | string | null | undefined): Locale {
|
||||
return (code && DATE_FNS_LOCALES[code as LocaleCode]) || enUS;
|
||||
if (!code || !Object.prototype.hasOwnProperty.call(DATE_FNS_LOCALE_LOADERS, code)) return enUS;
|
||||
let locale = loaded.get(code);
|
||||
if (!locale) {
|
||||
locale = DATE_FNS_LOCALE_LOADERS[code as LocaleCode]();
|
||||
loaded.set(code, locale);
|
||||
}
|
||||
return locale;
|
||||
}
|
||||
|
||||
/** `{ locale }` options for date-fns `format()` plus the translate function. */
|
||||
|
||||
Reference in New Issue
Block a user