npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

i18n-agent

v0.9.1

Published

Locale files translated by the coding-agent subscription you already pay for — diff-synced via a lockfile, placeholder-safe, manual edits stay sacred. No API keys, no per-word fees.

Readme

i18n-agent

Your locale files, translated by the coding-agent subscription you already pay for. No API keys, no per-word fees, no cloud. Diff-synced through a lockfile, placeholder-safe, and your manual edits are never overwritten.

npx i18n-agent translate   # en.json → ru.json, es.json, de.json — via `claude -p` on your subscription

The idea: modern coding agents run on subscriptions that already include a cheap model tier. i18n-agent batches your untranslated locale strings and pipes them through a headless agent call (claude -p --model haiku) — so keeping 10 languages in sync costs you $0 on top of the subscription you already have. Prefer API keys or CI without a subscription? A provider switch away.

Quick start

npm install -g i18n-agent            # or npx i18n-agent …
cd your-app
i18n-agent init                      # detects locales/, writes config + documented templates
i18n-agent add-locale ru es --translate
i18n-agent check                     # CI gate: exit 1 on drift
i18n-agent report --days 7           # volumes, real cost receipts, DeepL-API equivalent

How it works

my-app/
├── locales/
│   ├── en/              # source of truth — authored by you (or your coding agent)
│   │   ├── common.json
│   │   └── auth.json
│   ├── ru/              # targets — generated, but hand-editable
│   └── es/
├── i18n-agent.config.yaml    # source, targets, provider
├── i18n-agent.context.yaml   # optional: hints for the translator per key
├── i18n-agent.glossary.yaml  # optional: terms to pin or keep untranslated
└── i18n-agent.lock           # what's translated, what changed, what a human touched

Locale files may be JSON, YAML, or TypeScript modules (export default { … } as const; — the layout typed web codebases use for compile-checked keys). The format is auto-detected from the source locale and mirrored to targets.

  1. You (or your agent) edit the source locale as part of normal feature work.
  2. i18n-agent translate diffs against the lockfile and translates only new and changed keys, batched through the subscription agent. Placeholders ({name}, {{var}}, %s, ICU plurals, HTML tags) are validated after translation — a violation gets one retry, then the key is reported instead of silently broken.
  3. Run it again — zero calls. The lockfile knows.
  4. i18n-agent check in CI fails the build when targets drift out of sync. For Android exports add i18n-agent check --platform android — CLDR plural coverage, format-arg parity (%1$s must match source), and <annotation> markup preservation (no AI calls). i18n-agent status --platform android prints a per-language structural summary.

Manual edits are sacred

The lockfile stores a hash of every translation i18n-agent writes. If you hand-fix ru/common.json, i18n-agent notices the value is no longer its own and never overwrites it. If the English source of that key changes later, the key shows up in i18n-agent translate --review for a human decision (or --retranslate-stale to bulk-accept machine translation). Translation memory semantics — as plain files in your git, not rented server state with a retention timer.

Multi-platform export: one source, native locales everywhere

Your product has web, Android and iOS? Keep ONE canonical set of locales (typically next to the backend) and generate platform-native files at build time — the OpenAPI model applied to translations. No drift between platforms, translation work done once.

# i18n-agent.config.yaml
exports:
  - platform: android        # values-<lang>/strings.xml, ICU plural → <plurals>, arrays → <string-array>
    out: ../android-app/app/src/main/res
    namespaces: [android]    # optional — only this locale ns (skip server auth/email/…)
    prefixNamespace: false   # optional — R.string.nav_overview instead of android_nav_overview
  - platform: ios-xcstrings  # single Localizable.xcstrings (String Catalog), plural variations
    out: ../ios-app/Resources
  - platform: web-json       # canonical layout re-emitted as JSON
    out: ../web-app/public/locales
  - platform: ts-keys        # generated key unions — typo-proof t() calls
    out: ../web-app/src/i18n

For a mobile pilot that keeps English in the Android repo under namespace android, set namespaces: [android] and prefixNamespace: false so the served / exported strings.xml matches R.string.*. Those options also apply to export --bundle (self-hosted GET /i18n/android/…). i18n-agent export after translate. Named placeholders become positional per platform ({name}%1$s / %1$@) with the argument order taken from the source string — every language numbers the same argument identically, even when a translation reorders the sentence.

