Appearance
Runtime API
Runtime imports come from @number10/typekit-i18n.
Core Types
TranslationTable<TKey, TLanguage>PlaceholderandPlaceholderValueMissingTranslationEventPlaceholderFormatterMap
createTranslator(table, options?)
Creates a typed translator function:
ts
;(key, language?, placeholder?) => stringOptions:
defaultLanguage?: TLanguage('en'by default when available in table)language?: TLanguage(initial active language, defaults todefaultLanguage)missingStrategy?: 'fallback' | 'strict'formatters?: PlaceholderFormatterMap<TKey, TLanguage>onMissingTranslation?: (event) => void
Missing reasons:
missingKeymissingLanguagemissingFallback
Behavior summary:
- uses target language value when non-empty
- falls back to
defaultLanguagewhen target language value is empty defaultLanguagefalls back to'en'when omitted and available in table- creating a translator throws when
defaultLanguageis omitted and table does not contain'en' - returns key when no value can be resolved
- throws in strict mode
Category-aware APIs:
translateIn(category, key, language?, placeholder?)in(category, key, language?, placeholder?)(alias oftranslateIn)withCategory(category)(returns a category-bound translate function)
Language state APIs:
setLanguage(language)getLanguage()
Example:
ts
import { createTranslator } from '@number10/typekit-i18n'
import { translationTable } from './generated/translationTable'
const t = createTranslator(translationTable)
t('welcome_title') // active language ("en" by default)
t.setLanguage('de')
t('welcome_title') // now "de"
t.in('home', 'welcome_title')
const tHome = t.withCategory('home')
tHome('welcome_title')createIcuTranslator(table, options?)
Same base behavior as createTranslator, plus ICU rendering.
Additional option:
localeByLanguage?: Partial<Record<TLanguage, string>>
Supported ICU subset:
select:{gender, select, male {...} female {...} other {...}}plural:{count, plural, =0 {...} one {...} other {...}}pluralwith offset:{count, plural, offset:1 one {...} other {...}}selectordinal:{place, selectordinal, one {...} two {...} few {...} other {...}}- number arguments:
{amount, number}{ratio, number, percent}{amount, number, currency/EUR}- skeleton form:
{amount, number, ::compact-short}
- date/time arguments:
{when, date, short|medium|long|full}{when, time, short|medium|long|full}- skeleton form:
{when, time, ::HH:mm}or{when, date, ::yyyy-MM-dd}
#replacement in plural/selectordinal branches- apostrophe escaping (
'', quoted literals)
Explicitly unsupported ICU features:
- expression types outside the supported subset, for example
choice selectnumeric selectors like=1(numeric selectors are only supported inplural/selectordinal)- full ICU number skeleton support (only documented tokens are supported)
- full ICU date/time skeleton support (only documented pattern letters are supported)
- MessageFormat-2 syntax
Invalid ICU expressions throw detailed syntax errors with key, language, line, and column.
createFormatjsIcuTranslator(table, options?)
Runtime import:
ts
import { createFormatjsIcuTranslator } from '@number10/typekit-i18n/runtime/icu-formatjs'Behavior:
- same translator API shape as
createIcuTranslator - ICU rendering delegated to
intl-messageformat(FormatJS) - supports legacy
{name|formatter}placeholders for backward compatibility intl-messageformatis an optional peer dependency and only needed for this import path
Placeholder Replacement
Payload shape:
ts
{
data: [{ key: 'name', value: 'Mara' }]
}Tokens:
{name}: raw replacement{amount|currency}: named formatter callback
If formatter is missing, fallback is String(value).
Translation Runtime Object
createTranslationRuntime(table, options?) returns:
translate(key, language?, placeholder?)translateIn(category, key, language?, placeholder?)withCategory(category)setLanguage(language)getLanguage()configure(options)getCollectedMissingTranslations()clearCollectedMissingTranslations()
configure can update:
defaultLanguagelanguagemissingStrategyonMissingTranslation(nullclears)formatters(nullclears)collectMissingTranslations
Also exported:
createConsoleMissingTranslationReporter(writer?)— console warn reporter for missing events
onError Callback (ICU Translators)
Both createIcuTranslator and createFormatjsIcuTranslator accept an optional onError callback:
ts
import { createIcuTranslator } from '@number10/typekit-i18n'
import type { TranslationErrorEvent } from '@number10/typekit-i18n'
const t = createIcuTranslator(table, {
onError: (event: TranslationErrorEvent) => {
console.warn(`ICU error for key "${event.key}": ${event.error.message}`)
},
})When onError is provided, ICU parse and render errors are reported via the callback instead of throwing. The translation returns the raw key as fallback value. Without onError, errors throw as before.
Error event shape:
key— translation keylanguage— requested languagedefaultLanguage— fallback languagereason—'icuParseError'or'icuRenderError'error— originalErrorobject
Plural Helpers (Basic Translator)
For pluralization without ICU syntax, use the convention-based pluralKey helper:
ts
import { createTranslator, pluralKey } from '@number10/typekit-i18n'
// Translation table with suffixed keys:
// item_count_one: "{count} item"
// item_count_other: "{count} items"
const t = createTranslator(table)
const key = pluralKey('item_count', 5) // → "item_count_other"
const key = pluralKey('item_count', 1) // → "item_count_one"
const key = pluralKey('item_count', 0, 'ar') // → "item_count_zero"
t(key, { data: [{ key: 'count', value: 5 }] })pluralCategory(count, locale?) returns the raw Intl.LDMLPluralRule if more control is needed.
React Integration
React hooks are available via @number10/typekit-i18n/react:
tsx
import { TranslationProvider, useTranslate } from '@number10/typekit-i18n/react'
function App() {
return (
<TranslationProvider table={translationTable} defaultLanguage="en">
<Welcome />
</TranslationProvider>
)
}
function Welcome() {
const { t, language, setLanguage } = useTranslate()
return <h1>{t('greeting_title')}</h1>
}ICU variant: <IcuTranslationProvider localeByLanguage={{ de: 'de-DE' }}> + useIcuTranslate().