build: reformat repo to new clang@1.4.0 (#36628)

PR Close #36628
This commit is contained in:
Joey Perrott
2020-04-13 17:43:52 -07:00
committed by atscott
parent 4b3f9ac739
commit 26f49151e7
1163 changed files with 31727 additions and 24036 deletions

View File

@ -5,7 +5,7 @@
* 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 {$localize, LocalizeFn, _global} from '../src/localize';
import {$localize, _global, LocalizeFn} from '../src/localize';
export {LocalizeFn, TranslateFn} from '../src/localize';

View File

@ -8,4 +8,4 @@
// This file exports all the `utils` as private exports so that other parts of `@angular/localize`
// can make use of them.
export {MessageId as ɵMessageId, MissingTranslationError as ɵMissingTranslationError, ParsedMessage as ɵParsedMessage, ParsedTranslation as ɵParsedTranslation, ParsedTranslations as ɵParsedTranslations, SourceMessage as ɵSourceMessage, TargetMessage as ɵTargetMessage, computeMsgId as ɵcomputeMsgId, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, splitBlock as ɵsplitBlock, translate as ɵtranslate} from './src/utils';
export {computeMsgId as ɵcomputeMsgId, findEndOfBlock as ɵfindEndOfBlock, isMissingTranslationError as ɵisMissingTranslationError, makeParsedTranslation as ɵmakeParsedTranslation, makeTemplateObject as ɵmakeTemplateObject, MessageId as ɵMessageId, MissingTranslationError as ɵMissingTranslationError, ParsedMessage as ɵParsedMessage, ParsedTranslation as ɵParsedTranslation, ParsedTranslations as ɵParsedTranslations, parseMessage as ɵparseMessage, parseMetadata as ɵparseMetadata, parseTranslation as ɵparseTranslation, SourceMessage as ɵSourceMessage, splitBlock as ɵsplitBlock, TargetMessage as ɵTargetMessage, translate as ɵtranslate} from './src/utils';

View File

@ -9,7 +9,7 @@
*/
import {virtualFs} from '@angular-devkit/core';
import {Rule, Tree, chain} from '@angular-devkit/schematics';
import {chain, Rule, Tree} from '@angular-devkit/schematics';
import {getWorkspace} from '@schematics/angular/utility/config';
import {getProjectTargets} from '@schematics/angular/utility/project-targets';
import {validateProjectName} from '@schematics/angular/utility/validation';
@ -25,13 +25,12 @@ function getAllOptionValues<T>(
const targets = getProjectTargets(host, projectName);
// Find all targets of a specific build in a project.
const builderTargets: (BrowserBuilderTarget | ServeBuilderTarget)[] =
Object.values(targets).filter(
(target: BrowserBuilderTarget | ServeBuilderTarget) => target.builder === builderName);
const builderTargets: (BrowserBuilderTarget|ServeBuilderTarget)[] = Object.values(targets).filter(
(target: BrowserBuilderTarget|ServeBuilderTarget) => target.builder === builderName);
// Get all options contained in target configuration partials.
const configurationOptions = builderTargets.filter(t => t.configurations)
.map(t => Object.values(t.configurations !))
.map(t => Object.values(t.configurations!))
.reduce((acc, cur) => acc.concat(...cur), []);
// Now we have all option sets. We can use it to find all references to a given property.

View File

@ -13,7 +13,6 @@ import {localizePolyfill} from './index';
describe('ng-add schematic', () => {
const countInstances = (str: string, substr: string) => str.split(substr).length - 1;
const defaultOptions = {name: 'demo'};
let host: UnitTestTree;
@ -112,25 +111,25 @@ export { renderModule, renderModuleFactory } from '@angular/platform-server';`;
new SchematicTestRunner('@angular/localize', require.resolve('../collection.json'));
});
it('should add localize polyfill to polyfill files', async() => {
it('should add localize polyfill to polyfill files', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
expect(host.readContent('/src/polyfills.ts')).toContain(localizePolyfill);
expect(host.readContent('/src/another-polyfills.ts')).toContain(localizePolyfill);
});
it('should add localize polyfill to server main files', async() => {
it('should add localize polyfill to server main files', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
expect(host.readContent('/src/main.server.ts')).toContain(localizePolyfill);
expect(host.readContent('/src/another-main.server.ts')).toContain(localizePolyfill);
});
it('should add localize polyfill at the start of file', async() => {
it('should add localize polyfill at the start of file', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const content = host.readContent('/src/polyfills.ts');
expect(content.indexOf(localizePolyfill)).toBeLessThan(content.indexOf(polyfillsContent));
});
it('should not add localize polyfill to files referenced in other targets files', async() => {
it('should not add localize polyfill to files referenced in other targets files', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
expect(host.readContent('/src/unrelated-polyfills.ts')).not.toContain(localizePolyfill);
expect(host.readContent('/src/another-unrelated-polyfills.ts')).not.toContain(localizePolyfill);
@ -139,13 +138,13 @@ export { renderModule, renderModuleFactory } from '@angular/platform-server';`;
.not.toContain(localizePolyfill);
});
it('should only add localize polyfill once if multiple builds reference it', async() => {
it('should only add localize polyfill once if multiple builds reference it', async () => {
host = await schematicRunner.runSchematicAsync('ng-add', defaultOptions, host).toPromise();
const content = host.readContent('/src/polyfills.ts');
expect(countInstances(content, localizePolyfill)).toBe(1);
});
it('should not add localize polyfill if it\'s already there', async() => {
it('should not add localize polyfill if it\'s already there', async () => {
const polyfillVariation = localizePolyfill.replace(/'/g, '"');
host.overwrite('/src/polyfills.ts', `${localizePolyfill}\n${polyfillsContent}`);
host.overwrite('/src/another-polyfills.ts', `${polyfillVariation}\n${polyfillsContent}`);
@ -154,7 +153,7 @@ export { renderModule, renderModuleFactory } from '@angular/platform-server';`;
expect(countInstances(host.readContent('/src/another-polyfills.ts'), localizePolyfill)).toBe(0);
});
it('should not break when there are no polyfills', async() => {
it('should not break when there are no polyfills', async () => {
host.overwrite('angular.json', JSON.stringify({
projects: {
'demo': {

View File

@ -11,77 +11,87 @@ describe('$localize tag', () => {
describe('with no `translate()` defined (the default)', () => {
it('should render template literals as-is', () => {
expect($localize.translate).toBeUndefined();
expect($localize `abc`).toEqual('abc');
expect($localize `abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
expect($localize`abc`).toEqual('abc');
expect($localize`abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize`abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!');
expect($localize`Hello, ${getName()}!`).toEqual('Hello, World!');
});
it('should strip metadata block from message parts', () => {
expect($localize.translate).toBeUndefined();
expect($localize `:meaning|description@@custom-id:abcdef`).toEqual('abcdef');
expect($localize`:meaning|description@@custom-id:abcdef`).toEqual('abcdef');
});
it('should ignore escaped metadata block marker', () => {
expect($localize.translate).toBeUndefined();
expect($localize `\:abc:def`).toEqual(':abc:def');
expect($localize`\:abc:def`).toEqual(':abc:def');
});
it('should strip metadata block containing escaped block markers', () => {
expect($localize.translate).toBeUndefined();
expect($localize `:abc\:def:content`).toEqual('content');
expect($localize`:abc\:def:content`).toEqual('content');
});
it('should strip placeholder names from message parts', () => {
expect($localize.translate).toBeUndefined();
expect($localize `abc${1 + 2 + 3}:ph1:def${4 + 5 + 6}:ph2:`).toEqual('abc6def15');
expect($localize`abc${1 + 2 + 3}:ph1:def${4 + 5 + 6}:ph2:`).toEqual('abc6def15');
});
it('should ignore escaped placeholder name marker', () => {
expect($localize.translate).toBeUndefined();
expect($localize `abc${1 + 2 + 3}\:ph1:def${4 + 5 + 6}\:ph2:`).toEqual('abc6:ph1:def15:ph2:');
expect($localize`abc${1 + 2 + 3}\:ph1:def${4 + 5 + 6}\:ph2:`).toEqual('abc6:ph1:def15:ph2:');
});
});
describe('with `translate()` defined as an identity', () => {
beforeEach(() => { $localize.translate = identityTranslate; });
afterEach(() => { $localize.translate = undefined; });
beforeEach(() => {
$localize.translate = identityTranslate;
});
afterEach(() => {
$localize.translate = undefined;
});
it('should render template literals as-is', () => {
expect($localize `abc`).toEqual('abc');
expect($localize `abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
expect($localize`abc`).toEqual('abc');
expect($localize`abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize`abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!');
expect($localize`Hello, ${getName()}!`).toEqual('Hello, World!');
});
});
describe('with `translate()` defined to upper-case messageParts', () => {
beforeEach(() => { $localize.translate = upperCaseTranslate; });
afterEach(() => { $localize.translate = undefined; });
beforeEach(() => {
$localize.translate = upperCaseTranslate;
});
afterEach(() => {
$localize.translate = undefined;
});
it('should render template literals with messages upper-cased', () => {
expect($localize `abc`).toEqual('ABC');
expect($localize `abc${1 + 2 + 3}`).toEqual('ABC6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('ABC6DEF');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15');
expect($localize`abc`).toEqual('ABC');
expect($localize`abc${1 + 2 + 3}`).toEqual('ABC6');
expect($localize`abc${1 + 2 + 3}def`).toEqual('ABC6DEF');
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('HELLO, World!');
expect($localize`Hello, ${getName()}!`).toEqual('HELLO, World!');
});
});
describe('with `translate()` defined to reverse expressions', () => {
beforeEach(() => { $localize.translate = reverseTranslate; });
afterEach(() => { $localize.translate = undefined; });
beforeEach(() => {
$localize.translate = reverseTranslate;
});
afterEach(() => {
$localize.translate = undefined;
});
it('should render template literals with expressions reversed', () => {
const getName = () => 'World';
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
.toEqual('abcWorlddef15 - Hello, 6!');
});
});

View File

@ -11,13 +11,19 @@
* of the tools.
*/
export class Diagnostics {
readonly messages: {type: 'warning' | 'error', message: string}[] = [];
get hasErrors() { return this.messages.some(m => m.type === 'error'); }
warn(message: string) { this.messages.push({type: 'warning', message}); }
error(message: string) { this.messages.push({type: 'error', message}); }
readonly messages: {type: 'warning'|'error', message: string}[] = [];
get hasErrors() {
return this.messages.some(m => m.type === 'error');
}
warn(message: string) {
this.messages.push({type: 'warning', message});
}
error(message: string) {
this.messages.push({type: 'error', message});
}
formatDiagnostics(message: string): string {
const errors = this.messages !.filter(d => d.type === 'error').map(d => ' - ' + d.message);
const warnings = this.messages !.filter(d => d.type === 'warning').map(d => ' - ' + d.message);
const errors = this.messages!.filter(d => d.type === 'error').map(d => ' - ' + d.message);
const warnings = this.messages!.filter(d => d.type === 'warning').map(d => ' - ' + d.message);
if (errors.length) {
message += '\nERRORS:\n' + errors.join('\n');
}

View File

@ -9,9 +9,13 @@ import * as fs from 'fs';
import * as path from 'path';
export class FileUtils {
static readFile(absolutePath: string): string { return fs.readFileSync(absolutePath, 'utf8'); }
static readFile(absolutePath: string): string {
return fs.readFileSync(absolutePath, 'utf8');
}
static readFileBuffer(absolutePath: string): Buffer { return fs.readFileSync(absolutePath); }
static readFileBuffer(absolutePath: string): Buffer {
return fs.readFileSync(absolutePath);
}
static writeFile(absolutePath: string, contents: string|Buffer) {
FileUtils.ensureDir(path.dirname(absolutePath));
@ -25,7 +29,7 @@ export class FileUtils {
absolutePath = path.dirname(absolutePath);
}
while (parents.length) {
fs.mkdirSync(parents.pop() !);
fs.mkdirSync(parents.pop()!);
}
}

View File

@ -14,7 +14,9 @@ import {TranslationBundle, TranslationHandler} from '../translator';
* Translate an asset file by simply copying it to the appropriate translation output paths.
*/
export class AssetTranslationHandler implements TranslationHandler {
canTranslate(_relativeFilePath: string, _contents: Buffer): boolean { return true; }
canTranslate(_relativeFilePath: string, _contents: Buffer): boolean {
return true;
}
translate(
diagnostics: Diagnostics, _sourceRoot: string, relativeFilePath: string, contents: Buffer,
outputPathFn: OutputPathFn, translations: TranslationBundle[], sourceLocale?: string): void {

View File

@ -88,8 +88,16 @@ if (require.main === module) {
const sourceLocale: string|undefined = options['l'];
const translationFileLocales: string[] = options['target-locales'] || [];
translateFiles({sourceRootPath, sourceFilePaths, translationFilePaths, translationFileLocales,
outputPathFn, diagnostics, missingTranslation, sourceLocale});
translateFiles({
sourceRootPath,
sourceFilePaths,
translationFilePaths,
translationFileLocales,
outputPathFn,
diagnostics,
missingTranslation,
sourceLocale
});
diagnostics.messages.forEach(m => console.warn(`${m.type}: ${m.message}`));
process.exit(diagnostics.hasErrors ? 1 : 0);
@ -135,9 +143,16 @@ export interface TranslateFilesOptions {
sourceLocale?: string;
}
export function translateFiles({sourceRootPath, sourceFilePaths, translationFilePaths,
translationFileLocales, outputPathFn, diagnostics,
missingTranslation, sourceLocale}: TranslateFilesOptions) {
export function translateFiles({
sourceRootPath,
sourceFilePaths,
translationFilePaths,
translationFileLocales,
outputPathFn,
diagnostics,
missingTranslation,
sourceLocale
}: TranslateFilesOptions) {
const translationLoader = new TranslationLoader(
[
new Xliff2TranslationParser(),

View File

@ -7,7 +7,9 @@
*/
import {join} from 'path';
export interface OutputPathFn { (locale: string, relativePath: string): string; }
export interface OutputPathFn {
(locale: string, relativePath: string): string;
}
/**
* Create a function that will compute the absolute path to where a translated file should be

View File

@ -8,8 +8,10 @@
import {ɵParsedTranslation} from '@angular/localize';
import {NodePath, PluginObj} from '@babel/core';
import {TaggedTemplateExpression} from '@babel/types';
import {Diagnostics} from '../../diagnostics';
import {TranslatePluginOptions, buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromTemplateLiteral} from './source_file_utils';
import {buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, TranslatePluginOptions, unwrapMessagePartsFromTemplateLiteral} from './source_file_utils';
export function makeEs2015TranslatePlugin(
diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>,

View File

@ -8,8 +8,10 @@
import {ɵParsedTranslation} from '@angular/localize';
import {NodePath, PluginObj} from '@babel/core';
import {CallExpression} from '@babel/types';
import {Diagnostics} from '../../diagnostics';
import {TranslatePluginOptions, buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, unwrapMessagePartsFromLocalizeCall, unwrapSubstitutionsFromLocalizeCall} from './source_file_utils';
import {buildCodeFrameError, buildLocalizeReplacement, isBabelParseError, isLocalize, translate, TranslatePluginOptions, unwrapMessagePartsFromLocalizeCall, unwrapSubstitutionsFromLocalizeCall} from './source_file_utils';
export function makeEs5TranslatePlugin(
diagnostics: Diagnostics, translations: Record<string, ɵParsedTranslation>,

View File

@ -8,7 +8,7 @@
import {NodePath, PluginObj} from '@babel/core';
import {MemberExpression, stringLiteral} from '@babel/types';
import {TranslatePluginOptions, isLocalize} from './source_file_utils';
import {isLocalize, TranslatePluginOptions} from './source_file_utils';
/**
* This Babel plugin will replace the following code forms with a string literal containing the

View File

@ -5,9 +5,10 @@
* 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 {ɵParsedTranslation, ɵisMissingTranslationError, ɵmakeTemplateObject, ɵtranslate} from '@angular/localize';
import {ɵisMissingTranslationError, ɵmakeTemplateObject, ɵParsedTranslation, ɵtranslate} from '@angular/localize';
import {NodePath} from '@babel/traverse';
import * as t from '@babel/types';
import {Diagnostics} from '../../diagnostics';
/**
@ -33,18 +34,18 @@ export function isNamedIdentifier(
}
/**
* Is the given `identifier` declared globally.
* @param identifier The identifier to check.
*/
* Is the given `identifier` declared globally.
* @param identifier The identifier to check.
*/
export function isGlobalIdentifier(identifier: NodePath<t.Identifier>) {
return !identifier.scope || !identifier.scope.hasBinding(identifier.node.name);
}
/**
* Build a translated expression to replace the call to `$localize`.
* @param messageParts The static parts of the message.
* @param substitutions The expressions to substitute into the message.
*/
* Build a translated expression to replace the call to `$localize`.
* @param messageParts The static parts of the message.
* @param substitutions The expressions to substitute into the message.
*/
export function buildLocalizeReplacement(
messageParts: TemplateStringsArray, substitutions: readonly t.Expression[]): t.Expression {
let mappedString: t.Expression = t.stringLiteral(messageParts[0]);
@ -57,13 +58,13 @@ export function buildLocalizeReplacement(
}
/**
* Extract the message parts from the given `call` (to `$localize`).
*
* The message parts will either by the first argument to the `call` or it will be wrapped in call
* to a helper function like `__makeTemplateObject`.
*
* @param call The AST node of the call to process.
*/
* Extract the message parts from the given `call` (to `$localize`).
*
* The message parts will either by the first argument to the `call` or it will be wrapped in call
* to a helper function like `__makeTemplateObject`.
*
* @param call The AST node of the call to process.
*/
export function unwrapMessagePartsFromLocalizeCall(call: NodePath<t.CallExpression>):
TemplateStringsArray {
let cooked = call.get('arguments')[0];
@ -144,7 +145,7 @@ export function unwrapMessagePartsFromLocalizeCall(call: NodePath<t.CallExpressi
export function unwrapSubstitutionsFromLocalizeCall(call: t.CallExpression): t.Expression[] {
const expressions = call.arguments.splice(1);
if (!isArrayOfExpressions(expressions)) {
const badExpression = expressions.find(expression => !t.isExpression(expression)) !;
const badExpression = expressions.find(expression => !t.isExpression(expression))!;
throw new BabelParseError(
badExpression,
'Invalid substitutions for `$localize` (expected all substitution arguments to be expressions).');
@ -166,12 +167,12 @@ export function unwrapMessagePartsFromTemplateLiteral(elements: t.TemplateElemen
}
/**
* Wrap the given `expression` in parentheses if it is a binary expression.
*
* This ensures that this expression is evaluated correctly if it is embedded in another expression.
*
* @param expression The expression to potentially wrap.
*/
* Wrap the given `expression` in parentheses if it is a binary expression.
*
* This ensures that this expression is evaluated correctly if it is embedded in another expression.
*
* @param expression The expression to potentially wrap.
*/
export function wrapInParensIfNecessary(expression: t.Expression): t.Expression {
if (t.isBinaryExpression(expression)) {
return t.parenthesizedExpression(expression);
@ -181,9 +182,9 @@ export function wrapInParensIfNecessary(expression: t.Expression): t.Expression
}
/**
* Extract the string values from an `array` of string literals.
* @param array The array to unwrap.
*/
* Extract the string values from an `array` of string literals.
* @param array The array to unwrap.
*/
export function unwrapStringLiteralArray(array: t.Expression): string[] {
if (!isStringLiteralArray(array)) {
throw new BabelParseError(
@ -280,19 +281,19 @@ function getReturnedExpression(fn: NodePath<t.FunctionDeclaration>): NodePath<t.
}
/**
* Is the given `node` an array of literal strings?
*
* @param node The node to test.
*/
* Is the given `node` an array of literal strings?
*
* @param node The node to test.
*/
export function isStringLiteralArray(node: t.Node): node is t.Expression&
{elements: t.StringLiteral[]} {
return t.isArrayExpression(node) && node.elements.every(element => t.isStringLiteral(element));
}
/**
* Are all the given `nodes` expressions?
* @param nodes The nodes to test.
*/
* Are all the given `nodes` expressions?
* @param nodes The nodes to test.
*/
export function isArrayOfExpressions(nodes: t.Node[]): nodes is t.Expression[] {
return nodes.every(element => t.isExpression(element));
}
@ -306,7 +307,7 @@ export interface TranslatePluginOptions {
/**
* How to handle missing translations.
*/
export type MissingTranslationStrategy = 'error' | 'warning' | 'ignore';
export type MissingTranslationStrategy = 'error'|'warning'|'ignore';
/**
* Translate the text of the given message, using the given translations.
@ -340,7 +341,9 @@ export function translate(
export class BabelParseError extends Error {
private readonly type = 'BabelParseError';
constructor(public node: t.Node, message: string) { super(message); }
constructor(public node: t.Node, message: string) {
super(message);
}
}
export function isBabelParseError(e: any): e is BabelParseError {

View File

@ -9,7 +9,7 @@ import {Element, Expansion, ExpansionCase, Node, Text, visitAll} from '@angular/
import {BaseVisitor} from '../base_visitor';
import {TranslationParseError} from '../translation_parsers/translation_parse_error';
import {getAttrOrThrow, getAttribute} from '../translation_parsers/translation_utils';
import {getAttribute, getAttrOrThrow} from '../translation_parsers/translation_utils';
import {MessageRenderer} from './message_renderer';
@ -55,7 +55,9 @@ export class MessageSerializer<T> extends BaseVisitor {
}
}
visitText(text: Text): void { this.renderer.text(text.value); }
visitText(text: Text): void {
this.renderer.text(text.value);
}
visitExpansion(expansion: Expansion): void {
this.renderer.startIcu();
@ -109,6 +111,6 @@ export class MessageSerializer<T> extends BaseVisitor {
}
private isPlaceholderContainer(node: Node): boolean {
return node instanceof Element && node.name === this.config.placeholderContainer !.elementName;
return node instanceof Element && node.name === this.config.placeholderContainer!.elementName;
}
}

View File

@ -5,7 +5,8 @@
* 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 {ɵParsedTranslation, ɵmakeParsedTranslation} from '@angular/localize';
import {ɵmakeParsedTranslation, ɵParsedTranslation} from '@angular/localize';
import {MessageRenderer} from './message_renderer';
/**
@ -20,11 +21,21 @@ export class TargetMessageRenderer implements MessageRenderer<ɵParsedTranslatio
return ɵmakeParsedTranslation(messageParts, placeholderNames);
}
startRender(): void {}
endRender(): void { this.storeMessagePart(); }
text(text: string): void { this.current.text += text; }
placeholder(name: string, body: string|undefined): void { this.renderPlaceholder(name); }
startPlaceholder(name: string): void { this.renderPlaceholder(name); }
closePlaceholder(name: string): void { this.renderPlaceholder(name); }
endRender(): void {
this.storeMessagePart();
}
text(text: string): void {
this.current.text += text;
}
placeholder(name: string, body: string|undefined): void {
this.renderPlaceholder(name);
}
startPlaceholder(name: string): void {
this.renderPlaceholder(name);
}
closePlaceholder(name: string): void {
this.renderPlaceholder(name);
}
startContainer(): void {}
closeContainer(): void {}
startIcu(): void {
@ -35,7 +46,9 @@ export class TargetMessageRenderer implements MessageRenderer<ɵParsedTranslatio
this.icuDepth--;
this.text('}');
}
private normalizePlaceholderName(name: string) { return name.replace(/-/g, '_'); }
private normalizePlaceholderName(name: string) {
return name.replace(/-/g, '_');
}
private renderPlaceholder(name: string) {
name = this.normalizePlaceholderName(name);
if (this.icuDepth > 0) {

View File

@ -51,14 +51,15 @@ export class TranslationLoader {
const providedLocale = translationFileLocales[index];
const locale = providedLocale || parsedLocale;
if (locale === undefined) {
throw new Error(
`The translation file "${filePath}" does not contain a target locale and no explicit locale was provided for this file.`);
throw new Error(`The translation file "${
filePath}" does not contain a target locale and no explicit locale was provided for this file.`);
}
if (parsedLocale !== undefined && providedLocale !== undefined &&
parsedLocale !== providedLocale) {
diagnostics.warn(
`The provided locale "${providedLocale}" does not match the target locale "${parsedLocale}" found in the translation file "${filePath}".`);
`The provided locale "${providedLocale}" does not match the target locale "${
parsedLocale}" found in the translation file "${filePath}".`);
}
// If we were passed a diagnostics object then copy the messages over to it.

View File

@ -24,7 +24,9 @@ import {ParsedTranslationBundle, TranslationParser} from './translation_parser';
* ```
*/
export class SimpleJsonTranslationParser implements TranslationParser {
canParse(filePath: string, _contents: string): boolean { return (extname(filePath) === '.json'); }
canParse(filePath: string, _contents: string): boolean {
return (extname(filePath) === '.json');
}
parse(_filePath: string, contents: string): ParsedTranslationBundle {
const {locale: parsedLocale, translations} = JSON.parse(contents);

View File

@ -9,8 +9,8 @@ import {ɵMessageId, ɵParsedTranslation} from '@angular/localize/private';
import {Diagnostics} from '../../../diagnostics';
/**
* An object that holds translations that have been parsed from a translation file.
*/
* An object that holds translations that have been parsed from a translation file.
*/
export interface ParsedTranslationBundle {
locale: string|undefined;
translations: Record<ɵMessageId, ɵParsedTranslation>;

View File

@ -47,8 +47,8 @@ export function parseInnerRange(element: Element): Node[] {
* @param element The element whose inner range we want to compute.
*/
function getInnerRange(element: Element): LexerRange {
const start = element.startSourceSpan !.end;
const end = element.endSourceSpan !.start;
const start = element.startSourceSpan!.end;
const end = element.endSourceSpan!.start;
return {
startPos: start.offset,
startLine: start.line,

View File

@ -14,7 +14,7 @@ import {MessageSerializer} from '../message_serialization/message_serializer';
import {TargetMessageRenderer} from '../message_serialization/target_message_renderer';
import {ParsedTranslationBundle, TranslationParser} from './translation_parser';
import {XmlTranslationParserHint, addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange} from './translation_utils';
import {addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange, XmlTranslationParserHint} from './translation_utils';
/**
* A translation parser that can load XLIFF 1.2 files.
@ -74,7 +74,8 @@ export class Xliff1TranslationParser implements TranslationParser<XmlTranslation
if (localesFound.size > 1) {
addParseDiagnostic(
diagnostics, element.sourceSpan,
`More than one locale found in translation file: ${JSON.stringify(Array.from(localesFound))}. Using "${bundle.locale}"`,
`More than one locale found in translation file: ${
JSON.stringify(Array.from(localesFound))}. Using "${bundle.locale}"`,
ParseErrorLevel.WARNING);
}

View File

@ -14,7 +14,7 @@ import {MessageSerializer} from '../message_serialization/message_serializer';
import {TargetMessageRenderer} from '../message_serialization/target_message_renderer';
import {ParsedTranslationBundle, TranslationParser} from './translation_parser';
import {XmlTranslationParserHint, addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange} from './translation_utils';
import {addParseDiagnostic, addParseError, canParseXml, getAttribute, isNamedElement, parseInnerRange, XmlTranslationParserHint} from './translation_utils';
/**
* A translation parser that can load translations from XLIFF 2 files.

View File

@ -15,7 +15,7 @@ import {MessageSerializer} from '../message_serialization/message_serializer';
import {TargetMessageRenderer} from '../message_serialization/target_message_renderer';
import {ParsedTranslationBundle, TranslationParser} from './translation_parser';
import {XmlTranslationParserHint, addParseDiagnostic, addParseError, canParseXml, getAttribute, parseInnerRange} from './translation_utils';
import {addParseDiagnostic, addParseError, canParseXml, getAttribute, parseInnerRange, XmlTranslationParserHint} from './translation_utils';
/**
@ -94,7 +94,8 @@ class XtbVisitor extends BaseVisitor {
} catch (error) {
if (typeof error === 'string') {
bundle.diagnostics.warn(
`Could not parse message with id "${id}" - perhaps it has an unrecognised ICU format?\n` +
`Could not parse message with id "${
id}" - perhaps it has an unrecognised ICU format?\n` +
error);
} else if (error.span && error.msg && error.level) {
addParseDiagnostic(bundle.diagnostics, error.span, error.msg, error.level);

View File

@ -19,7 +19,9 @@ describe('translateFiles()', () => {
const testDir = resolve(tmpDir, 'translatedFiles_tests');
beforeEach(() => FileUtils.ensureDir(testDir));
afterEach(() => { FileUtils.remove(testDir); });
afterEach(() => {
FileUtils.remove(testDir);
});
it('should copy non-code files to the destination folders', () => {
const diagnostics = new Diagnostics();
@ -31,7 +33,8 @@ describe('translateFiles()', () => {
translationFilePaths: resolveAll(
__dirname + '/locales',
['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']),
translationFileLocales: [], diagnostics,
translationFileLocales: [],
diagnostics,
missingTranslation: 'error'
});
@ -60,11 +63,13 @@ describe('translateFiles()', () => {
const outputPathFn = getOutputPathFn(resolve(testDir, '{{LOCALE}}'));
translateFiles({
sourceRootPath: resolve(__dirname, 'test_files'),
sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']), outputPathFn,
sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']),
outputPathFn,
translationFilePaths: resolveAll(
__dirname + '/locales',
['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']),
translationFileLocales: [], diagnostics,
translationFileLocales: [],
diagnostics,
missingTranslation: 'error',
});
@ -85,11 +90,13 @@ describe('translateFiles()', () => {
const outputPathFn = getOutputPathFn(resolve(testDir, '{{LOCALE}}'));
translateFiles({
sourceRootPath: resolve(__dirname, 'test_files'),
sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']), outputPathFn,
sourceFilePaths: resolveAll(__dirname + '/test_files', ['test.js']),
outputPathFn,
translationFilePaths: resolveAll(
__dirname + '/locales',
['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']),
translationFileLocales: ['xde', undefined, 'fr'], diagnostics,
translationFileLocales: ['xde', undefined, 'fr'],
diagnostics,
missingTranslation: 'error',
});
@ -97,7 +104,8 @@ describe('translateFiles()', () => {
expect(diagnostics.messages).toContain({
type: 'warning',
message:
`The provided locale "xde" does not match the target locale "de" found in the translation file "${resolve(__dirname, 'locales', 'messages.de.json')}".`
`The provided locale "xde" does not match the target locale "de" found in the translation file "${
resolve(__dirname, 'locales', 'messages.de.json')}".`
});
expect(FileUtils.readFile(resolve(testDir, 'xde', 'test.js')))
@ -121,7 +129,8 @@ describe('translateFiles()', () => {
translationFilePaths: resolveAll(
__dirname + '/locales',
['messages.de.json', 'messages.es.xlf', 'messages.fr.xlf', 'messages.it.xtb']),
translationFileLocales: [], diagnostics,
translationFileLocales: [],
diagnostics,
missingTranslation: 'error',
});

View File

@ -1,2 +1,2 @@
var name = 'World';
var message = $localize `Hello, ${name}!`;
var message = $localize`Hello, ${name}!`;

View File

@ -16,24 +16,21 @@ describe('makeEs2015Plugin', () => {
it('should transform `$localize` tags with binary expression', () => {
const diagnostics = new Diagnostics();
const input = 'const b = 10;\n$localize`try\\n${40 + b}\\n me`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";');
});
it('should strip meta blocks', () => {
const diagnostics = new Diagnostics();
const input = 'const b = 10;\n$localize `:description:try\\n${40 + b}\\n me`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";');
});
it('should not strip escaped meta blocks', () => {
const diagnostics = new Diagnostics();
const input = 'const b = 10;\n$localize `\\:description:try\\n${40 + b}\\n me`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('const b = 10;\n":description:try\\n" + (40 + b) + "\\n me";');
});
@ -41,24 +38,21 @@ describe('makeEs2015Plugin', () => {
it('should transform nested `$localize` tags', () => {
const diagnostics = new Diagnostics();
const input = '$localize`a${1}b${$localize`x${5}y${6}z`}c`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"a" + 1 + "b" + ("x" + 5 + "y" + 6 + "z") + "c";');
});
it('should transform tags inside functions', () => {
const diagnostics = new Diagnostics();
const input = 'function foo() { $localize`a${1}b${2}c`; }';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('function foo() {\n "a" + 1 + "b" + 2 + "c";\n}');
});
it('should ignore tags with the wrong name', () => {
const diagnostics = new Diagnostics();
const input = 'other`a${1}b${2}c`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('other`a${1}b${2}c`;');
});
@ -66,16 +60,14 @@ describe('makeEs2015Plugin', () => {
const diagnostics = new Diagnostics();
const input = 'other`a${1}b${2}c`;';
const output = transformSync(
input,
{plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]}) !;
input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]})!;
expect(output.code).toEqual('"a" + 1 + "b" + 2 + "c";');
});
it('should ignore tags if the identifier is not global', () => {
const diagnostics = new Diagnostics();
const input = 'function foo($localize) { $localize`a${1}b${2}c`; }';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('function foo($localize) {\n $localize`a${1}b${2}c`;\n}');
});
@ -85,12 +77,12 @@ describe('makeEs2015Plugin', () => {
const input = 'const b = 10;\n$localize `try\\n${40 + b}\\n me`;';
transformSync(input, {
plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'error'})]
}) !;
})!;
expect(diagnostics.hasErrors).toBe(true);
expect(diagnostics.messages[0]).toEqual({
type: 'error',
message:
`No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
message: `No translation found for "${
ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
});
});
@ -99,14 +91,13 @@ describe('makeEs2015Plugin', () => {
const diagnostics = new Diagnostics();
const input = 'const b = 10;\n$localize `try\\n${40 + b}\\n me`;';
transformSync(input, {
plugins:
[makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'warning'})]
}) !;
plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'warning'})]
})!;
expect(diagnostics.hasErrors).toBe(false);
expect(diagnostics.messages[0]).toEqual({
type: 'warning',
message:
`No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
message: `No translation found for "${
ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
});
});
@ -115,9 +106,8 @@ describe('makeEs2015Plugin', () => {
const diagnostics = new Diagnostics();
const input = 'const b = 10;\n$localize `try\\n${40 + b}\\n me`;';
transformSync(input, {
plugins:
[makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'ignore'})]
}) !;
plugins: [makeEs2015TranslatePlugin(diagnostics, {}, {missingTranslation: 'ignore'})]
})!;
expect(diagnostics.hasErrors).toBe(false);
expect(diagnostics.messages).toEqual([]);
});
@ -139,7 +129,7 @@ describe('makeEs2015Plugin', () => {
'$localize `abc${1 + 2 + 3}def${4 + 5 + 6}`;\n' +
'$localize `Hello, ${getName()}!`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!;
expect(output.code)
.toEqual(
'"abc";\n' +
@ -164,7 +154,7 @@ describe('makeEs2015Plugin', () => {
'$localize `abc${1 + 2 + 3}def${4 + 5 + 6}`;\n' +
'$localize `Hello, ${getName()}!`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!;
expect(output.code)
.toEqual(
'"ABC";\n' +
@ -182,7 +172,7 @@ describe('makeEs2015Plugin', () => {
};
const input = '$localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!;
expect(output.code)
.toEqual('"abc" + getName() + "def" + (4 + 5 + 6) + " - Hello, " + (1 + 2 + 3) + "!";');
});
@ -195,7 +185,7 @@ describe('makeEs2015Plugin', () => {
};
const input = '$localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`;';
const output =
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs2015TranslatePlugin(diagnostics, translations)]})!;
expect(output.code).toEqual('"abc" + (1 + 2 + 3) + " - Hello, " + getName() + "!";');
});
});

