feat(ivy): i18n - render legacy message ids in $localize
if requested (#32937)
The `$localize` library uses a new message digest function for computing message ids. This means that translations in legacy translation files will no longer match the message ids in the code and so will not be translated. This commit adds the ability to specify the format of your legacy translation files, so that the appropriate message id can be rendered in the `$localize` tagged strings. This results in larger code size and requires that all translations are in the legacy format. Going forward the developer should migrate their translation files to use the new message id format. PR Close #32937
This commit is contained in:

committed by
atscott

parent
fc28b266cd
commit
bcbf3e4123
@ -6,12 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {decimalDigest} from '../../../i18n/digest';
|
||||
import {computeDecimalDigest, computeDigest, decimalDigest} from '../../../i18n/digest';
|
||||
import * as i18n from '../../../i18n/i18n_ast';
|
||||
import {createI18nMessageFactory} from '../../../i18n/i18n_parser';
|
||||
import * as html from '../../../ml_parser/ast';
|
||||
import {DEFAULT_INTERPOLATION_CONFIG, InterpolationConfig} from '../../../ml_parser/interpolation_config';
|
||||
import {ParseTreeResult} from '../../../ml_parser/parser';
|
||||
import * as o from '../../../output/output_ast';
|
||||
|
||||
import {I18N_ATTR, I18N_ATTR_PREFIX, hasI18nAttrs, icuFromI18nMessage} from './util';
|
||||
@ -19,6 +18,7 @@ import {I18N_ATTR, I18N_ATTR_PREFIX, hasI18nAttrs, icuFromI18nMessage} from './u
|
||||
export type I18nMeta = {
|
||||
id?: string,
|
||||
customId?: string,
|
||||
legacyId?: string,
|
||||
description?: string,
|
||||
meaning?: string
|
||||
};
|
||||
@ -51,6 +51,19 @@ export class I18nMetaVisitor implements html.Visitor {
|
||||
// generate (or restore) message id if not specified in template
|
||||
message.id = typeof meta !== 'string' && (meta as i18n.Message).id || decimalDigest(message);
|
||||
}
|
||||
|
||||
if (this.i18nLegacyMessageIdFormat === 'xlf') {
|
||||
message.legacyId = computeDigest(message);
|
||||
} else if (
|
||||
this.i18nLegacyMessageIdFormat === 'xlf2' || this.i18nLegacyMessageIdFormat === 'xmb') {
|
||||
message.legacyId = computeDecimalDigest(message);
|
||||
} else if (typeof meta !== 'string') {
|
||||
// This occurs if we are doing the 2nd pass after whitespace removal
|
||||
// In that case we want to reuse the legacy message generated in the 1st pass
|
||||
// See `parseTemplate()` in `packages/compiler/src/render3/view/template.ts`
|
||||
message.legacyId = (meta as i18n.Message).legacyId;
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
@ -130,6 +143,7 @@ export function metaFromI18nMessage(message: i18n.Message, id: string | null = n
|
||||
return {
|
||||
id: typeof id === 'string' ? id : message.id || '',
|
||||
customId: message.customId,
|
||||
legacyId: message.legacyId,
|
||||
meaning: message.meaning || '',
|
||||
description: message.description || ''
|
||||
};
|
||||
@ -180,8 +194,8 @@ export function serializeI18nHead(meta: I18nMeta, messagePart: string): string {
|
||||
if (meta.meaning) {
|
||||
metaBlock = `${meta.meaning}|${metaBlock}`;
|
||||
}
|
||||
if (meta.customId) {
|
||||
metaBlock = `${metaBlock}@@${meta.customId}`;
|
||||
if (meta.customId || meta.legacyId) {
|
||||
metaBlock = `${metaBlock}@@${meta.customId || meta.legacyId}`;
|
||||
}
|
||||
if (metaBlock === '') {
|
||||
// There is no metaBlock, so we must ensure that any starting colon is escaped.
|
||||
|
@ -1905,6 +1905,19 @@ export interface ParseTemplateOptions {
|
||||
* included in source-map segments. A common example is whitespace.
|
||||
*/
|
||||
leadingTriviaChars?: string[];
|
||||
|
||||
/**
|
||||
* Render `$localize` message ids with the specified legacy format (xlf, xlf2 or xmb).
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* @deprecated
|
||||
* `i18nLegacyMessageIdFormat` should only be used while migrating from legacy message id
|
||||
* formatted translation files and will be removed at the same time as ViewEngine support is
|
||||
* removed.
|
||||
*/
|
||||
i18nLegacyMessageIdFormat?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1917,7 +1930,7 @@ export interface ParseTemplateOptions {
|
||||
export function parseTemplate(
|
||||
template: string, templateUrl: string, options: ParseTemplateOptions = {}):
|
||||
{errors?: ParseError[], nodes: t.Node[], styleUrls: string[], styles: string[]} {
|
||||
const {interpolationConfig, preserveWhitespaces} = options;
|
||||
const {interpolationConfig, preserveWhitespaces, i18nLegacyMessageIdFormat} = options;
|
||||
const bindingParser = makeBindingParser(interpolationConfig);
|
||||
const htmlParser = new HtmlParser();
|
||||
const parseResult = htmlParser.parse(
|
||||
@ -1934,8 +1947,9 @@ export function parseTemplate(
|
||||
// before we run whitespace removal process, because existing i18n
|
||||
// extraction process (ng xi18n) relies on a raw content to generate
|
||||
// message ids
|
||||
rootNodes =
|
||||
html.visitAll(new I18nMetaVisitor(interpolationConfig, !preserveWhitespaces), rootNodes);
|
||||
rootNodes = html.visitAll(
|
||||
new I18nMetaVisitor(interpolationConfig, !preserveWhitespaces, i18nLegacyMessageIdFormat),
|
||||
rootNodes);
|
||||
|
||||
if (!preserveWhitespaces) {
|
||||
rootNodes = html.visitAll(new WhitespaceVisitor(), rootNodes);
|
||||
|
Reference in New Issue
Block a user