i18n-boost 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +838 -0
- package/bin/i18n-boost.js +5 -0
- package/dist/anthropic-6WICO575.mjs +1 -0
- package/dist/backend-F4QW23OL.mjs +1 -0
- package/dist/chunk-3V2WXULC.mjs +1 -0
- package/dist/chunk-4GJXND3H.mjs +1 -0
- package/dist/chunk-BCR6DFAS.mjs +1 -0
- package/dist/chunk-NFSRAD6K.mjs +11 -0
- package/dist/chunk-Q5SEXPLC.mjs +1 -0
- package/dist/chunk-XH7NJHX6.mjs +11 -0
- package/dist/cli.mjs +12 -0
- package/dist/deepl-N327FF46.mjs +1 -0
- package/dist/index.cjs +40 -0
- package/dist/index.d.cts +28 -0
- package/dist/index.d.ts +28 -0
- package/dist/index.mjs +13 -0
- package/dist/init-EPCKGU3C.mjs +33 -0
- package/dist/libre-translate-NQGYY2HV.mjs +1 -0
- package/dist/none-JRFHRYLI.mjs +1 -0
- package/dist/openai-O4RCRFGT.mjs +1 -0
- package/dist/server/index.cjs +219 -0
- package/dist/server/index.d.cts +50 -0
- package/dist/server/index.d.ts +50 -0
- package/dist/server/index.mjs +180 -0
- package/dist/setup/postinstall.cjs +33 -0
- package/dist/tt.cjs +1 -0
- package/dist/tt.d.cts +3 -0
- package/dist/tt.d.ts +3 -0
- package/dist/tt.mjs +1 -0
- package/locales/languages.json +72 -0
- package/package.json +90 -0
- package/schema.json +133 -0
package/README.md
ADDED
|
@@ -0,0 +1,838 @@
|
|
|
1
|
+
# i18n-boost
|
|
2
|
+
|
|
3
|
+
Automate i18n in TypeScript and JavaScript projects. Mark strings with `tt()`, run one command, and get translated locale JSON files — no manual key management, no copy-paste, no drift.
|
|
4
|
+
|
|
5
|
+
**Works with:** i18next · next-intl · Express · Fastify · NestJS · React · Next.js · Vue · any Node.js framework
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install --save-dev i18n-boost
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## How it works
|
|
14
|
+
|
|
15
|
+
1. **Mark** strings in your source code with `tt(key, defaultText)`
|
|
16
|
+
2. **Run** `npx i18n-boost generate --translate`
|
|
17
|
+
3. **Get** locale JSON files written to your output directory
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Before
|
|
21
|
+
const message = tt('auth.welcome', 'Welcome back, {{name}}!');
|
|
22
|
+
|
|
23
|
+
// After generate (src/locales/en-US.json)
|
|
24
|
+
{ "auth.welcome": "Welcome back, {{name}}!" }
|
|
25
|
+
|
|
26
|
+
// After generate (src/locales/es-ES.json)
|
|
27
|
+
{ "auth.welcome": "¡Bienvenido de nuevo, {{name}}!" }
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
i18n-boost is a **build-time tool only** — it never runs in production. Declare it as `devDependency`.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## Table of contents
|
|
35
|
+
|
|
36
|
+
- [Installation](#installation)
|
|
37
|
+
- [Backend setup](#backend-setup)
|
|
38
|
+
- [Express](#express)
|
|
39
|
+
- [Fastify](#fastify)
|
|
40
|
+
- [NestJS](#nestjs)
|
|
41
|
+
- [Frontend setup](#frontend-setup)
|
|
42
|
+
- [React + i18next (via backend)](#react--i18next--via-backend)
|
|
43
|
+
- [React + i18next (direct, CI/CD)](#react--i18next--direct-cicd)
|
|
44
|
+
- [Next.js + next-intl (SSR)](#nextjs--next-intl-ssr)
|
|
45
|
+
- [Next.js + next-intl (via backend)](#nextjs--next-intl-via-backend)
|
|
46
|
+
- [CI/CD](#cicd)
|
|
47
|
+
- [The `tt()` function](#the-tt-function)
|
|
48
|
+
- [Configuration reference](#configuration-reference)
|
|
49
|
+
- [Translation providers](#translation-providers)
|
|
50
|
+
- [Supported locales](#supported-locales)
|
|
51
|
+
- [CLI reference](#cli-reference)
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## Installation
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
# npm
|
|
59
|
+
npm install --save-dev i18n-boost
|
|
60
|
+
|
|
61
|
+
# pnpm
|
|
62
|
+
pnpm add -D i18n-boost
|
|
63
|
+
|
|
64
|
+
# yarn
|
|
65
|
+
yarn add -D i18n-boost
|
|
66
|
+
|
|
67
|
+
# bun
|
|
68
|
+
bun add -d i18n-boost
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
After install, the setup wizard runs automatically. You can also run it manually:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npx i18n-boost init
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Backend setup
|
|
80
|
+
|
|
81
|
+
In a backend project, i18n-boost extracts `tt()` keys from your source code and writes a source locale file (`en-US.json`). It also exposes a `/sync` endpoint that your frontend can call to get translations.
|
|
82
|
+
|
|
83
|
+
### Express
|
|
84
|
+
|
|
85
|
+
**1. Install and configure**
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
npx i18n-boost init
|
|
89
|
+
# Choose: Back-End
|
|
90
|
+
# Choose your translation provider
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
This creates `.i18nrc.json`:
|
|
94
|
+
|
|
95
|
+
```json
|
|
96
|
+
{
|
|
97
|
+
"type": "backend",
|
|
98
|
+
"sourceLocale": "en-US",
|
|
99
|
+
"outputDir": "src/locales",
|
|
100
|
+
"provider": { "name": "deepl" }
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
**2. Mark your strings**
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { tt } from 'i18n-boost/tt';
|
|
108
|
+
|
|
109
|
+
export function notFoundError() {
|
|
110
|
+
return tt('errors.notFound', 'Resource not found');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export function welcomeMessage(name: string) {
|
|
114
|
+
return tt('auth.welcome', 'Welcome back, {{name}}!').replace('{{name}}', name);
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
**3. Mount the sync endpoint**
|
|
119
|
+
|
|
120
|
+
```typescript
|
|
121
|
+
import express from 'express';
|
|
122
|
+
import { createI18nRouter } from 'i18n-boost/server';
|
|
123
|
+
import { createProvider } from 'i18n-boost';
|
|
124
|
+
|
|
125
|
+
const app = express();
|
|
126
|
+
|
|
127
|
+
// Only mount in development — throws in production/staging automatically
|
|
128
|
+
app.use(
|
|
129
|
+
'/api/i18n',
|
|
130
|
+
createI18nRouter({
|
|
131
|
+
provider: createProvider({ name: 'deepl' }),
|
|
132
|
+
secret: process.env.I18N_SECRET,
|
|
133
|
+
localesDir: './src/locales',
|
|
134
|
+
sourceLocale: 'en-US',
|
|
135
|
+
}),
|
|
136
|
+
);
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
> The router throws at startup if `NODE_ENV` is `production` or `staging`. It is safe to leave in your codebase — it will never run in production.
|
|
140
|
+
|
|
141
|
+
**4. Generate locale files**
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
# Extract keys only (no translation)
|
|
145
|
+
npx i18n-boost generate
|
|
146
|
+
|
|
147
|
+
# Extract and translate
|
|
148
|
+
I18NBOOST_KEY=your-key npx i18n-boost generate --translate
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Add to `package.json`:
|
|
152
|
+
|
|
153
|
+
```json
|
|
154
|
+
{
|
|
155
|
+
"scripts": {
|
|
156
|
+
"i18gen": "i18n-boost generate --translate"
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
### Fastify
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import Fastify from 'fastify';
|
|
167
|
+
import { createI18nPlugin } from 'i18n-boost/server';
|
|
168
|
+
import { createProvider } from 'i18n-boost';
|
|
169
|
+
|
|
170
|
+
const fastify = Fastify();
|
|
171
|
+
|
|
172
|
+
await fastify.register(
|
|
173
|
+
createI18nPlugin({
|
|
174
|
+
provider: createProvider({ name: 'deepl' }),
|
|
175
|
+
secret: process.env.I18N_SECRET,
|
|
176
|
+
localesDir: './src/locales',
|
|
177
|
+
sourceLocale: 'en-US',
|
|
178
|
+
}),
|
|
179
|
+
{ prefix: '/api/i18n' },
|
|
180
|
+
);
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
---
|
|
184
|
+
|
|
185
|
+
### NestJS
|
|
186
|
+
|
|
187
|
+
NestJS does not have a built-in adapter — use `handleSync` directly:
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
import { Controller, Post, Body, Headers, HttpException } from '@nestjs/common';
|
|
191
|
+
import { handleSync, I18nHandlerError } from 'i18n-boost/server';
|
|
192
|
+
import { createProvider } from 'i18n-boost';
|
|
193
|
+
|
|
194
|
+
@Controller('api/i18n')
|
|
195
|
+
export class I18nController {
|
|
196
|
+
private provider = createProvider({ name: 'deepl' });
|
|
197
|
+
|
|
198
|
+
@Post('sync')
|
|
199
|
+
async sync(
|
|
200
|
+
@Body() body: unknown,
|
|
201
|
+
@Headers('x-i18n-secret') secret?: string,
|
|
202
|
+
) {
|
|
203
|
+
try {
|
|
204
|
+
return await handleSync(body, {
|
|
205
|
+
provider: this.provider,
|
|
206
|
+
secret: process.env.I18N_SECRET,
|
|
207
|
+
localesDir: './src/locales',
|
|
208
|
+
sourceLocale: 'en-US',
|
|
209
|
+
requestSecret: secret,
|
|
210
|
+
});
|
|
211
|
+
} catch (err) {
|
|
212
|
+
if (err instanceof I18nHandlerError) {
|
|
213
|
+
throw new HttpException(err.message, err.statusCode);
|
|
214
|
+
}
|
|
215
|
+
throw err;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
Set the env var for your translation provider:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
# .env (development only)
|
|
225
|
+
I18NBOOST_KEY=your-deepl-key
|
|
226
|
+
I18N_SECRET=a-random-secret-string
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
---
|
|
230
|
+
|
|
231
|
+
## Frontend setup
|
|
232
|
+
|
|
233
|
+
In a frontend project, i18n-boost extracts `tt()` keys and either calls your backend's `/sync` endpoint for translations, or calls a translation provider directly (for SSR or CI/CD builds).
|
|
234
|
+
|
|
235
|
+
### React + i18next — via backend
|
|
236
|
+
|
|
237
|
+
Best for: React SPA where your backend handles translation. API keys never leave the server.
|
|
238
|
+
|
|
239
|
+
**1. Configure**
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
npx i18n-boost init
|
|
243
|
+
# Choose: Front-End
|
|
244
|
+
# Preset: i18next
|
|
245
|
+
# Strategy: Via backend
|
|
246
|
+
# Backend URL: http://localhost:3001/api/i18n/sync
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
`.i18nrc.json`:
|
|
250
|
+
|
|
251
|
+
```json
|
|
252
|
+
{
|
|
253
|
+
"type": "frontend",
|
|
254
|
+
"preset": "i18next",
|
|
255
|
+
"sourceLocale": "en-US",
|
|
256
|
+
"targetLocales": ["es-ES", "pt-BR", "fr-FR"],
|
|
257
|
+
"outputDir": "src/locales",
|
|
258
|
+
"provider": {
|
|
259
|
+
"name": "backend",
|
|
260
|
+
"url": "http://localhost:3001/api/i18n/sync",
|
|
261
|
+
"secret": "a-random-secret-string"
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
**2. Mark your strings**
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
import { tt } from 'i18n-boost/tt';
|
|
270
|
+
|
|
271
|
+
// In components (before transform)
|
|
272
|
+
export function SubmitButton() {
|
|
273
|
+
return <button>{tt('ui.submit', 'Submit')}</button>;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// With variables
|
|
277
|
+
const label = tt('greeting', 'Hello, {{name}}!');
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
**3. Generate**
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
npx i18n-boost generate --translate
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
This calls your backend's `/sync` endpoint and writes:
|
|
287
|
+
|
|
288
|
+
```
|
|
289
|
+
src/locales/
|
|
290
|
+
en-US.json
|
|
291
|
+
es-ES.json
|
|
292
|
+
pt-BR.json
|
|
293
|
+
fr-FR.json
|
|
294
|
+
.i18n-meta.json
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
**4. Wire up i18next** (standard setup)
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
import i18n from 'i18next';
|
|
301
|
+
import { initReactI18next } from 'react-i18next';
|
|
302
|
+
import en from './locales/en-US.json';
|
|
303
|
+
import es from './locales/es-ES.json';
|
|
304
|
+
|
|
305
|
+
i18n.use(initReactI18next).init({
|
|
306
|
+
resources: {
|
|
307
|
+
'en-US': { translation: en },
|
|
308
|
+
'es-ES': { translation: es },
|
|
309
|
+
},
|
|
310
|
+
lng: 'en-US',
|
|
311
|
+
fallbackLng: 'en-US',
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
**Compatible i18next packages:**
|
|
316
|
+
- `i18next` ≥ 23.0.0
|
|
317
|
+
- `react-i18next` ≥ 14.0.0
|
|
318
|
+
- `i18next-browser-languagedetector` ≥ 8.0.0
|
|
319
|
+
- `i18next-http-backend` ≥ 2.0.0
|
|
320
|
+
- `i18next-fs-backend` ≥ 2.0.0
|
|
321
|
+
|
|
322
|
+
---
|
|
323
|
+
|
|
324
|
+
### React + i18next — direct (CI/CD)
|
|
325
|
+
|
|
326
|
+
Best for: React apps built in CI/CD pipelines where you can set env vars. No backend needed.
|
|
327
|
+
|
|
328
|
+
**1. Configure**
|
|
329
|
+
|
|
330
|
+
```bash
|
|
331
|
+
npx i18n-boost init
|
|
332
|
+
# Choose: Front-End
|
|
333
|
+
# Preset: i18next
|
|
334
|
+
# Strategy: Direct
|
|
335
|
+
# Provider: DeepL (or any)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
`.i18nrc.json`:
|
|
339
|
+
|
|
340
|
+
```json
|
|
341
|
+
{
|
|
342
|
+
"type": "frontend",
|
|
343
|
+
"preset": "i18next",
|
|
344
|
+
"sourceLocale": "en-US",
|
|
345
|
+
"targetLocales": ["es-ES", "pt-BR", "de-DE"],
|
|
346
|
+
"outputDir": "src/locales",
|
|
347
|
+
"provider": { "name": "deepl" }
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
**2. Generate in CI/CD**
|
|
352
|
+
|
|
353
|
+
```bash
|
|
354
|
+
npx i18n-boost generate --translate
|
|
355
|
+
npm run build
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
The locale files are generated before your bundler runs — no `tt()` in the production bundle.
|
|
359
|
+
|
|
360
|
+
**With `--transform`** (recommended): rewrites `tt()` calls to `t()` before bundling:
|
|
361
|
+
|
|
362
|
+
```bash
|
|
363
|
+
npx i18n-boost generate --translate --transform
|
|
364
|
+
npm run build
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
After transform, `tt()` is gone from your source code and `i18n-boost` has zero footprint in production.
|
|
368
|
+
|
|
369
|
+
---
|
|
370
|
+
|
|
371
|
+
### Next.js + next-intl (SSR)
|
|
372
|
+
|
|
373
|
+
Best for: Next.js App Router with server-side rendering. Set env vars in `.env.local` — they stay server-side.
|
|
374
|
+
|
|
375
|
+
**1. Configure**
|
|
376
|
+
|
|
377
|
+
```bash
|
|
378
|
+
npx i18n-boost init
|
|
379
|
+
# Choose: Front-End
|
|
380
|
+
# Preset: next-intl
|
|
381
|
+
# Strategy: Direct
|
|
382
|
+
# Provider: Anthropic (or any)
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
`.i18nrc.json`:
|
|
386
|
+
|
|
387
|
+
```json
|
|
388
|
+
{
|
|
389
|
+
"type": "frontend",
|
|
390
|
+
"preset": "next-intl",
|
|
391
|
+
"sourceLocale": "en-US",
|
|
392
|
+
"targetLocales": ["es-ES", "pt-BR", "de-DE", "fr-FR"],
|
|
393
|
+
"outputDir": "src/locales",
|
|
394
|
+
"provider": {
|
|
395
|
+
"name": "anthropic",
|
|
396
|
+
"model": "claude-haiku-4-5-20251001"
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
**2. Set env var** (server-side only, safe)
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# .env.local — never exposed to the browser
|
|
405
|
+
I18NBOOST_KEY=<your-api-key>
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
**3. Mark strings in server components**
|
|
409
|
+
|
|
410
|
+
```typescript
|
|
411
|
+
import { tt } from 'i18n-boost/tt';
|
|
412
|
+
import { getTranslations } from 'next-intl/server';
|
|
413
|
+
|
|
414
|
+
export default async function HomePage() {
|
|
415
|
+
const t = await getTranslations();
|
|
416
|
+
return <h1>{t(tt('home.title', 'Welcome'))}</h1>;
|
|
417
|
+
}
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
**4. Generate** (run before `next build` or during dev)
|
|
421
|
+
|
|
422
|
+
```bash
|
|
423
|
+
npx i18n-boost generate --translate --transform
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
**5. Wire up next-intl** (standard setup)
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
// get-request-config.ts
|
|
430
|
+
import { getRequestConfig } from 'next-intl/server';
|
|
431
|
+
|
|
432
|
+
export default getRequestConfig(async ({ locale }) => ({
|
|
433
|
+
messages: (await import(`./locales/${locale}.json`)).default,
|
|
434
|
+
}));
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
```json
|
|
438
|
+
// next.config.ts
|
|
439
|
+
import createNextIntlPlugin from 'next-intl/plugin';
|
|
440
|
+
const withNextIntl = createNextIntlPlugin();
|
|
441
|
+
export default withNextIntl({});
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
**Compatible next-intl versions:** ≥ 3.0.0
|
|
445
|
+
|
|
446
|
+
---
|
|
447
|
+
|
|
448
|
+
### Next.js + next-intl — via backend
|
|
449
|
+
|
|
450
|
+
Best for: monorepos where Next.js and the backend are separate apps.
|
|
451
|
+
|
|
452
|
+
`.i18nrc.json` on the frontend:
|
|
453
|
+
|
|
454
|
+
```json
|
|
455
|
+
{
|
|
456
|
+
"type": "frontend",
|
|
457
|
+
"preset": "next-intl",
|
|
458
|
+
"sourceLocale": "en-US",
|
|
459
|
+
"targetLocales": ["es-ES", "de-DE"],
|
|
460
|
+
"outputDir": "src/locales",
|
|
461
|
+
"provider": {
|
|
462
|
+
"name": "backend",
|
|
463
|
+
"url": "http://localhost:3001/api/i18n/sync",
|
|
464
|
+
"secret": "a-random-secret-string"
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
Run on the frontend:
|
|
470
|
+
|
|
471
|
+
```bash
|
|
472
|
+
npx i18n-boost generate --translate --transform
|
|
473
|
+
```
|
|
474
|
+
|
|
475
|
+
The backend handles the API keys. The frontend never sees them.
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## CI/CD
|
|
480
|
+
|
|
481
|
+
### GitHub Actions
|
|
482
|
+
|
|
483
|
+
```yaml
|
|
484
|
+
name: Build
|
|
485
|
+
|
|
486
|
+
on: [push]
|
|
487
|
+
|
|
488
|
+
jobs:
|
|
489
|
+
build:
|
|
490
|
+
runs-on: ubuntu-latest
|
|
491
|
+
steps:
|
|
492
|
+
- uses: actions/checkout@v4
|
|
493
|
+
- uses: actions/setup-node@v4
|
|
494
|
+
with:
|
|
495
|
+
node-version: 20
|
|
496
|
+
|
|
497
|
+
- name: Install dependencies
|
|
498
|
+
run: npm ci
|
|
499
|
+
|
|
500
|
+
- name: Generate translations
|
|
501
|
+
run: npx i18n-boost generate --translate --transform
|
|
502
|
+
env:
|
|
503
|
+
I18NBOOST_KEY: ${{ secrets.I18NBOOST_KEY }}
|
|
504
|
+
|
|
505
|
+
- name: Build
|
|
506
|
+
run: npm run build
|
|
507
|
+
```
|
|
508
|
+
|
|
509
|
+
### GitLab CI
|
|
510
|
+
|
|
511
|
+
```yaml
|
|
512
|
+
build:
|
|
513
|
+
script:
|
|
514
|
+
- npm ci
|
|
515
|
+
- npx i18n-boost generate --translate --transform
|
|
516
|
+
- npm run build
|
|
517
|
+
variables:
|
|
518
|
+
I18NBOOST_KEY: $I18NBOOST_KEY # set in GitLab CI/CD settings
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
### Tip: cache locale files
|
|
522
|
+
|
|
523
|
+
If translation keys rarely change, cache `src/locales/` and only regenerate when source files change:
|
|
524
|
+
|
|
525
|
+
```yaml
|
|
526
|
+
- name: Cache locales
|
|
527
|
+
uses: actions/cache@v4
|
|
528
|
+
with:
|
|
529
|
+
path: src/locales
|
|
530
|
+
key: locales-${{ hashFiles('src/**/*.ts', 'src/**/*.tsx') }}
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
---
|
|
534
|
+
|
|
535
|
+
## The `tt()` function
|
|
536
|
+
|
|
537
|
+
`tt()` is a zero-dependency marker function (~200 bytes minified). It returns the `defaultText` at runtime and is picked up by the scanner at build time.
|
|
538
|
+
|
|
539
|
+
```typescript
|
|
540
|
+
import { tt } from 'i18n-boost/tt';
|
|
541
|
+
|
|
542
|
+
// Signature
|
|
543
|
+
tt(key: string, defaultText: string): string
|
|
544
|
+
|
|
545
|
+
// Examples
|
|
546
|
+
tt('ui.submit', 'Submit')
|
|
547
|
+
tt('errors.notFound', 'Resource not found')
|
|
548
|
+
tt('greeting', 'Hello, {{name}}!') // i18next interpolation
|
|
549
|
+
tt('greeting', 'Hello, {name}!') // next-intl interpolation
|
|
550
|
+
tt('count', '{count, plural, one {# item} other {# items}}') // ICU plurals
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
**Rules:**
|
|
554
|
+
- Both arguments must be **string literals** — no variables, no template literals
|
|
555
|
+
- Keys use dot notation: `'section.subsection.key'`
|
|
556
|
+
- The `defaultText` is your source language (usually English)
|
|
557
|
+
- `tt()` in test files is ignored by default (`**/*.test.*` is excluded)
|
|
558
|
+
|
|
559
|
+
**With `--transform`**, after running `generate --transform`, all `tt()` calls are rewritten to your i18n library's function:
|
|
560
|
+
|
|
561
|
+
```typescript
|
|
562
|
+
// Before transform
|
|
563
|
+
const label = tt('ui.submit', 'Submit');
|
|
564
|
+
|
|
565
|
+
// After transform (i18next preset)
|
|
566
|
+
const label = t('ui.submit');
|
|
567
|
+
|
|
568
|
+
// After transform (next-intl preset, server component)
|
|
569
|
+
const label = t('ui.submit');
|
|
570
|
+
```
|
|
571
|
+
|
|
572
|
+
---
|
|
573
|
+
|
|
574
|
+
## Configuration reference
|
|
575
|
+
|
|
576
|
+
Create `.i18nrc.json` at your project root (or run `npx i18n-boost init`):
|
|
577
|
+
|
|
578
|
+
```json
|
|
579
|
+
{
|
|
580
|
+
"type": "frontend",
|
|
581
|
+
"sourceLocale": "en-US",
|
|
582
|
+
"targetLocales": ["es-ES", "pt-BR", "de-DE", "fr-FR"],
|
|
583
|
+
"include": ["src/**/*.{ts,tsx}"],
|
|
584
|
+
"exclude": ["**/*.test.*", "**/*.spec.*"],
|
|
585
|
+
"outputDir": "src/locales",
|
|
586
|
+
"preset": "i18next",
|
|
587
|
+
"provider": {
|
|
588
|
+
"name": "deepl"
|
|
589
|
+
},
|
|
590
|
+
"transform": {
|
|
591
|
+
"enabled": false,
|
|
592
|
+
"importSource": "i18next",
|
|
593
|
+
"functionName": "t"
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
| Field | Type | Description |
|
|
599
|
+
|-------|------|-------------|
|
|
600
|
+
| `type` | `"backend"` \| `"frontend"` | Project type. Backend only writes source locale. Frontend writes all locales. |
|
|
601
|
+
| `sourceLocale` | `string` | BCP-47 code of the language you write in (e.g. `"en-US"`). |
|
|
602
|
+
| `targetLocales` | `string[]` | Languages to translate into. Backend type ignores this. |
|
|
603
|
+
| `include` | `string[]` | Glob patterns for files to scan. Default: `["src/**/*.{ts,tsx,js,jsx}"]`. |
|
|
604
|
+
| `exclude` | `string[]` | Glob patterns to skip. Default includes test and spec files. |
|
|
605
|
+
| `outputDir` | `string` | Where to write locale JSON files. |
|
|
606
|
+
| `preset` | `"i18next"` \| `"next-intl"` | Sets interpolation syntax and file format for the transform step. |
|
|
607
|
+
| `provider` | `object` | Translation provider config. See [Translation providers](#translation-providers). |
|
|
608
|
+
| `transform.enabled` | `boolean` | Enable rewriting `tt()` to `t()` after generation. |
|
|
609
|
+
| `transform.importSource` | `string` | Import source for the injected import. Default: `"i18next"`. |
|
|
610
|
+
| `transform.functionName` | `string` | Function name to replace `tt()` with. Default: `"t"`. |
|
|
611
|
+
|
|
612
|
+
### Alternative config locations
|
|
613
|
+
|
|
614
|
+
```js
|
|
615
|
+
// .i18nrc.js
|
|
616
|
+
module.exports = {
|
|
617
|
+
type: 'frontend',
|
|
618
|
+
sourceLocale: 'en-US',
|
|
619
|
+
// ...
|
|
620
|
+
};
|
|
621
|
+
```
|
|
622
|
+
|
|
623
|
+
```json
|
|
624
|
+
// package.json
|
|
625
|
+
{
|
|
626
|
+
"i18n-boost": {
|
|
627
|
+
"type": "frontend",
|
|
628
|
+
"sourceLocale": "en-US"
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
```
|
|
632
|
+
|
|
633
|
+
---
|
|
634
|
+
|
|
635
|
+
## Translation providers
|
|
636
|
+
|
|
637
|
+
### DeepL
|
|
638
|
+
|
|
639
|
+
Fast, high quality, free tier available (500K chars/month).
|
|
640
|
+
|
|
641
|
+
```json
|
|
642
|
+
{ "provider": { "name": "deepl" } }
|
|
643
|
+
```
|
|
644
|
+
|
|
645
|
+
```bash
|
|
646
|
+
export I18NBOOST_KEY=<your-api-key>
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
Requires: `npm install --save-dev` (no extra packages — uses native `fetch`)
|
|
650
|
+
|
|
651
|
+
---
|
|
652
|
+
|
|
653
|
+
### OpenAI-compatible API
|
|
654
|
+
|
|
655
|
+
Works with OpenAI, DeepSeek, Groq, Mistral, Ollama, and any OpenAI-compatible endpoint.
|
|
656
|
+
|
|
657
|
+
```json
|
|
658
|
+
{ "provider": { "name": "openai", "model": "gpt-4o-mini" } }
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
```bash
|
|
662
|
+
export I18NBOOST_KEY=your-api-key
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Requires: `npm install --save-dev openai`
|
|
666
|
+
|
|
667
|
+
**Custom endpoints:**
|
|
668
|
+
|
|
669
|
+
```json
|
|
670
|
+
// DeepSeek
|
|
671
|
+
{ "provider": { "name": "openai", "model": "deepseek-chat", "baseUrl": "https://api.deepseek.com" } }
|
|
672
|
+
|
|
673
|
+
// Groq
|
|
674
|
+
{ "provider": { "name": "openai", "model": "llama-3.1-8b-instant", "baseUrl": "https://api.groq.com/openai/v1" } }
|
|
675
|
+
|
|
676
|
+
// Ollama (local, no key needed)
|
|
677
|
+
{ "provider": { "name": "openai", "model": "llama3", "baseUrl": "http://localhost:11434/v1" } }
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
---
|
|
681
|
+
|
|
682
|
+
### Anthropic
|
|
683
|
+
|
|
684
|
+
Claude models — excellent at preserving interpolation markers and ICU syntax.
|
|
685
|
+
|
|
686
|
+
```json
|
|
687
|
+
{ "provider": { "name": "anthropic", "model": "claude-haiku-4-5-20251001" } }
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
export I18NBOOST_KEY=<your-api-key>
|
|
692
|
+
```
|
|
693
|
+
|
|
694
|
+
Requires: `npm install --save-dev @anthropic-ai/sdk`
|
|
695
|
+
|
|
696
|
+
---
|
|
697
|
+
|
|
698
|
+
### LibreTranslate
|
|
699
|
+
|
|
700
|
+
Open source, self-hosted. No API key required for local instances.
|
|
701
|
+
|
|
702
|
+
```json
|
|
703
|
+
{ "provider": { "name": "libre-translate", "apiUrl": "http://localhost:5000" } }
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
No env var required. Run locally with Docker:
|
|
707
|
+
|
|
708
|
+
```bash
|
|
709
|
+
docker run -ti --rm -p 5000:5000 libretranslate/libretranslate
|
|
710
|
+
```
|
|
711
|
+
|
|
712
|
+
---
|
|
713
|
+
|
|
714
|
+
### Backend (frontend only)
|
|
715
|
+
|
|
716
|
+
Frontend delegates translation to your own backend. API keys stay server-side.
|
|
717
|
+
|
|
718
|
+
```json
|
|
719
|
+
{
|
|
720
|
+
"provider": {
|
|
721
|
+
"name": "backend",
|
|
722
|
+
"url": "http://localhost:3001/api/i18n/sync",
|
|
723
|
+
"secret": "a-random-secret-string"
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
```
|
|
727
|
+
|
|
728
|
+
No env var needed on the frontend. The backend holds the provider keys.
|
|
729
|
+
|
|
730
|
+
---
|
|
731
|
+
|
|
732
|
+
### None
|
|
733
|
+
|
|
734
|
+
Extracts keys and writes source locale only. Useful when setting up or in environments without API keys.
|
|
735
|
+
|
|
736
|
+
```json
|
|
737
|
+
{ "provider": { "name": "none" } }
|
|
738
|
+
```
|
|
739
|
+
|
|
740
|
+
---
|
|
741
|
+
|
|
742
|
+
## Supported locales
|
|
743
|
+
|
|
744
|
+
30 BCP-47 codes supported:
|
|
745
|
+
|
|
746
|
+
| Code | Language |
|
|
747
|
+
|------|----------|
|
|
748
|
+
| `en-US` | English (US) |
|
|
749
|
+
| `en-GB` | English (UK) |
|
|
750
|
+
| `es-ES` | Spanish (Spain) |
|
|
751
|
+
| `es-419` | Spanish (Latin America) |
|
|
752
|
+
| `pt-BR` | Portuguese (Brazil) |
|
|
753
|
+
| `pt-PT` | Portuguese (Portugal) |
|
|
754
|
+
| `fr-FR` | French |
|
|
755
|
+
| `fr-CA` | French (Canada) |
|
|
756
|
+
| `de-DE` | German |
|
|
757
|
+
| `it-IT` | Italian |
|
|
758
|
+
| `nl-NL` | Dutch |
|
|
759
|
+
| `zh-CN` | Chinese (Simplified) |
|
|
760
|
+
| `zh-TW` | Chinese (Traditional) |
|
|
761
|
+
| `ja-JP` | Japanese |
|
|
762
|
+
| `ko-KR` | Korean |
|
|
763
|
+
| `ar-SA` | Arabic |
|
|
764
|
+
| `hi-IN` | Hindi |
|
|
765
|
+
| `ru-RU` | Russian |
|
|
766
|
+
| `tr-TR` | Turkish |
|
|
767
|
+
| `id-ID` | Indonesian |
|
|
768
|
+
| `vi-VN` | Vietnamese |
|
|
769
|
+
| `th-TH` | Thai |
|
|
770
|
+
| `pl-PL` | Polish |
|
|
771
|
+
| `sv-SE` | Swedish |
|
|
772
|
+
| `da-DK` | Danish |
|
|
773
|
+
| `nb-NO` | Norwegian |
|
|
774
|
+
| `fi-FI` | Finnish |
|
|
775
|
+
| `cs-CZ` | Czech |
|
|
776
|
+
| `ro-RO` | Romanian |
|
|
777
|
+
| `uk-UA` | Ukrainian |
|
|
778
|
+
|
|
779
|
+
---
|
|
780
|
+
|
|
781
|
+
## CLI reference
|
|
782
|
+
|
|
783
|
+
```bash
|
|
784
|
+
npx i18n-boost --help
|
|
785
|
+
```
|
|
786
|
+
|
|
787
|
+
### `npx i18n-boost init`
|
|
788
|
+
|
|
789
|
+
Interactive wizard. Creates `.i18nrc.json` in the current directory.
|
|
790
|
+
|
|
791
|
+
```bash
|
|
792
|
+
npx i18n-boost init
|
|
793
|
+
npx i18n-boost init --cwd /path/to/project
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
### `npx i18n-boost generate`
|
|
797
|
+
|
|
798
|
+
Extract `tt()` keys from source files, write locale JSON files.
|
|
799
|
+
|
|
800
|
+
```bash
|
|
801
|
+
npx i18n-boost generate # extract only, no translation
|
|
802
|
+
npx i18n-boost generate --translate # extract + translate
|
|
803
|
+
npx i18n-boost generate --translate --transform # extract + translate + rewrite tt() calls
|
|
804
|
+
npx i18n-boost generate --dry-run # preview without writing files
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
| Flag | Description |
|
|
808
|
+
|------|-------------|
|
|
809
|
+
| `--translate` | Call the configured provider to translate new/changed strings |
|
|
810
|
+
| `--no-translate` | Skip translation — only write source locale JSON (default) |
|
|
811
|
+
| `--dry-run` | Preview what would change without writing any files |
|
|
812
|
+
| `--transform` | Rewrite `tt()` calls to `t()` (or configured `functionName`) after generating |
|
|
813
|
+
| `--cwd <dir>` | Working directory (default: `process.cwd()`) |
|
|
814
|
+
|
|
815
|
+
### `npx i18n-boost scan`
|
|
816
|
+
|
|
817
|
+
List all `tt()` keys found in source files. No files written.
|
|
818
|
+
|
|
819
|
+
```bash
|
|
820
|
+
npx i18n-boost scan
|
|
821
|
+
```
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
## Environment variables
|
|
826
|
+
|
|
827
|
+
| Variable | Used by | Notes |
|
|
828
|
+
|----------|---------|-------|
|
|
829
|
+
| `I18NBOOST_KEY` | `anthropic`, `openai`, `deepl`, `libre-translate` | API key for the configured translation provider |
|
|
830
|
+
| `I18N_SECRET` | server endpoint | Shared secret between frontend and backend |
|
|
831
|
+
|
|
832
|
+
API keys are **never stored** in `.i18nrc.json`. Always read from environment variables at generate time.
|
|
833
|
+
|
|
834
|
+
---
|
|
835
|
+
|
|
836
|
+
## License
|
|
837
|
+
|
|
838
|
+
MIT
|