{"_id":"@dan-nachmany/i18n","_rev":"3-afd267ec8c9ffc901ec0e8ba9b850813","name":"@dan-nachmany/i18n","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@dan-nachmany/i18n","version":"0.1.0","keywords":["i18n","internationalization","translation","gemini","s3","cloudflare-r2"],"author":{"name":"dan-nachmany"},"license":"MIT","_id":"@dan-nachmany/i18n@0.1.0","maintainers":[{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"}],"homepage":"https://github.com/danbjnbh1/i18n#readme","bugs":{"url":"https://github.com/danbjnbh1/i18n/issues"},"bin":{"i18n-translate":"dist/cli/index.js"},"dist":{"shasum":"38ef6a25d8678813edf7882a3be749d8221b8f5b","tarball":"https://registry.npmjs.org/@dan-nachmany/i18n/-/i18n-0.1.0.tgz","fileCount":92,"integrity":"sha512-+38oENA7OBDW0gaSEWfBPzlI8EfA8ae78U9gxWimc6UNNchRVddJvUWZR2CWdbhO73f9uhbGwIGlIuaBrPVcww==","signatures":[{"sig":"MEUCIQDhxkw/KMz+zJEsTYSWFY8chn9KUE2OSToV8c9VMefPRwIgNGiTiTbTp1b0voHkBz4XqOuxZJ3wmH8/FmDH4wltl2Y=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":85349},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"402a55838932248cdcb69aa6c81d3b10092b2af0","scripts":{"dev":"tsc --watch","lint":"eslint src tests","test":"vitest run","build":"tsc && chmod +x dist/cli/index.js","clean":"rm -rf dist coverage","format":"prettier --write \"src/**/*.{ts,js,json,md}\" \"tests/**/*.ts\"","lint:fix":"eslint src tests --fix","translate":"ts-node src/cli/index.ts","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.{ts,js,json,md}\" \"tests/**/*.ts\"","test:coverage":"vitest run --coverage","prepublishOnly":"npm run clean && npm run typecheck && npm run lint && npm test && npm run build"},"_npmUser":{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"},"repository":{"url":"git+https://github.com/danbjnbh1/i18n.git","type":"git"},"_npmVersion":"10.8.2","description":"Standalone i18n with auto key generation, pluggable storage (local/S3), and an LLM-powered translation CLI.","directories":{},"_nodeVersion":"20.19.2","dependencies":{"@aws-sdk/client-s3":"^3.600.0","@google/generative-ai":"^0.15.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.10.0","vitest":"^1.6.0","ts-node":"^10.9.2","prettier":"^3.3.3","@eslint/js":"^9.10.0","typescript":"^5.4.0","@types/node":"^20.0.0","typescript-eslint":"^8.5.0","@vitest/coverage-v8":"^1.6.0"},"_npmOperationalInternal":{"tmp":"tmp/i18n_0.1.0_1776433174273_0.21580998562565967","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@dan-nachmany/i18n","version":"0.1.1","keywords":["i18n","internationalization","translation","gemini","s3","cloudflare-r2"],"author":{"name":"dan-nachmany"},"license":"MIT","_id":"@dan-nachmany/i18n@0.1.1","maintainers":[{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"}],"homepage":"https://github.com/danbjnbh1/i18n#readme","bugs":{"url":"https://github.com/danbjnbh1/i18n/issues"},"bin":{"i18n-translate":"dist/cli/index.js"},"dist":{"shasum":"8bd5a113bd8acdd4ba40a652634f921a2b960b8a","tarball":"https://registry.npmjs.org/@dan-nachmany/i18n/-/i18n-0.1.1.tgz","fileCount":96,"integrity":"sha512-CzjnthRF7ZwYFTiPweZ6UJywVQmUJGYfLW+kSGip1Cg4vtQI0B6R1QS7oRMnVWjYlasJiR91B1sWvylT0zeQHA==","signatures":[{"sig":"MEQCIBZS6Gvn7R4KVrgGK2Hybf42UJDo/Is8p3B7rOdo1R63AiBqPho/pIA0ApuV9MTlvadYBw5XrDJ1opWHcID5V15KPw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":88429},"main":"dist/index.js","types":"dist/index.d.ts","engines":{"node":">=18.0.0"},"gitHead":"6a5d1c327371f80147056c63f2c45442c3a785af","scripts":{"dev":"tsc --watch","lint":"eslint src tests","test":"vitest run","build":"tsc && chmod +x dist/cli/index.js","clean":"rm -rf dist coverage","format":"prettier --write \"src/**/*.{ts,js,json,md}\" \"tests/**/*.ts\"","lint:fix":"eslint src tests --fix","translate":"ts-node src/cli/index.ts","typecheck":"tsc --noEmit","test:watch":"vitest","format:check":"prettier --check \"src/**/*.{ts,js,json,md}\" \"tests/**/*.ts\"","test:coverage":"vitest run --coverage","prepublishOnly":"npm run clean && npm run typecheck && npm run lint && npm test && npm run build"},"_npmUser":{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"},"repository":{"url":"git+https://github.com/danbjnbh1/i18n.git","type":"git"},"_npmVersion":"10.8.2","description":"Standalone i18n with auto key generation, pluggable storage (local/S3), and an LLM-powered translation CLI.","directories":{},"_nodeVersion":"20.19.2","dependencies":{"@aws-sdk/client-s3":"^3.600.0","@google/generative-ai":"^0.15.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"eslint":"^9.10.0","vitest":"^1.6.0","ts-node":"^10.9.2","prettier":"^3.3.3","@eslint/js":"^9.10.0","typescript":"^5.4.0","@types/node":"^20.0.0","typescript-eslint":"^8.5.0","@vitest/coverage-v8":"^1.6.0"},"_npmOperationalInternal":{"tmp":"tmp/i18n_0.1.1_1776434861819_0.7485283899466937","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@dan-nachmany/i18n","version":"0.2.0","description":"Standalone i18n with auto key generation, pluggable storage (local/S3), and an LLM-powered translation CLI.","keywords":["i18n","internationalization","translation","gemini","s3","cloudflare-r2"],"license":"MIT","author":{"name":"dan-nachmany"},"main":"dist/index.js","module":"dist/index.mjs","types":"dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.mjs","require":"./dist/index.js"},"./package.json":"./package.json"},"bin":{"i18n-translate":"dist/cli/index.js"},"scripts":{"build":"npm run clean && npm run build:lib && npm run build:cli && chmod +x dist/cli/index.js","build:lib":"tsup src/index.ts --format cjs,esm --dts --sourcemap --out-dir dist","build:cli":"tsup src/cli/index.ts --format cjs --sourcemap --out-dir dist/cli","dev":"tsup src/index.ts src/cli/index.ts --format cjs,esm --dts --sourcemap --out-dir dist --watch","clean":"rm -rf dist coverage","lint":"eslint src tests","lint:fix":"eslint src tests --fix","format":"prettier --write \"src/**/*.{ts,js,json,md}\" \"tests/**/*.ts\"","format:check":"prettier --check \"src/**/*.{ts,js,json,md}\" \"tests/**/*.ts\"","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","translate":"ts-node src/cli/index.ts","prepublishOnly":"npm run clean && npm run typecheck && npm run lint && npm test && npm run build"},"repository":{"type":"git","url":"git+https://github.com/danbjnbh1/i18n.git"},"homepage":"https://github.com/danbjnbh1/i18n#readme","bugs":{"url":"https://github.com/danbjnbh1/i18n/issues"},"dependencies":{"@aws-sdk/client-s3":"^3.600.0","@aws-sdk/credential-providers":"^3.1031.0","@google/generative-ai":"^0.15.0","axios":"^1.15.0"},"devDependencies":{"@eslint/js":"^9.20.0","@types/node":"^20.0.0","@vitest/coverage-v8":"^1.6.0","eslint":"^9.20.0","eslint-config-prettier":"^9.0.0","eslint-plugin-prettier":"^5.0.0","prettier":"^3.3.3","ts-node":"^10.9.2","tsup":"^8.2.0","typescript":"^5.4.0","typescript-eslint":"^8.5.0","vitest":"^1.6.0"},"engines":{"node":">=18.0.0"},"publishConfig":{"access":"public"},"_id":"@dan-nachmany/i18n@0.2.0","gitHead":"1e9b421e59409712e7a617499bea678773028a28","_nodeVersion":"20.19.2","_npmVersion":"10.8.2","dist":{"integrity":"sha512-N/pcS52ZItdK5BMUP0+TrNN/kyhvoQIhzxp2L7AuRtNCAO+XVDYgzM8oIf4000WJDK8MSd32dxcaN02dvZ7eTg==","shasum":"008adb2a6a9b8f050ad79a3f6660303314dca44c","tarball":"https://registry.npmjs.org/@dan-nachmany/i18n/-/i18n-0.2.0.tgz","fileCount":12,"unpackedSize":24185259,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQDSZaZ9nxw0ALIxMmiR0eJVfDQnLtvuPU/JNcG5va4o0QIhALDqoafALKZsU3ov9+qkBeToN1aJ6BfFyZOCtwqKJoj4"}]},"_npmUser":{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"},"directories":{},"maintainers":[{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/i18n_0.2.0_1776508981074_0.15720235473333966"},"_hasShrinkwrap":false}},"time":{"created":"2026-04-17T13:39:34.212Z","modified":"2026-04-18T10:43:01.440Z","0.1.0":"2026-04-17T13:39:34.472Z","0.1.1":"2026-04-17T14:07:41.982Z","0.2.0":"2026-04-18T10:43:01.324Z"},"bugs":{"url":"https://github.com/danbjnbh1/i18n/issues"},"author":{"name":"dan-nachmany"},"license":"MIT","homepage":"https://github.com/danbjnbh1/i18n#readme","keywords":["i18n","internationalization","translation","gemini","s3","cloudflare-r2"],"repository":{"type":"git","url":"git+https://github.com/danbjnbh1/i18n.git"},"description":"Standalone i18n with auto key generation, pluggable storage (local/S3), and an LLM-powered translation CLI.","maintainers":[{"name":"dan-nachmany","email":"danbjnbh1@gmail.com"}],"readme":"# @dan-nachmany/i18n\n\n[![npm](https://img.shields.io/npm/v/@dan-nachmany/i18n)](https://www.npmjs.com/package/@dan-nachmany/i18n)\n\nStandalone i18n with auto key generation, pluggable storage (local / S3-compatible), and an LLM-powered translation CLI.\n\n- **Zero key bookkeeping** — write `t(\"Welcome to the app\")`, the key derives automatically from source location + string\n- **Pluggable storage** — local filesystem, AWS S3, Cloudflare R2, Backblaze B2, MinIO\n- **Pluggable translation** — Gemini included; implement `TranslationProvider` to swap in OpenAI / DeepL / Anthropic\n- **Typed errors** — `I18nConfigError`, `StorageError`, `TranslationError`\n- **Fully tested core**, strict TypeScript\n\n## Install\n\n```bash\nnpm install @danbjnbh1/i18n\n```\n\n## Quick start\n\n```ts\nimport { init, t } from \"@danbjnbh1/i18n\";\n\nawait init({\n  locale: \"fr\",\n  fallback: \"en\",\n  project: \"my-app\",\n});\n\nt(\"Welcome to the app\");                          // → \"Bienvenue dans l'application\"\nt(\"Hello {{name}}\", { name: \"Alice\" });           // → \"Bonjour Alice\"\n```\n\n## How keys are generated\n\nA key is `{file_slug}:{text_slug}`:\n\n| Component  | Rule                                                     |\n|------------|----------------------------------------------------------|\n| File slug  | strip everything up to `src/`, drop extension, `/` → `_`, lowercase |\n| Text slug  | lowercase, non-alphanumerics → `_`, max 30 chars         |\n\n```ts\n// src/pages/home.tsx\nt(\"Welcome to the app\")  // key: \"pages_home:welcome_to_the_app\"\n```\n\nThe file path is detected automatically via the call stack — no need to pass `__filename`.\n\n## Translation CLI\n\n```bash\n# Set GEMINI_API_KEY in .env, then:\nnpx i18n-translate ./src fr es ja\n```\n\nThis walks `./src`, extracts every `t(\"…\")` call, writes the source-of-truth `en.json`, and translates only missing keys for each target locale.\n\n### CLI environment variables\n\n| Variable                | Default      | Description                              |\n|-------------------------|--------------|------------------------------------------|\n| `GEMINI_API_KEY`        | *required*   | Google Gemini API key                    |\n| `I18N_PROJECT`          | `app`        | Project name (storage namespace)         |\n| `I18N_SOURCE_LOCALE`    | `en`         | Source-of-truth locale                   |\n| `I18N_STORAGE`          | `local`      | `local` or `s3`                          |\n| `LOCALES_DIR`           | `./locales`  | Local storage directory                  |\n| `I18N_RATE_LIMIT_MS`    | `200`        | Delay between provider calls             |\n| `LOG_LEVEL`             | `info`       | `debug` \\| `info` \\| `warn` \\| `error`   |\n\n### S3-compatible storage\n\n```bash\nS3_BUCKET=my-translations\nS3_ENDPOINT=https://accountid.r2.cloudflarestorage.com   # optional, e.g. R2\nS3_REGION=auto                                            # \"auto\" for R2\nAWS_ACCESS_KEY_ID=...\nAWS_SECRET_ACCESS_KEY=...\n```\n\n## Advanced usage\n\n### Multiple instances (multi-tenant servers)\n\n```ts\nimport { I18n } from \"@danbjnbh1/i18n\";\n\nconst enInstance = await I18n.create({ locale: \"en\", project: \"tenant-a\" });\nconst frInstance = await I18n.create({ locale: \"fr\", project: \"tenant-a\" });\n```\n\n### Custom storage adapter\n\n```ts\nimport { init, type Storage } from \"@danbjnbh1/i18n\";\n\nconst memoryStore: Storage = {\n  async read() { return {}; },\n  async write() {},\n};\n\nawait init({ locale: \"en\", project: \"test\", storageAdapter: memoryStore });\n```\n\n### Custom translation provider\n\n```ts\nimport type { TranslationProvider } from \"@danbjnbh1/i18n\";\n\nclass OpenAIProvider implements TranslationProvider {\n  async translate(text: string, locale: string) { /* ... */ }\n}\n```\n\n## Project layout\n\n```\nsrc/\n  index.ts              public API\n  i18n.ts               I18n class + singleton\n  config.ts, errors.ts, logger.ts, constants.ts\n  core/                 key, caller, interpolate\n  storage/              types, local, s3, factory\n  translation/          types, gemini, languages\n  cli/                  index, scanner, extractor, sync\ntests/                  vitest suites\n```\n\n## License\n\nMIT\n","readmeFilename":"README.md"}