View File

@ -16,7 +16,7 @@ describe('makeEs5Plugin', () => {
it('should transform `$localize` calls with binary expression', () => {
const diagnostics = new Diagnostics();
const input = 'const b = 10;\n$localize(["try\\n", "\\n me"], 40 + b);';
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";');
});
@ -24,7 +24,7 @@ describe('makeEs5Plugin', () => {
const diagnostics = new Diagnostics();
const input =
'const b = 10;\n$localize([":description:try\\n", ":placeholder:\\n me"], 40 + b);';
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('const b = 10;\n"try\\n" + (40 + b) + "\\n me";');
});
@ -32,28 +32,28 @@ describe('makeEs5Plugin', () => {
const diagnostics = new Diagnostics();
const input =
`$localize(__makeTemplateObject([':desc:try', 'me'], ['\\\\\\:desc:try', 'me']), 40 + 2);`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('":desc:try" + (40 + 2) + "me";');
});
it('should transform nested `$localize` calls', () => {
const diagnostics = new Diagnostics();
const input = '$localize(["a", "b", "c"], 1, $localize(["x", "y", "z"], 5, 6));';
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"a" + 1 + "b" + ("x" + 5 + "y" + 6 + "z") + "c";');
});
it('should transform calls inside functions', () => {
const diagnostics = new Diagnostics();
const input = 'function foo() { $localize(["a", "b", "c"], 1, 2); }';
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('function foo() {\n "a" + 1 + "b" + 2 + "c";\n}');
});
it('should ignore tags with the wrong name', () => {
const diagnostics = new Diagnostics();
const input = 'other(["a", "b", "c"], 1, 2);';
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('other(["a", "b", "c"], 1, 2);');
});
@ -61,14 +61,14 @@ describe('makeEs5Plugin', () => {
const diagnostics = new Diagnostics();
const input = 'other(["a", "b", "c"], 1, 2);';
const output = transformSync(
input, {plugins: [makeEs5TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]}) !;
input, {plugins: [makeEs5TranslatePlugin(diagnostics, {}, {localizeName: 'other'})]})!;
expect(output.code).toEqual('"a" + 1 + "b" + 2 + "c";');
});
it('should ignore tags if the identifier is not global', () => {
const diagnostics = new Diagnostics();
const input = 'function foo($localize) { $localize(["a", "b", "c"], 1, 2); }';
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code)
.toEqual('function foo($localize) {\n $localize(["a", "b", "c"], 1, 2);\n}');
});
@ -76,14 +76,14 @@ describe('makeEs5Plugin', () => {
it('should handle template object helper calls', () => {
const diagnostics = new Diagnostics();
const input = `$localize(__makeTemplateObject(['try', 'me'], ['try', 'me']), 40 + 2);`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"try" + (40 + 2) + "me";');
});
it('should handle template object aliased helper calls', () => {
const diagnostics = new Diagnostics();
const input = `$localize(m(['try', 'me'], ['try', 'me']), 40 + 2);`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"try" + (40 + 2) + "me";');
});
@ -91,7 +91,7 @@ describe('makeEs5Plugin', () => {
const diagnostics = new Diagnostics();
const input =
`$localize((this&&this.__makeTemplateObject||function(e,t){return Object.defineProperty?Object.defineProperty(e,"raw",{value:t}):e.raw=t,e})(['try', 'me'], ['try', 'me']), 40 + 2);`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"try" + (40 + 2) + "me";');
});
@ -99,7 +99,7 @@ describe('makeEs5Plugin', () => {
const diagnostics = new Diagnostics();
const input =
`$localize(cachedObj||(cachedObj=__makeTemplateObject(['try', 'me'],['try', 'me'])),40 + 2)`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"try" + (40 + 2) + "me";');
});
@ -115,7 +115,7 @@ describe('makeEs5Plugin', () => {
cookedParts.raw=rawParts,
cachedObj=cookedParts
),40 + 2)`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toEqual('"try" + (40 + 2) + "me";');
});
@ -139,7 +139,7 @@ describe('makeEs5Plugin', () => {
console.log($localize(_templateObject(), '\ufffd0\ufffd'));
}
`;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]}) !;
const output = transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, {})]})!;
expect(output.code).toContain('const message = ":escaped-colons:Welcome to the i18n app."');
expect(output.code).toContain('console.log(" Hello " + \'\ufffd0\ufffd\' + "! ");');
expect(output.code).not.toContain('templateObject');
@ -290,8 +290,8 @@ describe('makeEs5Plugin', () => {
expect(diagnostics.hasErrors).toBe(true);
expect(diagnostics.messages[0]).toEqual({
type: 'error',
message:
`No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
message: `No translation found for "${
ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
});
});
@ -305,8 +305,8 @@ describe('makeEs5Plugin', () => {
expect(diagnostics.hasErrors).toBe(false);
expect(diagnostics.messages[0]).toEqual({
type: 'warning',
message:
`No translation found for "${ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
message: `No translation found for "${
ɵcomputeMsgId('try\n{$PH}\n me')}" ("try\n{$PH}\n me").`
});
});
@ -338,7 +338,7 @@ describe('(with translations)', () => {
'$localize(["abc", "def", ""], 1 + 2 + 3, 4 + 5 + 6);\n' +
'$localize(["Hello, ", "!"], getName());';
const output =
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!;
expect(output.code)
.toEqual(
'"abc";\n' +
@ -363,7 +363,7 @@ describe('(with translations)', () => {
'$localize(["abc", "def", ""], 1 + 2 + 3, 4 + 5 + 6);\n' +
'$localize(["Hello, ", "!"], getName());';
const output =
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!;
expect(output.code)
.toEqual(
'"ABC";\n' +
@ -381,7 +381,7 @@ describe('(with translations)', () => {
};
const input = '$localize(["abc", "def", " - Hello, ", "!"], 1 + 2 + 3, 4 + 5 + 6, getName());';
const output =
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!;
expect(output.code)
.toEqual('"abc" + getName() + "def" + (4 + 5 + 6) + " - Hello, " + (1 + 2 + 3) + "!";');
});
@ -394,7 +394,7 @@ describe('(with translations)', () => {
};
const input = '$localize(["abc", "def", " - Hello, ", "!"], 1 + 2 + 3, 4 + 5 + 6, getName());';
const output =
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]}) !;
transformSync(input, {plugins: [makeEs5TranslatePlugin(diagnostics, translations)]})!;
expect(output.code).toEqual('"abc" + (1 + 2 + 3) + " - Hello, " + getName() + "!";');
});
});

