Idea
Today every package imports its l10n/translations.json statically. Each of those files holds all languages at the top level. Because of this, the browser downloads the translations of all languages on initial load, even though only one language is used. New strings and new languages silently grow the initial payload and hurt load times.
Current numbers: ~1.24 MB of raw translation JSON across all packages, ~38 KB per language. English users download all of it and use none of it, because gettext falls back to the msgid.
Goal: one chunk per language, and only the chunk for the current language gets loaded.
Proposed approach
-
A Vite plugin that serves virtual modules built from the existing translations.json files:
virtual:l10n/<pkg> returns a small loader map, { de: () => import('virtual:l10n-lang/<pkg>/de'), ... }
virtual:l10n-lang/<pkg>/<lang> returns only that language slice
This keeps translations.json as the single source and needs no change to the gettext extraction pipeline.
-
In vite.config.ts, replace the pkg-translations code splitting group with one generated group per language, so all packages' slices for a language end up in a single chunk (l10n-de.mjs, l10n-fr.mjs, ...).
-
Make loading language aware:
loadTranslations() in packages/web-runtime/src/defaults/index.ts takes a lang argument
ApplicationInformation.translations accepts a loader map, keeping the plain object valid for external apps
loadAppTranslations() and setCurrentLanguage() in packages/web-runtime/src/helpers/language.ts await the chunks of the current language
- skip
en entirely, it needs no chunk
Expected result
- English: the ~1.24 MB of translation JSON drops out of the initial load completely
- Other languages: ~38 KB in one extra request
- Adding languages or strings no longer grows the initial payload
- Fully backwards compatible, installing external apps keeps working as before
Idea
Today every package imports its
l10n/translations.jsonstatically. Each of those files holds all languages at the top level. Because of this, the browser downloads the translations of all languages on initial load, even though only one language is used. New strings and new languages silently grow the initial payload and hurt load times.Current numbers: ~1.24 MB of raw translation JSON across all packages, ~38 KB per language. English users download all of it and use none of it, because
gettextfalls back to themsgid.Goal: one chunk per language, and only the chunk for the current language gets loaded.
Proposed approach
A Vite plugin that serves virtual modules built from the existing
translations.jsonfiles:virtual:l10n/<pkg>returns a small loader map,{ de: () => import('virtual:l10n-lang/<pkg>/de'), ... }virtual:l10n-lang/<pkg>/<lang>returns only that language sliceThis keeps
translations.jsonas the single source and needs no change to thegettextextraction pipeline.In
vite.config.ts, replace thepkg-translationscode splitting group with one generated group per language, so all packages' slices for a language end up in a single chunk (l10n-de.mjs,l10n-fr.mjs, ...).Make loading language aware:
loadTranslations()inpackages/web-runtime/src/defaults/index.tstakes alangargumentApplicationInformation.translationsaccepts a loader map, keeping the plain object valid for external appsloadAppTranslations()andsetCurrentLanguage()inpackages/web-runtime/src/helpers/language.tsawait the chunks of the current languageenentirely, it needs no chunkExpected result