New:Introducing Socket Scanning for VS Code Marketplace Extensions.Learn more →
Get Started

internationalizer

Package Overview
Dependencies
Maintainers
1
Versions
6
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

internationalizer

AI-native internationalization CLI for software projects

Source
npmnpm
Version
0.1.2
Version published
Weekly downloads
135
-3.57%
Maintainers
1
Weekly downloads
 
Created
Source

Internationalizer

Internationalizer

AI-native internationalization pipeline for software projects. Translate, validate, and manage i18n files using LLMs.

CI License: AGPL-3.0

العربية · বাংলা · Čeština · Dansk · Deutsch · Ελληνικά · Español · Suomi · Français · עברית · हिन्दी · Indonesia · Italiano · 日本語 · 한국어 · Bahasa Melayu
Nederlands · ਪੰਜਾਬੀ · Polski · Português · Română · Русский · Svenska · తెలుగు · ไทย · Türkçe · Українська · Tiếng Việt · 粵語 · 简体中文 · 繁體中文

Why Internationalizer?

Most i18n tools are either runtime libraries (i18next, react-intl) or key-management SaaS platforms (Crowdin, Lokalise). None of them solve the actual translation problem well:

  • Manual translation doesn't scale past a few languages
  • Machine translation APIs (Google Translate, DeepL) ignore your terminology, tone, and UI conventions
  • Generic LLM translation works better, but without glossaries and style guides, you get inconsistent results

Internationalizer is different. It's a CLI pipeline that combines LLM translation with:

  • Per-language glossaries — enforce consistent terminology across your app
  • Per-language style guides — control tone, formality, pluralization, and typography
  • Translation memory — skip unchanged strings, save money on API calls
  • Deterministic validation — catch missing or extra keys, protected-structure drift, glossary issues, and plural or ICU errors before they ship
  • Explicit approval — keep provider or adopted provenance separate from human review
  • Fluent and pseudolocales — preserve translator context and exercise accented or bidirectional layouts without an API call

Installation

Install from npm:

npm install -g internationalizer

Or run without a global install:

npx internationalizer --help

The npm package installs the matching prebuilt binary from npm via platform-specific optional dependencies.

Install with Go:

go install github.com/Tom-R-Main/Internationalizer/cmd/internationalizer@latest

Or build from source:

git clone https://github.com/Tom-R-Main/Internationalizer.git
cd Internationalizer
go build -o internationalizer ./cmd/internationalizer

npm Packages

  • Git tags and npm package versions must match, for example v0.1.0 and 0.1.0
  • The root internationalizer package depends on platform packages such as internationalizer-darwin-arm64
  • Supported npm targets: macOS arm64/x64, Linux arm64/x64, Windows x64
  • CI publishing requires a GitHub secret named NPM_TOKEN

Quick Start

  • Create a config file in your project root:
# .internationalizer.yml
source_locale: en
target_locales: [fr, de, es, ja]
bundles:
  - id: app
    source: locales/en.json
    target: locales/{locale}.json
    format: json

llm:
  provider: gemini
  model: gemini-3.8-flash
  api_key_env: GOOGLE_AI_STUDIO_API_KEY
  • Set your API key:
export GOOGLE_AI_STUDIO_API_KEY=your-ai-studio-key
  • Preview what will be translated:
internationalizer translate --dry-run
  • Run the translation:
internationalizer translate
  • Validate and approve the exact generated artifacts:
internationalizer validate
internationalizer review list --status needs_review
internationalizer review approve --locale fr --all
internationalizer validate --require-approved

Commands

translate

Find missing or stale keys and translate them via an LLM.

internationalizer translate                    # translate all locales
internationalizer translate -l fr              # translate French only
internationalizer translate --dry-run          # preview without API calls
internationalizer translate --adopt-existing   # baseline existing translations without API calls
internationalizer translate --refresh-policy   # refresh prompt/style/model-stale entries
internationalizer translate --batch-size 20    # smaller batches
internationalizer translate --concurrency 2    # fewer parallel calls

Translation state independently reports missing, source-stale, policy-stale, current, and manually edited conditions, so a manual edit cannot conceal a source or policy change. Policy-stale values are reported but only retranslated with --refresh-policy. Manually edited values are never overwritten automatically. Use --adopt-existing when introducing the manifest to existing translations or when explicitly accepting a manual edit as the new provenance baseline. Adoption does not imply human approval; use review approve for that separate decision.

