# @embra/i18n agent guide Use `@embra/i18n` for i18n. Pick the entrypoint that matches the current code. ## Canonical entrypoints | Context | Import | Main usage | | --- | --- | --- | | Core | `@embra/i18n` | `I18n`, `detectLang`, locale types, `i18n.t()` | | React | `@embra/i18n/react` | `I18nProvider`, hooks, React `` | | Astro | `@embra/i18n/astro` | Astro `` for static/server-rendered markup | ## Core translation model ```ts import { I18n, detectLang, type Locales } from "@embra/i18n"; const locales: Locales = { en: { stock: { fruit: "apple" }, eat: "{{name}} eats {{fruit}}.", apple: "{{@}} apples", "apple@0": "No apple", "apple@1": "An apple", }, }; const i18n = new I18n("en", locales); i18n.t("stock.fruit"); // "apple" i18n.t("eat", { fruit: "apple", name: "CRIMX" }); // "CRIMX eats apple." i18n.t("apple", { "@": 1 }); // "An apple" i18n.t("apple", { "@": 3 }); // "3 apples" detectLang(["en", "zh-CN"]); ``` - Locale keys can be nested, for example `stock.fruit`. - Template placeholders use `{{name}}`. - Count/plural matching uses modifier keys such as `apple@0`, `apple@1`; pass the count as `{ "@": count }`. - Dynamic locales use `I18n.preload(lang, loader)`. ## React usage ```tsx import { I18n } from "@embra/i18n"; import { I18nProvider, Trans, useTranslate } from "@embra/i18n/react"; function Message() { const t = useTranslate(); return ( {t("author")} {t("fruit")} ); } ; ``` - Use `useTranslate()` inside React components so UI updates when language or locales change. - React `` matches placeholders with `data-t-slot="name"`. - For one placeholder, React `` can use its child without `data-t-slot`. ## Astro usage ```astro --- import { I18n } from "@embra/i18n"; import { Trans } from "@embra/i18n/astro"; const i18n = new I18n("en", locales); const t = i18n.t; --- {t("author")} {t("fruit")} ``` - Astro `` matches placeholders with Astro named slots like `slot="name"`. - For one placeholder, Astro `` can use the default slot. - Astro `` renders at build time or on the server. Use a framework island for client-side language switching. Missing Trans slots are rendered back as `{{name}}`.