i18n-smell-detector
v0.9.1
Published
Find copied locale values, placeholder mismatches, and hardcoded user-visible strings.
Maintainers
Readme
i18n-smell-detector
Find localization issues that key coverage checks miss.
i18n-smell-detector checks locale files for copied base-locale values and placeholder mismatches. It can also scan Vue, JavaScript, TypeScript, JSX, and TSX source for hardcoded user-visible strings.
The classifier is deterministic and conservative. Start with --fail-on none, review the report, then tune allowlists before enforcing CI.
Features
- Detect copied base-locale values.
- Detect missing or extra placeholders.
- Detect hardcoded user-visible strings in Vue, JS, TS, JSX, and TSX.
- Output console, JSON, Markdown, SARIF, or HTML reports.
- Support baselines for gradual adoption.
- Publish TypeScript types and a small public API for integrations.
Install
npm install -D i18n-smell-detectorQuick Start
npx i18n-smell-detector init
npx i18n-smell-detector check --config i18n-smell.config.mjs --fail-on noneinit creates i18n-smell.config.mjs. When it finds locale JSON files in src/locales, src/i18n, locales, or i18n, it writes them into the config automatically.
A typical config:
export default {
baseLocale: 'en',
locales: {
en: './src/locales/en.json',
zh: './src/locales/zh.json',
'zh-Hans': './src/locales/zh-Hans.json',
},
source: ['src/**/*.{vue,js,jsx,ts,tsx}'],
failOn: 'none',
};Locale keys that contain -, such as 'zh-Hans', must be quoted.
With ignoreSameLanguageFamily enabled, locale tags are compared by language, inferred script, and explicitly declared region. Different scripts are checked normally, two different explicit regions are reported at low severity, and otherwise matching language and script are ignored. The last case includes comparisons where one or both locale tags do not explicitly declare a region.
Commands
npx i18n-smell-detector check --config i18n-smell.config.mjs
npx i18n-smell-detector check-identical --config i18n-smell.config.mjs
npx i18n-smell-detector check-hardcoded --config i18n-smell.config.mjs
npx i18n-smell-detector check-placeholders --config i18n-smell.config.mjsCommon options:
| Option | Description |
| --------------------- | -------------------------------------------------- |
| -c, --config <path> | Use a specific config file. |
| --format <format> | console, json, markdown, sarif, or html. |
| --output <path> | Write the full report to a file. |
| --fail-on <level> | high, medium, low, or none. |
| --baseline <path> | Suppress findings stored in a baseline file. |
| --update-baseline | Write current findings to the baseline file. |
| --include-ignored | Include ignored findings in the report. |
| --debug | Print stack traces for troubleshooting. |
| -V, --version | Print the installed package version. |
Configure precise JavaScript and TypeScript message sinks when messages flow through application-specific APIs:
export default {
hardcoded: {
sinks: {
calls: [{ callee: 'notify', arguments: [0] }],
assignments: ['error.value'],
properties: ['summary', 'detail'],
},
},
};Configured sinks recursively inspect conditional, logical, parenthesized, and TypeScript wrapper expressions. An
interpolated template such as `Delete ${item.name}?` is reported once as Delete {item.name}?, with the raw
template and interpolation ranges available in JSON and SARIF output.
Categorize values that must intentionally remain identical across locales:
export default {
doNotTranslate: [
{
values: ['PRODUCT_X', /^MODEL-\d+$/],
category: 'product-name',
reason: 'Official product terminology',
owner: 'localization-team',
},
{
keys: [/^technical\./],
category: 'technical-term',
reason: 'Protocol terminology',
},
],
hardcoded: {
technicalTerms: ['PROTOCOL_X', /^MODEL-\d+$/],
},
};doNotTranslate applies to identical-translation findings and preserves auditable suppression metadata. Hardcoded
findings expose confidence separately from severity; failOn continues to use severity only.
Reports
npx i18n-smell-detector check --format markdown --output reports/i18n-smell.md
npx i18n-smell-detector check --format html --output reports/i18n-smell.html
npx i18n-smell-detector check --format sarif --output reports/i18n-smell.sarifUse --format json for automation and --format sarif for code-scanning tools.
CI
Start in reporting mode:
npx i18n-smell-detector check --config i18n-smell.config.mjs --fail-on noneAfter tuning allowlists and baselines, enforce a severity threshold:
npx i18n-smell-detector check --config i18n-smell.config.mjs --fail-on highTypeScript API
The package exposes types and a small public API from the package root:
import { checkIdenticalTranslations, severityRank } from 'i18n-smell-detector';
import type { DetectorConfigInput, DetectorIssue, CheckResult } from 'i18n-smell-detector';Documentation
Full documentation lives in the GitHub Wiki:
- Home
- Getting started
- Commands
- Configuration
- Checks
- Reports and CI
- Baseline
- TypeScript API
- Integrations
- Performance
- Troubleshooting
Development
npm install
npm run typecheck
npm test
npm run check
npm run benchmarkLicense
MIT
