i18n Solution
Solution
Provider
provides intl
dictionary, Consumer
takes the intl
and translate()
it with hardcoded (nested)id, and fallback,
Pluralise and templating:
In dictionary, each fields supports plural
// Dictionary:
"passengers": {
"none":"No passengers",
"one":"One passenger",
"many":"{{count}} passengers"
}
// Component:
<Text id="passengers" plural={0} /> // "No passengers"
<Text id="passengers" plural={1} /> // "One passenger"
<Text id="passengers" plural={2} fields={{ count: 2 }} /> // "2 passengers"
// HOC
withIntl((t) => {
return t('passengers', "fallback", { plural:2 })
})
Basic function
Context
createContext({ dictionary: null, highlight: false });
Provider:
<IntlContext.Provider value={{ highlight, dictionary }}>{children}</IntlContext.Provider>
Consumer:
<IntlContext.Consumer>(intl) => {children}</IntlContext.Consumer>
or
useContext(IntlContext)
Detail in consumer:
const intl = useContext(IntlContext);
const t = useCallback(
(id, fallback, opts = {}) => {
const highlight = opts.highlight != null ? opts.highlight : intl.highlight;
const value = translate(id, intl && intl.dictionary, opts.fields, opts.plural, fallback);
return highlight ? <Highlight id={id} value={value} fallback={fallback} /> : value;
},
[intl]
);
translate() from intl
translate(
id: string,
dictionary: object,
fields: object,
plural: number,
fallback: string
) => {
let value = dictionary && delve(dictionary, id);
if ((plural || plural === 0) && value && typeof value === 'object') {
if (Array.isArray(value)) {
value = value[plural] || value[0];
} else if (plural === 0 && value.none != null) {
value = value.none;
} else if (plural === 1 && (value.one != null || value.singular != null)) {
value = value.one || value.singular;
} else {
value = value.some || value.many || value.plural || value.other || value;
}
}
return (value && template(value, fields, dictionary)) || fallback || null;
}
return translated string.