Šķîþ ţö ḿàîñ çöñţéñţ

Ŕüñţîḿé ṽš. îñļîñé ḿöđé

Ţĥé ḿöđé đéçîđéš ĥöŵ ţŕàñšļàţéđ ţéẋţ ŕéàçĥéš ţĥé ƃŕöŵšéŕ. Ŕüñţîḿé ḿöđé šĥîþš öñé ƃüñđļé àñđ ƒéţçĥéš à đîçţ ƒöŕ ţĥé àçţîṽé ļöçàļé, àñđ îñļîñé ḿöđé ƃüîļđš öñé ƃüñđļé þéŕ ļöçàļé ŵîţĥ ţĥé ţŕàñšļàţéđ ţéẋţ àļŕéàđý îñ îţ. Þîçķ ţĥé öñé ţĥàţ ḿàţçĥéš ĥöŵ ýöü đéþļöý.

Ŕüñţîḿé ḿöđé​

neokapi({ mode: "runtime" });

Ýöü šĥîþ öñé ƃüñđļé, àñđ ţĥé àþþ ƒéţçĥéš à þéŕ-ļöçàļé ĴŠÖÑ ƒîļé àţ ŕüñţîḿé.

Your JSXOne bundle__t(hash) lookupsfetch{locale}.jsonRendered pageany locale

Ŕüñţîḿé ḿöđé: öñé ƃüîļđ, àñđ ţĥé đîçţ ƒöŕ ţĥé àçţîṽé ļöçàļé ļöàđš îñ ţĥé ƃŕöŵšéŕ.

Éṽéŕý ţŕàñšļàţàƃļé ĴŠẊ šîţé ĝéţš ŕéŵŕîţţéñ ţö à __t(hash, fallback, params) çàļļ:

// Source
<h1>Welcome</h1>

// Output (runtime mode)
<h1>{__t("aB3", "Welcome")}</h1>

Ţĥé ŕüñţîḿé îš ~2 ķƂ ĝžîþþéđ; îţ ĥöļđš ţĥé àçţîṽé đîçţ àñđ à šüƃšçŕîƃéŕ šéţ. Ŵĥéñ loadTranslations(locale, url) ŕéšöļṽéš, éṽéŕý šüƃšçŕîƃéđ çöḿþöñéñţ ŕé-ŕéñđéŕš.

Ŵĥéñ ŕüñţîḿé ḿöđé ƒîţš​

  • Ýöü šĥîþ à šîñĝļé ĴŠ ƃüñđļé ţö à ÇĐÑ àñđ ƒļîþ ļöçàļéš ƃàšéđ öñ üšéŕ þŕéƒéŕéñçé.
  • Ýöü ŵàñţ ţö àđđ ñéŵ ļöçàļéš ŵîţĥöüţ ŕé-đéþļöýîñĝ ýöüŕ ĴŠ.
  • Ýöü ĥàṽé ḿöŕé ţĥàñ à ĥàñđƒüļ öƒ ļöçàļéš; ţĥé þéŕ-ļöçàļé ĴŠÖÑ îš à šḿàļļ đöŵñļöàđ çöḿþàŕéđ ţö ýöüŕ ĴŠ ƃüñđļé.
  • Ýöü ŵàñţ ţö šŵîţçĥ ļöçàļé îñ ţĥé þàĝé (ļàñĝüàĝé þîçķéŕ, À/Ƃ).

Ļöàđ öñçé, šüƃšçŕîƃé ţö çĥàñĝéš​

import { loadTranslations, setTranslations, useNeokapi } from "@neokapi/i18n-react/runtime";

async function bootstrap() {
const locale = navigator.language.split("-")[0];
if (locale !== "en") {
await loadTranslations(locale, `/translations/${locale}.json`).catch(() => {});
}
ReactDOM.createRoot(root).render(<App />);
}

// Somewhere in the tree that should re-render on locale change
function AppRoot() {
useNeokapi(); // subscribe
return <Routes />;
}

useNeokapi() šüƃšçŕîƃéš ţö ţĥé ţŕàñšļàţîöñ šţöŕé ṽîà useSyncExternalStore. Ŵĥéñ ţĥé đîçţ üþđàţéš, éṽéŕý çöḿþöñéñţ ţĥàţ çàļļéđ ţĥé ĥööķ ŕé-ŕéñđéŕš, àñđ Ŕéàçţ ŕé-ŕéñđéŕš îţš çĥîļđŕéñ àš üšüàļ.

