Building a Node CLI Tool for Frontend Internationalization Validation in Large Vue Projects
This article explains how to create a Node‑based CLI utility that automatically scans Vue and JavaScript files in a large front‑end codebase, extracts i18n calls via AST parsing, validates translation keys, and outputs consolidated results to improve internationalization efficiency and accuracy.
When large front‑end projects undergo internationalization, developers often face massive workload, numerous interference items, and a high risk of missing translations; the article proposes an automated solution using a Node CLI tool to address these challenges.
The background section describes the WMS6.0 front‑end system built with Vue, the need for i18n, and the three main difficulties: extensive work volume, many interfering elements such as Chinese comments and non‑i18n files, and easy omission during manual checks.
Node CLI was chosen because it is written in JavaScript, enjoys strong third‑party support for parsing Vue and JS files, works cross‑platform on Windows and macOS, and is independent of any specific IDE.
The implementation is divided into four steps: (1) define search rules to locate Vue and JS files, supporting ignore patterns; (2) read file contents and convert JS files to JS‑AST using @babel/parser and Vue single‑file components to Template‑AST using @vue/compiler-sfc ; (3) traverse the ASTs to find i18n method calls, extract keys, resolve languages, and record validation results; (4) merge per‑file results and write them to a JSON file.
Core code examples include the parsing module, validation logic, and file traversal:
// parse.ts
import { parse as vueParser } from "@vue/compiler-sfc";
import { parse as babelParser } from "@babel/parser";
export function parseVue(code: string) {
return vueParser(code).descriptor;
}
export function parseJS(code: string) {
return babelParser(code, {
sourceType: "module",
plugins: ["jsx"],
});
} valid() {
if (!Object.values(FileType).includes(this.fileType)) {
logError(`Unsupported file type: ${this.filename}`);
return;
}
if (this.hasI18NCall(this.sourceCode)) {
if (this.fileType === FileType.JS) {
this.collectRecordFromJs(this.sourceCode);
} else if (this.fileType === FileType.VUE) {
const descriptor = parseVue(this.sourceCode);
if (descriptor?.template?.content && this.hasI18NCall(descriptor?.template?.content)) {
this.collectRecordFromTemplate(descriptor?.template.ast);
}
if (descriptor?.script?.content && this.hasI18NCall(descriptor?.script?.content)) {
this.collectRecordFromJs(descriptor.script.content);
}
}
}
} glob.sync(options.pattern!, { ignore: options.ignore })
.forEach((filename) => {
const filePath = path.resolve(process.cwd(), filename);
logInfo(`detecting file: ${filePath}`);
const sourceCode = fs.readFileSync(filePath, "utf8");
try {
const { records } = new Validator({ code: sourceCode, filename, getLangCheck: options.getLangCheck });
if (options.onlyCollectError) {
const errorRecords = records.filter(item => !item.valid);
if (errorRecords.length > 0) {
locales[filePath] = errorRecords;
}
} else {
locales[filePath] = records;
}
} catch (err) {
console.log(err);
}
});Running the tool on the WMS6.0 project reduced internationalization effort by about 35%, improved validation accuracy, and enabled continuous usage across other front‑end modules, with plans to extend support to TypeScript, TSX, and JSX files in the future.
JD Tech
Official JD technology sharing platform. All the cutting‑edge JD tech, innovative insights, and open‑source solutions you’re looking for, all in one place.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.