Translations
View as MarkdownTurns the texts of a translations prop into the functions a state machine wants.
Many translations depend on state: the name of a file, the value of a number, the item a screen reader announces. A machine wants a function for those, but Fluid has no callbacks. A template writes a text with %placeholders% instead, a client script passes the function, and resolveTranslations() makes both the same function.
In a template, write the text. The % form survives Fluid, a curly-brace placeholder would be read as a variable:
<ui:numberInput.root translations="{valueText: '%value% pieces'}"> ... </ui:numberInput.root>
In a client script, pass the function itself:
import { mountAll } from 'fluid-primitives';
import { NumberInput } from 'fluid-primitives/numberInput';
mountAll('primitives:numberInput', ({ props }) =>
new NumberInput({
...props,
translations: { ...props.translations, valueText: value => `${value} pieces` },
}).init()
);
Build a component with translations
Permalink to heading "Build a component with translations"Pass the translations prop and the keys that are functions to resolveTranslations(). Each key lists what fills its placeholders from the details the machine calls it with. Keys that are not listed stay texts, anything else is left out so the machine keeps its default.
import { resolveTranslations } from 'fluid-primitives';
const translations = resolveTranslations(props.translations, {
valueText: (value: string) => ({ value }),
});
Use fillPlaceholders() where you build the text yourself. A placeholder without a value stays as written.
API Reference
Permalink to heading "API Reference"Turns the texts of a translations prop into what a machine takes. Fluid can't author a callback, so a template writes a text with %placeholders% for each translation that a machine wants as a function, while a client script passes the function itself. Both end up as the same function here.
Every key of functions becomes a function: a text is filled with the placeholder values functions derives from the details the machine calls it with, a function is kept as it is. Every other key stays a text. Anything else, such as false, is left out, so the machine falls back to its own default.
resolveTranslations<T = Record<string, unknown>>(translations: Record<string, unknown> | undefined, functions?: Record<string, (details: any) => PlaceholderValues>): T | undefined
| Name | Description | Required | Default |
|---|---|---|---|
translations | Record<string, unknown> | undefinedThe translations prop as it arrives, or undefined. | Yes | - |
functions | Record<string, (details: any) => PlaceholderValues>The keys that are functions in the machine, each with what fills its placeholders. | No | {} |
Returns T | undefined. The translations for the machine, or undefined without any.
resolveTranslations(
{ valueText: '%value% items', incrementLabel: 'More' },
{ valueText: (value: string) => ({ value }) }
);
// { valueText: value => `${value} items`, incrementLabel: 'More' }
Replaces every %name% in text with the value of name. A placeholder without a value is left as written, so a typo stays visible.
fillPlaceholders(text: string, values: PlaceholderValues): string
| Name | Description | Required | Default |
|---|---|---|---|
text | stringThe text with its placeholders. | Yes | - |
values | PlaceholderValuesThe values by placeholder name. | Yes | - |
fillPlaceholders('Preview of %fileName%', { fileName: 'a.png' }); // 'Preview of a.png'
A translation as a template author or a client script writes it: a text with %placeholders% for what is only known when the text is shown, or a function that builds the text from the same details.
type TranslationText<TDetails> = string | ((details: TDetails) => string)
What a %placeholder% of a translation can be filled with.
type PlaceholderValues = Record<string, string | number | null | undefined>