@liam-public/node-i18n-lint
v0.2.0
Published
Detect hardcoded, untranslated strings in JSX/TSX — JSX text, user-facing attributes, and bare string literals — so you can wrap them in t().
Downloads
304
Readme
@liam-public/node-i18n-lint
Detects hardcoded, untranslated strings in JSX/TSX so you can wrap them in t(). Parses with
the TypeScript compiler API (not regex) and flags three things:
- JSX text —
<button>Add Source</button> - User-facing attributes —
placeholder,title,alt,aria-label,label, … - Bare string literals in JSX —
<span>{'No sources found.'}</span>
It ignores numbers, URLs, CSS selectors, whitespace, t(...) calls, and any line carrying an
i18n-ignore comment.
CLI
# scan a directory (or files); exits non-zero if any are found (CI-friendly)
npx i18n-lint src/
# example output
src/pages/sources/SourcesPage.tsx:42:14 [jsx-text] "No sources found."
src/components/AddSourceDialog.tsx:31:20 [jsx-attribute:placeholder] "https://example.com/feed.xml"Baseline (adopt on a large codebase without fixing everything first)
Lock in the existing backlog so CI only fails on new hardcoded strings:
# 1. record the current findings (run once, commit the file)
i18n-lint --update-baseline --baseline .i18n-lint-baseline.json src
# 2. in CI — passes unless a NEW string is introduced; baselined ones reduce as you fix them
i18n-lint --baseline .i18n-lint-baseline.json srcThe baseline keys findings by path :: text (not line/column), so it survives edits. Fixing a
string and re-running --update-baseline shrinks the baseline — the backlog only goes down.
Programmatic
import { scanSource } from '@liam-public/node-i18n-lint'
const findings = scanSource('SourcesPage.tsx', code)
// [{ line, column, text, kind: 'jsx-text' | 'jsx-attribute' | 'jsx-expression', attribute? }]typescript is a peer dependency (every TS project already has it).
