https://github.com/weprodev/ui-localization
A lightweight, professional localization package for React and React Native applications built on top of i18next and react-i18next. This package provides a clean, type-safe API for managing translations with built-in language switching, variable injection, and component interpolation capabilities.
https://github.com/weprodev/ui-localization
localization react react-native reactjs translation translation-package ui-localization
Last synced: 11 days ago
JSON representation
A lightweight, professional localization package for React and React Native applications built on top of i18next and react-i18next. This package provides a clean, type-safe API for managing translations with built-in language switching, variable injection, and component interpolation capabilities.
- Host: GitHub
- URL: https://github.com/weprodev/ui-localization
- Owner: weprodev
- Created: 2025-08-25T05:12:39.000Z (5 months ago)
- Default Branch: develop
- Last Pushed: 2025-12-31T10:36:29.000Z (23 days ago)
- Last Synced: 2026-01-04T15:31:37.430Z (18 days ago)
- Topics: localization, react, react-native, reactjs, translation, translation-package, ui-localization
- Language: TypeScript
- Homepage: https://www.npmjs.com/package/@weprodev/ui-localization
- Size: 176 KB
- Stars: 5
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# @weprodev/ui-localization
A lightweight, professional localization package for React and React Native applications built on top of i18next and react-i18next. This package provides a clean, type-safe API for managing translations with built-in language switching, variable injection, and component interpolation capabilities.
## โจ Features
- ๐ **Simple React Hooks** - Clean, intuitive hooks for translations and language management
- ๐ **Language Switching** - Built-in language switching with persistence
- ๐ **Type-Safe Variable Injection** - Dynamic content insertion with compile-time parameter validation
- ๐งฉ **Unified Component Interpolation** - Embed React components within translations using the same `t` function
- ๐ **Translation Validation** - CLI tools to ensure translation consistency
- ๐ **Translation Sync** - Automated synchronization of translation files
- ๐ฑ **React Native Support** - Full compatibility with React Native applications
- ๐ก๏ธ **Full Type Safety** - TypeScript support with type-safe keys, parameters, and component interpolation
- โก **Performance Optimized** - Lightweight wrapper with minimal overhead
## ๐ฆ Installation
```bash
npm install @weprodev/ui-localization
```
## ๐ Quick Start
### React Applications
#### 1. Create Translation Files
Create a `translations` directory in your project with language files. **Important:** Use `as const` to enable type-safe parameter validation:
```typescript
// translations/en.ts
const en = {
common: {
hello: "Hello {{name}}!",
welcome: "Welcome {{name}}!",
goodbye: "Goodbye {{name}}!",
greeting: "Hello, {{name}}!"
},
auth: {
login: "Login",
signup: "Sign Up",
forgotPassword: "Forgot Password",
welcomeMessage: "Welcome {{name}}! Please sign in to continue."
},
dashboard: {
title: "Dashboard",
summary: "Summary",
recentActivity: "Recent Activity"
}
} as const;
export default en;
```
```typescript
// translations/es.ts
const es = {
common: {
hello: "Hola {{name}}!",
welcome: "Bienvenido {{name}}!",
goodbye: "Adiรณs {{name}}!",
greeting: "ยกHola, {{name}}!"
},
auth: {
login: "Iniciar sesiรณn",
signup: "Registrarse",
forgotPassword: "Contraseรฑa olvidada",
welcomeMessage: "Bienvenido {{name}}! Por favor inicia sesiรณn para continuar."
},
dashboard: {
title: "Panel de control",
summary: "Resumen",
recentActivity: "Actividad reciente"
}
} as const;
export default es;
```
#### 2. Create Localization Configuration
```typescript
// src/localizationConfig.ts
import { LocalizationConfig, LanguageStore } from '@weprodev/ui-localization';
import en from '../translations/en';
import es from '../translations/es';
// Optional: Create a custom language store for persistence
class CustomLanguageStore implements LanguageStore {
getLanguage(): string | null {
return localStorage.getItem("app-language") || null;
}
setLanguage(language: string): void {
localStorage.setItem("app-language", language);
}
}
export const localizationConfig: LocalizationConfig = {
resources: {
en: { translation: en },
es: { translation: es }
},
fallbackLng: 'en',
languageStore: new CustomLanguageStore()
};
```
#### 3. Initialize Localization
```typescript
// src/index.tsx
import React, { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { initLocalization } from '@weprodev/ui-localization';
import { localizationConfig } from './localizationConfig';
import App from './App';
const rootElement = document.getElementById('root');
// Initialize localization before rendering the app
initLocalization(localizationConfig).then(() => {
ReactDOM.createRoot(rootElement).render(
);
});
```
#### 4. Use Translations in Components
```typescript
// src/components/Welcome.tsx
import React from 'react';
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
const Welcome: React.FC<{ name: string }> = ({ name }) => {
// Type-safe translation hook with path-based keys
const { t } = useTranslation();
return (
{/* TypeScript requires 'name' parameter because translation has {{name}} placeholder */}
{t('common.welcome', { name })}
{t('common.hello', { name })}
{/* TypeScript will error if you use invalid keys like t('common.invalid') */}
{/* TypeScript will error if you forget required parameters */}
);
};
export default Welcome;
```
**Alternative: Create a custom hook for better reusability**
```typescript
// src/hooks/useAppTranslation.ts
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
export const useAppTranslation = () => {
return useTranslation();
};
// Usage in components
import { useAppTranslation } from '../hooks/useAppTranslation';
const Welcome: React.FC = () => {
const { t } = useAppTranslation();
return (
{t('common.welcome')}
{/* Full intellisense and type safety */}
{t('common.hello')}
{/* t('common.invalid') will show TypeScript error */}
);
};
```
**Important:** For type-safe parameter validation to work, your translation files must use `as const`. This ensures TypeScript preserves literal string types, allowing the system to extract parameter names from placeholders like `{{name}}`.
**Troubleshooting:** If you encounter TypeScript errors with the type-safe hook, you can use `useTranslationFallback()` as an escape hatch. See the API Reference for details.
#### 5. Language Switching
```typescript
// src/components/LanguageSwitcher.tsx
import React from 'react';
import { useLanguage } from '@weprodev/ui-localization';
const LanguageSwitcher: React.FC = () => {
const { currentLanguage, changeLanguage, availableLanguages } = useLanguage();
return (
changeLanguage(e.target.value)}
>
{availableLanguages.map(lang => (
{lang.toUpperCase()}
))}
);
};
export default LanguageSwitcher;
```
### React Native Applications
#### 1. Create Translation Files
Same structure as React applications (see above).
#### 2. Create Localization Configuration
```typescript
// src/localizationConfig.ts
import { LocalizationConfig, LanguageStore } from '@weprodev/ui-localization';
import AsyncStorage from '@react-native-async-storage/async-storage';
import en from '../translations/en';
import es from '../translations/es';
// React Native language store using AsyncStorage
class ReactNativeLanguageStore implements LanguageStore {
async getLanguage(): Promise {
try {
return await AsyncStorage.getItem("app-language");
} catch {
return null;
}
}
async setLanguage(language: string): Promise {
try {
await AsyncStorage.setItem("app-language", language);
} catch {
// Handle storage error silently
}
}
}
export const localizationConfig: LocalizationConfig = {
resources: {
en: { translation: en },
es: { translation: es }
},
fallbackLng: 'en',
languageStore: new ReactNativeLanguageStore()
};
```
#### 3. Initialize Localization
```typescript
// src/App.tsx
import React, { useEffect, useState } from 'react';
import { View, Text } from 'react-native';
import { initLocalization } from '@weprodev/ui-localization';
import { localizationConfig } from './localizationConfig';
const App: React.FC = () => {
const [isInitialized, setIsInitialized] = useState(false);
useEffect(() => {
initLocalization(localizationConfig).then(() => {
setIsInitialized(true);
});
}, []);
if (!isInitialized) {
return (
Loading...
);
}
return (
{/* Your app content */}
);
};
export default App;
```
#### 4. Use Translations in React Native Components
```typescript
// src/components/Welcome.tsx
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
const Welcome: React.FC<{ name: string }> = ({ name }) => {
// Type-safe translation hook with path-based keys
const { t } = useTranslation();
return (
{t('common.welcome', { name })}
{t('common.hello', { name })}
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
padding: 20,
},
title: {
fontSize: 24,
fontWeight: 'bold',
marginBottom: 10,
},
subtitle: {
fontSize: 16,
color: '#666',
},
});
export default Welcome;
```
#### 5. Language Switching in React Native
```typescript
// src/components/LanguageSwitcher.tsx
import React from 'react';
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
import { useLanguage } from '@weprodev/ui-localization';
const LanguageSwitcher: React.FC = () => {
const { currentLanguage, changeLanguage, availableLanguages } = useLanguage();
return (
Language:
{availableLanguages.map(lang => (
changeLanguage(lang)}
>
{lang.toUpperCase()}
))}
);
};
const styles = StyleSheet.create({
container: {
padding: 20,
},
label: {
fontSize: 16,
fontWeight: 'bold',
marginBottom: 10,
},
buttonContainer: {
flexDirection: 'row',
gap: 10,
},
button: {
paddingHorizontal: 16,
paddingVertical: 8,
borderRadius: 4,
borderWidth: 1,
borderColor: '#ddd',
},
activeButton: {
backgroundColor: '#007AFF',
borderColor: '#007AFF',
},
buttonText: {
fontSize: 14,
color: '#333',
},
activeButtonText: {
color: '#fff',
},
});
export default LanguageSwitcher;
```
## ๐ง Advanced Usage
### Translation with Variables (Type-Safe Parameters)
The `t` function enforces type-safe parameters based on placeholders in your translation strings. Parameters are **required** when placeholders exist, and **optional** when they don't.
```typescript
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
const Greeting: React.FC<{ name: string }> = ({ name }) => {
const { t } = useTranslation();
// Translation: "common.greeting": "Hello, {{name}}!"
// โ
TypeScript requires the 'name' parameter
const greeting = t('common.greeting', { name });
// โ TypeScript error: missing required parameter 'name'
// const greeting = t('common.greeting');
// โ TypeScript error: wrong parameter name
// const greeting = t('common.greeting', { wrongName: name });
// โ
No parameters needed for translations without placeholders
const title = t('dashboard.title');
return
{greeting}
;
};
```
### Translation with Component Interpolation
The unified `t` function supports both string and component interpolation. When you pass a `components` object as the third argument, it returns a React element instead of a string.
```typescript
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
const WelcomeMessage: React.FC<{ name: string }> = ({ name }) => {
const { t } = useTranslation();
// Translation: "auth.welcomeMessage": "Welcome {{name}}! Please sign in to continue."
// The translation string must contain matching HTML-like tags (, , etc.)
const welcomeElement = t(
'auth.welcomeMessage',
{ name },
{
strong: ,
link: (props: { children?: React.ReactNode }) => (
{props.children}
)
}
);
// Returns JSX.Element when components are provided
return {welcomeElement};
};
```
**Important Notes:**
- Component interpolation only works when the translation string contains matching HTML-like tags (e.g., ``, ``)
- The component keys in your `components` object must match the tag names in the translation
- For self-closing tags like ``, use self-closing components
- For tags with content like `text`, use function components that accept `props.children`
### Usage Outside React Components
For utility functions or other non-component files where hooks are not available, you can use `createTranslation` to get a type-safe `t` function.
```typescript
import { createTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
// Create a standalone translation function
const t = createTranslation();
// Basic usage - Returns string
const greeting = t('common.hello');
// With parameters - Returns string
const message = t('common.welcome', { name: 'World' });
// With components - Returns JSX.Element
// Useful for creating localized constants with React elements
const content = t('common.info', undefined, {
link: More
});
```
## ๐ ๏ธ Translation Management Tools
The package includes powerful CLI tools to help manage your translations. You can use these tools in multiple ways:
### Option 1: Using NPM Scripts (Recommended)
Add these commands to your project's `package.json` scripts:
```json
{
"scripts": {
"translation:validate": "wpd-translation-validate --dir ./translations --source en",
"translation:sync": "wpd-translation-sync --dir ./translations --source en"
}
}
```
Then run:
```bash
npm run translation:validate
npm run translation:sync
```
**Customizing paths:**
Modify the scripts in your `package.json` to use different directories or source language:
```json
{
"scripts": {
"translation:validate": "wpd-translation-validate --dir ./src/translations --source es",
"translation:sync": "wpd-translation-sync --dir ./src/translations --source es"
}
}
```
### Option 2: Using npx (Direct CLI)
Run the CLI tools directly via npx:
```bash
# Validate translations
npx wpd-translation-validate --dir ./translations --source en
# Sync translations
npx wpd-translation-sync --dir ./translations --source en
```
### What These Tools Do
**Validate Translations** (`validate-translations`)
- Checks if all language files have the same keys as the source language
- Reports missing keys for each language file
- Exits with error code if inconsistencies are found
- Perfect for CI/CD integration
**Sync Translations** (`sync-translations`)
- Adds missing keys from the source language to all other language files
- Preserves existing translations
- Sets empty string values for new keys (ready for translation)
- Updates translation files automatically
### CI/CD Integration
We recommend running `translation:validate` as part of your CI pipeline to ensure translation consistency:
```yaml
# .github/workflows/ci.yml
- name: Validate Translations
run: npm run translation:validate
```
## ๐ API Reference
### Hooks
#### `useTranslation()`
Returns a type-safe translation function with intellisense support and type-safe parameter validation.
**Parameters:**
- None (the translation object type `T` is provided as a generic parameter for type safety)
**Returns:** Object with `t` function that accepts type-safe translation keys
**The `t` function supports two modes:**
1. **String interpolation** (returns `string`):
```typescript
import en from '../translations/en';
const { t } = useTranslation();
// No parameters needed for translations without placeholders
const title = t('dashboard.title'); // โ
Returns string
// Parameters required when placeholders exist
const greeting = t('common.greeting', { name: 'John' }); // โ
Returns string
const greeting = t('common.greeting'); // โ TypeScript error: missing required parameter
```
2. **Component interpolation** (returns `JSX.Element`):
```typescript
// Pass components as third argument
const welcomeElement = t(
'auth.welcomeMessage',
{ name: 'Alice' },
{
strong: ,
link: (props) => {props.children}
}
); // โ
Returns JSX.Element
```
**Type-Safe Parameters:**
- Parameters are **required** when the translation string contains placeholders like `{{name}}`
- Parameters are **optional** when the translation has no placeholders
- TypeScript validates parameter names match the placeholders in the translation
**Note:** For better reusability, consider creating a custom hook:
```typescript
// src/hooks/useAppTranslation.ts
import { useTranslation } from '@weprodev/ui-localization';
import en from '../translations/en';
export const useAppTranslation = () => {
return useTranslation();
};
// Usage
const { t } = useAppTranslation();
const text = t('common.welcome', { name: 'User' }); // Full type safety and intellisense
```
#### `useLanguage()`
Provides language management functionality.
```typescript
const { currentLanguage, changeLanguage, availableLanguages } = useLanguage();
```
#### `useTranslationFallback()`
**โ ๏ธ Escape hatch hook - use only when the main `useTranslation` hook has TypeScript issues.**
Returns the raw i18next translation function without type safety. This should only be used in rare edge cases where the type-safe hook encounters problems.
```typescript
// Only use when useTranslation has TypeScript errors
const t = useTranslationFallback();
const text = t('common.hello'); // No type safety - standard i18next usage
const withVars = t('greeting', { name: 'John' });
```
**Note:** The main `useTranslation` hook should be preferred in 99% of cases.
### Core Functions
#### `initLocalization(config)`
Initializes the localization system.
```typescript
await initLocalization({
resources: { en: { translation: enTranslations } },
fallbackLng: 'en',
languageStore: new CustomLanguageStore()
});
```
### Types
#### `LanguageStore`
Interface for custom language storage implementations.
```typescript
interface LanguageStore {
getLanguage(): string | null;
setLanguage(language: string): void;
}
```
#### `LocalizationConfig`
Configuration object for localization initialization.
```typescript
interface LocalizationConfig {
resources: Resource;
fallbackLng?: string;
compatibilityJSON?: "v4";
interpolation?: {
escapeValue?: boolean;
};
languageStore?: LanguageStore;
}
```
#### `ComponentMap`
Type for component interpolation map. Supports both React elements and function components.
```typescript
type ComponentMap = {
[key: string]:
| React.ReactElement
| ((props: { children?: React.ReactNode; [key: string]: any }) => React.ReactElement)
}
```
#### `TranslateFunction`
Type definition for the type-safe translation function.
```typescript
type TranslateFunction
```
#### `UseTranslationReturn`
Return type of the `useTranslation` hook.
```typescript
interface UseTranslationReturn {
t: TranslateFunction;
}
```
#### `NestedRecord`
Base type for translation resources, allowing recursive nesting of primitive values.
```typescript
type NestedRecord = {
[key: string]: string | number | boolean | null | undefined | NestedRecord
};
```
## ๐ Support
For support, bug reports, or feature requests, please contact the WeProDev team or create an issue in our internal repository.
## ๐ License
This project is licensed under the MIT License.
## ๐ Links
- [i18next Documentation](https://www.i18next.com/)
- [react-i18next Documentation](https://react.i18next.com/)
---
**@weprodev/ui-localization** - Professional localization solution by WeProDev