@rustling-pines/typesafe-locale-generator
Version:
A TypeScript-based tool to generate locale JSON files for i18n frameworks with type safety. It ensures missing translations are caught during development, reducing errors and streamlining localization. Fully customizable input/output paths, compatible wit
304 lines (229 loc) β’ 9.62 kB
Markdown
A TypeScript-based tool to generate locale JSON files for i18n frameworks with type safety. It ensures missing translations are caught during development, reducing errors and streamlining localization. Fully customizable input/output paths, compatible with frameworks like React, Angular, and Vue.
- π‘ **Type Safety:** Validates translation keys and locales at development time to catch issues early.
- β
**Consistency Across Locales:** Ensures all keys are present in every locale, identifying missing translations during development.
- π **Customizable Paths:** Configure input and output directories easily using environment variables.
- π **Localized JSON Output:** Generates JSON files for each locale, ready to use with libraries like `react-i18next`, `ngx-translate`.
- π§© **Interpolation Support:** Supports placeholders like `{name}` and `{count}`, enabling dynamic runtime replacements.
- π **Automation:** Automatically generates locale files during the build step, streamlining the workflow.
- β¨ **One-Place Key Updates:** Modify a key once, and updates propagate across all locale files.
- π€ **Helper for Translation Libraries:** Works as a helper for libraries like `i18n`, adding type safety to eliminate runtime errors.
- β³ **Lazy Loading Support:** Translations are stored externally, enabling on-demand loading to reduce initial load times.
- π **Reduced Bundle Size:** Excludes translation definitions from the final bundle, keeping your app lightweight.
- π **Framework-Agnostic:** Compatible with React, Angular, Vue, and other TypeScript-based frameworks.
Install the package as a **dev dependency**:
```bash
npm install typesafe-locale-generator --save-dev
```
> β
Feel free to **create as many Message files as you want**. These files **will not be bundled** or sent to the browser.
> The **Input Directory**, where translations are defined, is used solely during the build process.
```bash
client-app/
βββ src/
β βββ translations/
β β βββ messages/
β β β βββ goodbye.msg.ts
β β β βββ login.msg.ts
β β β βββ welcome.msg.ts
β β β βββ ...
β β βββ index.ts
βββ package.json
βββ tsconfig.json
```
> π Auto Generated during build process
```bash
client-app/
βββ src/
β βββ i18n/
β β βββ locales/
β β β βββ en-us.json
β β β βββ fr.json
β β β βββ de.json
β β β βββ ...
```
You can customize the input and output paths for the locale files by setting the following variables in a .env file at the root of your project:
*This flexibility allows you to integrate the package into projects with varying directory structures.*
```bash
TRANSLATIONS_INPUT_FILE=src/translations/index.ts
LOCALES_OUTPUT_DIRECTORY=src/i18n/locales
```
> By default, the package will use the following locations if these variables are not set:
β’ *Input File*: **src/translations/index.ts**
β’ *Output Directory*: **src/i18n/locales**
```bash
"scripts": {
"build": "generate-locales && react-scripts build",
}
```
> You can define translations for each message in a dedicated folder for cleaner organization, or directly in the index.ts file for smaller projects.
You can directly provide the translations in the `index.ts` file:
**File: `src/translations/index.ts`**
```typescript
import { ITranslations } from "@rustling-pines/typesafe-locale-generator";
// 1. Define the locales for your application (JSON files will be generated for each locale).
export const locales = ['en-us', 'fr', 'de', 'es', 'jp'] as const;
// 2. Derive Type from the locales array
export type Locales = typeof locales[number];
// 3. Use the derived Locales type to enforce type safety in translations.
export const translations: ITranslations<Locales>[] = [
{
key: 'WELCOME_MESSAGE',
'en-us': 'Welcome, {name}!',
fr: 'Bienvenue, {name}!',
de: 'Willkommen, {name}!',
in: 'ΰ€Έΰ₯ΰ€΅ΰ€Ύΰ€ΰ€€ ΰ€Ήΰ₯, {name}!',
jp: '{name} γγγγγγγοΌ',
},
{
key: 'LOGIN',
'en-us': 'Login',
fr: 'Connexion',
de: 'Anmelden',
es: 'Iniciar sesiΓ³n',
jp: 'γγ°γ€γ³',
},
// ...
];
```
For better organization, you can keep translations in a `messages` folder (**or any folder of your choice**) and import them into `index.ts`:
**This approach is especially useful for large projects with extensive translations.**
**File: `src/translations/index.ts`**
```typescript
import { ITranslations } from "@rustling-pines/typesafe-locale-generator";
import { WelcomeMessage } from "./messages/welcome.msg";
import { GoodbyeMessage } from "./messages/goodbye.msg";
import { LoginMessage } from "./messages/login.msg";
// 1. Define the locales for your application (JSON files will be generated for each locale).
export const locales = ['en-us', 'fr', 'de', 'es', 'jp'] as const;
// 2. Derive Type from the locales array
export type Locales = typeof locales[number];
// 3. Use the derived Locales type to enforce type safety in translations.
export const translations: ITranslations<Locales>[] = [
WelcomeMessage,
GoodbyeMessage,
LoginMessage,
];
```
**File: `src/translations/messages/wleome.msg.ts`**
```typescript
import { ITranslations } from "@rustling-pines/typesafe-locale-generator";
import { Locales } from "..";
// {name} - placeholder
export const WelcomeMessage: ITranslations<Locales> = {
key: 'WELCOME_MESSAGE',
'en-us': 'Welcome, {name}!',
fr: 'Bienvenue, {name}!',
de: 'Willkommen, {name}!',
in: 'ΰ€Έΰ₯ΰ€΅ΰ€Ύΰ€ΰ€€ ΰ€Ήΰ₯, {name}!',
jp: '{name} γγγγγγγοΌ',
};
```
**File: `src/translations/messages/goodbye.msg.ts`**
```typescript
import { ITranslations } from "@rustling-pines/typesafe-locale-generator";
import { Locales } from "..";
export const GoodbyeMessage: ITranslations<Locales> = {
key: 'GOODBYE',
'en-us': 'Goodbye',
fr: 'Au revoir',
de: 'Auf Wiedersehen',
es: 'AdiΓ³s',
jp: 'γγγγͺγ',
};
```
**File: `src/translations/messages/login.msg.ts`**
```typescript
import { ITranslations } from "@rustling-pines/typesafe-locale-generator";
import { Locales } from "..";
export const LoginMessage: ITranslations<Locales> = {
key: 'LOGIN',
'en-us': 'Login',
fr: 'Connexion',
de: 'Anmelden',
es: 'Iniciar sesiΓ³n',
jp: 'γγ°γ€γ³',
};
```
If a locale is missing for a translation, TypeScript will throw a compile-time error. For instance, removing `jp` from the `LoginMessage` in `login.msg.ts`:
```typescript
export const LoginMessage: ITranslations<Locales> = {
key: 'LOGIN',
'en-us': 'Login',
fr: 'Connexion',
de: 'Anmelden',
es: 'Iniciar sesiΓ³n',
// jp: 'γγ°γ€γ³', // β Missing 'jp'
};
```
**Error Message:**
```typescript
Type '{ key: "LOGIN"; "en-us": string; fr: string; de: string; es: string; }' is missing the following properties from type 'ITranslations<Locales>': jp
```
This package is designed to generate JSON files from your translation definitions for **lazy loading** at runtime. The generated JSON files will not be bundled with your application, ensuring a smaller bundle size and efficient loading of translation files only when needed.
**Do not reference** the translations folder or its files directly in your project outside of the **src/translations/index.ts** Including these files elsewhere will cause them to be bundled into the application, defeating the purpose of lazy loading and increasing the bundle size.
> Below are examples of the JSON files generated for each locale. These files are structured for use with translation libraries like i18n.
```json
{
"WELCOME": "Welcome {name}",
"LOGIN": "Login",
"GOODBYE": "Goodbye"
}
```
```json
{
"WELCOME": "Bienvenue {name}",
"LOGIN": "Connexion",
"GOODBYE": "Au revoir"
}
```
```json
{
"WELCOME": "Willkommen {name}",
"LOGIN": "Anmelden",
"GOODBYE": "Auf Wiedersehen"
}
```
```json
{
"WELCOME": "Bienvenido {name}",
"LOGIN": "Iniciar sesiΓ³n",
"GOODBYE": "AdiΓ³s"
}
```
```json
{
"WELCOME": "{name} γγγγγγγοΌ",
"LOGIN": "γγ°γ€γ³",
"GOODBYE": "γγγγͺγ"
}
```
---
- **Node.js**: Version >=14.x
- **TypeScript**: Version >=4.1
Contributions are welcome! If youβd like to report a bug or suggest a feature, feel free to open an issue or submit a pull request.
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.