pseudo

Generate deterministic test locales without a provider or translation-memory lookup. Accented output defaults to en-XA; bidirectional output defaults to ar-XB. ICU and Fluent runtime syntax, code, links, and markup are preserved.

internationalizer pseudo                         # accented en-XA
internationalizer pseudo --strategy bidi         # bidi ar-XB
internationalizer pseudo --dry-run                # show planned artifacts only
internationalizer pseudo --locale qps-ploc        # choose another valid locale tag

The generator refreshes only artifacts it previously recorded as pseudo output. Use --force to replace any other existing target deliberately.

review

Inspect and approve the exact target content currently bound to its source and translation policy. Generated, cached, and adopted values all begin in needs_review; approval is invalidated by later source, policy, or target changes. Pseudolocales are tracked separately as test artifacts.

internationalizer review list --status needs_review
internationalizer review approve --locale fr --bundle app --key common.save
internationalizer review approve --locale fr --all

validate

Check all locale files against their source bundles. Default validation checks structural coverage (the percentage of required target keys present), reports extra keys as warnings, and fails for missing keys, interpolation mismatches, or invalid ICU MessageFormat structure.

internationalizer validate                     # human-readable output
internationalizer validate --json              # machine-readable JSON
internationalizer validate -q                  # exit code only
internationalizer validate --strict             # enforce translation quality rules
internationalizer validate --require-state      # require current manifest provenance
internationalizer validate --require-approved   # also require explicit approval

--strict also reports translated coverage. A linguistic value identical to its source is untranslated unless the glossary explicitly contains an exact same-source, same-target entry for the complete value; ignore_case is honored, but a glossary term embedded in a longer value is not an exemption. Strict mode fails on extra keys, source-identical values, changed interpolation/HTML/code/ Markdown-link structure, glossary violations, and configured plural forms.

--require-state verifies each target against .internationalizer.lock. It fails when a key is untracked, or when its recorded source, translation policy, or target hash is stale. --require-approved implies --require-state and also fails if the exact current artifact has not been approved. Both can be combined with --strict.

Human and JSON reports use stable finding codes:

CodeMeaning
missing_key / extra_keySource and target key sets differ
blank_translationA non-empty source has an empty strict-mode target
source_identicalA strict-mode linguistic value remains untranslated
protected_structure_mismatchInterpolation, HTML, code, or link structure changed
glossary_violationNo approved target term or variant was found
plural_form_missingA configured locale plural form is absent
icu_message_syntaxA source or target ICU message is malformed
icu_argument_mismatchICU argument names, types, or formatter styles differ
icu_selector_mismatchSelectors differ or a plural category is invalid for the target locale
untrackedNo manifest record exists for the target
source_staleSource content changed after the recorded translation
policy_staleThe generated prompt or model settings changed
target_modifiedTarget content differs from the manifest record
needs_reviewCurrent provenance exists, but the exact target is not approved

detect

Auto-detect the i18n framework and suggest a configuration.

internationalizer detect

Supports: react-i18next, next-intl, vue-i18n, vanilla JSON, markdown docs.

glossary

Manage per-language glossary terms that are enforced during translation.

internationalizer glossary list --locale fr
internationalizer glossary add --locale fr --source "Dashboard" --target "Tableau de bord"
internationalizer glossary remove --locale fr --source "Dashboard"

tm

Manage translation memory (JSONL cache of previously translated strings).

internationalizer tm stats                     # show record counts
internationalizer tm export                    # dump as JSON
internationalizer tm clear --force             # delete all records

Configuration Reference

# .internationalizer.yml

# Source language (default: en)
source_locale: en

# Languages to translate into (required)
target_locales: [fr, de, es, ja, yue, zh-CN, zh-TW, ar]

# One or more source-to-target mappings (required).
# {locale} is replaced with each configured target locale.
bundles:
  - id: app
    source: locales/en.json
    target: locales/{locale}.json
    format: json
  - id: docs
    source: README.md
    target: docs/i18n/{locale}.md
    format: markdown
  - id: browser
    source: browser/locales/en-US/browser.ftl
    target: browser/locales/{locale}/browser.ftl
    format: fluent

