import {
ExecutorContext,
ProjectConfiguration,
ProjectGraph,
joinPathFragments,
parseTargetString
} from '@nx/devkit';
import { execSync } from 'child_process';
import { normalizeExecutorOptions } from '../shared/normalize-executor-options';
import { ExtractI18nExecutorSchema } from './schema';
const DEFAULT_TRANSLATION_FILE_FORMAT = 'xlf';
interface SourceLocaleConfiguration {
code: string;
baseHref: string;
}
export default async function runI18nExtractExecutor(
options: ExtractI18nExecutorSchema,
context: ExecutorContext
) {
try {
if (!context.projectName) {
return {
success: false,
error: `'projectName' property is missing from Executor context.`
};
}
const buildTarget = options.buildTarget;
if (!buildTarget) {
return {
success: false,
error: `'buildTarget' property is missing from Executor options.`
};
}
const parsedBuildTarget = parseTargetString(buildTarget, context.projectGraph as ProjectGraph);
const buildOutputPath: string | undefined =
context.workspace?.projects[context.projectName].targets?.[parsedBuildTarget.target].options
.outputPath;
if (!buildOutputPath) {
throw new Error(
`The "outputPath" option is missing from the "${parsedBuildTarget.target}" target. Please configure it and rerun the executor.`
);
}
execSync(
`npx nx run ${buildTarget} --configuration=production --localize=false --optimization`,
{
stdio: 'inherit'
}
);
const outputFileName = options.outFile ?? getI18nOutputFileName(options.format);
const outputPath = joinPathFragments(options.outputPath ?? '', outputFileName);
const sourceLocaleConfig: SourceLocaleConfiguration | undefined = (
context.workspace?.projects[context.projectName] as ProjectConfiguration & {
i18n: Record<string, SourceLocaleConfiguration>;
}
)?.i18n?.['sourceLocale'];
const normalizedOptions = normalizeExecutorOptions({
source: joinPathFragments(buildOutputPath, '**/*.js'),
format: options.format ?? DEFAULT_TRANSLATION_FILE_FORMAT,
outputPath: outputPath,
locale: getSourceLocaleCode(sourceLocaleConfig)
});
execSync(`npx localize-extract ${normalizedOptions.join(' ')}`, {
stdio: 'inherit'
});
return { success: true };
} catch (error) {
console.error(`Error during the localization extraction: ${(error as Error).message}`);
return { success: false };
}
}
/**
* Cherry picked from angular-cli
* via https://github.com/angular/angular-cli/blob/956e7ea1f53f8e705e7e6a9fa141742f06e907a7/packages/angular_devkit/build_angular/src/builders/extract-i18n/index.ts#L31
*/
function getI18nOutputFileName(format = DEFAULT_TRANSLATION_FILE_FORMAT) {
switch (format) {
case 'xmb':
return 'messages.xmb';
case 'xlf':
case 'xlif':
case 'xliff':
case 'xlf2':
case 'xliff2':
return 'messages.xlf';
case 'json':
case 'legacy-migrate':
return 'messages.json';
case 'arb':
return 'messages.arb';
default:
throw new Error(`Unsupported format "${format}"`);
}
}
function getSourceLocaleCode(sourceLocaleConfig: SourceLocaleConfiguration | undefined) {
if (typeof sourceLocaleConfig === 'object') {
return sourceLocaleConfig.code;
}
return sourceLocaleConfig;
}