View File

@ -11,88 +11,88 @@ import {makeLocalePlugin} from '../../../src/translate/source_files/locale_plugi
describe('makeLocalePlugin', () => {
it('should replace $localize.locale with the locale string', () => {
const input = '$localize.locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('"fr";');
});
it('should replace $localize.locale with the locale string in the context of a variable assignment',
() => {
const input = 'const a = $localize.locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('const a = "fr";');
});
it('should replace $localize.locale with the locale string in the context of a binary expression',
() => {
const input = '$localize.locale || "default";';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('"fr" || "default";');
});
it('should remove reference to `$localize` if used to guard the locale', () => {
const input = 'typeof $localize !== "undefined" && $localize.locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('"fr";');
});
it('should remove reference to `$localize` if used in a longer logical expression to guard the locale',
() => {
const input1 = 'x || y && typeof $localize !== "undefined" && $localize.locale;';
const output1 = transformSync(input1, {plugins: [makeLocalePlugin('fr')]}) !;
const output1 = transformSync(input1, {plugins: [makeLocalePlugin('fr')]})!;
expect(output1.code).toEqual('x || y && "fr";');
const input2 = 'x || y && "undefined" !== typeof $localize && $localize.locale;';
const output2 = transformSync(input2, {plugins: [makeLocalePlugin('fr')]}) !;
const output2 = transformSync(input2, {plugins: [makeLocalePlugin('fr')]})!;
expect(output2.code).toEqual('x || y && "fr";');
const input3 = 'x || y && typeof $localize != "undefined" && $localize.locale;';
const output3 = transformSync(input3, {plugins: [makeLocalePlugin('fr')]}) !;
const output3 = transformSync(input3, {plugins: [makeLocalePlugin('fr')]})!;
expect(output3.code).toEqual('x || y && "fr";');
const input4 = 'x || y && "undefined" != typeof $localize && $localize.locale;';
const output4 = transformSync(input4, {plugins: [makeLocalePlugin('fr')]}) !;
const output4 = transformSync(input4, {plugins: [makeLocalePlugin('fr')]})!;
expect(output4.code).toEqual('x || y && "fr";');
});
it('should ignore properties on $localize other than `locale`', () => {
const input = '$localize.notLocale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('$localize.notLocale;');
});
it('should ignore indexed property on $localize', () => {
const input = '$localize["locale"];';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('$localize["locale"];');
});
it('should ignore `locale` on objects other than $localize', () => {
const input = '$notLocalize.locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('$notLocalize.locale;');
});
it('should ignore `$localize.locale` if `$localize` is not global', () => {
const input = 'const $localize = {};\n$localize.locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('const $localize = {};\n$localize.locale;');
});
it('should ignore `locale` if it is not directly accessed from `$localize`', () => {
const input = 'const {locale} = $localize;\nconst a = locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('const {\n locale\n} = $localize;\nconst a = locale;');
});
it('should ignore `$localize.locale` on LHS of an assignment', () => {
const input = 'let a;\na = $localize.locale = "de";';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('let a;\na = $localize.locale = "de";');
});
it('should handle `$localize.locale on RHS of an assignment', () => {
const input = 'let a;\na = $localize.locale;';
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]}) !;
const output = transformSync(input, {plugins: [makeLocalePlugin('fr')]})!;
expect(output.code).toEqual('let a;\na = "fr";');
});
});

