We do actually have per-language code splitting with React/Vite. We essentially just have a map of [language, loader], where the loader utilizes lazy imports. Vite is smart enough to split those all out of the main bundle and they get loaded on demand as expected.
const LOCALE_MAP: any = {
en: () =>
document.body.dataset["appEnv"] === "development"
? Promise.resolve({ default: {} as LocaleMap })
: import("@locales/admin.en.compiled.json"),
fr: () => import("@locales/admin.fr.compiled.json"),
es: () => import("@locales/admin.es.compiled.json"),
...
};
Then we consume it in a component which accepts the language key, lazy-loads the bundle by just calling `LOCALE_MAP[key]()`, and then uses it as the string translation set for a context function which looks up keys in a dict. Super simple.