# Backward compatibility: source_path still maps targets to sibling files
# such as locales/fr.json. Prefer bundles for new projects.
# source_path: locales/en.json

# LLM provider settings
llm:
  # Provider: "anthropic", "openai", "gemini", or "openrouter" (default: gemini)
  provider: gemini

  # Model name defaults by provider:
  #   anthropic:  claude-opus-5
  #   openai:     gpt-5.6-luna (reasoning effort defaults to max)
  #   gemini:     gemini-3.8-flash
  #   openrouter: deepseek/deepseek-v4-pro-0813
  model: gemini-3.8-flash

  # Environment variable containing the API key
  api_key_env: GOOGLE_AI_STUDIO_API_KEY

  # Base URL for OpenAI-compatible endpoints (optional)
  # base_url: https://api.openai.com

  # OpenAI GPT-5-series Responses API reasoning effort
  # (default: max for the OpenAI provider)
  reasoning_effort: max

  # Optional LLM settings for individual target locales. An override using the
  # global provider inherits unspecified global settings. A different provider
  # uses that provider's defaults for unspecified settings.
  locale_overrides:
    yue:
      provider: openrouter
      model: deepseek/deepseek-v4-flash-0731
      api_key_env: OPENROUTER_API_KEY
    zh-CN:
      provider: openrouter
      model: deepseek/deepseek-v4-flash-0731
      api_key_env: OPENROUTER_API_KEY
    zh-TW:
      provider: openrouter
      model: deepseek/deepseek-v4-flash-0731
      api_key_env: OPENROUTER_API_KEY

# Keys per LLM call (default: 40)
batch_size: 40

# Parallel LLM calls (default: 4)
concurrency: 4

# Directory containing per-locale style guide Markdown files (default: style-guides)
style_guides_dir: style-guides

# Directory containing per-locale glossary JSON files (default: glossary)
glossary_dir: glossary

# Path to translation memory file (default: .internationalizer/tm.jsonl)
tm_path: .internationalizer/tm.jsonl

# Versioned source, policy, target, and provenance state
# (default: .internationalizer.lock; commit this file)
manifest_path: .internationalizer.lock

# Optional translation and strict-validation rules
validation:
  plural_style: i18next-v4 # generate and validate target-locale plural forms

Locale identifiers must be well-formed BCP 47 tags such as fr, pt-BR, or sr-Latn-RS. Canonical-equivalent target locales are rejected as duplicates, and locale-specific provider overrides match canonical-equivalent spelling. In the example above, locales without an override—including Japanese—inherit the global Gemini configuration.

ICU MessageFormat values are parsed structurally. Simple arguments, select, plural, selectordinal, number, date, and time are supported, including nested messages, plural offsets, exact-number selectors, and #. Validation checks syntax, argument types and formatter styles, plural offsets, select branch identity, and target-locale CLDR plural categories. Provider output that breaks these invariants is rejected before a locale file or translation-memory record is written.

Fluent (.ftl) resources are handled as semantic source documents rather than flattened maps. Message values, terms, and attributes become independent units; comments are passed to the provider as developer context and included in source provenance. Serialization preserves resource comments and ordering. Validation protects variables, references, functions, selector defaults and branches, and data-l10n-name markup slots while allowing target-locale selector variants and natural reordering of named rich-text elements.

With i18next-v4, recognized source plural families are expanded during translation to the target locale's CLDR categories. A target-only category uses the source family's _other value as its translation template. Strict validation requires those target categories; source-only categories are optional for target locales that do not use them.

Style Guides

Style guides are Markdown files that get injected into the LLM translation prompt. They control tone, formality, typography, and other language-specific conventions.

style-guides/
  _conventions.md    # shared rules for all languages
  fr.md              # French-specific rules
  ja.md              # Japanese-specific rules
  ar.md              # Arabic-specific rules

Shared conventions (_conventions.md)

Define rules that apply to all languages: interpolation syntax, HTML preservation, string type conventions (buttons vs. labels vs. errors), etc.

Per-language guides ({locale}.md)

Define language-specific rules: formality register (tu vs. vous), punctuation (guillemets, inverted question marks), plural forms, date/number formatting, and a terminology glossary.

