Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions goldens/public-api/angular_devkit/build_angular/src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ export interface BrowserBuilderOptions {
deployUrl?: string;
extractLicenses?: boolean;
fileReplacements?: FileReplacement[];
i18nMissingTranslation?: I18NMissingTranslation;
i18nDuplicateTranslation?: I18NTranslation;
i18nMissingTranslation?: I18NTranslation;
index: IndexUnion;
inlineStyleLanguage?: InlineStyleLanguage;
localize?: Localize;
Expand Down Expand Up @@ -259,7 +260,8 @@ export interface ServerBuilderOptions {
externalDependencies?: string[];
extractLicenses?: boolean;
fileReplacements?: FileReplacement_3[];
i18nMissingTranslation?: I18NMissingTranslation_2;
i18nDuplicateTranslation?: I18NTranslation_2;
i18nMissingTranslation?: I18NTranslation_2;
inlineStyleLanguage?: InlineStyleLanguage_3;
localize?: Localize_2;
main: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@
"enum": ["warning", "error", "ignore"],
"default": "warning"
},
"i18nDuplicateTranslation": {
"type": "string",
"description": "How to handle duplicate translations for i18n.",
"enum": ["warning", "error", "ignore"],
"default": "warning"
},
"localize": {
"description": "Translate the bundles in one or more locales.",
"oneOf": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -366,14 +366,22 @@ async function setupLocalize(
compiler.hooks.thisCompilation.tap('build-angular', (compilation) => {
if (i18n.shouldInline && i18nLoaderOptions.translation === undefined) {
// Reload translations
loadTranslations(locale, localeDescription, context.workspaceRoot, loader, {
warn(message) {
addWarning(compilation, message);
},
error(message) {
addError(compilation, message);
loadTranslations(
locale,
localeDescription,
context.workspaceRoot,
loader,
{
warn(message) {
addWarning(compilation, message);
},
error(message) {
addError(compilation, message);
},
},
});
undefined,
browserOptions.i18nDuplicateTranslation,
);
i18nLoaderOptions.translation = localeDescription.translation;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,12 @@
"enum": ["warning", "error", "ignore"],
"default": "warning"
},
"i18nDuplicateTranslation": {
"type": "string",
"description": "How to handle duplicate translations for i18n.",
"enum": ["warning", "error", "ignore"],
"default": "warning"
},
"localize": {
"description": "Translate the bundles in one or more locales.",
"oneOf": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
Budget,
CrossOrigin,
ExtraEntryPoint,
I18NMissingTranslation,
I18NTranslation,
IndexUnion,
InlineStyleLanguage,
Localize,
Expand All @@ -38,7 +38,7 @@ export interface BuildOptions {
verbose?: boolean;
progress?: boolean;
localize?: Localize;
i18nMissingTranslation?: I18NMissingTranslation;
i18nMissingTranslation?: I18NTranslation;
bundleDependencies?: boolean;
externalDependencies?: string[];
watch?: boolean;
Expand Down
19 changes: 15 additions & 4 deletions packages/angular_devkit/build_angular/src/utils/i18n-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import fs from 'fs';
import module from 'module';
import os from 'os';
import path from 'path';
import { Schema as BrowserBuilderSchema } from '../builders/browser/schema';
import { Schema as BrowserBuilderSchema, I18NTranslation } from '../builders/browser/schema';
import { Schema as ServerBuilderSchema } from '../builders/server/schema';
import { readTsconfig } from '../utils/read-tsconfig';
import { TranslationLoader, createTranslationLoader } from './load-translations';
Expand Down Expand Up @@ -233,6 +233,7 @@ export async function configureI18nBuild<T extends BrowserBuilderSchema | Server
},
},
usedFormats,
buildOptions.i18nDuplicateTranslation,
);

if (usedFormats.size > 1 && tsConfig.options.enableI18nLegacyMessageIdFormat !== false) {
Expand Down Expand Up @@ -282,6 +283,7 @@ export function loadTranslations(
loader: TranslationLoader,
logger: { warn: (message: string) => void; error: (message: string) => void },
usedFormats?: Set<string>,
duplicateTranslation?: I18NTranslation,
) {
for (const file of desc.files) {
const loadResult = loader(path.join(workspaceRoot, file.path));
Expand All @@ -308,9 +310,18 @@ export function loadTranslations(
// Merge translations
for (const [id, message] of Object.entries(loadResult.translations)) {
if (desc.translation[id] !== undefined) {
logger.warn(
`WARNING [${file.path}]: Duplicate translations for message '${id}' when merging`,
);
const duplicateTranslationMessage = `[${file.path}]: Duplicate translations for message '${id}' when merging.`;
switch (duplicateTranslation) {
case I18NTranslation.Ignore:
break;
case I18NTranslation.Error:
logger.error(`ERROR ${duplicateTranslationMessage}`);
break;
case I18NTranslation.Warning:
default:
logger.warn(`WARNING ${duplicateTranslationMessage}`);
break;
}
}
desc.translation[id] = message;
}
Expand Down
23 changes: 17 additions & 6 deletions tests/legacy-cli/e2e/tests/i18n/ivy-localize-merging.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,20 @@

import { ng } from '../../utils/process';
import { updateJsonFile } from '../../utils/project';
import { expectToFail } from '../../utils/utils';
import { setupI18nConfig } from './setup';

export default async function() {
export default async function () {
// Setup i18n tests and config.
await setupI18nConfig();

// Update angular.json
await updateJsonFile('angular.json', workspaceJson => {
await updateJsonFile('angular.json', (workspaceJson) => {
const appProject = workspaceJson.projects['test-project'];
// tslint:disable-next-line: no-any
const i18n: Record<string, any> = appProject.i18n;

i18n.locales['fr'] = [
i18n.locales['fr'],
i18n.locales['fr'],
]
i18n.locales['fr'] = [i18n.locales['fr'], i18n.locales['fr']];
appProject.architect['build'].options.localize = ['fr'];
});

Expand All @@ -32,5 +30,18 @@ export default async function() {
throw new Error('duplicate translations warning not shown');
}

await updateJsonFile('angular.json', (workspaceJson) => {
const appProject = workspaceJson.projects['test-project'];
appProject.architect['build'].options.i18nDuplicateTranslation = 'error';
});
await expectToFail(() => ng('build'));

await updateJsonFile('angular.json', (workspaceJson) => {
const appProject = workspaceJson.projects['test-project'];
appProject.architect['build'].options.i18nDuplicateTranslation = 'ignore';
});
const { stderr: err2 } = await ng('build');
if (err2.includes('Duplicate translations for message')) {
throw new Error('duplicate translations message not ignore');
}
}