Ƒöŕ à ļöçàļé šŵîţçĥéŕ ÜÎ: çàļļ loadTranslations öŕ setTranslations("en", {}) öñ çĥàñĝé, àñđ ḿàķé šüŕé useNeokapi() îš çàļļéđ ĥîĝĥ éñöüĝĥ îñ ţĥé ţŕéé ƒöŕ ţĥé ŵĥöļé ṽîšîƃļé šüŕƒàçé ţö ŕé-ŕéñđéŕ.

Ţö šķîþ ţĥàţ đéçîšîöñ, ŵŕàþ ţĥé ţŕéé îñ <NeokapiProvider>. Îţ šüƃšçŕîƃéš ƒöŕ ýöü àñđ ŕé-ķéýš îţš çĥîļđŕéñ öñ éṽéŕý ļöçàļé çĥàñĝé, šö ţĥé ŵĥöļé šüƃţŕéé ŕéḿöüñţš àñđ ŕé-ŕéàđš ţĥé đîçţ:

import { NeokapiProvider } from "@neokapi/i18n-react/runtime";

ReactDOM.createRoot(root).render(
<NeokapiProvider>
<App />
</NeokapiProvider>,
);

À ŕéḿöüñţ đîšçàŕđš ţĥé çöḿþöñéñţ šţàţé ƃéļöŵ îţ. Ţĥàţ îš üšüàļļý ƒîñé öñ à ļöçàļé šŵîţçĥ àñđ üšüàļļý ŵŕöñĝ îñ ţĥé ḿîđđļé öƒ à ƒöŕḿ. useNeokapi() ŕé-ŕéñđéŕš öñļý ţĥé çöḿþöñéñţš ţĥàţ šüƃšçŕîƃé, àñđ NeokapiProvider ŕéàçĥéš éṽéŕý çöḿþöñéñţ îñ ţĥé ţŕéé.

Ƒàļļƃàçķ çĥàîñ​

loadTranslations ţàķéš à ļîšţ öƒ ÜŔĻš àš ŵéļļ àš à šîñĝļé öñé. Ţĥé ļîšţ îš à ƒàļļƃàçķ çĥàîñ: ƒàļļƃàçķš ƒîŕšţ, þŕîḿàŕý ļàšţ:

await loadTranslations("pt-BR", ["/translations/pt.json", "/translations/pt-BR.json"]);

Éṽéŕýţĥîñĝ ḿéŕĝéš îñţö öñé đîçţ, ŵîţĥ ļàţéŕ éñţŕîéš öṽéŕŕîđîñĝ éàŕļîéŕ öñéš, šö pt-BR ŵîñš ŵĥéŕé îţ ĥàš à šţŕîñĝ àñđ pt ƒîļļš ţĥé ŕéšţ. ΃ à ƒàļļƃàçķ ƒàîļš ţö ļöàđ, ýöü ĝéţ ţĥé šţŕîñĝš ţĥàţ đîđ ļöàđ. ΃ ţĥé þŕîḿàŕý ƒàîļš, ţĥé çàļļ ŕéĵéçţš, šö ýöü šéé ţĥé éŕŕöŕ.

loadTranslations àñđ setTranslations àļšö šéţ <html lang> àñđ <html dir> ţö ţĥé ñéŵ ļöçàļé, ŵĥîçĥ šçŕééñ ŕéàđéŕš, ƒöñţš, ĥýþĥéñàţîöñ àñđ ŔŢĻ ļàýöüţ đéþéñđ öñ. Öþţ öüţ ŵîţĥ { syncDocumentLocale: false } îƒ ýöüŕ àþþ öŵñš ţĥöšé àţţŕîƃüţéš. Đéţàîļš: Çöñƒîĝüŕàţîöñ → ĤŢḾĻ lang àñđ dir.

Ļàžý ļöàđîñĝ þéŕ ŕöüţé (çöđé šþļîţţîñĝ)​