Style guides are durable policy inputs, not generated output. Internationalizer reads them but never rewrites them. Their content is hashed separately from the glossary and prompt contract, so an application code change does not make a translation stale. Editing a guide intentionally marks that locale for policy review; changing internal prompt wording does not, unless the prompt contract version also changes.

See examples/react-app/style-guides/ for a working example.

Glossary Format

Glossary files are JSON arrays stored in {glossary_dir}/{locale}.json:

[
  {
    "source": "Dashboard",
    "target": "Tableau de bord",
    "variants": ["Panneau de contrôle"],
    "enforcement": "error",
    "ignore_case": false,
    "whole_word": true
  }
]

variants lists other approved target forms. enforcement may be error, warning, or omitted for the default error behavior. Terms are injected into the LLM prompt as a terminology table, ensuring consistent translation across your application. An exact entry such as {"source":"API","target":"API"} also exempts that complete source-identical value from strict untranslated-value findings; it does not exempt a longer value merely containing API.

Translation Memory

Translation memory is stored as a JSONL file (one JSON record per line). Each record contains:

  • The bundle, key, source value, translated value, and canonical target locale
  • Source, style-guide, glossary, prompt-contract, and combined policy hashes
  • The provider and model that produced the translation
  • A timestamp

On subsequent runs, strings with the same source and policy hashes are served from the cache without calling the LLM. The default path is under the ignored .internationalizer/ directory, so it remains a local cache. Set tm_path to a tracked location if your project intentionally shares translation memory. The reviewable .internationalizer.lock manifest is versioned separately. Manifest schema v2 records provenance origin and review status independently, so “generated successfully” and “approved by a person” cannot be conflated.

Supported Formats

FormatExtensionsMode
JSON.jsonKey-value (nested, dot-notation flattened)
YAML.yml, .yamlKey-value (preserves comments and ordering)
Markdown.md, .mdxPreamble and H2-level sections
Fluent.ftlSemantic messages, terms, attributes, comments, and selectors

Markdown targets contain invisible internationalizer:unit comments before H2 sections. These stable markers let Internationalizer add, move, or edit one source section without retranslating unrelated sections. Existing unmarked documents receive markers on their next successful update.

Project Type Detection

internationalizer detect identifies your i18n setup by checking:

  • package.json dependencies for react-i18next, next-intl, or vue-i18n
  • Directory structures matching common locale patterns
  • File extensions and naming conventions

Architecture

cmd/internationalizer/     CLI entry point and command definitions
internal/
  config/                  YAML config loading with defaults
  detect/                  Project type auto-detection
  fluentpattern/           Fluent pattern validation and safe text transforms
  formats/                 Format adapters (JSON, YAML, Markdown, Fluent)
  glossary/                Per-locale glossary management
  llm/                     LLM provider interface + implementations
    anthropic.go           Anthropic Claude backend
    openai.go              OpenAI / compatible backend
    gemini.go              Google Gemini via AI Studio backend
                           OpenRouter uses openai.go with custom base_url
  locale/                  BCP 47 identity and CLDR plural categories
  message/                 ICU MessageFormat parser and structural comparison
  policy/                  Stable translation-policy hashing
  pseudo/                  Provider-free accented and bidi test locales
  review/                  Explicit artifact approval workflow
  state/                   Versioned translation manifest
  styleguide/              Style guide loader
  tm/                      JSONL translation memory
  translate/               Translation orchestrator
  validate/                Locale validation and diffing

Comparison to Alternatives

FeatureInternationalizeri18nextCrowdinGeneric LLM
LLM-powered translationYesNoPartialYes
Per-language style guidesYesNoNoNo
Glossary enforcementYesNoYesNo
Translation memoryYesNoYesNo
CLI / local executionYesN/ANoManual
Git-friendly filesYesYesPartialManual
No SaaS dependencyYesYesNoVaries
Open source (AGPL-3.0)YesYesNoVaries

License

AGPL-3.0

See THIRD_PARTY_NOTICES.md for dependency notices.

Contributing

See CONTRIBUTING.md for development setup and guidelines. All contributions require DCO sign-off.

Keywords

i18n

FAQs

Package last updated on 04 Sep 2026

Related posts