Skip to main content

useTranslationResolver

Read the translation resolver that is active for this part of the tree.

Import​

import { useTranslationResolver } from '@bedrock-core/ui';

Signature​

function useTranslationResolver(): TranslationResolver | null
type TranslationResolver = (key: string) => string | undefined;

Parameters​

None

Returns​

TranslationResolver | null — A lookup from a real .lang key to its display string in the viewing player's locale, or undefined when nothing carries that key. null when there is no resolver at all — no i18n instance was created, or the component was invoked outside a fiber (tests, build tooling).

It is sugar over useContext(TranslationContext), with the out-of-fiber case returning null instead of throwing, so a component invoked as a plain function still works — strings simply measure and paint literally.

What it is for​

The runtime already resolves localized Text children for you. This hook is for components that build display strings themselves and therefore have to know whether a string is a key before they touch it:

Header and MenuRow in ore-styled are the two built-in consumers.

Usage​

import { Text, useTranslationResolver } from '@bedrock-core/ui';
import { resolveDisplay, type DisplayText } from '@bedrock-core/i18n';

function Banner({ label }: { label: DisplayText }) {
const resolver = useTranslationResolver();

// Literal strings pass through; keys and RawMessages become their display strings.
return <Text>{`§e${resolveDisplay(resolver, label)}`}</Text>;
}

Examples​

Detecting a key​

A resolver hit means the world publishes this string as a key.

function Line({ source, color }: { source: DisplayText; color: string }) {
const resolver = useTranslationResolver();
const literal = typeof source === 'string' && (source === '' || resolver?.(source) === undefined);

// Only color literals — a § prefix on a key would stop it resolving.
return <Text>{literal ? `${color}${source}` : source}</Text>;
}

Measuring localized text yourself​

function Truncated({ keyText }: { keyText: string }) {
const resolver = useTranslationResolver();
const display = resolver?.(keyText) ?? keyText;

return <Text>{display.length > 40 ? `${display.slice(0, 40)}...` : keyText}</Text>;
}

Where the resolver comes from​

render() wraps every root so the resolver is always populated: the addon's default i18n instance — the last createI18n(bundle) call that did not opt out — bound to the viewing player through the full locale chain, and re-derived on every build pass so a setLocale override is picked up on the next render rather than frozen at mount.

A TranslationContext provider inside the tree shadows it for that subtree.

Notes​

Guard for null​

// ✅ Good — optional call, literal fallback
const text = resolver?.(candidate) ?? candidate;

// ❌ Bad — throws in trees with no i18n instance
const text = resolver!(candidate);

Prefer resolveDisplay over hand-rolling​

resolveDisplay(resolver, value) from @bedrock-core/i18n already handles all three DisplayText shapes, including filling a RawMessage's with parameters. Reach for the raw resolver only when you specifically need the key/literal distinction.

Don't use it to fetch your own strings​

For an addon's own text, useTranslation(i18n) gives fully typed verbs. This hook is untyped by design — it takes a real key string, because it exists to resolve keys that came from somewhere else.

  • useTranslation — typed verbs bound to the viewing player
  • TranslationContext — providing a different resolver for a subtree
  • i18n — resolve(), display() and the DisplayText union