Misko Hevery 250e299dc3 refactor(core): break i18n.ts into smaller files (#38368)
This commit contains no changes to code. It only breaks `i18n.ts` file
into `i18n.ts` + `i18n_apply.ts` + `i18n_parse.ts` +
`i18n_postprocess.ts` for easier maintenance.

PR Close #38368
2020-08-10 15:07:42 -07:00

176 lines
7.4 KiB
TypeScript
Raw Blame History

/**
* @license
* Copyright Google LLC All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import '../../util/ng_dev_mode';
import '../../util/ng_i18n_closure_mode';
import {assertDefined} from '../../util/assert';
import {bindingUpdated} from '../bindings';
import {applyI18n, i18nEndFirstPass, pushI18nIndex, setMaskBit} from '../i18n/i18n_apply';
import {i18nAttributesFirstPass, i18nStartFirstPass} from '../i18n/i18n_parse';
import {i18nPostprocess} from '../i18n/i18n_postprocess';
import {HEADER_OFFSET} from '../interfaces/view';
import {getLView, getTView, nextBindingIndex} from '../state';
import {setDelayProjection} from './all';
/**
* Marks a block of text as translatable.
*
* The instructions `i18nStart` and `i18nEnd` mark the translation block in the template.
* The translation `message` is the value which is locale specific. The translation string may
* contain placeholders which associate inner elements and sub-templates within the translation.
*
* The translation `message` placeholders are:
* - `<60>{index}(:{block})<29>`: *Binding Placeholder*: Marks a location where an expression will be
* interpolated into. The placeholder `index` points to the expression binding index. An optional
* `block` that matches the sub-template in which it was declared.
* - `<60>#{index}(:{block})<29>`/`<60>/#{index}(:{block})<29>`: *Element Placeholder*: Marks the beginning
* and end of DOM element that were embedded in the original translation block. The placeholder
* `index` points to the element index in the template instructions set. An optional `block` that
* matches the sub-template in which it was declared.
* - `<60>!{index}(:{block})<29>`/`<60>/!{index}(:{block})<29>`: *Projection Placeholder*: Marks the
* beginning and end of <ng-content> that was embedded in the original translation block.
* The placeholder `index` points to the element index in the template instructions set.
* An optional `block` that matches the sub-template in which it was declared.
* - `<60>*{index}:{block}<7D>`/`<60>/*{index}:{block}<7D>`: *Sub-template Placeholder*: Sub-templates must be
* split up and translated separately in each angular template function. The `index` points to the
* `template` instruction index. A `block` that matches the sub-template in which it was declared.
*
* @param index A unique index of the translation in the static block.
* @param message The translation message.
* @param subTemplateIndex Optional sub-template index in the `message`.
*
* @codeGenApi
*/
export function ɵɵi18nStart(index: number, message: string, subTemplateIndex?: number): void {
const tView = getTView();
ngDevMode && assertDefined(tView, `tView should be defined`);
pushI18nIndex(index);
// We need to delay projections until `i18nEnd`
setDelayProjection(true);
if (tView.firstCreatePass && tView.data[index + HEADER_OFFSET] === null) {
i18nStartFirstPass(getLView(), tView, index, message, subTemplateIndex);
}
}
/**
* Translates a translation block marked by `i18nStart` and `i18nEnd`. It inserts the text/ICU nodes
* into the render tree, moves the placeholder nodes and removes the deleted nodes.
*
* @codeGenApi
*/
export function ɵɵi18nEnd(): void {
const lView = getLView();
const tView = getTView();
ngDevMode && assertDefined(tView, `tView should be defined`);
i18nEndFirstPass(tView, lView);
// Stop delaying projections
setDelayProjection(false);
}
/**
*
* Use this instruction to create a translation block that doesn't contain any placeholder.
* It calls both {@link i18nStart} and {@link i18nEnd} in one instruction.
*
* The translation `message` is the value which is locale specific. The translation string may
* contain placeholders which associate inner elements and sub-templates within the translation.
*
* The translation `message` placeholders are:
* - `<60>{index}(:{block})<29>`: *Binding Placeholder*: Marks a location where an expression will be
* interpolated into. The placeholder `index` points to the expression binding index. An optional
* `block` that matches the sub-template in which it was declared.
* - `<60>#{index}(:{block})<29>`/`<60>/#{index}(:{block})<29>`: *Element Placeholder*: Marks the beginning
* and end of DOM element that were embedded in the original translation block. The placeholder
* `index` points to the element index in the template instructions set. An optional `block` that
* matches the sub-template in which it was declared.
* - `<60>*{index}:{block}<7D>`/`<60>/*{index}:{block}<7D>`: *Sub-template Placeholder*: Sub-templates must be
* split up and translated separately in each angular template function. The `index` points to the
* `template` instruction index. A `block` that matches the sub-template in which it was declared.
*
* @param index A unique index of the translation in the static block.
* @param message The translation message.
* @param subTemplateIndex Optional sub-template index in the `message`.
*
* @codeGenApi
*/
export function ɵɵi18n(index: number, message: string, subTemplateIndex?: number): void {
ɵɵi18nStart(index, message, subTemplateIndex);
ɵɵi18nEnd();
}
/**
* Marks a list of attributes as translatable.
*
* @param index A unique index in the static block
* @param values
*
* @codeGenApi
*/
export function ɵɵi18nAttributes(index: number, values: string[]): void {
const lView = getLView();
const tView = getTView();
ngDevMode && assertDefined(tView, `tView should be defined`);
i18nAttributesFirstPass(lView, tView, index, values);
}
/**
* Stores the values of the bindings during each update cycle in order to determine if we need to
* update the translated nodes.
*
* @param value The binding's value
* @returns This function returns itself so that it may be chained
* (e.g. `i18nExp(ctx.name)(ctx.title)`)
*
* @codeGenApi
*/
export function ɵɵi18nExp<T>(value: T): typeof ɵɵi18nExp {
const lView = getLView();
setMaskBit(bindingUpdated(lView, nextBindingIndex(), value));
return ɵɵi18nExp;
}
/**
* Updates a translation block or an i18n attribute when the bindings have changed.
*
* @param index Index of either {@link i18nStart} (translation block) or {@link i18nAttributes}
* (i18n attribute) on which it should update the content.
*
* @codeGenApi
*/
export function ɵɵi18nApply(index: number) {
applyI18n(getTView(), getLView(), index);
}
/**
* Handles message string post-processing for internationalization.
*
* Handles message string post-processing by transforming it from intermediate
* format (that might contain some markers that we need to replace) to the final
* form, consumable by i18nStart instruction. Post processing steps include:
*
* 1. Resolve all multi-value cases (like [<5B>*1:1<><31>#2:1<>|<7C>#4:1<>|<7C>5<EFBFBD>])
* 2. Replace all ICU vars (like "VAR_PLURAL")
* 3. Replace all placeholders used inside ICUs in a form of {PLACEHOLDER}
* 4. Replace all ICU references with corresponding values (like <20>ICU_EXP_ICU_1<5F>)
* in case multiple ICUs have the same placeholder name
*
* @param message Raw translation string for post processing
* @param replacements Set of replacements that should be applied
*
* @returns Transformed string that can be consumed by i18nStart instruction
*
* @codeGenApi
*/
export function ɵɵi18nPostprocess(
message: string, replacements: {[key: string]: (string|string[])} = {}): string {
return i18nPostprocess(message, replacements);
}