{"_id":"@boring-stack-pkg/eslint-plugin-i18n-keys","_rev":"4-895d7fab634700d7946ed35c238f01dd","name":"@boring-stack-pkg/eslint-plugin-i18n-keys","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.1":{"name":"@boring-stack-pkg/eslint-plugin-i18n-keys","version":"0.1.1","keywords":["eslint","eslintplugin","i18n","i18next"],"license":"MIT","_id":"@boring-stack-pkg/eslint-plugin-i18n-keys@0.1.1","maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"homepage":"https://github.com/AI-Starter-Templates/eslint-plugins#readme","bugs":{"url":"https://github.com/AI-Starter-Templates/eslint-plugins/issues"},"dist":{"shasum":"4cebf048889df3a03d3d5dea16ad817cd1106bda","tarball":"https://registry.npmjs.org/@boring-stack-pkg/eslint-plugin-i18n-keys/-/eslint-plugin-i18n-keys-0.1.1.tgz","fileCount":6,"integrity":"sha512-CGYEGsPsy2i9BBe3kJZ7wIkW3l1EIHL2O7iqjhwo9qqag2LJYizsDIK+33kifRo3bT54JM2LPqXuQv42eLQnow==","signatures":[{"sig":"MEUCIH5+14U4a7Fpcul2Ze/kiK0iHndkezSbp8LTlQ1hUjkXAiEAscYepK4UOKeU62ffM+ahLkf/8fWU6BNw9X2/jo/RUZc=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@boring-stack-pkg%2feslint-plugin-i18n-keys@0.1.1","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":15167},"main":"./dist/index.cjs","type":"module","_from":"file:boring-stack-pkg-eslint-plugin-i18n-keys-0.1.1.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"agjs","email":"hi@aleksandar.xyz"},"_resolved":"/tmp/43a621ff183647d75c8883aed1cc338a/boring-stack-pkg-eslint-plugin-i18n-keys-0.1.1.tgz","_integrity":"sha512-CGYEGsPsy2i9BBe3kJZ7wIkW3l1EIHL2O7iqjhwo9qqag2LJYizsDIK+33kifRo3bT54JM2LPqXuQv42eLQnow==","repository":{"url":"git+https://github.com/AI-Starter-Templates/eslint-plugins.git","type":"git","directory":"eslint-plugin-i18n-keys"},"_npmVersion":"10.9.7","description":"ESLint rule: static i18n t() keys must exist in a canonical JSON dictionary.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.2","dependencies":{"@typescript-eslint/utils":"8.0.0"},"publishConfig":{"access":"public","provenance":true},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.0.0","eslint":"9.0.0","vitest":"2.0.0","typescript":"6.0.3","@types/node":"22.0.0","@typescript-eslint/parser":"8.0.0","@typescript-eslint/rule-tester":"8.0.0"},"peerDependencies":{"eslint":"8.57.0 || ^9.0.0","typescript":">=5.0.0","@typescript-eslint/parser":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-plugin-i18n-keys_0.1.1_1779219579408_0.26250096674519985","host":"s3://npm-registry-packages-npm-production"}},"0.1.2":{"name":"@boring-stack-pkg/eslint-plugin-i18n-keys","version":"0.1.2","keywords":["eslint","eslintplugin","i18n","i18next"],"license":"MIT","_id":"@boring-stack-pkg/eslint-plugin-i18n-keys@0.1.2","maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"homepage":"https://github.com/boringstack-xyz/eslint-plugins#readme","bugs":{"url":"https://github.com/boringstack-xyz/eslint-plugins/issues"},"dist":{"shasum":"5ac854b763bb570153371f06574d1b0fe693db96","tarball":"https://registry.npmjs.org/@boring-stack-pkg/eslint-plugin-i18n-keys/-/eslint-plugin-i18n-keys-0.1.2.tgz","fileCount":6,"integrity":"sha512-wB7aGvhZYdhI6tMlyA0bUgihjQRhC2FbXxxwkCT2vjyWlQq69ZhcWKyWkciGdQeKeArQMXx6xbCDNpFalYKA4g==","signatures":[{"sig":"MEUCIBvKefGQINEE1ldLmIlKPiOqSfAW14wTHmDVex8sZ/OoAiEAhjTv43GOUxFzLI7pkbzgL9uIfKywQQQulno+g/C15uY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":15335},"main":"./dist/index.cjs","type":"module","_from":"file:boring-stack-pkg-eslint-plugin-i18n-keys-0.1.2.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"agjs","email":"hi@aleksandar.xyz"},"_resolved":"/tmp/daf3f655a6f3bd80da2d75dd962b1e63/boring-stack-pkg-eslint-plugin-i18n-keys-0.1.2.tgz","_integrity":"sha512-wB7aGvhZYdhI6tMlyA0bUgihjQRhC2FbXxxwkCT2vjyWlQq69ZhcWKyWkciGdQeKeArQMXx6xbCDNpFalYKA4g==","repository":{"url":"git+https://github.com/boringstack-xyz/eslint-plugins.git","type":"git","directory":"eslint-plugin-i18n-keys"},"_npmVersion":"11.15.0","description":"ESLint rule: static i18n t() keys must exist in a canonical JSON dictionary.","directories":{},"sideEffects":false,"_nodeVersion":"22.22.3","dependencies":{"@typescript-eslint/utils":"8.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.0.0","eslint":"9.0.0","vitest":"2.0.0","typescript":"6.0.3","@types/node":"22.0.0","@typescript-eslint/parser":"8.0.0","@typescript-eslint/rule-tester":"8.0.0"},"peerDependencies":{"eslint":"8.57.0 || ^9.0.0","typescript":">=5.0.0","@typescript-eslint/parser":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-plugin-i18n-keys_0.1.2_1779695633785_0.5220527692752435","host":"s3://npm-registry-packages-npm-production"}},"0.1.3":{"name":"@boring-stack-pkg/eslint-plugin-i18n-keys","version":"0.1.3","keywords":["eslint","eslintplugin","i18n","i18next"],"license":"MIT","_id":"@boring-stack-pkg/eslint-plugin-i18n-keys@0.1.3","maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"homepage":"https://github.com/boringstack-xyz/eslint-plugins#readme","bugs":{"url":"https://github.com/boringstack-xyz/eslint-plugins/issues"},"dist":{"shasum":"8b7a6850d527bb8fcbc202f1e575aeff336357e8","tarball":"https://registry.npmjs.org/@boring-stack-pkg/eslint-plugin-i18n-keys/-/eslint-plugin-i18n-keys-0.1.3.tgz","fileCount":6,"integrity":"sha512-kYfID72RcE7VxWxwHu/+maIEe96Vm/QS3qBbO00vBjJvSo+Ph+gW8ZScY7xYB0RfiDkUbTnv2QWo3HrMSE61Ug==","signatures":[{"sig":"MEUCIHCwypyYSIAnmreVrTzPzjnoAnwE+V8JOSNxGQkyw+PGAiEA07VG7F/o8/uqlA82qZqQmUxHyvkG629xEzHtvkiSMwA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"sig":"MEUCIHxqiYevuyRAz4OmN7JT40/yyv1WqWjAn9fMzXcvPBmVAiEAnaTSjiT4/ycTiJbGIYavc0mVRoTXuNsGFp2B2piYhIY=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":20927},"main":"./dist/index.cjs","type":"module","_from":"file:boring-stack-pkg-eslint-plugin-i18n-keys-0.1.3.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"agjs","email":"hi@aleksandar.xyz"},"_resolved":"/tmp/9d9b989bb332edaf88328bfa80f5f23e/boring-stack-pkg-eslint-plugin-i18n-keys-0.1.3.tgz","_integrity":"sha512-kYfID72RcE7VxWxwHu/+maIEe96Vm/QS3qBbO00vBjJvSo+Ph+gW8ZScY7xYB0RfiDkUbTnv2QWo3HrMSE61Ug==","repository":{"url":"git+https://github.com/boringstack-xyz/eslint-plugins.git","type":"git","directory":"eslint-plugin-i18n-keys"},"_npmVersion":"11.4.2","description":"ESLint rule: static i18n t() keys must exist in a canonical JSON dictionary.","directories":{},"sideEffects":false,"_nodeVersion":"24.4.1","dependencies":{"@typescript-eslint/utils":"8.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.0.0","eslint":"9.0.0","vitest":"2.0.0","typescript":"6.0.3","@types/node":"22.0.0","@typescript-eslint/parser":"8.0.0","@typescript-eslint/rule-tester":"8.0.0"},"peerDependencies":{"eslint":"8.57.0 || ^9.0.0 || ^10.0.0","typescript":">=5.0.0","@typescript-eslint/parser":">=8.0.0"},"_npmOperationalInternal":{"tmp":"tmp/eslint-plugin-i18n-keys_0.1.3_1789406558338_0.9738225251955397","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"_id":"@boring-stack-pkg/eslint-plugin-i18n-keys@0.2.0","bugs":{"url":"https://github.com/boringstack-xyz/eslint-plugins/issues"},"dist":{"shasum":"84d1d0cc8b18c36bd76aab37ab0ba3bf15b128c4","tarball":"https://registry.npmjs.org/@boring-stack-pkg/eslint-plugin-i18n-keys/-/eslint-plugin-i18n-keys-0.2.0.tgz","fileCount":6,"integrity":"sha512-MgLrbacdAyrfOPQhAYXjzZFPQmS5DAkkEMSW6HmNFay3GqwkHrzQJsgV9ztRCt/rcFhmx6sqz0sYiRtqZBo4zA==","signatures":[{"sig":"MEUCIE68HTF7dhFWgjsPYEQ4d8Zt/m/zKJa+8KF/wXlKZ+lZAiEAonPxmmKS3JjD2mIwagzTDishwYgE6vj+H54dQK5sAUA=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCICJXh9qUYPg+Dw7yMt/KwQ4Nu0XxsWviDBQWfC6AvxziAiEA4NQTtyHHFL6GcNdPaeXX7TtO3Zbz+Qv1bN9CKttekFs="}],"unpackedSize":22883},"main":"./dist/index.cjs","name":"@boring-stack-pkg/eslint-plugin-i18n-keys","type":"module","_from":"file:boring-stack-pkg-eslint-plugin-i18n-keys-0.2.0.tgz","types":"./dist/index.d.ts","module":"./dist/index.js","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"license":"MIT","scripts":{"test":"vitest run","build":"tsup src/index.ts --format esm,cjs --dts --clean","typecheck":"tsc --noEmit"},"version":"0.2.0","_npmUser":{"name":"agjs","email":"hi@aleksandar.xyz"},"homepage":"https://github.com/boringstack-xyz/eslint-plugins#readme","keywords":["eslint","eslintplugin","i18n","i18next"],"_resolved":"/tmp/f019597c18388f14f41b37fe9bc01580/boring-stack-pkg-eslint-plugin-i18n-keys-0.2.0.tgz","_integrity":"sha512-MgLrbacdAyrfOPQhAYXjzZFPQmS5DAkkEMSW6HmNFay3GqwkHrzQJsgV9ztRCt/rcFhmx6sqz0sYiRtqZBo4zA==","repository":{"url":"git+https://github.com/boringstack-xyz/eslint-plugins.git","type":"git","directory":"eslint-plugin-i18n-keys"},"_npmVersion":"11.19.1","description":"ESLint rule: static i18n t() keys must exist in a canonical JSON dictionary.","directories":{},"maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"sideEffects":false,"_nodeVersion":"22.23.2","dependencies":{"@typescript-eslint/utils":"8.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"8.0.0","eslint":"9.0.0","vitest":"2.0.0","typescript":"6.0.3","@types/node":"22.0.0","@typescript-eslint/parser":"8.0.0","@typescript-eslint/rule-tester":"8.0.0"},"peerDependencies":{"eslint":"8.57.0 || ^9.0.0 || ^10.0.0","typescript":">=5.0.0","@typescript-eslint/parser":">=8.0.0"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/eslint-plugin-i18n-keys_0.2.0_1789510726284_0.7833589577990909"}}},"time":{"created":"2026-05-19T19:39:39.186Z","modified":"2026-09-15T22:18:46.559Z","0.1.1":"2026-05-19T19:39:39.559Z","0.1.2":"2026-05-25T07:53:53.908Z","0.1.3":"2026-09-14T17:22:38.436Z","0.2.0":"2026-09-15T22:18:46.379Z"},"bugs":{"url":"https://github.com/boringstack-xyz/eslint-plugins/issues"},"license":"MIT","homepage":"https://github.com/boringstack-xyz/eslint-plugins#readme","keywords":["eslint","eslintplugin","i18n","i18next"],"repository":{"url":"git+https://github.com/boringstack-xyz/eslint-plugins.git","type":"git","directory":"eslint-plugin-i18n-keys"},"description":"ESLint rule: static i18n t() keys must exist in a canonical JSON dictionary.","maintainers":[{"name":"agjs","email":"hi@aleksandar.xyz"}],"readme":"# eslint-plugin-i18n-keys\n\n[![npm](https://img.shields.io/npm/v/@boring-stack-pkg/eslint-plugin-i18n-keys?logo=npm)](https://www.npmjs.com/package/@boring-stack-pkg/eslint-plugin-i18n-keys) [![source](https://img.shields.io/badge/source-github-blue?logo=github)](https://github.com/boringstack-xyz/eslint-plugins/tree/main/eslint-plugin-i18n-keys)\n\nESLint rule: **static** `t(\"…\")` / `i18n.t(\"…\")` translation keys must exist in a canonical JSON dictionary (nested keys use dot paths).\n\n## Install\n\n```sh\npnpm add -D @boring-stack-pkg/eslint-plugin-i18n-keys\n```\n\nPeer deps: `eslint` 8.57 / 9 / 10, `@typescript-eslint/parser` 8+, `typescript` 5+.\n\n## Use (flat config)\n\n```js\nimport tsParser from \"@typescript-eslint/parser\";\nimport i18nKeys from \"eslint-plugin-i18n-keys\";\n\nexport default [\n  {\n    files: [\"**/*.{ts,tsx}\"],\n    languageOptions: { parser: tsParser },\n    plugins: { \"i18n-keys\": i18nKeys },\n    rules: {\n      \"i18n-keys/static-translation-key-exists\": [\n        \"error\",\n        { dictionary: \"src/lib/i18n/locales/en/common.json\" },\n      ],\n    },\n  },\n];\n```\n\nThe bundled `recommended` config enables the same rule; **override `dictionary`** to match your repo’s locale file path.\n\n`dictionary` also accepts an array. The leaf keys of every file are merged,\nfor a namespace whose copy is split between the client bundle and text\nserved at runtime (paid lesson content, remotely managed strings):\n\n```js\n{ dictionary: [\"src/lib/i18n/locales/en/guide.json\", \"../api/src/api/courses/content/en/wiring.json\"] }\n```\n\n## Rules\n\n| Rule                            | Description                                                                                       |\n| ------------------------------- | ------------------------------------------------------------------------------------------------- |\n| `static-translation-key-exists` | String-literal keys must appear in the JSON dictionary (leaf strings define valid terminal keys). |\n\n### Plural and context suffixes\n\nThe rule resolves keys the way i18next does, so the call site can use the\nbase key while the dictionary stores the suffixed forms:\n\n| Call                                        | Accepted when the dictionary has            |\n| ------------------------------------------- | ------------------------------------------- |\n| `t(\"files\", { count })`                     | `files_other` (or the plain `files`)        |\n| `t(\"rank\", { count, ordinal: true })`       | `rank_ordinal_other`                        |\n| `t(\"friend\", { context: \"male\" })`          | `friend_male` (or the plain `friend`)       |\n| `t(\"guests\", { count, context: \"vip\" })`    | `guests_vip_other`, falling back as i18next |\n\n`_other` is the fallback every language needs, so it is the form the rule\nrequires; `_one`, `_few`, `_many` and friends are optional extras. A counted\ncall whose `_other` form is missing reports `missingPluralKey` naming the\nexpected key. An uncounted call to a plural-only key (`t(\"files\")`) is still\nan error, because i18next would render the raw key. Only string-literal\n`context` values are resolved; a variable context falls back to the base key.\n\n## Development\n\n```bash\npnpm install\npnpm test\npnpm build\n```\n\n## License\n\nMIT.\n","readmeFilename":"README.md"}