Îñ à ļàŕĝéŕ àþþ, öñé çàţàļöĝ þéŕ ļöçàļé ḿéàñš ţĥé üšéŕ đöŵñļöàđš éṽéŕý šţŕîñĝ, îñçļüđîñĝ ţĥöšé ƒöŕ ŕöüţéš ţĥéý ñéṽéŕ ṽîšîţ. Ţĥé þļüĝîñ àñđ ţĥé ŕüñţîḿé çàñ šþļîţ ţŕàñšļàţîöñš àļöñĝ ţĥé šàḿé ļîñéš ţĥé ƃüñđļéŕ šþļîţš çöđé:

  1. Îñ ŕüñţîḿé ḿöđé, ţĥé þļüĝîñ éḿîţš translations-manifest.json ñéẋţ ţö ýöüŕ ĴŠ çĥüñķš, à {chunkName: hashes[]} ḿàþ öƒ ŵĥîçĥ šţŕîñĝš éàçĥ çĥüñķ ñééđš. Ṽîţé, Ŕöļļüþ, ŵéƃþàçķ, Ŕšþàçķ, àñđ éšƃüîļđ àļļ éḿîţ îţ (éšƃüîļđ ñééđš metafile: true).
  2. neokapi-i18n split šļîçéš éàçĥ ḿàšţéŕ {locale}.json îñţö þéŕ-çĥüñķ šüƃšéţš ({locale}/{chunkName}.json), đüþļîçàţîñĝ šţŕîñĝš šĥàŕéđ àçŕöšš çĥüñķš šö éàçĥ ƒîļé îš îñđéþéñđéñţļý ļöàđàƃļé.
  3. Ţĥé ŕüñţîḿé'š loadTranslationChunk(locale, url) ƒéţçĥéš öñé šüƃšéţ àñđ ḿéŕĝéš îţ îñţö ţĥé àçţîṽé đîçţ. Çöñçüŕŕéñţ ŕéǫüéšţš ƒöŕ ţĥé šàḿé (locale, url) þàîŕ šĥàŕé à šîñĝļé ƒéţçĥ.

Ŵîŕé îţ îñţö à Ŕéàçţ Ŕöüţéŕ ļàžý ŕöüţé:

import { loadTranslationChunk } from "@neokapi/i18n-react/runtime";

const routes = [
{
path: "/settings",
lazy: async () => {
const [mod] = await Promise.all([
import("./SettingsPage"),
loadTranslationChunk(locale, `/translations/${locale}/SettingsPage.json`),
]);
return { Component: mod.default };
},
},
];

Ƃüîļđ þîþéļîñé:

vite build # emits dist/translations-manifest.json
neokapi-i18n compile i18n/ --out public/translations
neokapi-i18n split \
--manifest dist/translations-manifest.json \
--locales public/translations \
--out dist/translations

À ḿîššîñĝ ĥàšĥ ŕéñđéŕš ţĥé šöüŕçé ţéẋţ ƃàķéđ îñţö îţš __t / __tx çàļļ àţ ƃüîļđ ţîḿé, šö à ļàţé çĥüñķ ñéṽéŕ ƃŕéàķš ţĥé ŕéñđéŕ. Ţĥé üšéŕ šééš Éñĝļîšĥ ƒöŕ àƃöüţ 100ḿš ŵĥîļé ţĥé çĥüñķ ļöàđš.

Ŵîţĥ merge: true, setTranslations àñđ loadTranslations ḿéŕĝé ţĥé îñçöḿîñĝ éñţŕîéš îñţö ţĥé éẋîšţîñĝ đîçţ îñšţéàđ öƒ ŕéþļàçîñĝ îţ. loadTranslationChunk üšéš ţĥîš îñţéŕñàļļý. Šŵîţçĥîñĝ ļöçàļé ŵîţĥöüţ merge đŕöþš àñý îñ-ƒļîĝĥţ çĥüñķ ļöàđš ƒöŕ ţĥé þŕéṽîöüš ļöçàļé, šö ţĥéîŕ þàýļöàđš çàñ'ţ öṽéŕŵŕîţé éñţŕîéš îñ ţĥé ñéŵ đîçţ.

Ŕüñţîḿé þšéüđö-ţŕàñšļàţîöñ​

Ŕüñţîḿé ḿöđé çàñ þšéüđö-ţŕàñšļàţé öñ ţĥé ƒļý, ŵîţĥ ñö ƃüîļđ šţéþ àñđ ñö çàţàļöĝ. Üšé îţ đüŕîñĝ đéṽéļöþḿéñţ ţö çĥéçķ ļàýöüţ àñđ ţö šéé ŵĥîçĥ šţŕîñĝš þàšš ţĥŕöüĝĥ ţŕàñšļàţîöñ:

import { setPseudoMode } from "@neokapi/i18n-react/runtime/pseudo";

// Turn on with defaults (▒-wrapped, accented)
setPseudoMode({});

// Tune
setPseudoMode({
prefix: "« ",
suffix: " »",
expansion: 30, // +30% padding to test layout
alphabet: "accented", // ASCII → accented variants (the default)
});

// Off
setPseudoMode(null);

Ţĥé ţŕàñšƒöŕḿ àþþļîéš öñ ţöþ öƒ ţĥé ŕüñţîḿé đîçţ. Ýöü çàñ ļöàđ à ŕéàļ Ƒŕéñçĥ çàţàļöĝ, ţĥéñ ţüŕñ þšéüđö öñ ţö šéé Ƒŕéñçĥ àţ +30% ļéñĝţĥ, ŵîţĥ ḿàŕķéŕš ţĥàţ šĥöŵ ŵĥîçĥ šţŕîñĝš ŵéŕé ţŕàñšļàţéđ àñđ ŵĥîçĥ ƒéļļ ƃàçķ ţö šöüŕçé. {param} / {=m0} ţöķéñš àŕé þŕéšéŕṽéđ ṽéŕƃàţîḿ, šö þàŕàḿ šüƃšţîţüţîöñ šţîļļ ŵöŕķš.

Ţéẋţ îñšîđé à <code>, à <kbd>, à <samp> öŕ à <var> çöḿéš ţĥŕöüĝĥ àš ţĥé àüţĥöŕ ŵŕöţé îţ, ţĥé šàḿé ƃýţéš à kapi pseudo-translate çàţàļöĝ çàŕŕîéš. Run <code>kapi check --ship</code> first. ŕéàđš àš àççéñţéđ þŕöšé àŕöüñđ à çöḿḿàñđ ţĥàţ šţîļļ ŕüñš. À translate="yes" öñ ţĥé šþàñ çļàîḿš îţš ţéẋţ ƃàçķ ƒöŕ ţĥé ţŕàñšƒöŕḿ. Þàđđîñĝ šķîþš ţĥöšé šþàñš ţöö, ƃéçàüšé à çöḿḿàñđ ķééþš îţš ļéñĝţĥ îñ à ŕéàļ ţŕàñšļàţîöñ.

Ŵöŕķš ŵîţĥöüţ à çàţàļöĝ. Ţĥé šöüŕçé šţŕîñĝ ļàñđš îñ ţĥé __t / __tx çàļļ àš ţĥé fallback àŕĝüḿéñţ àţ ƃüîļđ ţîḿé. Ŵĥéñ ţĥé đîçţ îš éḿþţý ţĥé ŕüñţîḿé üšéš ţĥé ƒàļļƃàçķ, àñđ þšéüđö ţŕàñšƒöŕḿš îţ. Éđîţ <h1>Welcome</h1> → šàṽé → ĤḾŔ ŕéþļàçéš ţĥé ḿöđüļé → Ŕéàçţ ŕé-ŕéñđéŕš → "▒ Ŵéļçöḿé ▒". Ýöü ñééđ ñö éẋţŕàçţ, çöḿþîļé öŕ ŕéƃüîļđ šţéþ. Ţĥé öñļý þŕéŕéǫüîšîţé îš neokapi({ mode: "runtime" }) îñ vite.config.ts; ŵîţĥöüţ ŕüñţîḿé ḿöđé ţĥé þļüĝîñ đöéš ñöţĥîñĝ, àñđ ţĥéŕé îš ñö __t çàļļ ƒöŕ þšéüđö ţö ţŕàñšƒöŕḿ.

Ţĥé þàñéļ ƃéļöŵ ŕüñš ţĥé ŕéàļ ñéöķàþî-î18ñ ŕüñţîḿé îñ ýöüŕ ƃŕöŵšéŕ, ŵîţĥ ñö çàţàļöĝ ļöàđéđ. Ţöĝĝļé þšéüđö ḿöđé àñđ ţĥé šàḿé šţŕîñĝš ƒļîþ ţö àççéñţéđ, éẋþàñđéđ ţéẋţ; {name} šţàýš ļîţéŕàļ ƃéçàüšé {param} ţöķéñš àŕé þŕéšéŕṽéđ ţĥŕöüĝĥ ţĥé ţŕàñšƒöŕḿ:

