UNPKG

@mailbutler/i18n-utils

Version:

Manage i18n localization with static analysis

79 lines (78 loc) 3.4 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractI18NReport = extractI18NReport; exports.writeReportToFile = writeReportToFile; const fs_1 = __importDefault(require("fs")); function stripBounding(item) { return { path: item.path, file: item.file, line: item.line }; } function mightBeDynamic(item) { return item.path.includes('${') && !!item.previousCharacter.match(/`/g) && !!item.nextCharacter.match(/`/g); } function dynamicRegex(item) { if (!item.path.match(/[\w\-]\$\{[^}]+\}/)) return new RegExp('^$'); // there must be more to the string then just the interpolated part return new RegExp(item.path.replace(/\$\{[^}]+\}/g, `\\w+`), 'i'); } // Looping through the arays multiple times might not be the most effecient, but it's the easiest to read and debug. Which at this scale is an accepted trade-off. function extractI18NReport(i18nItems, languageFiles) { const missingKeys = []; const unusedKeys = []; const duplicatedKeys = []; const maybeDynamicKeys = i18nItems .filter((item) => mightBeDynamic(item)) .map((item) => stripBounding(item)); const dynamicRegexes = maybeDynamicKeys.filter((item) => !!dynamicRegex(item)).map((item) => dynamicRegex(item)); Object.keys(languageFiles).forEach((language) => { const languageItems = languageFiles[language]; const duplicatedKeysInLanguage = languageItems.reduce((acc, languageItem) => { if (acc.find((item) => item.path === languageItem.path)) return acc; const duplicates = languageItems.filter((item) => item.path === languageItem.path); if (duplicates.length > 1) { acc.push({ path: languageItem.path, files: duplicates.map(({ file }) => file !== null && file !== void 0 ? file : 'unknown'), language }); } return acc; }, []); const missingKeysInLanguage = i18nItems .filter((item) => !mightBeDynamic(item)) .filter((item) => !languageItems.some((languageItem) => item.path === languageItem.path)) .map((item) => ({ ...stripBounding(item), language })); const unusedKeysInLanguage = languageItems .filter((languageItem) => !i18nItems.some((item) => languageItem.path === item.path || languageItem.path.startsWith(item.path + '.')) && !dynamicRegexes.some((regex) => regex.test(languageItem.path))) .map((languageItem) => ({ ...languageItem, language })); missingKeys.push(...missingKeysInLanguage); unusedKeys.push(...unusedKeysInLanguage); duplicatedKeys.push(...duplicatedKeysInLanguage); }); return { missingKeys, unusedKeys, duplicatedKeys, maybeDynamicKeys }; } async function writeReportToFile(report, writePath) { const reportString = JSON.stringify(report); return new Promise((resolve, reject) => { fs_1.default.writeFile(writePath, reportString, (err) => { if (err) { reject(err); return; } resolve(); }); }); }