fix(ivy): i18n - throw an error if a translation contains an invalid placeholder (#32867)

Previously if a translation contains a placeholder that
does not exist in the message being translated, that
placeholder is evaluated as `undefined`.

Translations should never contain such placeholder names
so now `translate` will throw a helpful error in instead.

PR Close #32867
This commit is contained in:
Pete Bacon Darwin 2019-10-02 18:17:56 +01:00 committed by atscott
parent 052cae6427
commit 601f87c2ec
2 changed files with 23 additions and 3 deletions

View File

@ -33,7 +33,9 @@ export type ParsedTranslations = Record<MessageId, ParsedTranslation>;
* `substitutions`.
* The translation may reorder (or remove) substitutions as appropriate.
*
* If no translation matches then an error is thrown.
* If there is no translation with a matching message id then an error is thrown.
* If a translation contains a placeholder that is not found in the message being translated then an
* error is thrown.
*/
export function translate(
translations: Record<string, ParsedTranslation>, messageParts: TemplateStringsArray,
@ -42,8 +44,14 @@ export function translate(
const translation = translations[message.messageId];
if (translation !== undefined) {
return [
translation.messageParts,
translation.placeholderNames.map(placeholder => message.substitutions[placeholder])
translation.messageParts, translation.placeholderNames.map(placeholder => {
if (message.substitutions.hasOwnProperty(placeholder)) {
return message.substitutions[placeholder];
} else {
throw new Error(
`No placeholder found with name ${placeholder} in message "${message.messageId}" ("${message.messageString}").`);
}
})
];
} else {
throw new Error(

View File

@ -80,6 +80,18 @@ describe('utils', () => {
});
describe('translate', () => {
it('should throw an error if there is no matching translation', () => {
expect(() => doTranslate({}, parts `abc`))
.toThrowError('No translation found for "2674653928643152084" ("abc").');
});
it('should throw an error if the translation contains placeholders that are not in the message',
() => {
expect(() => doTranslate({'abc': 'a{$PH}bc'}, parts `abc`))
.toThrowError(
'No placeholder found with name PH in message "2674653928643152084" ("abc").');
});
it('(with identity translations) should render template literals as-is', () => {
const translations = {
'abc': 'abc',