中文文档 | English
A modern, TypeScript-first internationalization scanner and translation management toolkit for JavaScript/TypeScript projects.
- Smart Text Extraction - Automatically scan and extract translatable text from your codebase
- Missing Translation Detection - Identify untranslated content across multiple languages
- CSV Export/Import - Seamless translation workflow with CSV file support
- Custom Pattern Support - Works with custom functions like
$LS()
,t()
,$t()
, etc. - Framework Agnostic - Supports React, Vue, Angular, and vanilla JavaScript/TypeScript
- Zero Dependencies - Lightweight, single-file distribution
- TypeScript First - Full TypeScript support with comprehensive type definitions
npm install --save-dev i18n-scanner-toolkit
# or
yarn add --dev i18n-scanner-toolkit
# or
pnpm add --save-dev i18n-scanner-toolkit
const { I18nScanner } = require('i18n-scanner-toolkit');
const config = {
framework: 'custom',
sourceDir: 'src',
localeDir: 'src/localized/strings',
extractPattern: /\$LS\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
ignoreKeyPatterns: ['src', 'components']
};
const scanner = new I18nScanner(config);
// 1. Scan for missing translations
const missingTranslations = await scanner.scanAll();
console.log(missingTranslations);
// Output: { "key1": "text1", "key2": "text2" }
// 2. Export to CSV
const csvPath = await scanner.export();
console.log(`Exported to: ${csvPath}`);
// 3. Import from CSV (after manual translation)
await scanner.import('./translations.csv');
// React with react-i18next
const config = {
framework: 'react',
sourceDir: 'src',
localeDir: 'src/locales',
extractPattern: /t\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g
};
// Vue with vue-i18n
const config = {
framework: 'vue',
sourceDir: 'src',
localeDir: 'src/locales',
extractPattern: /\$t\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g
};
// Custom pattern (like $LS function)
const config = {
framework: 'custom',
sourceDir: 'src',
localeDir: 'src/localized/strings',
extractPattern: /\$LS\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g,
ignoreKeyPatterns: ['src', 'components']
};
Option | Type | Default | Description |
---|---|---|---|
framework |
string |
'custom' |
Framework preset: 'react' , 'vue' , 'angular' , 'custom' |
sourceDir |
string |
'src' |
Directory to scan for source files |
localeDir |
string |
'src/locales' |
Directory containing language files |
extractPattern |
RegExp |
- | Regular expression to extract translatable text |
extensions |
string[] |
['js', 'jsx', 'ts', 'tsx'] |
File extensions to scan |
ignoreDirs |
string[] |
['node_modules', '.git', 'dist'] |
Directories to ignore |
ignoreKeyPatterns |
string[] |
[] |
Patterns to ignore when generating keys |
defaultLocale |
string |
'en.js' |
Default language file |
const config = {
framework: 'react',
projectDir: './',
sourceDir: 'src',
localeDir: 'src/locales',
extensions: ['js', 'jsx', 'ts', 'tsx'],
ignoreDirs: ['node_modules', '.git', 'dist', 'build', '.next'],
ignoreKeyPatterns: ['components', 'utils', 'common', 'hooks'],
defaultLocale: 'en.json',
extractPattern: /\bt\s*\(\s*['"`]([^'"`]+)['"`]/g
};
const config = {
framework: 'vue',
projectDir: './',
sourceDir: 'src',
localeDir: 'src/locales',
extensions: ['vue', 'js', 'ts'],
ignoreDirs: ['node_modules', '.git', 'dist', 'build'],
ignoreKeyPatterns: ['components', 'utils', 'common', 'composables'],
defaultLocale: 'zh-CN.json',
extractPattern: /\$t\s*\(\s*['"`]([^'"`]+)['"`]/g
};
const config = {
framework: 'angular',
projectDir: './',
sourceDir: 'src',
localeDir: 'src/assets/i18n',
extensions: ['ts', 'html'],
ignoreDirs: ['node_modules', '.git', 'dist', 'build'],
ignoreKeyPatterns: ['components', 'services', 'shared'],
defaultLocale: 'en.json',
extractPattern: /translate\.(?:get|instant)\s*\(\s*['"`]([^'"`]+)['"`]/g
};
const config = {
framework: 'custom',
projectDir: './',
sourceDir: 'src',
localeDir: 'src/localized/strings',
extensions: ['js', 'jsx', 'ts', 'tsx'],
ignoreDirs: ['node_modules', '.git', 'dist', 'build'],
ignoreKeyPatterns: ['src', 'components'],
defaultLocale: 'zh_hans.js',
extractPattern: /\$LS\s*\(\s*['"`]([^'"`]+)['"`]\s*\)/g
};
Creates a new scanner instance with the specified configuration.
Scans all files and returns missing translations as a JSON object.
const missing = await scanner.scanAll();
// Returns: { "HomePage101": "Welcome", "Button102": "Click me" }
Exports all translations to a CSV file. Returns the file path.
const csvPath = await scanner.export('./translations.csv');
// Creates: lang_bulid_20250720_143022.csv
Imports translations from a CSV file and updates language files.
await scanner.import('./translations.csv');
// 1. Add translatable text in your code
function HomePage() {
return <h1>{$LS("Welcome to our app")}</h1>;
}
// 2. Scan for missing translations
const scanner = new I18nScanner(config);
const missing = await scanner.scanAll();
// 3. Export to CSV for translation
await scanner.export('./translations.csv');
// 4. Translate in Excel/CSV editor
// 5. Import back to update language files
await scanner.import('./translations.csv');
The exported CSV file follows this format:
key,en,zh_hans
HomePage101,Welcome to our app,欢迎使用我们的应用
Button102,Click me,点击我
Navigation103,,导航
- First column: Generated key
- Following columns: Language codes
- Empty cells: Missing translations
See the demo-project for a complete React example with custom $LS()
function.
Full TypeScript support with comprehensive type definitions:
import { I18nScanner, I18nConfig, ScanResult } from 'i18n-scanner-toolkit';
const config: I18nConfig = {
framework: 'react',
sourceDir: 'src',
localeDir: 'src/locales'
};
const scanner = new I18nScanner(config);
const result: Record<string, string> = await scanner.scanAll();
MIT License - see LICENSE file for details.
Contributions are welcome! Please read our contributing guidelines and submit pull requests to our repository.