UNPKG

@venuu/i18n-js-webpack-plugin

Version:

webpack companion plugin for i18n-js to include only used translations

94 lines (83 loc) 3.04 kB
/* @flow weak */ const Bacon = require("baconjs"); const makeTranslationPlaceholderScanner = require("./placeholder-scanner"); const makeUsedTranslationKeypathScanner = require("./keypath-scanner"); const makeTranslationGraphMinimizer = require("./minimize-translations"); const replacePlaceholders = require("./replace-placeholders"); /*:: type TranslationLeafNode = string | number | boolean | null; type Translation = TranslationLeafNode | Array<TranslationLeafNode> | { [key: string]: Translation }; type Translations = { [locale: string]: { [key: string]: Translation } } type Options = {| functionNames: Array<string>, translationPlaceholderConstantName: string, fullTranslations: Translations |}; type Compiler = Object type Compilation = { plugin: (event: string, listener: Function) => void } */ function I18nRuntimePlugin(opts /*: Options */) { const functionNames = opts.functionNames; const translationPlaceholderConstantName = opts.translationPlaceholderConstantName; const fullTranslations = opts.fullTranslations; // We'll be wanting to hook into the compilation process for // - scanning for a list of keypaths used in calls to `functionNames` // - scanning for instances of `translationPlaceholderConstantName` expressions // - replacing the placeholder expressions with an expression with the required translations const translationPlaceholderScanner = makeTranslationPlaceholderScanner({ translationPlaceholderConstantName }); const usedTranslationKeypathScanner = makeUsedTranslationKeypathScanner({ functionNames }); const pickUsedTranslations = makeTranslationGraphMinimizer({ fullTranslations }); return { // `apply` gets called _once_ to hook itself to the Compiler; it has to take care of // maintaining state between build runs apply(compiler /*: Compiler */) { const translationPlaceholders$ = toNonEmptyList( translationPlaceholderScanner(compiler) ); const usedTranslationKeypaths$ = toNonEmptyList( usedTranslationKeypathScanner(compiler) ); // 'should-emit' runs once after 'make' and allows us to bail out if we detected errors let error = null; compiler.hooks.shouldEmit.tap("foo", () => { if (error) { throw error; } }); Bacon.combineTemplate({ translationPlaceholders: translationPlaceholders$, usedTranslationKeypaths: usedTranslationKeypaths$ }).onValue(({ translationPlaceholders, usedTranslationKeypaths }) => { try { const minimizedTranslations = pickUsedTranslations( usedTranslationKeypaths ); replacePlaceholders({ translationPlaceholders, minimizedTranslations }); } catch (e) { error = e; } }); } }; } module.exports = I18nRuntimePlugin; function toNonEmptyList(stream$) { return stream$ .scan([], (acc, next) => { acc.push(next); return acc; }) .skip(1); }