Skip to content

Instantly share code, notes, and snippets.

@timofei-iatsenko
Last active December 2, 2019 09:53
Show Gist options
  • Save timofei-iatsenko/e122abbafaaf2191b84cbc8a7ca8a9a8 to your computer and use it in GitHub Desktop.
Save timofei-iatsenko/e122abbafaaf2191b84cbc8a7ca8a9a8 to your computer and use it in GitHub Desktop.
const webpack = require('webpack');
const os = require('os');
const rimraf = require('rimraf');
const helpers = require('../helpers');
const gutil = require('gulp-util');
const argv = require('process').argv;
const fs = require('fs');
const path = require('path');
const {statsToString, statsErrorsToString, statsWarningsToString} = require('../stats');
const {getEmittedFiles} = require('@angular-devkit/build-webpack/src/utils');
const {createTranslationLoader} = require('@angular-devkit/build-angular/src/utils/load-translations');
const {i18nInlineEmittedFiles} = require('@angular-devkit/build-angular/src/utils/i18n-inlining');
// Run this function to start build. It might be a gulp task or just standalone script to execute.
function bundle(config) {
return new Promise((resolve) => {
// If inlining, store the output in a temporary location to facilitate post-processing
const tempPath = fs.mkdtempSync(path.join(fs.realpathSync(os.tmpdir()), 'angular-cli-i18n-'));
const origingalOutputPath = config.output.path;
config.output.path = tempPath;
// Remove temporary directory used for i18n processing
process.on('exit', () => {
try {
rimraf.sync(tempPath);
} catch (e) {}
});
// run Webpack with passed config
webpack(config, async (err, stats) => {
if (err) {
throw err; // hard error
}
// you may skip these lines until createI18nInlinedBundles function,
// they are not important and need just to run webpack without webpack-cli
const colors = gutil.colors.supportsColor;
const json = stats.toJson(config.stats);
console.info(statsToString(json, colors));
if (stats.hasWarnings()) {
console.warn(statsWarningsToString(json, colors));
}
if (stats.hasErrors()) {
console.error(statsErrorsToString(json, colors));
}
// Create inlined bundles
await createI18nInlinedBundles(stats, tempPath, origingalOutputPath);
resolve();
});
});
}
async function createI18nInlinedBundles(stats, tempPath, outputPath) {
// Create appropriate structure of data using provided by angular-devkit functions
const emittedFiles = getEmittedFiles(stats.compilation);
const context = {
logger: console,
};
// Create a configuration
const i18n = {
inlineLocales: new Set(['ru', 'de']),
sourceLocale: 'en-US',
locales: {
ru: {
file: './src/translates/messages.ru.xlf',
},
de: {
file: './src/translates/messages.de.xlf',
},
},
shouldInline: true,
flatOutput: true,
};
const loader = await createTranslationLoader();
for (const [locale, desc] of Object.entries(i18n.locales)) {
if (i18n.inlineLocales.has(locale) && desc.file) {
// helpers.path.root() returns absolute path to project
const result = loader(path.join(helpers.path.root(), desc.file));
for (const diagnostics of result.diagnostics.messages) {
if (diagnostics.type === 'error') {
throw new Error(
`Error parsing translation file '${desc.file}': ${diagnostics.message}`,
);
} else {
context.logger.warn(`WARNING [${desc.file}]: ${diagnostics.message}`);
}
}
desc.format = result.format;
desc.translation = result.translation;
desc.integrity = result.integrity;
desc.dataPath = path.join(findLocaleDataBasePath(helpers.path.root()), locale + '.js');
}
}
// During this step following function spawn workers
// for each language and each file and replace all plachelders to translations
// It takes bundles from `tempPath` and copying them to the `outputPath`.
const success = await i18nInlineEmittedFiles(
context,
emittedFiles,
i18n,
outputPath,
[outputPath],
[],
tempPath, // temp path generated for i18n
true,
'warning',
);
// Probable here you might want to throw non-zero result if error happened to stop all your pipeline
console.log(success);
}
// function copied and simplified from @angular-devkit
function findLocaleDataBasePath(projectRoot) {
try {
const commonPath = path.dirname(
require.resolve('@angular/common/package.json', {paths: [projectRoot]}),
);
const localesPath = path.join(commonPath, 'locales/global');
if (!fs.existsSync(localesPath)) {
return null;
}
return localesPath;
} catch (e) {
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment