refactor(compiler): i18n - render legacy i18n message ids (#34135)
Now that `@angular/localize` can interpret multiple legacy message ids in the metablock of a `$localize` tagged template string, this commit adds those ids to each i18n message extracted from component templates, but only if the `enableI18nLegacyMessageIdFormat` is not `false`. PR Close #34135
This commit is contained in:
parent
8e96b450e2
commit
e524322c43
|
@ -52,7 +52,7 @@ export class ComponentDecoratorHandler implements
|
||||||
private scopeReader: ComponentScopeReader, private scopeRegistry: LocalModuleScopeRegistry,
|
private scopeReader: ComponentScopeReader, private scopeRegistry: LocalModuleScopeRegistry,
|
||||||
private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[],
|
private isCore: boolean, private resourceLoader: ResourceLoader, private rootDirs: string[],
|
||||||
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean,
|
private defaultPreserveWhitespaces: boolean, private i18nUseExternalIds: boolean,
|
||||||
private i18nLegacyMessageIdFormat: string, private moduleResolver: ModuleResolver,
|
private enableI18nLegacyMessageIdFormat: boolean, private moduleResolver: ModuleResolver,
|
||||||
private cycleAnalyzer: CycleAnalyzer, private refEmitter: ReferenceEmitter,
|
private cycleAnalyzer: CycleAnalyzer, private refEmitter: ReferenceEmitter,
|
||||||
private defaultImportRecorder: DefaultImportRecorder,
|
private defaultImportRecorder: DefaultImportRecorder,
|
||||||
private annotateForClosureCompiler: boolean,
|
private annotateForClosureCompiler: boolean,
|
||||||
|
@ -710,7 +710,7 @@ export class ComponentDecoratorHandler implements
|
||||||
preserveWhitespaces,
|
preserveWhitespaces,
|
||||||
interpolationConfig: interpolation,
|
interpolationConfig: interpolation,
|
||||||
range: templateRange, escapedString,
|
range: templateRange, escapedString,
|
||||||
i18nLegacyMessageIdFormat: this.i18nLegacyMessageIdFormat, ...options,
|
enableI18nLegacyMessageIdFormat: this.enableI18nLegacyMessageIdFormat, ...options,
|
||||||
}),
|
}),
|
||||||
template: templateStr, templateUrl,
|
template: templateStr, templateUrl,
|
||||||
isInline: component.has('template'),
|
isInline: component.has('template'),
|
||||||
|
|
|
@ -63,7 +63,7 @@ runInEachFileSystem(() => {
|
||||||
reflectionHost, evaluator, metaRegistry, metaReader, scopeRegistry, scopeRegistry,
|
reflectionHost, evaluator, metaRegistry, metaReader, scopeRegistry, scopeRegistry,
|
||||||
/* isCore */ false, new NoopResourceLoader(), /* rootDirs */[''],
|
/* isCore */ false, new NoopResourceLoader(), /* rootDirs */[''],
|
||||||
/* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true,
|
/* defaultPreserveWhitespaces */ false, /* i18nUseExternalIds */ true,
|
||||||
/* i18nLegacyMessageIdFormat */ '', moduleResolver, cycleAnalyzer, refEmitter,
|
/* enableI18nLegacyMessageIdFormat */ false, moduleResolver, cycleAnalyzer, refEmitter,
|
||||||
NOOP_DEFAULT_IMPORT_RECORDER, /* annotateForClosureCompiler */ false);
|
NOOP_DEFAULT_IMPORT_RECORDER, /* annotateForClosureCompiler */ false);
|
||||||
const TestCmp = getDeclaration(program, _('/entry.ts'), 'TestCmp', isNamedClassDeclaration);
|
const TestCmp = getDeclaration(program, _('/entry.ts'), 'TestCmp', isNamedClassDeclaration);
|
||||||
const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp));
|
const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp));
|
||||||
|
|
|
@ -623,9 +623,9 @@ export class NgtscProgram implements api.Program {
|
||||||
this.reflector, evaluator, metaRegistry, this.metaReader !, scopeReader, scopeRegistry,
|
this.reflector, evaluator, metaRegistry, this.metaReader !, scopeReader, scopeRegistry,
|
||||||
this.isCore, this.resourceManager, this.rootDirs,
|
this.isCore, this.resourceManager, this.rootDirs,
|
||||||
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false,
|
this.options.preserveWhitespaces || false, this.options.i18nUseExternalIds !== false,
|
||||||
this.getI18nLegacyMessageFormat(), this.moduleResolver, this.cycleAnalyzer,
|
this.options.enableI18nLegacyMessageIdFormat !== false, this.moduleResolver,
|
||||||
this.refEmitter, this.defaultImportTracker, this.closureCompilerEnabled,
|
this.cycleAnalyzer, this.refEmitter, this.defaultImportTracker,
|
||||||
this.incrementalDriver),
|
this.closureCompilerEnabled, this.incrementalDriver),
|
||||||
new DirectiveDecoratorHandler(
|
new DirectiveDecoratorHandler(
|
||||||
this.reflector, evaluator, metaRegistry, this.defaultImportTracker, this.isCore,
|
this.reflector, evaluator, metaRegistry, this.defaultImportTracker, this.isCore,
|
||||||
this.closureCompilerEnabled),
|
this.closureCompilerEnabled),
|
||||||
|
@ -648,11 +648,6 @@ export class NgtscProgram implements api.Program {
|
||||||
this.options.compileNonExportedClasses !== false);
|
this.options.compileNonExportedClasses !== false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private getI18nLegacyMessageFormat(): string {
|
|
||||||
return this.options.enableI18nLegacyMessageIdFormat !== false && this.options.i18nInFormat ||
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
|
|
||||||
private get reflector(): TypeScriptReflectionHost {
|
private get reflector(): TypeScriptReflectionHost {
|
||||||
if (this._reflector === undefined) {
|
if (this._reflector === undefined) {
|
||||||
this._reflector = new TypeScriptReflectionHost(this.tsProgram.getTypeChecker());
|
this._reflector = new TypeScriptReflectionHost(this.tsProgram.getTypeChecker());
|
||||||
|
|
|
@ -263,11 +263,10 @@ export interface CompilerOptions extends ts.CompilerOptions {
|
||||||
i18nUseExternalIds?: boolean;
|
i18nUseExternalIds?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render `$localize` message ids with the legacy format (xlf, xlf2 or xmb) specified in
|
* Render `$localize` messages with legacy format ids.
|
||||||
* `i18nInFormat`.
|
|
||||||
*
|
*
|
||||||
* This is only active if we are building with `enableIvy: true` and a valid
|
* This is only active if we are building with `enableIvy: true`.
|
||||||
* `i18nInFormat` has been provided. The default value for now is `true`.
|
* The default value for now is `true`.
|
||||||
*
|
*
|
||||||
* Use this option when use are using the `$localize` based localization messages but
|
* Use this option when use are using the `$localize` based localization messages but
|
||||||
* have not migrated the translation files to use the new `$localize` message id format.
|
* have not migrated the translation files to use the new `$localize` message id format.
|
||||||
|
|
|
@ -210,7 +210,8 @@ export function compile(
|
||||||
scripts, {
|
scripts, {
|
||||||
target: ts.ScriptTarget.ES2015,
|
target: ts.ScriptTarget.ES2015,
|
||||||
module: ts.ModuleKind.ES2015,
|
module: ts.ModuleKind.ES2015,
|
||||||
moduleResolution: ts.ModuleResolutionKind.NodeJs, ...options,
|
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
||||||
|
enableI18nLegacyMessageIdFormat: false, ...options,
|
||||||
},
|
},
|
||||||
mockCompilerHost);
|
mockCompilerHost);
|
||||||
program.emit();
|
program.emit();
|
||||||
|
|
|
@ -3457,6 +3457,38 @@ describe('i18n support in the template compiler', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('$localize legacy message ids', () => {
|
||||||
|
it('should add legacy message ids if `enableI18nLegacyMessageIdFormat` is true', () => {
|
||||||
|
const input = `<div i18n>Some Message</div>`;
|
||||||
|
|
||||||
|
const output = String.raw `
|
||||||
|
var $I18N_0$;
|
||||||
|
if (ngI18nClosureMode) { … }
|
||||||
|
else {
|
||||||
|
$I18N_0$ = $localize \`:␟ec93160d6d6a8822214060dd7938bf821c22b226␟6795333002533525253:Some Message\`;
|
||||||
|
}
|
||||||
|
…
|
||||||
|
`;
|
||||||
|
|
||||||
|
verify(input, output, {compilerOptions: {enableI18nLegacyMessageIdFormat: true}});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add legacy message ids if `enableI18nLegacyMessageIdFormat` is undefined', () => {
|
||||||
|
const input = `<div i18n>Some Message</div>`;
|
||||||
|
|
||||||
|
const output = String.raw `
|
||||||
|
var $I18N_0$;
|
||||||
|
if (ngI18nClosureMode) { … }
|
||||||
|
else {
|
||||||
|
$I18N_0$ = $localize \`:␟ec93160d6d6a8822214060dd7938bf821c22b226␟6795333002533525253:Some Message\`;
|
||||||
|
}
|
||||||
|
…
|
||||||
|
`;
|
||||||
|
|
||||||
|
verify(input, output, {compilerOptions: {enableI18nLegacyMessageIdFormat: undefined}});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('errors', () => {
|
describe('errors', () => {
|
||||||
const verifyNestedSectionsError = (errorThrown: any, expectedErrorText: string) => {
|
const verifyNestedSectionsError = (errorThrown: any, expectedErrorText: string) => {
|
||||||
expect(errorThrown.ngParseErrors.length).toBe(1);
|
expect(errorThrown.ngParseErrors.length).toBe(1);
|
||||||
|
|
|
@ -2454,82 +2454,23 @@ runInEachFileSystem(os => {
|
||||||
expect(jsContents).not.toContain('MSG_EXTERNAL_');
|
expect(jsContents).not.toContain('MSG_EXTERNAL_');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should render legacy id when `enableI18nLegacyMessageIdFormat` is not false and `i18nInFormat` is set to "xlf"',
|
it('should render legacy ids when `enableI18nLegacyMessageIdFormat` is not false', () => {
|
||||||
() => {
|
env.tsconfig({});
|
||||||
env.tsconfig({i18nInFormat: 'xlf'});
|
env.write(`test.ts`, `
|
||||||
env.write(`test.ts`, `
|
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'test',
|
selector: 'test',
|
||||||
template: '<div i18n>Some text</div>'
|
template: '<div i18n>Some text</div>'
|
||||||
})
|
})
|
||||||
class FooCmp {}`);
|
class FooCmp {}`);
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents).toContain(':@@5dbba0a3da8dff890e20cf76eb075d58900fbcd3:Some text');
|
expect(jsContents)
|
||||||
});
|
.toContain(
|
||||||
|
'":\\u241F5dbba0a3da8dff890e20cf76eb075d58900fbcd3\\u241F8321000940098097247:Some text"');
|
||||||
|
});
|
||||||
|
|
||||||
it('should render legacy id when `enableI18nLegacyMessageIdFormat` is not false and `i18nInFormat` is set to "xliff"',
|
it('should render custom id and legacy ids if `enableI18nLegacyMessageIdFormat` is not false',
|
||||||
() => {
|
|
||||||
env.tsconfig({i18nInFormat: 'xliff'});
|
|
||||||
env.write(`test.ts`, `
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
@Component({
|
|
||||||
selector: 'test',
|
|
||||||
template: '<div i18n>Some text</div>'
|
|
||||||
})
|
|
||||||
class FooCmp {}`);
|
|
||||||
env.driveMain();
|
|
||||||
const jsContents = env.getContents('test.js');
|
|
||||||
expect(jsContents).toContain(':@@5dbba0a3da8dff890e20cf76eb075d58900fbcd3:Some text');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render legacy id when `enableI18nLegacyMessageIdFormat` is not false and `i18nInFormat` is set to "xlf2"',
|
|
||||||
() => {
|
|
||||||
env.tsconfig({i18nInFormat: 'xlf2'});
|
|
||||||
env.write(`test.ts`, `
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
@Component({
|
|
||||||
selector: 'test',
|
|
||||||
template: '<div i18n>Some text</div>'
|
|
||||||
})
|
|
||||||
class FooCmp {}`);
|
|
||||||
env.driveMain();
|
|
||||||
const jsContents = env.getContents('test.js');
|
|
||||||
expect(jsContents).toContain(':@@8321000940098097247:Some text');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render legacy id when `enableI18nLegacyMessageIdFormat` is not false and `i18nInFormat` is set to "xliff2"',
|
|
||||||
() => {
|
|
||||||
env.tsconfig({i18nInFormat: 'xliff2'});
|
|
||||||
env.write(`test.ts`, `
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
@Component({
|
|
||||||
selector: 'test',
|
|
||||||
template: '<div i18n>Some text</div>'
|
|
||||||
})
|
|
||||||
class FooCmp {}`);
|
|
||||||
env.driveMain();
|
|
||||||
const jsContents = env.getContents('test.js');
|
|
||||||
expect(jsContents).toContain(':@@8321000940098097247:Some text');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render legacy id when `enableI18nLegacyMessageIdFormat` is not false and `i18nInFormat` is set to "xmb"',
|
|
||||||
() => {
|
|
||||||
env.tsconfig({i18nInFormat: 'xmb'});
|
|
||||||
env.write(`test.ts`, `
|
|
||||||
import {Component} from '@angular/core';
|
|
||||||
@Component({
|
|
||||||
selector: 'test',
|
|
||||||
template: '<div i18n>Some text</div>'
|
|
||||||
})
|
|
||||||
class FooCmp {}`);
|
|
||||||
env.driveMain();
|
|
||||||
const jsContents = env.getContents('test.js');
|
|
||||||
expect(jsContents).toContain(':@@8321000940098097247:Some text');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should render custom id even if `enableI18nLegacyMessageIdFormat` is not false and `i18nInFormat` is set',
|
|
||||||
() => {
|
() => {
|
||||||
env.tsconfig({i18nFormatIn: 'xlf'});
|
env.tsconfig({i18nFormatIn: 'xlf'});
|
||||||
env.write(`test.ts`, `
|
env.write(`test.ts`, `
|
||||||
|
@ -2541,25 +2482,28 @@ runInEachFileSystem(os => {
|
||||||
class FooCmp {}`);
|
class FooCmp {}`);
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents).toContain(':@@custom:Some text');
|
expect(jsContents)
|
||||||
|
.toContain(
|
||||||
|
':@@custom\\u241F5dbba0a3da8dff890e20cf76eb075d58900fbcd3\\u241F8321000940098097247:Some text');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not render legacy id when `enableI18nLegacyMessageIdFormat` is set to false', () => {
|
it('should not render legacy ids when `enableI18nLegacyMessageIdFormat` is set to false',
|
||||||
env.tsconfig({enableI18nLegacyMessageIdFormat: false, i18nInFormat: 'xmb'});
|
() => {
|
||||||
env.write(`test.ts`, `
|
env.tsconfig({enableI18nLegacyMessageIdFormat: false, i18nInFormat: 'xmb'});
|
||||||
|
env.write(`test.ts`, `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'test',
|
selector: 'test',
|
||||||
template: '<div i18n>Some text</div>'
|
template: '<div i18n>Some text</div>'
|
||||||
})
|
})
|
||||||
class FooCmp {}`);
|
class FooCmp {}`);
|
||||||
env.driveMain();
|
env.driveMain();
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
// Note that the colon would only be there if there is an id attached to the string.
|
// Note that the colon would only be there if there is an id attached to the string.
|
||||||
expect(jsContents).not.toContain(':Some text');
|
expect(jsContents).not.toContain(':Some text');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should also render legacy id for ICUs when normal messages are using legacy ids', () => {
|
it('should also render legacy ids for ICUs when normal messages are using legacy ids', () => {
|
||||||
env.tsconfig({i18nInFormat: 'xliff'});
|
env.tsconfig({i18nInFormat: 'xliff'});
|
||||||
env.write(`test.ts`, `
|
env.write(`test.ts`, `
|
||||||
import {Component} from '@angular/core';
|
import {Component} from '@angular/core';
|
||||||
|
@ -2572,8 +2516,10 @@ runInEachFileSystem(os => {
|
||||||
const jsContents = env.getContents('test.js');
|
const jsContents = env.getContents('test.js');
|
||||||
expect(jsContents)
|
expect(jsContents)
|
||||||
.toContain(
|
.toContain(
|
||||||
':@@720ba589d043a0497ac721ff972f41db0c919efb:{VAR_PLURAL, plural, 10 {ten} other {other}}');
|
':\\u241F720ba589d043a0497ac721ff972f41db0c919efb\\u241F3221232817843005870:{VAR_PLURAL, plural, 10 {ten} other {other}}');
|
||||||
expect(jsContents).toContain(':@@custom:Some text');
|
expect(jsContents)
|
||||||
|
.toContain(
|
||||||
|
':@@custom\\u241Fdcb6170595f5d548a3d00937e87d11858f51ad04\\u241F7419139165339437596:Some text');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('@Component\'s `interpolation` should override default interpolation config', () => {
|
it('@Component\'s `interpolation` should override default interpolation config', () => {
|
||||||
|
|
|
@ -11,8 +11,8 @@ import {ParseSourceSpan} from '../parse_util';
|
||||||
export class Message {
|
export class Message {
|
||||||
sources: MessageSpan[];
|
sources: MessageSpan[];
|
||||||
id: string = this.customId;
|
id: string = this.customId;
|
||||||
/** The id to use if there is no custom id and if `i18nLegacyMessageIdFormat` is not empty */
|
/** The ids to use if there are no custom id and if `i18nLegacyMessageIdFormat` is not empty */
|
||||||
legacyId?: string = '';
|
legacyIds: string[] = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param nodes message AST
|
* @param nodes message AST
|
||||||
|
|
|
@ -509,12 +509,20 @@ export class LocalizedString extends Expression {
|
||||||
* @param messagePart The first part of the tagged string
|
* @param messagePart The first part of the tagged string
|
||||||
*/
|
*/
|
||||||
serializeI18nHead(): {cooked: string, raw: string} {
|
serializeI18nHead(): {cooked: string, raw: string} {
|
||||||
|
const MEANING_SEPARATOR = '|';
|
||||||
|
const ID_SEPARATOR = '@@';
|
||||||
|
const LEGACY_ID_INDICATOR = '␟';
|
||||||
|
|
||||||
let metaBlock = this.metaBlock.description || '';
|
let metaBlock = this.metaBlock.description || '';
|
||||||
if (this.metaBlock.meaning) {
|
if (this.metaBlock.meaning) {
|
||||||
metaBlock = `${this.metaBlock.meaning}|${metaBlock}`;
|
metaBlock = `${this.metaBlock.meaning}${MEANING_SEPARATOR}${metaBlock}`;
|
||||||
}
|
}
|
||||||
if (this.metaBlock.customId || this.metaBlock.legacyId) {
|
if (this.metaBlock.customId) {
|
||||||
metaBlock = `${metaBlock}@@${this.metaBlock.customId || this.metaBlock.legacyId}`;
|
metaBlock = `${metaBlock}${ID_SEPARATOR}${this.metaBlock.customId}`;
|
||||||
|
}
|
||||||
|
if (this.metaBlock.legacyIds) {
|
||||||
|
this.metaBlock.legacyIds.forEach(
|
||||||
|
legacyId => { metaBlock = `${metaBlock}${LEGACY_ID_INDICATOR}${legacyId}`; });
|
||||||
}
|
}
|
||||||
return createCookedRawString(metaBlock, this.messageParts[0]);
|
return createCookedRawString(metaBlock, this.messageParts[0]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {I18N_ATTR, I18N_ATTR_PREFIX, hasI18nAttrs, icuFromI18nMessage} from './u
|
||||||
export type I18nMeta = {
|
export type I18nMeta = {
|
||||||
id?: string,
|
id?: string,
|
||||||
customId?: string,
|
customId?: string,
|
||||||
legacyId?: string,
|
legacyIds?: string[],
|
||||||
description?: string,
|
description?: string,
|
||||||
meaning?: string
|
meaning?: string
|
||||||
};
|
};
|
||||||
|
@ -52,7 +52,7 @@ export class I18nMetaVisitor implements html.Visitor {
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG,
|
private interpolationConfig: InterpolationConfig = DEFAULT_INTERPOLATION_CONFIG,
|
||||||
private keepI18nAttrs: boolean = false, private i18nLegacyMessageIdFormat: string = '') {}
|
private keepI18nAttrs = false, private enableI18nLegacyMessageIdFormat = false) {}
|
||||||
|
|
||||||
private _generateI18nMessage(
|
private _generateI18nMessage(
|
||||||
nodes: html.Node[], meta: string|i18n.I18nMeta = '',
|
nodes: html.Node[], meta: string|i18n.I18nMeta = '',
|
||||||
|
@ -60,7 +60,7 @@ export class I18nMetaVisitor implements html.Visitor {
|
||||||
const {meaning, description, customId} = this._parseMetadata(meta);
|
const {meaning, description, customId} = this._parseMetadata(meta);
|
||||||
const message = this._createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
|
const message = this._createI18nMessage(nodes, meaning, description, customId, visitNodeFn);
|
||||||
this._setMessageId(message, meta);
|
this._setMessageId(message, meta);
|
||||||
this._setLegacyId(message, meta);
|
this._setLegacyIds(message, meta);
|
||||||
return message;
|
return message;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,13 +171,9 @@ export class I18nMetaVisitor implements html.Visitor {
|
||||||
* @param message the message whose legacy id should be set
|
* @param message the message whose legacy id should be set
|
||||||
* @param meta information about the message being processed
|
* @param meta information about the message being processed
|
||||||
*/
|
*/
|
||||||
private _setLegacyId(message: i18n.Message, meta: string|i18n.I18nMeta): void {
|
private _setLegacyIds(message: i18n.Message, meta: string|i18n.I18nMeta): void {
|
||||||
if (this.i18nLegacyMessageIdFormat === 'xlf' || this.i18nLegacyMessageIdFormat === 'xliff') {
|
if (this.enableI18nLegacyMessageIdFormat) {
|
||||||
message.legacyId = computeDigest(message);
|
message.legacyIds = [computeDigest(message), computeDecimalDigest(message)];
|
||||||
} else if (
|
|
||||||
this.i18nLegacyMessageIdFormat === 'xlf2' || this.i18nLegacyMessageIdFormat === 'xliff2' ||
|
|
||||||
this.i18nLegacyMessageIdFormat === 'xmb') {
|
|
||||||
message.legacyId = computeDecimalDigest(message);
|
|
||||||
} else if (typeof meta !== 'string') {
|
} else if (typeof meta !== 'string') {
|
||||||
// This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in
|
// This occurs if we are doing the 2nd pass after whitespace removal (see `parseTemplate()` in
|
||||||
// `packages/compiler/src/render3/view/template.ts`).
|
// `packages/compiler/src/render3/view/template.ts`).
|
||||||
|
@ -186,7 +182,7 @@ export class I18nMetaVisitor implements html.Visitor {
|
||||||
const previousMessage = meta instanceof i18n.Message ?
|
const previousMessage = meta instanceof i18n.Message ?
|
||||||
meta :
|
meta :
|
||||||
meta instanceof i18n.IcuPlaceholder ? meta.previousMessage : undefined;
|
meta instanceof i18n.IcuPlaceholder ? meta.previousMessage : undefined;
|
||||||
message.legacyId = previousMessage && previousMessage.legacyId;
|
message.legacyIds = previousMessage ? previousMessage.legacyIds : [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -195,7 +191,7 @@ export function metaFromI18nMessage(message: i18n.Message, id: string | null = n
|
||||||
return {
|
return {
|
||||||
id: typeof id === 'string' ? id : message.id || '',
|
id: typeof id === 'string' ? id : message.id || '',
|
||||||
customId: message.customId,
|
customId: message.customId,
|
||||||
legacyId: message.legacyId,
|
legacyIds: message.legacyIds,
|
||||||
meaning: message.meaning || '',
|
meaning: message.meaning || '',
|
||||||
description: message.description || ''
|
description: message.description || ''
|
||||||
};
|
};
|
||||||
|
|
|
@ -1945,17 +1945,14 @@ export interface ParseTemplateOptions {
|
||||||
leadingTriviaChars?: string[];
|
leadingTriviaChars?: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render `$localize` message ids with the specified legacy format (xlf, xlf2 or xmb).
|
* Render `$localize` message ids with additional legacy message ids.
|
||||||
*
|
*
|
||||||
* Use this option when use are using the `$localize` based localization messages but
|
* This option defaults to `true` but in the future the defaul will be flipped.
|
||||||
* have not migrated the translation files to use the new `$localize` message id format.
|
|
||||||
*
|
*
|
||||||
* @deprecated
|
* For now set this option to false if you have migrated the translation files to use the new
|
||||||
* `i18nLegacyMessageIdFormat` should only be used while migrating from legacy message id
|
* `$localize` message id format and you are not using compile time translation merging.
|
||||||
* formatted translation files and will be removed at the same time as ViewEngine support is
|
|
||||||
* removed.
|
|
||||||
*/
|
*/
|
||||||
i18nLegacyMessageIdFormat?: string;
|
enableI18nLegacyMessageIdFormat?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1968,7 +1965,7 @@ export interface ParseTemplateOptions {
|
||||||
export function parseTemplate(
|
export function parseTemplate(
|
||||||
template: string, templateUrl: string, options: ParseTemplateOptions = {}):
|
template: string, templateUrl: string, options: ParseTemplateOptions = {}):
|
||||||
{errors?: ParseError[], nodes: t.Node[], styleUrls: string[], styles: string[]} {
|
{errors?: ParseError[], nodes: t.Node[], styleUrls: string[], styles: string[]} {
|
||||||
const {interpolationConfig, preserveWhitespaces, i18nLegacyMessageIdFormat} = options;
|
const {interpolationConfig, preserveWhitespaces, enableI18nLegacyMessageIdFormat} = options;
|
||||||
const bindingParser = makeBindingParser(interpolationConfig);
|
const bindingParser = makeBindingParser(interpolationConfig);
|
||||||
const htmlParser = new HtmlParser();
|
const htmlParser = new HtmlParser();
|
||||||
const parseResult = htmlParser.parse(
|
const parseResult = htmlParser.parse(
|
||||||
|
@ -1986,7 +1983,8 @@ export function parseTemplate(
|
||||||
// extraction process (ng xi18n) relies on a raw content to generate
|
// extraction process (ng xi18n) relies on a raw content to generate
|
||||||
// message ids
|
// message ids
|
||||||
const i18nMetaVisitor = new I18nMetaVisitor(
|
const i18nMetaVisitor = new I18nMetaVisitor(
|
||||||
interpolationConfig, /* keepI18nAttrs */ !preserveWhitespaces, i18nLegacyMessageIdFormat);
|
interpolationConfig, /* keepI18nAttrs */ !preserveWhitespaces,
|
||||||
|
enableI18nLegacyMessageIdFormat);
|
||||||
rootNodes = html.visitAll(i18nMetaVisitor, rootNodes);
|
rootNodes = html.visitAll(i18nMetaVisitor, rootNodes);
|
||||||
|
|
||||||
if (!preserveWhitespaces) {
|
if (!preserveWhitespaces) {
|
||||||
|
|
|
@ -14,6 +14,7 @@ import {computeMsgId, digest, sha1} from '../../src/i18n/digest';
|
||||||
it('must return the ID if it\'s explicit', () => {
|
it('must return the ID if it\'s explicit', () => {
|
||||||
expect(digest({
|
expect(digest({
|
||||||
id: 'i',
|
id: 'i',
|
||||||
|
legacyIds: [],
|
||||||
nodes: [],
|
nodes: [],
|
||||||
placeholders: {},
|
placeholders: {},
|
||||||
placeholderToMessage: {},
|
placeholderToMessage: {},
|
||||||
|
|
Loading…
Reference in New Issue