UNPKG

@mailbutler/i18n-utils

Version:

Manage i18n localization with static analysis

96 lines (95 loc) 3.85 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.readSrcFiles = readSrcFiles; exports.extractI18NItemsFromSrcFiles = extractI18NItemsFromSrcFiles; exports.parseSrcFiles = parseSrcFiles; const is_valid_glob_1 = __importDefault(require("is-valid-glob")); const glob_1 = require("glob"); const fs_1 = __importDefault(require("fs")); function readSrcFiles(src) { if (!(0, is_valid_glob_1.default)(src)) { throw new Error(`srcFiles isn't a valid glob pattern.`); } if (!Array.isArray(src)) { src = [src]; } const targetFiles = src.flatMap((targetFile) => (0, glob_1.globSync)(targetFile)).sort((a, b) => (a > b ? -1 : 1)); if (targetFiles.length === 0) { throw new Error('srcFiles glob has no files.'); } return targetFiles.map((f) => { const fileName = f.replace(process.cwd(), '.'); return { fileName, path: f, content: fs_1.default.readFileSync(f, 'utf8') }; }); } function* getMatches(file, regExp, captureGroup = 1) { while (true) { const match = regExp.exec(file.content); if (match === null) { break; } const path = match[captureGroup]; const pathAtIndex = file.content.indexOf(path); const previousCharacter = file.content.charAt(pathAtIndex - 1); const nextCharacter = file.content.charAt(pathAtIndex + path.length); const line = (file.content.substring(0, match.index).match(/\n/g) || []).length + 1; yield { path, previousCharacter, nextCharacter, file: file.fileName, line }; } } /** * Extracts translation keys from methods such as `$t` and `$tc`. * * - **regexp pattern**: (?:[$\s.:"'`+\(\[\{]t[cm]?)\( * * **description**: Matches the sequence t(, tc( or tm(, optionally with either “$”, SPACE, “.”, “:”, “"”, “'”, * “`”, "+", "(", "[" or "{" in front of it. * * - **regexp pattern**: (["'`]) * * **description**: 1. capturing group. Matches either “"”, “'”, or “`”. * * - **regexp pattern**: ((?:[^\\]|\\.)*?) * * **description**: 2. capturing group. Matches anything except a backslash * *or* matches any backslash followed by any character (e.g. “\"”, “\`”, “\t”, etc.) * * - **regexp pattern**: \1 * * **description**: matches whatever was matched by capturing group 1 (e.g. the starting string character) * * @param file a file object * @returns a list of translation keys found in `file`. */ function extractMethodMatches(file) { const methodRegExp = /(?:[$\s.:"'`+\(\[\{]t[cmt]?)\(\s*?(["'`])((?:[^\\]|\\.)*?)\1/g; return [...getMatches(file, methodRegExp, 2)]; } function extractComponentMatches(file) { const componentRegExp = /(?:<(?:i18n|Translation))(?:.|\n)*?(?:[^:]path=("|'))((?:[^\\]|\\.)*?)\1/gi; return [...getMatches(file, componentRegExp, 2)]; } function extractDirectiveMatches(file) { const directiveRegExp = /v-t="'((?:[^\\]|\\.)*?)'"/g; return [...getMatches(file, directiveRegExp)]; } function extractI18NItemsFromSrcFiles(sourceFiles) { return sourceFiles.reduce((accumulator, file) => { const methodMatches = extractMethodMatches(file); const componentMatches = extractComponentMatches(file); const directiveMatches = extractDirectiveMatches(file); return [...accumulator, ...methodMatches, ...componentMatches, ...directiveMatches]; }, []); } // This is a convenience function for users implementing in their own projects, and isn't used internally function parseSrcFiles(srcFiles) { return extractI18NItemsFromSrcFiles(readSrcFiles(srcFiles)); }