Ţö ḿàķé þšéüđö ţĥé đéƒàüļţ îñ đéṽéļöþḿéñţ, çàļļ îţ àţ ţĥé ţöþ öƒ main.tsx, ĝüàŕđéđ öñ import.meta.env.DEV, àñđ ķééþ à çöñšöļé ĥàñđļé ƒöŕ ţüñîñĝ:

import { setPseudoMode } from "@neokapi/i18n-react/runtime/pseudo";

if (import.meta.env.DEV) {
setPseudoMode({ expansion: 30 });
// @ts-expect-error: dev-only global so you can re-tune from the console
window.setPseudoMode = setPseudoMode;
}

Ţĥé þšéüđö ḿöđüļé ĥàš îţš öŵñ šüƃþàţĥ (@neokapi/i18n-react/runtime/pseudo), šö ýöü îḿþöŕţ îţ öñļý ŵĥéñ ýöü ŵàñţ îţ, àñđ ţĥé ḿàîñ ŕüñţîḿé šţàýš ~2 ķƂ. Îţ îš ƃüîļţ öñ setStringTransform, à þöšţ-ļööķüþ ĥööķ ţĥàţ ţĥé ḿàîñ ŕüñţîḿé àļšö éẋþöŕţš ƒöŕ çüšţöḿ ţŕàñšƒöŕḿš šüçĥ àš đéƃüĝ ḿàŕķéŕš öŕ ļéţţéŕ-šþàçîñĝ àüđîţš.

À çüšţöḿ ţŕàñšƒöŕḿ ţàķéš ţĥé ḿéššàĝé ţéẋţ àñđ à çöñţéẋţ. Ţĥé çöñţéẋţ çàŕŕîéš markers, öñé éñţŕý þéŕ îñļîñé éļéḿéñţ ţĥàţ àñšŵéŕš ƒöŕ ţĥé ţéẋţ îñšîđé îţ: "no" ƒöŕ à šþàñ ĥöļđîñĝ à çöḿḿàñđ, à ķéý öŕ àñ îđéñţîƒîéŕ, "yes" ŵĥéŕé ţĥé šöüŕçé çļàîḿéđ îţ ƃàçķ. protectionMask(text, markers), éẋþöŕţéđ ƒŕöḿ ţĥé ŕüñţîḿé, ţüŕñš ţĥöšé àñšŵéŕš îñţö à þéŕ-çĥàŕàçţéŕ àŕŕàý šö à ţŕàñšƒöŕḿ çàñ ŕéŵŕîţé ţĥé þŕöšé àñđ ļéàṽé ţĥé ŕéšţ:

import { setStringTransform, protectionMask } from "@neokapi/i18n-react/runtime";

setStringTransform((text, context) => {
const guarded = protectionMask(text, context?.markers);
return [...text].map((ch, i) => (guarded?.[i] ? ch : ch.toUpperCase())).join("");
});

Îñļîñé ḿöđé​

neokapi({
mode: "inline",
locale: "fr",
translationsDir: "./translations",
});

Ýöü ƃüîļđ öñé ƃüñđļé þéŕ ļöçàļé, àñđ ţĥé ƃüîļđ ŕéþļàçéš éṽéŕý ĴŠẊ ţéẋţ ñöđé ŵîţĥ ţĥé ţŕàñšļàţéđ ļîţéŕàļ. Ţĥéŕé îš ñö ŕüñţîḿé đîçţ ļööķüþ, šüƃšçŕîþţîöñ öŕ loadTranslations() çàļļ:

Your JSXBuild per localetranslations/fr.jsonBundle for frtext inlinedRendered pagefr only

Îñļîñé ḿöđé: öñé ƃüîļđ þéŕ ļöçàļé, ŵîţĥ ţĥé ţŕàñšļàţéđ ţéẋţ ŵŕîţţéñ îñţö éàçĥ ƃüñđļé.

// Source
<h1>Welcome</h1>

// Output (inline mode, locale=fr)
<h1>Bienvenue</h1>

Ŕîçĥ ţéẋţ îš ŕéƃüîļţ àš ĴŠẊ, šö à ţŕàñšļàţöŕ îš ƒŕéé ţö ḿöṽé ţĥé ļîñķ, àñđ ţĥé ḿàŕķüþ ƒöļļöŵš:

// Source
<p>Read the <a href="/docs">docs</a> first.</p>

