mirror of
https://github.com/angular/angular-cli.git
synced 2025-05-23 23:59:27 +08:00
feat(@schematics/angular): add migration to add new i18n options for Ivy
This migration will update current projects by adding the `i18n` project level option and add `localize` option in the server and browser builder configurations when both `i18nLocale` and `i18nFile` are defined.
This commit is contained in:
parent
7045a781ea
commit
750baf92d6
@ -15,7 +15,7 @@ import {
|
|||||||
removePropertyInAstObject,
|
removePropertyInAstObject,
|
||||||
} from '../../utility/json-utils';
|
} from '../../utility/json-utils';
|
||||||
import { Builders } from '../../utility/workspace-models';
|
import { Builders } from '../../utility/workspace-models';
|
||||||
import { getAllOptions, getTargets, getWorkspace, isIvyEnabled } from './utils';
|
import { getAllOptions, getProjectTarget, getTargets, getWorkspace, isIvyEnabled } from './utils';
|
||||||
|
|
||||||
export const ANY_COMPONENT_STYLE_BUDGET = {
|
export const ANY_COMPONENT_STYLE_BUDGET = {
|
||||||
type: 'anyComponentStyle',
|
type: 'anyComponentStyle',
|
||||||
@ -33,6 +33,7 @@ export function updateWorkspaceConfig(): Rule {
|
|||||||
updateStyleOrScriptOption('scripts', recorder, target);
|
updateStyleOrScriptOption('scripts', recorder, target);
|
||||||
addAnyComponentStyleBudget(recorder, target);
|
addAnyComponentStyleBudget(recorder, target);
|
||||||
updateAotOption(tree, recorder, target);
|
updateAotOption(tree, recorder, target);
|
||||||
|
addBuilderI18NOptions(recorder, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const { target } of getTargets(workspace, 'test', Builders.Karma)) {
|
for (const { target } of getTargets(workspace, 'test', Builders.Karma)) {
|
||||||
@ -42,6 +43,11 @@ export function updateWorkspaceConfig(): Rule {
|
|||||||
|
|
||||||
for (const { target } of getTargets(workspace, 'server', Builders.Server)) {
|
for (const { target } of getTargets(workspace, 'server', Builders.Server)) {
|
||||||
updateOptimizationOption(recorder, target);
|
updateOptimizationOption(recorder, target);
|
||||||
|
addBuilderI18NOptions(recorder, target);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const { target, project } of getTargets(workspace, 'extract-i18n', Builders.ExtractI18n)) {
|
||||||
|
addProjectI18NOptions(recorder, target, project);
|
||||||
}
|
}
|
||||||
|
|
||||||
tree.commitUpdate(recorder);
|
tree.commitUpdate(recorder);
|
||||||
@ -50,6 +56,72 @@ export function updateWorkspaceConfig(): Rule {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addProjectI18NOptions(recorder: UpdateRecorder, builderConfig: JsonAstObject, projectConfig: JsonAstObject) {
|
||||||
|
const browserConfig = getProjectTarget(projectConfig, 'build', Builders.Browser);
|
||||||
|
if (!browserConfig || browserConfig.kind !== 'object') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// browser builder options
|
||||||
|
let locales: Record<string, string> | undefined;
|
||||||
|
const options = getAllOptions(browserConfig);
|
||||||
|
for (const option of options) {
|
||||||
|
const localeId = findPropertyInAstObject(option, 'i18nLocale');
|
||||||
|
if (!localeId || localeId.kind !== 'string') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localeFile = findPropertyInAstObject(option, 'i18nFile');
|
||||||
|
if (!localeFile || localeFile.kind !== 'string') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const localIdValue = localeId.value;
|
||||||
|
const localeFileValue = localeFile.value;
|
||||||
|
|
||||||
|
if (!locales) {
|
||||||
|
locales = {
|
||||||
|
[localIdValue]: localeFileValue,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
locales[localIdValue] = localeFileValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locales) {
|
||||||
|
// Get sourceLocale from extract-i18n builder
|
||||||
|
const i18nOptions = getAllOptions(builderConfig);
|
||||||
|
const sourceLocale = i18nOptions
|
||||||
|
.map(o => {
|
||||||
|
const sourceLocale = findPropertyInAstObject(o, 'i18nLocale');
|
||||||
|
|
||||||
|
return sourceLocale && sourceLocale.value;
|
||||||
|
})
|
||||||
|
.find(x => !!x);
|
||||||
|
|
||||||
|
// Add i18n project configuration
|
||||||
|
insertPropertyInAstObjectInOrder(recorder, projectConfig, 'i18n', {
|
||||||
|
locales,
|
||||||
|
// tslint:disable-next-line: no-any
|
||||||
|
sourceLocale: sourceLocale as any,
|
||||||
|
}, 6);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addBuilderI18NOptions(recorder: UpdateRecorder, builderConfig: JsonAstObject) {
|
||||||
|
const options = getAllOptions(builderConfig);
|
||||||
|
|
||||||
|
for (const option of options) {
|
||||||
|
const localeId = findPropertyInAstObject(option, 'i18nLocale');
|
||||||
|
if (!localeId || localeId.kind !== 'string') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add new localize option
|
||||||
|
insertPropertyInAstObjectInOrder(recorder, option, 'localize', [localeId.value], 12);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function updateAotOption(tree: Tree, recorder: UpdateRecorder, builderConfig: JsonAstObject) {
|
function updateAotOption(tree: Tree, recorder: UpdateRecorder, builderConfig: JsonAstObject) {
|
||||||
const options = findPropertyInAstObject(builderConfig, 'options');
|
const options = findPropertyInAstObject(builderConfig, 'options');
|
||||||
if (!options || options.kind !== 'object') {
|
if (!options || options.kind !== 'object') {
|
||||||
|
@ -296,5 +296,76 @@ describe('Migration to version 9', () => {
|
|||||||
expect(config.production.optimization).toBe(true);
|
expect(config.production.optimization).toBe(true);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('i18n configuration', () => {
|
||||||
|
function getI18NConfig(localId: string): object {
|
||||||
|
return {
|
||||||
|
outputPath: `dist/my-project-${localId}/`,
|
||||||
|
i18nFile: `src/locale/messages.${localId}.xlf`,
|
||||||
|
i18nFormat: 'xlf',
|
||||||
|
i18nLocale: localId,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('when i18n builder options are set', () => {
|
||||||
|
it(`should add 'localize' option in configuration`, async () => {
|
||||||
|
let config = getWorkspaceTargets(tree);
|
||||||
|
config.build.options.aot = false;
|
||||||
|
config.build.options = getI18NConfig('fr');
|
||||||
|
config.build.configurations.de = getI18NConfig('de');
|
||||||
|
updateWorkspaceTargets(tree, config);
|
||||||
|
|
||||||
|
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||||
|
config = getWorkspaceTargets(tree2).build;
|
||||||
|
expect(config.options.localize).toEqual(['fr']);
|
||||||
|
expect(config.configurations.de.localize).toEqual(['de']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should add i18n 'sourceLocale' project config when 'extract-i18n' 'i18nLocale' is defined`, async () => {
|
||||||
|
const config = getWorkspaceTargets(tree);
|
||||||
|
config.build.options.aot = false;
|
||||||
|
config.build.options = getI18NConfig('fr');
|
||||||
|
config['extract-i18n'].options.i18nLocale = 'en-GB';
|
||||||
|
config.build.configurations.de = getI18NConfig('de');
|
||||||
|
updateWorkspaceTargets(tree, config);
|
||||||
|
|
||||||
|
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||||
|
const projectConfig = JSON.parse(tree2.readContent(workspacePath)).projects['migration-test'];
|
||||||
|
expect(projectConfig.i18n.sourceLocale).toBe('en-GB');
|
||||||
|
expect(projectConfig.i18n.locales).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should add i18n 'locales' project config`, async () => {
|
||||||
|
const config = getWorkspaceTargets(tree);
|
||||||
|
config.build.options.aot = false;
|
||||||
|
config.build.options = getI18NConfig('fr');
|
||||||
|
config.build.configurations.de = getI18NConfig('de');
|
||||||
|
updateWorkspaceTargets(tree, config);
|
||||||
|
|
||||||
|
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||||
|
const projectConfig = JSON.parse(tree2.readContent(workspacePath)).projects['migration-test'];
|
||||||
|
expect(projectConfig.i18n.sourceLocale).toBeUndefined();
|
||||||
|
expect(projectConfig.i18n.locales).toEqual({
|
||||||
|
de: 'src/locale/messages.de.xlf',
|
||||||
|
fr: 'src/locale/messages.fr.xlf',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when i18n builder options are not set', () => {
|
||||||
|
it(`should not add 'localize' option`, async () => {
|
||||||
|
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||||
|
const config = getWorkspaceTargets(tree2).build;
|
||||||
|
expect(config.options.localize).toBeUndefined();
|
||||||
|
expect(config.configurations.production.localize).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not add i18n project config', async () => {
|
||||||
|
const tree2 = await schematicRunner.runSchematicAsync('migration-09', {}, tree.branch()).toPromise();
|
||||||
|
const projectConfig = JSON.parse(tree2.readContent(workspacePath)).projects['migration-test'];
|
||||||
|
expect(projectConfig.i18n).toBeUndefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -12,7 +12,36 @@ import { getWorkspacePath } from '../../utility/config';
|
|||||||
import { findPropertyInAstObject } from '../../utility/json-utils';
|
import { findPropertyInAstObject } from '../../utility/json-utils';
|
||||||
import { Builders, WorkspaceTargets } from '../../utility/workspace-models';
|
import { Builders, WorkspaceTargets } from '../../utility/workspace-models';
|
||||||
|
|
||||||
/** Get all workspace targets which builder and target names matches the provided. */
|
/** Get a project target which builder and target names matches the provided. */
|
||||||
|
export function getProjectTarget(
|
||||||
|
project: JsonAstObject,
|
||||||
|
targetName: Exclude<keyof WorkspaceTargets, number>,
|
||||||
|
builderName: Builders,
|
||||||
|
): JsonAstObject | undefined {
|
||||||
|
const projectRoot = findPropertyInAstObject(project, 'root');
|
||||||
|
if (!projectRoot || projectRoot.kind !== 'string') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const architect = findPropertyInAstObject(project, 'architect');
|
||||||
|
if (!architect || architect.kind !== 'object') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const target = findPropertyInAstObject(architect, targetName);
|
||||||
|
if (!target || target.kind !== 'object') {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const builder = findPropertyInAstObject(target, 'builder');
|
||||||
|
// Projects who's build builder is @angular-devkit/build-ng-packagr
|
||||||
|
if (builder && builder.kind === 'string' && builder.value === builderName) {
|
||||||
|
return target;
|
||||||
|
}
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
export function getTargets(
|
export function getTargets(
|
||||||
workspace: JsonAstObject,
|
workspace: JsonAstObject,
|
||||||
targetName: Exclude<keyof WorkspaceTargets, number>,
|
targetName: Exclude<keyof WorkspaceTargets, number>,
|
||||||
@ -30,24 +59,8 @@ export function getTargets(
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const projectRoot = findPropertyInAstObject(projectConfig, 'root');
|
const target = getProjectTarget(projectConfig, targetName, builderName);
|
||||||
if (!projectRoot || projectRoot.kind !== 'string') {
|
if (target) {
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const architect = findPropertyInAstObject(projectConfig, 'architect');
|
|
||||||
if (!architect || architect.kind !== 'object') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const target = findPropertyInAstObject(architect, targetName);
|
|
||||||
if (!target || target.kind !== 'object') {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const builder = findPropertyInAstObject(target, 'builder');
|
|
||||||
// Projects who's build builder is @angular-devkit/build-ng-packagr
|
|
||||||
if (builder && builder.kind === 'string' && builder.value === builderName) {
|
|
||||||
targets.push({ target, project: projectConfig });
|
targets.push({ target, project: projectConfig });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user