Delivery is yours to choose: publish the export dir as a CI/release artifact and fetch it in client builds (OpenAPI-style), keep clients in a monorepo, or let a bot PR the generated files.

Self-hosted delivery: your backend serves the translations

i18n-agent export --bundle          # → i18n-bundle/: all platforms + manifest.json (per-file sha256, content-derived etag)

Mount the bundle behind any static route — or, on NestJS, use the companion package i18n-agent-nest:

I18nAgentModule.forRoot({ bundleDir: 'i18n-bundle' })
// GET /i18n/manifest.json · /i18n/web/ru/common.json · /i18n/android/… · ETag/304 out of the box

Web clients fetch locales at runtime, mobile CI fetches native files at build time — from YOUR server. No third-party cloud, no retention timers: the "translation service" is static files in your deploy. Not on Nest? express.static or nginx serve the same bundle; the module only adds correct ETags and the manifest route.

Recommended: let your coding agent drive it

i18n-agent ships optional agent guides — install one and your coding agent handles localization correctly whenever you ask it to ("add localization to this app", "add German", "translate the new strings"). This is a recommendation surface, not background automation: the agent learns the workflow — author the source locale, run i18n-agent, never hand-write target files.

Claude Code (project-level skill):

mkdir -p .claude/skills && cp -r "$(npm root -g)/i18n-agent/agent-skills/claude-code/i18n-agent" .claude/skills/

Cursor (project rule):

mkdir -p .cursor/rules && cp "$(npm root -g)/i18n-agent/agent-skills/cursor/i18n-agent.mdc" .cursor/rules/

The guides encode the ownership rules (source is yours, targets are machine-owned, hand edits are sacred and reviewed) so an agent never fights the lockfile.

Status

v0.8.5 — CLDR plural # parity for expanded targets; universal printf guards; status --platform android; Android <annotation> markup. See ROADMAP.md. Built on @cursor-translate/core.

Migrating an existing app / syncing a client source locale

Already shipping with per-platform locales? Pull them into the canonical set — keeping every human translation on first import:

i18n-agent import --platform android --in app/src/main/res
i18n-agent import --platform ios-xcstrings --in Localizable.xcstrings
  • Android: values*/strings.xml land in one namespace (default android); <plurals> become ICU plural, <string-array> arrays; translatable="false" brand constants are skipped; non-language qualifier dirs (values-night, values-v21) are ignored.
  • iOS: dot keys become nesting and the top-level segment becomes the namespace (auth.signIn.titleauth.json); plural variations become ICU plural; Apple specifiers (%@, %lld) are understood by the placeholder guard.
  • Then run i18n-agent translate: every pre-existing translation is adopted as human-owned — sacred, never overwritten; only genuinely missing keys hit the translator.
  • Full migration refuses to overwrite existing locale files without --force.

Recurring sync: client keeps English, backend owns translations

When a mobile client authors English in-repo (Android values/strings.xml) and you only want to refresh the source language in the canonical set — without touching values-ru / target JSON — use --source-only. Safe to re-run whenever the client asks for new translations:

# --in may be res/, values/, or values/strings.xml
i18n-agent import --platform android --in ../android-app/app/src/main/res --source-only
i18n-agent translate
i18n-agent export --bundle   # or export --platform android; client commits values-<lang>/ only

--source-only always replaces the source namespace file (no --force), ignores sibling values-<lang>/ dirs, and never writes target locales. Clients must not overwrite their own values/ from the export — take only values-<lang>/.

Honest economics

  • Translation runs on your subscription's cheap tier (Haiku-class): a 2,000-string app × 10 languages ≈ a few dollars of API money — or ~$0 marginal on the subscription you already have.
  • i18n-agent stores nothing server-side because there is no server. The "translation memory" is i18n-agent.lock + your locale files, in your repo, forever.
  • What i18n-agent does not do: no TMS dashboard, no review workflow UI (use --review + git diff), no code extraction (your source locale is authored — by you or your coding agent; see /i18nify on the roadmap).

Every run logs volumes and real claude -p cost receipts — pull your own numbers:

$ i18n-agent report --days 7
i18n-agent report — last 7 day(s), project "demo-app"
  runs: 2 · strings translated: 2 (failed: 0) · agent calls: 2
  volume: 24 source chars → 34 translated chars
  spend: $0.0040 (claude -p receipts; ~$0 marginal on a subscription)
  DeepL API equivalent for the same volume: ~$0.00 (@ $25/M chars)

License

MIT