// Output (inline mode, locale=de): the link moved, the href stayed
<p>Lies zuerst die <a href="/docs">Dokumentation</a>.</p>

Ţĥé ÎÇÜ éẋçéþţîöñ​

Îñļîñé ḿöđé îš žéŕö-ŕüñţîḿé ŵîţĥ öñé đöçüḿéñţéđ éẋçéþţîöñ: <Plural>, <Select>, àñđ àñý šţŕîñĝ à ţŕàñšļàţöŕ ĝàṽé àñ ÎÇÜ ƒöŕḿàţ ţö ķééþ à ŕüñţîḿé çàļļ.

À þļüŕàļ'š þîṽöţ (ţĥé çöüñţ) îš ķñöŵñ öñļý ŵĥéñ ţĥé çöḿþöñéñţ ŕéñđéŕš, šö ñö ƃüîļđ šţéþ çàñ þîçķ ţĥé ƒöŕḿ. Îñļîñé ḿöđé đöéš ţĥé ĥàļƒ îţ çàñ: ţĥé ţŕàñšļàţéđ ÎÇÜ ţéḿþļàţé îš ƃàķéđ îñţö ţĥé çàļļ àš îţš ƒàļļƃàçķ, šö ţĥéŕé'š ñö đîçţîöñàŕý ţö ƒéţçĥ àñđ ñö ñéţŵöŕķ öñ ţĥé çŕîţîçàļ þàţĥ. Ŵĥàţ šţàýš îš ţĥé ~2 ķƂ ÎÇÜ ŕéšöļṽéŕ.

΃ ýöü ĥàṽé ñö þļüŕàļš àñđ ñö ÎÇÜ ƒöŕḿàţš, îñļîñé ḿöđé šĥîþš ñöţĥîñĝ. ΃ ýöü ĥàṽé öñé, ýöü šĥîþ ţĥé ŕéšöļṽéŕ. Éîţĥéŕ ŵàý ţĥé öüţþüţ îš ṽàļîđ ĴŠẊ, àñđ ţĥé šţŕîñĝ ŕéñđéŕš îñ ţĥé ţàŕĝéţ ļàñĝüàĝé.

Ŵĥéñ îñļîñé ḿöđé ƒîţš​

  • Ýöü šĥîþ þéŕ-ļöçàļé ƃüîļđš (www-fr.example.com, www-de.example.com).
  • Ýöü çàŕé àƃöüţ ƒîŕšţ-þàîñţ ƃüñđļé šîžé: ñö ŕüñţîḿé, ñö đîçţ ƒéţçĥ.
  • Ýöü ĥàṽé ŠŠŔ / ŠŠĜ àñđ ŵàñţ þŕé-ŕéñđéŕéđ ĤŢḾĻ îñ ţĥé ţàŕĝéţ ļöçàļé.
  • Ýöüŕ ļöçàļé šéţ îš šḿàļļ àñđ ŕàŕéļý çĥàñĝéš.

Ţýþîçàļ îñļîñé šéţüþ​

# Build one app per locale in CI
for locale in en fr de ja; do
LOCALE=$locale vite build --outDir dist/$locale
done
vite.config.ts
export default defineConfig({
plugins: [
neokapi({
mode: "inline",
locale: process.env.LOCALE ?? "en",
translationsDir: "./translations",
strict: "error", // fail the build on missing translations
}),
react(),
],
});

strict: "error" ţüŕñš ḿîššîñĝ ţŕàñšļàţîöñš îñţö à ƃüîļđ éŕŕöŕ: ñöţĥîñĝ üñţŕàñšļàţéđ šĥîþš. Ƒöŕ à ḿàŕķéţ-ƃý-ḿàŕķéţ ŕöļļöüţ, ķééþ strict: "warn" (ţĥé đéƒàüļţ) đüŕîñĝ đéṽéļöþḿéñţ àñđ šŵîţçĥ ţö "error" ƒöŕ ţĥé ŕéļéàšé ƃüîļđ.

Ƃüîļđ-ţîḿé ƒàļļƃàçķ çĥàîñ​

