diff --git a/packages/core/src/render3/i18n.ts b/packages/core/src/render3/i18n.ts index ae19790c0b..9e55eb569c 100644 --- a/packages/core/src/render3/i18n.ts +++ b/packages/core/src/render3/i18n.ts @@ -403,7 +403,7 @@ function i18nStartFirstPass( const icuExpressions: TIcu[] = []; const templateTranslation = getTranslationForTemplate(message, subTemplateIndex); - const msgParts = templateTranslation.split(PH_REGEXP); + const msgParts = replaceNgsp(templateTranslation).split(PH_REGEXP); for (let i = 0; i < msgParts.length; i++) { let value = msgParts[i]; if (i & 1) { @@ -1296,6 +1296,18 @@ function parseNodes( } } +/** + * Angular Dart introduced &ngsp; as a placeholder for non-removable space, see: + * https://github.com/dart-lang/angular/blob/0bb611387d29d65b5af7f9d2515ab571fd3fbee4/_tests/test/compiler/preserve_whitespace_test.dart#L25-L32 + * In Angular Dart &ngsp; is converted to the 0xE500 PUA (Private Use Areas) unicode character + * and later on replaced by a space. We are re-implementing the same idea here, since translations + * might contain this special character. + */ +const NGSP_UNICODE_REGEXP = /\uE500/g; +function replaceNgsp(value: string): string { + return value.replace(NGSP_UNICODE_REGEXP, ' '); +} + let TRANSLATIONS: {[key: string]: string} = {}; export interface I18nLocalizeOptions { translations: {[key: string]: string}; } diff --git a/packages/core/test/acceptance/i18n_spec.ts b/packages/core/test/acceptance/i18n_spec.ts index b4677823b4..e1b0c722ee 100644 --- a/packages/core/test/acceptance/i18n_spec.ts +++ b/packages/core/test/acceptance/i18n_spec.ts @@ -48,6 +48,14 @@ onlyInIvy('Ivy i18n logic').describe('runtime i18n', () => { expect(fixture.nativeElement.innerHTML).toBe('