vue-i18n-customized-extractor
Version:
A CLI tool to extract text and i18n keys from Vue.js files.
228 lines (190 loc) • 11.2 kB
JavaScript
#!/usr/bin/env node
// NOTES: The above line should be at the top of /bin/cli.js. It means: This is a Node.js script — please run it with Node.
const extractorHelper = require('../extractorHelper.js');
const splitHelper = require('../splitHelper.js');
const replaceHelper = require('../replaceHelper.js');
const astReplaceHelper = require('../astReplaceHelper.js');
const updateTranslationMappingHelper = require('../updateTranslationMappingHelper.js');
// Read targetDir from CLI args
const args = process.argv.slice(2);
const targetDir = args.findIndex(arg => arg.startsWith('--path='));
const excludeFiles = args.findIndex(arg => arg.startsWith('--exclude='))
const templateOnly = args.includes('--template-only');
// for extractor mode
const runExtractor = args.includes('--run-extractor');
const includeT = args.includes('--include-t');
const pageKeys = args.findIndex(arg => arg.startsWith('--keys=')); // also for runASTReplace mode
const configFilePath = args.findIndex(arg => arg.startsWith('--config='));
// for runSplit mode
const runSplit = args.includes('--run-split');
// for runReplace mode and runASTReplace mode
const runReplace = args.includes('--run-replace');
const runASTReplace = args.includes('--run-ast-replace');
const translationPageKey = args.findIndex(arg => arg.startsWith('--translation-page-key='));
const translationMappingPath = args.findIndex(arg => arg.startsWith('--translation-mapping-path='));
const isTranslationAsWholePointer = args.includes('--is-translation-as-whole-pointer');
// For runReplace Mode Only
const greedy = args.includes('--greedy');
// For runASTReplace Mode Only
const vueScriptMode = args.findIndex(arg => arg.startsWith('--vue-script-mode='));
// For deduplicateKey Mode Only
const runDeduplicateKey = args.includes('--run-deduplicate-key');
// For mergeKey Mode Only
const runMergeKey = args.includes('--run-merge-key');
// For deduplicateKey mode and mergeKey mode
const targetFilePath = args.findIndex(arg => arg.startsWith('--target-file-path='));
const sourceFilePath = args.findIndex(arg => arg.startsWith('--source-file-path='));
if (args.includes('--help')) {
console.log(`
vue-i18n-customized-extractor
A CLI tool to extract, split, replace, deduplicate, and merge i18n keys and text in Vue.js projects.
USAGE:
vue-i18n-customized-extractor [options]
OPTIONS:
General
--path=<target> Target file or folder to analyze. Defaults to ./src.
Extraction Mode (--run-extractor)
--run-extractor Extract i18n keys and text from source files.
--exclude=<files> Comma-separated files/folders to exclude.
--config=<path> Path to custom config file (.cjs). Defaults to vue-i18n-customized-extractor.config.cjs.
--keys=<key1,key2,...> Extract keys for specific components/pages.
--include-t Include $t() calls in extraction.
--template-only Only extract from template sections.
Split Mode (--run-split)
--run-split Split JSON translation files for translate-as-whole-pointer elements.
When using --run-split, explicitly target all input translation files to ensure consistent processing and alignment.
Replace Mode (--run-replace)
--run-replace Replace extracted text/keys with $t()/t() calls using a translation mapping.
--translation-mapping-path=<path> Path to translation mapping JSON file.
--translation-page-key=<key> Top-level page key for generated $t()/t() calls.
--is-translation-as-whole-pointer Use split mapping for translate-as-whole-pointer elements.
--greedy Use greedy matching when replacing keys.
--exclude=<files> Comma-separated files/folders to exclude.
--template-only Only replace in template sections.
AST Replace Mode (--run-ast-replace) [Recommended]
--run-ast-replace Use AST-based replacement for higher accuracy, following extraction logic and custom mappings.
--translation-mapping-path=<path> Path to translation mapping JSON file.
--translation-page-key=<key> Top-level page key for generated $t()/t() calls.
--is-translation-as-whole-pointer Use split mapping for translate-as-whole-pointer elements.
--exclude=<files> Comma-separated files/folders to exclude.
--template-only Only replace in template sections.
--config=<path> Path to custom config file (.cjs).
--keys=<key1,key2,...> Extract keys for specific components/pages.
Deduplicate Mode (--run-deduplicate-key)
--run-deduplicate-key Remove keys from target file(s) that already exist in the source file(s).
--target-file-path=<path> Path to the target JSON file or folder.
--source-file-path=<path> Path to the source JSON file or folder.
Merge Mode (--run-merge-key)
--run-merge-key Merge keys from target file(s) into source file(s), adding only new keys.
--target-file-path=<path> Path to the target JSON file or folder.
--source-file-path=<path> Path to the source JSON file or folder.
Help
--help Show help and usage instructions.
EXAMPLES:
Deduplicate keys in target file/folder based on source file/folder:
vue-i18n-customized-extractor --run-deduplicate-key --target-file-path=src/locales/en.json --source-file-path=src/locales/base.json
Merge keys from target file/folder into source file/folder:
vue-i18n-customized-extractor --run-merge-key --target-file-path=src/locales/new.json --source-file-path=src/locales/en.json
Extract i18n keys from the src directory:
vue-i18n-customized-extractor --path=./src
Extract i18n keys and include $t() calls:
vue-i18n-customized-extractor --path=./src --include-t
Split translation files for whole pointer elements:
vue-i18n-customized-extractor --run-split --path=./src/locales
Replace extracted text with $t() calls using mapping:
vue-i18n-customized-extractor --run-replace --translation-mapping-path=src/locales/en.json --path=./src
Use AST-based replacement for higher accuracy:
vue-i18n-customized-extractor --run-ast-replace --translation-mapping-path=src/locales/en.json --path=./src --translation-page-key=TestPage --keys=TestPage
For more details and advanced usage, see the README or visit the project repository.
`);
process.exit(0);
}
if (runSplit) {
console.log("1");
if(targetDir !== -1){
console.log('Running in split mode... Help to split and reorganize the json files of translate-as-whole-pointer');
splitHelper.runSplit(
args[targetDir].split('=')[1]
);
}else{
console.log("No target directory specified for split mode. Please use --path=<directory> to specify the target directory or file.");
process.exit(0);
}
}else if (runReplace) {
if(targetDir !== -1 && translationMappingPath !== -1){
console.log('Running in replace mode... Help to replace extracted keys with $t() calls');
replaceHelper.replaceExtractedKeysInFilesWithTCall(
args[targetDir].split('=')[1],
args[translationMappingPath].split('=')[1],
{
excludeFiles: excludeFiles !== -1 ? args[excludeFiles].split('=')[1].split(',') : [],
translationPageKey: translationPageKey!==-1 ? args[translationPageKey].split('=')[1] : null,
isTranslationAsWholePointer,
templateOnly,
greedy,
}
);
}else{
console.log("No target directory or target translation mapping path specified for replace mode. Please use --path=<directory> to specify the target directory or file, and --translation-mapping-path=<path> to specify the translation mapping path.");
process.exit(0);
}
}else if (runASTReplace) {
if(targetDir !== -1 && translationMappingPath !== -1){
console.log('Running in AST replace mode... Help to replace extracted keys with $t() calls');
astReplaceHelper.replace(
args[targetDir].split('=')[1],
args[translationMappingPath].split('=')[1],
{
excludeFiles: excludeFiles !== -1 ? args[excludeFiles].split('=')[1].split(',') : [],
translationPageKey: translationPageKey!==-1 ? args[translationPageKey].split('=')[1] : null,
configFilePath: configFilePath !== -1 ? args[configFilePath].split('=')[1] : 'vue-i18n-customized-extractor.config.cjs',
pageKeys: pageKeys !== -1 ? args[pageKeys].split('=')[1].split(',') : [],
isTranslationAsWholePointer,
templateOnly,
vueScriptMode: vueScriptMode !== -1 ? args[vueScriptMode].split('=')[1] : "Options",
}
);
}else{
console.log("No target directory or target translation mapping path specified for replace mode. Please use --path=<directory> to specify the target directory or file, and --translation-mapping-path=<path> to specify the translation mapping path.");
process.exit(0);
}
}else if (runExtractor) {
console.log(`Extracting from: ${targetDir}`);
console.log(`Include $t()? ${includeT}`);
console.log(`Extracting from: ${process.cwd()}`);
extractorHelper.run(
targetDir !== -1 ? args[targetDir].split('=')[1] : './src',
{
includeT,
excludeFiles: excludeFiles !== -1 ? args[excludeFiles].split('=')[1].split(',') : [],
pageKeys: pageKeys !== -1 ? args[pageKeys].split('=')[1].split(',') : [],
configFilePath: configFilePath !== -1 ? args[configFilePath].split('=')[1] : 'vue-i18n-customized-extractor.config.cjs',
templateOnly,
}
);
} else if (runDeduplicateKey) {
if (targetFilePath !== -1 && sourceFilePath !== -1) {
console.log('Running in deduplicate key mode... Help to deduplicate keys in target files based on source files');
updateTranslationMappingHelper.deduplicateKeys(
args[targetFilePath].split('=')[1],
args[sourceFilePath].split('=')[1]
);
} else {
console.log("No target file path or source file path specified for deduplicate key mode. Please use --target-file-path=<path> and --source-file-path=<path> to specify the target and source file paths.");
process.exit(0);
}
} else if (runMergeKey) {
if (targetFilePath !== -1 && sourceFilePath !== -1) {
console.log('Running in merge key mode... Help to merge target file into source file');
updateTranslationMappingHelper.merge(
args[targetFilePath].split('=')[1],
args[sourceFilePath].split('=')[1]
);
} else {
console.log("No target file path or source file path specified for merge key mode. Please use --target-file-path=<path> and --source-file-path=<path> to specify the target and source file paths.");
process.exit(0);
}
} else {
console.log("⚠️ No valid mode specified. Please use --run-extractor, --run-split, or --run-replace.");
process.exit(0);
}