Îñļîñé ḿöđé ĥàš îţš öŵñ ƒàļļƃàçķ çĥàîñ, ŕéšöļṽéđ àţ ƃüîļđ ŕàţĥéŕ ţĥàñ àţ ļöàđ (ţĥé ŕüñţîḿé-ḿöđé éǫüîṽàļéñţ îš loadTranslations ŵîţĥ à ÜŔĻ ļîšţ). Ŵĥéñ à ţŕàñšļàţîöñ îš ḿîššîñĝ îñ ţĥé þŕîḿàŕý ļöçàļé, îţ çöñšüļţš ƒàļļƃàçķ ļöçàļéš ƃéƒöŕé ĝîṽîñĝ üþ:

neokapi({
mode: "inline",
locale: "de-AT",
fallbackLocales: ["de", "en"],
});

Ƒöŕ ţĥé Àüšţŕîàñ-Ĝéŕḿàñ ƃüîļđ, à ḿîššîñĝ de-AT éñţŕý ƒàļļš ƃàçķ ţö de, ţĥéñ ţö en, ţĥéñ ţö ţĥé šöüŕçé ţéẋţ.

Ĥýƃŕîđ: îñļîñé çöŕé, ŕüñţîḿé öþţîöñàļ ļöçàļéš​

À çöḿḿöñ þàţţéŕñ îš ţö îñļîñé ţĥé þŕîḿàŕý ļöçàļé àţ ƃüîļđ ţîḿé (šö ţĥé đéƒàüļţ ḿàŕķéţ ļöàđš îñšţàñţļý) àñđ ḿàķé šéçöñđàŕý ļöçàļéš àṽàîļàƃļé ṽîà ţĥé ŕüñţîḿé đîçţ:

// Primary build
neokapi({ mode: "inline", locale: "en" });

// Secondary locales still get an OTA dict loaded via loadTranslations
// when the user switches, compiled from the same KBF directory.

À šîñĝļé ƃüîļđ üšéš öñé ḿöđé, àñđ ýöü çĥööšé ţĥé ḿöđé þéŕ đéþļöý.

Ḿöđé çöḿþàŕîšöñ​

ŕüñţîḿéîñļîñé
Ñüḿƃéŕ öƒ ƃüîļđš11 þéŕ ļöçàļé
Ŕüñţîḿé ƃüñđļé çöšţ~2 ķƂ0, öŕ ~2 ķƂ îƒ ýöü üšé ÎÇÜ / þļüŕàļš
Đîçţ ƒéţçĥ àţ ŕüñţîḿéýéš (þéŕ ļöçàļé)ñö
Ḿîššîñĝ ţŕàñšļàţîöñƒàļļƃàçķ ţö šöüŕçé ţéẋţŵàŕñ öŕ éŕŕöŕ àţ ƃüîļđ
Ĥöţ-šŵàþ ļöçàļé îñ-þàĝéý隃üļļ þàĝé ŕéļöàđ / šŵàþ ƃüñđļé
Ƃéšţ ƒöŕàþþ šĥéļļš, ŠààŠ đàšĥƃöàŕđšḿàŕķéţîñĝ šîţéš, ŠŠŔ, ŠŠĜ, ļöçàļé-þéŕ-đöḿàîñ

À ţŕàñšļàţîöñ ţĥàţ îš þŕéšéñţ ƃüţ üñšöüñđ çöüñţš àš ḿîššîñĝ ţöö: neokapi-i18n compile ļéàṽéš öüţ àñý ţàŕĝéţ ţĥàţ đöéš ñöţ çàŕŕý éṽéŕý þļàçéĥöļđéŕ îţš šöüŕçé ĥàš, šö îñ ŕüñţîḿé ḿöđé ţĥàţ éñţŕý ƒàļļš ƃàçķ ţö šöüŕçé ţéẋţ üñţîļ ţĥé ñéẋţ ţŕàñšļàţîöñ þàšš ŕéþàîŕš îţ.

Ŵĥàţ đöéšñ'ţ çĥàñĝé ƃéţŵééñ ḿöđéš​

  • Ţĥé éẋţŕàçţöŕ (neokapi-i18n extract) þŕöđüçéš ţĥé šàḿé .kbf.json ŕéĝàŕđļéšš öƒ ḿöđé.
  • Ĥàšĥéš àŕé ḿöđé-îñđéþéñđéñţ.
  • <Plural> / <Select> / t() àļļ ŵöŕķ ţĥé šàḿé îñ àüţĥöŕîñĝ.
  • Üñḿàþþéđ-çöḿþöñéñţ ŵàŕñîñĝš ƒîŕé îđéñţîçàļļý.

Ŕéļàţéđ​