in packages/api/src/hooks/useLocalizer.ts [20:75]
export default function useLocalizer({ plural }: { plural?: keyof Plural } = {}) {
const [globalize] = useLocalizedGlobalize();
const localizedStrings = useLocalizedStrings();
return useCallback(
(id: string | Plural, ...args: [(number | string)?, ...string[]]) => {
let stringId = id as string;
if (plural) {
const pluralId = id as Plural;
if (!isObject(pluralId)) {
throw new Error('useLocalizer: Plural string must pass "id" as a map instead of string.');
} else if (typeof pluralId.other !== 'string') {
throw new Error('useLocalizer: Plural string must have "id.other" of string.');
} else if (typeof args[0] !== 'number') {
throw new Error('useLocalizer: Plural string must have first argument as a number.');
}
for (const pluralForm of ['zero', 'one', 'two', 'few', 'many']) {
// Mitigation through allowlisting.
// eslint-disable-next-line security/detect-object-injection
const type = typeof id[pluralForm];
if (type !== 'string' && type !== 'undefined') {
throw new Error(`useLocalizer: Plural string must have "id.${pluralForm}" of string or undefined.`);
}
}
const unsupportedPluralForms = Object.keys(id).filter(
pluralForm => !['zero', 'one', 'two', 'few', 'many', 'other'].includes(pluralForm)
);
if (unsupportedPluralForms.length) {
throw new Error(
`useLocalizer: Plural string "id" must be either "zero", "one", "two", "few", "many", "other". But not ${unsupportedPluralForms
.map(pluralForm => `"${pluralForm}"`)
.join(', ')}.`
);
}
stringId = pluralId[globalize.plural(args[0])] || pluralId.other;
} else if (typeof id !== 'string') {
throw new Error('useLocalizer: "id" must be a string.');
}
return Object.entries(args).reduce(
(str, [index, arg]) => str.replace(`$${+index + 1}`, arg),
// Mitigation through denylisting.
// eslint-disable-next-line security/detect-object-injection
isForbiddenPropertyName(stringId) ? '' : localizedStrings[stringId] || DEFAULT_STRINGS[stringId] || ''
);
},
[globalize, localizedStrings, plural]
);
}