useTranslation()
The useTranslation hook returns the translated string for a text, inside a component. It is the hook behind I18nKeylessText — the component is this hook plus a fragment — so it takes the same options and resolves the text the same way.
Use it where an element will not do: a placeholder, a title, an aria-label, a string handed to another library (a markdown renderer, a navigator's tabBarLabel). Everywhere else, prefer <I18nKeylessText>.
Called without a text, it returns a reactive t() function instead — for a component with many strings, or strings inside an array or a .map(). See The function form.
Available since i18n-keyless-react@3.3.0; the function form since 3.6.0.
Function Signature
// docs-check: skip — a signature listing, not a snippet to run
useTranslation(
text: string,
options?: {
context?: string;
namespace?: string;
unpersistedNamespace?: boolean;
replace?: Record<string, string>;
forceTemporary?: Record<string, string>;
originLanguage?: Lang;
debug?: boolean;
}
): string
// The function form: no text, same options as defaults.
useTranslation(options?: TranslationOptions): (text: string, options?: TranslationOptions) => string
Parameters
text
type: string(required)
The text to translate, written in your primary language. It is also the translation key.
options
type: TranslationOptions
The same options as the props of I18nKeylessText — context, namespace, unpersistedNamespace, replace, forceTemporary, originLanguage, debug.
Return Value
type: string
The translated text in the current language. The source text when the current language is the primary language, or while the translation has not arrived yet.
Basic Usage
- Attributes
- With replace
- With context
- Another library
import { useTranslation } from 'i18n-keyless-react';
export function SearchBox() {
const placeholder = useTranslation('Search products...');
const label = useTranslation('Search input');
return <input type="search" placeholder={placeholder} aria-label={label} />;
}
import { useTranslation } from 'i18n-keyless-react';
export function PlanOption({ label, price }: { label: string; price: number }) {
const text = useTranslation('{label} — {price}€/month', {
replace: { '{label}': label, '{price}': String(price) },
});
return <option value={label}>{text}</option>;
}
import { useTranslation } from 'i18n-keyless-react';
export function Duration() {
// "8 heures" is ambiguous in French: "8 AM" or "8 hours".
const title = useTranslation('8 heures', { context: 'durée' });
return <abbr title={title}>8h</abbr>;
}
import { useTranslation } from 'i18n-keyless-react';
import ReactMarkdown from 'react-markdown';
export function Intro() {
const markdown = useTranslation('Welcome to **i18n-keyless**, the keyless i18n.');
return <ReactMarkdown>{markdown}</ReactMarkdown>;
}
The function form
For one or two strings, one hook call per string reads well. For a nav with twenty labels, a table header, or strings inside an array or a .map() — where the rules of hooks forbid a hook — call useTranslation() without a text. It returns a reactive t(text, options?) function with the same resolution as the string form. The options given to the hook are the defaults; the options given to a call merge over them.
import { useTranslation } from 'i18n-keyless-react';
const links = [
{ to: '/dashboard', label: 'Dashboard' },
{ to: '/inbox', label: 'Inbox' },
{ to: '/activity', label: 'Audit' },
];
export function Nav() {
const t = useTranslation({ context: 'navigation menu item' });
return (
<nav>
{links.map((link) => (
<a key={link.to} href={link.to}>
{t(link.label)}
</a>
))}
</nav>
);
}
The one difference with the string form: t() cannot know its strings ahead of time, so the component re-renders on every translation batch that lands, not only when its own strings change. That is the right trade for a nav; for a single placeholder, pass the text to the hook.
A call site uses one form or the other. The two forms call different hooks, so never switch a given call between them at runtime.
Under SSR the function form reads <I18nKeylessProvider> like the string form does, so it is correct in a TanStack Start component tree. Before init() has run (Storybook, a unit test), t() returns the text as-is.
useTranslation vs getTranslation
useTranslation(text) | getTranslation(text) | |
|---|---|---|
| Where | inside a component (const t = useTranslation() for many strings) | outside a component: a loader, head(), a utility |
| Reactive | yes — re-renders when the translation lands or the language changes | no — reads the store once |
| SSR | reads <I18nKeylessProvider>, like <I18nKeylessText> | reads the runWithI18nKeyless scope |
Under TanStack Start the component tree renders outside the runWithI18nKeyless scope, so getTranslation() in a component body renders the primary language on the server. useTranslation is the string API that is correct there.
Notes
- Must be called in a React component or another hook, unconditionally — the rules of hooks apply
- Queues the text for translation on first sight, like
<I18nKeylessText>does; nothing else to wire - Do not re-implement the lookup by reading
useI18nKeyless((s) => s.translations)yourself: the storage key format, the primary-language shortcut,originLanguageand the SSR snapshot are all inside this hook. When you need a function, use the function form