Quick Start
Set up Fuma Translate with compile-time type generation and React.
Fuma Translate extracts translation keys from your React code statically, generates a strict Translations type, and provides a lightweight runtime hook.
Install
npm install fuma-translate @fuma-translate/reactSetup
Add a compile script
Use the CLI to scan your source files and write generated translation files.
{
"type": "module",
"scripts": {
"compile:translations": "fuma-translate \"src/**/*.tsx\"",
"dev": "pnpm compile:translations && ...",
"build": "pnpm compile:translations && ..."
}
}By default, this writes .translations/index.ts and .translations/manifest.json.
export type Translations = {
"Close(dialog button)": string;
Hello: string;
"Hello {user}": string;
};Keys are generated from the original text with meaningful context, your future translation work can rely purely on the keys as a reference.
For other needs, see CLI Usage or Programmatic Usage.
Define translations
Create translations.ts and shape it strictly against the generated type.
import type { Translations } from "./.translations";
export const translations = {
Hello: "Hello",
"Hello {user}": "Hello {user}",
"Close(dialog button)": "Close",
} satisfies Translations;TypeScript will error on missing/unused keys.
Use in React
Wrap your app with TranslationProvider, then call useTranslations() in components.
import { TranslationProvider, useTranslations } from "@fuma-translate/react";
import { translations } from "./translations";
export function App() {
return (
<TranslationProvider translations={translations}>
<HomePage />
<Dialog />
</TranslationProvider>
);
}
function HomePage() {
const t = useTranslations();
return (
<main>
<h1>{t("Hello")}</h1>
<p>{t("Hello {user}", { variables: { user: "Ada" } })}</p>
{/* `note` provides additional context to the text */}
<button type="button">{t("Close", { note: "dialog button" })}</button>
</main>
);
}
function Dialog() {
const t = useTranslations({
note: "text in a dialog",
});
return (
<main>
{/* will inherit `note` from `useTranslations()` too */}
<h1>{t("Hello")}</h1>
</main>
);
}useTranslations() returns the translate hook, see the t() section for more details.
For JSX-only usage, import the T component and pass the original text as a static text prop:
import { T } from "@fuma-translate/react";
function HomePage() {
return <T text="Hello {user}" variables={{ user: <strong>Ada</strong> }} />;
}You can stack multiple providers to override or extend translations:
<TranslationProvider translations={translations}>
<TranslationProvider translations={{ Hello: "Bonjour" }}>
<HomePage />
</TranslationProvider>
</TranslationProvider>Recommended Workflow
- Write UI with static
t("...")calls,t.jsx("...")calls,<T text="..." />components, or annotated calls/components. - Run
pnpm compile:translationsto regenerate.translations/index.ts. - Fill in
translations.tsto satisfy the generated type. - Pass translations to
TranslationProvider.
Translation keys must be statically analyzable. Dynamic keys such as t(key), t(`Hello ${name}`), or <T text={label} /> will fail at compile time.