View File

@ -20,7 +20,9 @@ describe('SourceFileTranslationHandler', () => {
});
describe('translate()', () => {
beforeEach(() => { spyOn(FileUtils, 'writeFile'); });
beforeEach(() => {
spyOn(FileUtils, 'writeFile');
});
it('should copy files for each translation locale if they contain no reference to `$localize`',
() => {

View File

@ -114,7 +114,7 @@ describe('utils', () => {
describe('unwrapSubstitutionsFromLocalizeCall', () => {
it('should return the substitutions from a direct call to a tag function', () => {
const ast = template.ast `$localize(['a', 'b\t', 'c'], 1, 2)` as ExpressionStatement;
const ast = template.ast`$localize(['a', 'b\t', 'c'], 1, 2)` as ExpressionStatement;
const call = ast.expression as CallExpression;
const substitutions = unwrapSubstitutionsFromLocalizeCall(call);
expect(substitutions.map(s => (s as NumericLiteral).value)).toEqual([1, 2]);
@ -140,13 +140,13 @@ describe('utils', () => {
describe('wrapInParensIfNecessary', () => {
it('should wrap the expression in parentheses if it is binary', () => {
const ast = template.ast `a + b` as ExpressionStatement;
const ast = template.ast`a + b` as ExpressionStatement;
const wrapped = wrapInParensIfNecessary(ast.expression);
expect(isParenthesizedExpression(wrapped)).toBe(true);
});
it('should return the expression untouched if it is not binary', () => {
const ast = template.ast `a` as ExpressionStatement;
const ast = template.ast`a` as ExpressionStatement;
const wrapped = wrapInParensIfNecessary(ast.expression);
expect(isParenthesizedExpression(wrapped)).toBe(false);
});
@ -154,12 +154,12 @@ describe('utils', () => {
describe('unwrapStringLiteralArray', () => {
it('should return an array of string from an array expression', () => {
const ast = template.ast `['a', 'b', 'c']` as ExpressionStatement;
const ast = template.ast`['a', 'b', 'c']` as ExpressionStatement;
expect(unwrapStringLiteralArray(ast.expression)).toEqual(['a', 'b', 'c']);
});
it('should throw an error if any elements of the array are not literal strings', () => {
const ast = template.ast `['a', 2, 'c']` as ExpressionStatement;
const ast = template.ast`['a', 2, 'c']` as ExpressionStatement;
expect(() => unwrapStringLiteralArray(ast.expression))
.toThrowError('Unexpected messageParts for `$localize` (expected an array of strings).');
});
@ -167,29 +167,29 @@ describe('utils', () => {
describe('isStringLiteralArray()', () => {
it('should return true if the ast is an array of strings', () => {
const ast = template.ast `['a', 'b', 'c']` as ExpressionStatement;
const ast = template.ast`['a', 'b', 'c']` as ExpressionStatement;
expect(isStringLiteralArray(ast.expression)).toBe(true);
});
it('should return false if the ast is not an array', () => {
const ast = template.ast `'a'` as ExpressionStatement;
const ast = template.ast`'a'` as ExpressionStatement;
expect(isStringLiteralArray(ast.expression)).toBe(false);
});
it('should return false if at least on of the array elements is not a string', () => {
const ast = template.ast `['a', 1, 'b']` as ExpressionStatement;
const ast = template.ast`['a', 1, 'b']` as ExpressionStatement;
expect(isStringLiteralArray(ast.expression)).toBe(false);
});
});
describe('isArrayOfExpressions()', () => {
it('should return true if all the nodes are expressions', () => {
const ast = template.ast `function foo(a, b, c) {}` as FunctionDeclaration;
const ast = template.ast`function foo(a, b, c) {}` as FunctionDeclaration;
expect(isArrayOfExpressions(ast.params)).toBe(true);
});
it('should return false if any of the nodes is not an expression', () => {
const ast = template.ast `function foo(a, b, ...c) {}` as FunctionDeclaration;
const ast = template.ast`function foo(a, b, ...c) {}` as FunctionDeclaration;
expect(isArrayOfExpressions(ast.params)).toBe(false);
});
});
@ -203,13 +203,25 @@ function getTaggedTemplate(code: string): NodePath<TaggedTemplateExpression> {
function collectExpressionsPlugin() {
const expressions: NodePath<Expression>[] = [];
const visitor = {Expression: (path: NodePath<Expression>) => { expressions.push(path); }};
const visitor = {
Expression: (path: NodePath<Expression>) => {
expressions.push(path);
}
};
return {expressions, plugin: {visitor}};
}
function getLocalizeCall(code: string): NodePath<CallExpression> {
let callPaths: NodePath<CallExpression>[] = [];
transformSync(code, {plugins: [{visitor: {CallExpression(path) { callPaths.push(path); }}}]});
transformSync(code, {
plugins: [{
visitor: {
CallExpression(path) {
callPaths.push(path);
}
}
}]
});
const localizeCall = callPaths.find(p => {
const callee = p.get('callee');
return (callee.isIdentifier() && callee.node.name === '$localize');

View File

@ -84,11 +84,14 @@ describe('TranslationLoader', () => {
loader.loadBundles(
['/src/locale/messages.en.xlf', '/src/locale/messages.fr.xlf'], [undefined, 'FR']);
expect(diagnostics.messages.length).toEqual(1);
expect(diagnostics.messages).toContain({
type: 'warning',
message:
`The provided locale "FR" does not match the target locale "pl" found in the translation file "/src/locale/messages.fr.xlf".`,
}, );
expect(diagnostics.messages)
.toContain(
{
type: 'warning',
message:
`The provided locale "FR" does not match the target locale "pl" found in the translation file "/src/locale/messages.fr.xlf".`,
},
);
});
it('should throw an error if there is no provided nor parsed target locale', () => {

View File

@ -421,7 +421,6 @@ describe('Xliff2TranslationParser', () => {
.toEqual(ɵmakeParsedTranslation(
['', ' tnemele elbatalsnart ', 'sredlohecalp htiw', ''],
['INTERPOLATION', 'START_BOLD_TEXT', 'CLOSE_BOLD_TEXT']));
});
describe('[structure errors]', () => {
@ -969,7 +968,6 @@ describe('Xliff2TranslationParser', () => {
.toEqual(ɵmakeParsedTranslation(
['', ' tnemele elbatalsnart ', 'sredlohecalp htiw', ''],
['INTERPOLATION', 'START_BOLD_TEXT', 'CLOSE_BOLD_TEXT']));
});
describe('[structure errors]', () => {

View File

@ -12,7 +12,6 @@ import {TranslationBundle, TranslationHandler, Translator} from '../../src/trans
describe('Translator', () => {
describe('translateFiles()', () => {
beforeEach(() => {
spyOn(FileUtils, 'readFileBuffer')
.and.returnValues(Buffer.from('resource file 1'), Buffer.from('resource file 2'));

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {LocalizeFn} from './localize';
import {MessageId, ParsedTranslation, TargetMessage, parseTranslation, translate as _translate} from './utils';
import {MessageId, ParsedTranslation, parseTranslation, TargetMessage, translate as _translate} from './utils';
/**
* We augment the `$localize` object to also store the translations.

View File

@ -131,7 +131,8 @@ export function parseMessage(
messageString,
meaning: metadata.meaning || '',
description: metadata.description || '',
messageParts: cleanedMessageParts, placeholderNames,
messageParts: cleanedMessageParts,
placeholderNames,
};
}
@ -176,7 +177,7 @@ export function parseMetadata(cooked: string, raw: string): MessageMetadata {
} else {
const [meaningDescAndId, ...legacyIds] = block.split(LEGACY_ID_INDICATOR);
const [meaningAndDesc, id] = meaningDescAndId.split(ID_SEPARATOR, 2);
let [meaning, description]: (string | undefined)[] = meaningAndDesc.split(MEANING_SEPARATOR, 2);
let [meaning, description]: (string|undefined)[] = meaningAndDesc.split(MEANING_SEPARATOR, 2);
if (description === undefined) {
description = meaning;
meaning = undefined;
@ -236,9 +237,9 @@ function computePlaceholderName(index: number) {
*/
export function findEndOfBlock(cooked: string, raw: string): number {
/************************************************************************************************
* This function is repeated in `src/localize/src/localize.ts` and the two should be kept in sync.
* (See that file for more explanation of why.)
************************************************************************************************/
* This function is repeated in `src/localize/src/localize.ts` and the two should be kept in sync.
* (See that file for more explanation of why.)
************************************************************************************************/
for (let cookedIndex = 1, rawIndex = 1; cookedIndex < cooked.length; cookedIndex++, rawIndex++) {
if (raw[rawIndex] === '\\') {
rawIndex++;

View File

@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/
import {BLOCK_MARKER} from './constants';
import {MessageId, ParsedMessage, TargetMessage, parseMessage} from './messages';
import {MessageId, ParsedMessage, parseMessage, TargetMessage} from './messages';
/**
@ -68,8 +68,10 @@ export function translate(
return message.substitutions[placeholder];
} else {
throw new Error(
`There is a placeholder name mismatch with the translation provided for the message ${describeMessage(message)}.\n` +
`The translation contains a placeholder with name ${placeholder}, which does not exist in the message.`);
`There is a placeholder name mismatch with the translation provided for the message ${
describeMessage(message)}.\n` +
`The translation contains a placeholder with name ${
placeholder}, which does not exist in the message.`);
}
})
];

View File

@ -119,12 +119,12 @@ describe('messages utils', () => {
const message = parseMessage(makeTemplateObject(['a', 'b', 'c'], ['a', 'b', 'c']), [1, 2]);
expect(message.substitutions).toEqual({PH: 1, PH_1: 2});
});
});
describe('splitBlock()', () => {
it('should return just the text if there is no block',
() => { expect(splitBlock('abc def', 'abc def')).toEqual({text: 'abc def'}); });
it('should return just the text if there is no block', () => {
expect(splitBlock('abc def', 'abc def')).toEqual({text: 'abc def'});
});
it('should return just the text and block if there is one', () => {
expect(splitBlock(':block info:abc def', ':block info:abc def'))

View File

@ -5,7 +5,7 @@
* 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 {ParsedTranslation, TargetMessage, computeMsgId, makeTemplateObject, parseTranslation, translate} from '..';
import {computeMsgId, makeTemplateObject, ParsedTranslation, parseTranslation, TargetMessage, translate} from '..';
describe('utils', () => {
describe('makeTemplateObject', () => {
@ -80,9 +80,9 @@ describe('utils', () => {
describe('translate', () => {
it('should throw an error if there is no matching translation', () => {
expect(() => doTranslate({}, parts `abc`))
expect(() => doTranslate({}, parts`abc`))
.toThrowError('No translation found for "2674653928643152084" ("abc").');
expect(() => doTranslate({}, parts `:meaning|:abc`))
expect(() => doTranslate({}, parts`:meaning|:abc`))
.toThrowError('No translation found for "1071947593002928768" ("abc" - "meaning").');
});
@ -90,7 +90,7 @@ describe('utils', () => {
() => {
expect(
() => doTranslate(
{'abc{$INTERPOLATION}def': 'a{$PH}bc'}, parts `abc${1 + 2}:INTERPOLATION:def`))
{'abc{$INTERPOLATION}def': 'a{$PH}bc'}, parts`abc${1 + 2}:INTERPOLATION:def`))
.toThrowError(
`There is a placeholder name mismatch with the translation provided for the message "8986527425650846693" ("abc{$INTERPOLATION}def").\n` +
`The translation contains a placeholder with name PH, which does not exist in the message.`);
@ -104,15 +104,15 @@ describe('utils', () => {
'abc{$PH}def{$PH_1}': 'abc{$PH}def{$PH_1}',
'Hello, {$PH}!': 'Hello, {$PH}!',
};
expect(doTranslate(translations, parts `abc`)).toEqual(parts `abc`);
expect(doTranslate(translations, parts `abc${1 + 2 + 3}`)).toEqual(parts `abc${1 + 2 + 3}`);
expect(doTranslate(translations, parts `abc${1 + 2 + 3}def`))
.toEqual(parts `abc${1 + 2 + 3}def`);
expect(doTranslate(translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6}`))
.toEqual(parts `abc${1 + 2 + 3}def${4 + 5 + 6}`);
expect(doTranslate(translations, parts`abc`)).toEqual(parts`abc`);
expect(doTranslate(translations, parts`abc${1 + 2 + 3}`)).toEqual(parts`abc${1 + 2 + 3}`);
expect(doTranslate(translations, parts`abc${1 + 2 + 3}def`))
.toEqual(parts`abc${1 + 2 + 3}def`);
expect(doTranslate(translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6}`))
.toEqual(parts`abc${1 + 2 + 3}def${4 + 5 + 6}`);
const getName = () => 'World';
expect(doTranslate(translations, parts `Hello, ${getName()}!`))
.toEqual(parts `Hello, ${'World'}!`);
expect(doTranslate(translations, parts`Hello, ${getName()}!`))
.toEqual(parts`Hello, ${'World'}!`);
});
it('(with upper-casing translations) should render template literals with messages upper-cased',
@ -124,16 +124,15 @@ describe('utils', () => {
'abc{$PH}def{$PH_1}': 'ABC{$PH}DEF{$PH_1}',
'Hello, {$PH}!': 'HELLO, {$PH}!',
};
expect(doTranslate(translations, parts `abc`)).toEqual(parts `ABC`);
expect(doTranslate(translations, parts `abc${1 + 2 + 3}`))
.toEqual(parts `ABC${1 + 2 + 3}`);
expect(doTranslate(translations, parts `abc${1 + 2 + 3}def`))
.toEqual(parts `ABC${1 + 2 + 3}DEF`);
expect(doTranslate(translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6}`))
.toEqual(parts `ABC${1 + 2 + 3}DEF${4 + 5 + 6}`);
expect(doTranslate(translations, parts`abc`)).toEqual(parts`ABC`);
expect(doTranslate(translations, parts`abc${1 + 2 + 3}`)).toEqual(parts`ABC${1 + 2 + 3}`);
expect(doTranslate(translations, parts`abc${1 + 2 + 3}def`))
.toEqual(parts`ABC${1 + 2 + 3}DEF`);
expect(doTranslate(translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6}`))
.toEqual(parts`ABC${1 + 2 + 3}DEF${4 + 5 + 6}`);
const getName = () => 'World';
expect(doTranslate(translations, parts `Hello, ${getName()}!`))
.toEqual(parts `HELLO, ${'World'}!`);
expect(doTranslate(translations, parts`Hello, ${getName()}!`))
.toEqual(parts`HELLO, ${'World'}!`);
});
it('(with translations to reverse expressions) should render template literals with expressions reversed',
@ -143,8 +142,8 @@ describe('utils', () => {
};
const getName = () => 'World';
expect(doTranslate(
translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`))
.toEqual(parts `abc${'World'}def${4 + 5 + 6} - Hello, ${1 + 2 + 3}!`);
translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`))
.toEqual(parts`abc${'World'}def${4 + 5 + 6} - Hello, ${1 + 2 + 3}!`);
});
it('(with translations to remove expressions) should render template literals with expressions removed',
@ -154,8 +153,8 @@ describe('utils', () => {
};
const getName = () => 'World';
expect(doTranslate(
translations, parts `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`))
.toEqual(parts `abc${1 + 2 + 3} - Hello, ${'World'}!`);
translations, parts`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`))
.toEqual(parts`abc${1 + 2 + 3} - Hello, ${'World'}!`);
});
function parts(messageParts: TemplateStringsArray, ...substitutions: any[]):
@ -167,7 +166,6 @@ describe('utils', () => {
Record<string, ParsedTranslation> {
const parsedTranslations: Record<string, ParsedTranslation> = {};
Object.keys(translations).forEach(key => {
parsedTranslations[computeMsgId(key, '')] = parseTranslation(translations[key]);
});
return parsedTranslations;

View File

@ -9,7 +9,7 @@
import '@angular/localize/init';
import {clearTranslations, loadTranslations} from '../localize';
import {MessageId, TargetMessage, computeMsgId} from '../src/utils';
import {computeMsgId, MessageId, TargetMessage} from '../src/utils';
describe('$localize tag with translations', () => {
describe('identities', () => {
@ -22,15 +22,17 @@ describe('$localize tag with translations', () => {
'Hello, {$PH}!': 'Hello, {$PH}!',
}));
});
afterEach(() => { clearTranslations(); });
afterEach(() => {
clearTranslations();
});
it('should render template literals as-is', () => {
expect($localize `abc`).toEqual('abc');
expect($localize `abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
expect($localize`abc`).toEqual('abc');
expect($localize`abc${1 + 2 + 3}`).toEqual('abc6');
expect($localize`abc${1 + 2 + 3}def`).toEqual('abc6def');
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('abc6def15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('Hello, World!');
expect($localize`Hello, ${getName()}!`).toEqual('Hello, World!');
});
});
@ -44,15 +46,17 @@ describe('$localize tag with translations', () => {
'Hello, {$PH}!': 'HELLO, {$PH}!',
}));
});
afterEach(() => { clearTranslations(); });
afterEach(() => {
clearTranslations();
});
it('should render template literals with messages upper-cased', () => {
expect($localize `abc`).toEqual('ABC');
expect($localize `abc${1 + 2 + 3}`).toEqual('ABC6');
expect($localize `abc${1 + 2 + 3}def`).toEqual('ABC6DEF');
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15');
expect($localize`abc`).toEqual('ABC');
expect($localize`abc${1 + 2 + 3}`).toEqual('ABC6');
expect($localize`abc${1 + 2 + 3}def`).toEqual('ABC6DEF');
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6}`).toEqual('ABC6DEF15');
const getName = () => 'World';
expect($localize `Hello, ${getName()}!`).toEqual('HELLO, World!');
expect($localize`Hello, ${getName()}!`).toEqual('HELLO, World!');
});
});
@ -62,11 +66,13 @@ describe('$localize tag with translations', () => {
'abc{$PH}def{$PH_1} - Hello, {$PH_2}!': 'abc{$PH_2}def{$PH_1} - Hello, {$PH}!',
}));
});
afterEach(() => { clearTranslations(); });
afterEach(() => {
clearTranslations();
});
it('should render template literals with expressions reversed', () => {
const getName = () => 'World';
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
.toEqual('abcWorlddef15 - Hello, 6!');
});
});
@ -77,11 +83,13 @@ describe('$localize tag with translations', () => {
'abc{$PH}def{$PH_1} - Hello, {$PH_2}!': 'abc{$PH} - Hello, {$PH_2}!',
}));
});
afterEach(() => { clearTranslations(); });
afterEach(() => {
clearTranslations();
});
it('should render template literals with expressions removed', () => {
const getName = () => 'World';
expect($localize `abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
expect($localize`abc${1 + 2 + 3}def${4 + 5 + 6} - Hello, ${getName()}!`)
.toEqual('abc6 - Hello, World!');
});
});