Simple, pragmatic and performant i18n solution for JavaScript applications
There're great libraries for i18n that support absolutely everything like interpolation with React components, server-side rendering, and code splitting (or maybe I should call it - JSON splitting). This is one example of such library - react-i18next.
The biggest drawback and issue, something that keeps me from using it is its bundle size. Assuming you're using gzip for compression like everyone else, it will take 20kB+ from your bundle. For some people/teams it's an acceptable amount, but for me, I don't believe it to be a good trade-off.
And that's why I decided to write my implementation that has great DX (supports dotted paths with autocompletion) and is easy to scale/maintain. I used the js-cookie
library to get and parse the cookie with legible & declarative API.
The example is done specifically for Next.js, but you can seamlessly port it to any other library/framework.
// i18n.tsimport Cookies from "js-cookie";import get from "lodash/get";import { en } from "./en";type Locales = "en";const defaultTranslations: Record<Locales, Partial<typeof en>> = {en,};export const t = (key: Join<PathsToStringProps<typeof en>, ".">, translations = defaultTranslations) => {const locale = Cookies.get("NEXT_LOCALE") as Locales;return get(translations[locale] || translations["en"], key);};type PathsToStringProps<T> = T extends string? []: {[K in Extract<keyof T, string>]: [K, ...PathsToStringProps<T[K]>];}[Extract<keyof T, string>];type Join<T extends string[], D extends string> = T extends []? never: T extends [infer F]? F: T extends [infer F, ...infer R]? F extends string? `${F}${D}${Join<Extract<R, string[]>, D>}`: never: string;
This is how the translations file looks like
// en.tsexport const en = {ctaSection: {title: "Some value for demo purposes",// ...The rest of the items, removed for brevity}}
And this is how you use it:
You don't have to worry about the performance unless the file exceeds a few hundred lines. After that, you can use dynamic imports and split the translations file into smaller chunks.