Skip to content

Translation Function

The t() function is the primary way to translate strings in your app. It’s available from the useI18n() hook/composable (React/Vue/Solid/Svelte) or directly from the core instance.

const { t } = useI18n();
t('hello.world'); // "Hello, World!"
t('welcome', { name: 'Alice' }); // "Welcome, Alice!"
t(key: string, params?: TranslationParams): string

t() returns a plain string. For translations that contain HTML tags or components, use the <T> component — see Tag Interpolation.

All t() calls accept a params object with two categories: interpolation values and special options.

Interpolation values — any key/value pair replaces {key} in the translation:

t('greeting', { name: 'Alice' }); // {name} → Alice

Special options:

PropertyTypeDescription
nsstringNamespace override for this call. Defaults to defaultNs.
localestringForce a specific locale for this call, bypassing the current locale.
fallbackstringReturned (with interpolation) if the key is missing. Overrides any value returned by onMissingKey callbacks.

Mix interpolation values with options freely:

t('welcome', {
name: 'Alice', // interpolation value
ns: 'dashboard', // special option
locale: 'de', // special option
fallback: 'Hello!' // special option
});

Translation keys use dot notation to navigate nested translation objects. To look up a key in a non-default namespace, pass the namespace via the ns option — never as part of the key string.

en/common.json
{
"user": {
"profile": {
"title": "My Profile"
}
},
"errors": {
"validation": {
"required": "This field is required"
}
}
}
t('user.profile.title'); // "My Profile"
t('errors.validation.required'); // "This field is required"

Use the ns option to look up a key in a non-default namespace for a single call:

t('page.title', { ns: 'dashboard' }); // Looks in dashboard namespace
t('submit.label', { ns: 'forms' }); // Looks in forms namespace

To scope an entire component to a namespace, pass it to useI18n():

const { t } = useI18n('dashboard');
t('page.title'); // Looks up "page.title" in dashboard namespace
t('buttons.save', { ns: 'common' }); // Override to common namespace

Passing a namespace to useI18n() only scopes translation calls. It does not load that namespace by itself. Make sure the namespace is loaded during initialization, by your loader/plugin setup, or by calling addActiveNamespace().

See Namespaces for namespace configuration, lazy loading, and per-route strategies.

Force a specific locale for a single call:

t('greeting', { locale: 'de' }); // Always returns German, regardless of current locale

This is useful for mixed-language content or explicit language displays. See Language Switching for changing the app’s global language.

Provide a fallback for missing keys:

t('new.feature.title', { fallback: 'New Feature' });

The fallback text supports interpolation, so placeholders are replaced just like in regular translations:

t('welcome.new', { fallback: 'Welcome, {name}!', name: 'Alice' });
// "Welcome, Alice!" — if the key is missing

Translations can contain ICU MessageFormat syntax for pluralization (plural) and variant selection (select). The t() function handles this automatically — just pass the matching parameter:

// Plural: "{count, plural, =0 {No items} one {# item} other {# items}}"
t('cart.items', { count: 5 }); // "5 items"
// Select: "{gender, select, male {He} female {She} other {They}} left a comment"
t('user.action', { gender: 'female' }); // "She left a comment"

See Pluralization & ICU for plural categories, exact matches, nested messages, and full ICU MessageFormat reference.

Translations can contain named tags like <link> and <bold>. Use the <T> component to map these tags to real UI elements. See Tag Interpolation for the full guide with all framework examples.

When a key doesn’t exist in the current locale + namespace, the lookup proceeds in this order:

  1. Walk the fallback locale chain (if configured) and look for the key in each fallback locale
  2. Emit the 'missingKey' event
  3. Run any runtime callbacks registered via i18n.onMissingKey(cb) — collect the first non-undefined return value
  4. If still no value, run the option callback from createI18n({ onMissingKey }) (a single, instance-wide callback)
  5. If params.fallback is set, return its interpolated text — this overrides any value returned by the callbacks above
  6. Otherwise return the value from step 3/4, or the key string itself if nothing produced a fallback

The key precedence rule: params.fallback always wins over callback return values. Use callbacks for diagnostics (logging, error tracking) and params.fallback for the user-facing fallback text.

Register a single instance-wide callback at construction. The argument is a MissingKeyInfo object:

const i18n = createI18n({
locale: 'en',
onMissingKey: ({ key, locale, namespace }) => {
console.warn(`Missing translation: ${key} [${locale}/${namespace}]`);
// Return a string to use as fallback, or undefined to continue
},
});

Register additional callbacks at runtime. Note the different signature — the runtime callback receives three positional arguments, not a destructured object:

const cleanup = i18n.onMissingKey((key, locale, namespace) => {
// Report to error tracker (e.g., Sentry)
// Return a string for fallback, or undefined to let other callbacks run
});
cleanup(); // Unsubscribe

Multiple runtime callbacks can be registered; the first one to return a non-undefined value wins.

Provide a per-call fallback text:

t('new.feature.title', { fallback: 'New Feature' });

The fallback string supports interpolation, so parameters are still replaced:

t('welcome.new', {
fallback: 'Welcome, {name}!',
name: 'Alice'
}); // "Welcome, Alice!" if key is missing

Pattern: Use onMissingKey for diagnostics (logging, error tracking), and params.fallback for user-facing fallback text.

See Error Handling for fallback locale chains, error events, and production strategies.