webpack-angular-translate
Version:
Webpack plugin that extracts the translation-ids with the default texts.
110 lines (92 loc) • 3.35 kB
text/typescript
import * as path from "path";
import * as escodegen from "escodegen";
import * as acorn from "acorn";
import { CodeWithSourceMap, SourceMapConsumer } from "source-map";
import TranslateLoaderContext from "../translate-loader-context";
import createTranslateVisitor from "./translate-visitor";
import * as loaderUtils from "loader-utils";
/**
* The optional options passed to the plugin
*/
interface LoaderOptions {
/**
* Optional acorn options that are passed to the parser
*/
parserOptions?: acorn.Options;
}
/**
* Webpack loader that extracts translations from calls to the angular-translate $translate service.
* Additionally it provides the `i18n.registerTranslation(translationId, defaultText)` and `i18n.registerTranslations({})`
* functions that can be used to register new translations directly in code.
*
* The loader uses acorn to parse the input file and creates the output javascript using escodegen.
* @param source
* @param inputSourceMaps
*/
async function jsLoader(source: string, inputSourceMaps: any) {
const loader: TranslateLoaderContext = this;
const callback = this.async();
if (!loader.registerTranslation) {
return callback(
new Error(
"The WebpackAngularTranslate plugin is missing. Add the plugin to your webpack configurations 'plugins' section."
),
source,
inputSourceMaps
);
}
if (loader.cacheable) {
loader.cacheable();
}
if (isExcludedResource(loader.resourcePath)) {
return callback(null, source, inputSourceMaps);
}
const { code, sourceMaps } = await extractTranslations(
loader,
source,
inputSourceMaps
);
callback(null, code, sourceMaps);
}
async function extractTranslations(
loader: TranslateLoaderContext,
source: string,
sourceMaps: any
) {
const options: LoaderOptions = loaderUtils.getOptions(loader) || {};
const parserOptions = options.parserOptions || { ecmaVersion: "latest" };
loader.pruneTranslations(path.relative(loader.context, loader.resourcePath));
const visitor = createTranslateVisitor(loader, parserOptions);
const sourceAst = acorn.parse(source, visitor.options);
const transformedAst = visitor.visit(sourceAst);
let code = source;
if (visitor.changedAst) {
const generateSourceMaps = !!(loader.sourceMap || sourceMaps);
const result = escodegen.generate(transformedAst, {
comment: true,
sourceMap: generateSourceMaps ? loader.resourcePath : undefined,
sourceMapWithCode: generateSourceMaps,
sourceContent: generateSourceMaps ? source : undefined,
});
if (generateSourceMaps) {
const codeWithSourceMap = <CodeWithSourceMap>(result as any);
code = codeWithSourceMap.code;
if (sourceMaps) {
// Create a new source maps that is a mapping from original Source -> result from previous loader -> result from this loader
const originalSourceMap = await new SourceMapConsumer(sourceMaps);
codeWithSourceMap.map.applySourceMap(
originalSourceMap,
loader.resourcePath
);
}
sourceMaps = (<any>codeWithSourceMap.map).toJSON();
}
}
return { code, sourceMaps };
}
function isExcludedResource(resource: string): boolean {
return /angular-translate[\/\\]dist[\/\\]angular-translate\.js$/.test(
resource
);
}
export = jsLoader;