npm package: @jamx-framework/i18n
Description: JAMX Framework â€” Internationalization
Author: Stiven-21
Latest version: 1.0.0

# @jamx-framework/i18n

## Descripción
Módulo de internacionalización (i18n) para JAMX Framework. Proporciona una API completa para gestionar múltiples idiomas en aplicaciones, incluyendo carga de traducciones, detección automática del idioma del usuario, interpolación de variables y formateo de mensajes. Soporta múltiples estrategias de detección de idioma (headers, cookies, query params) y es completamente type-safe.

## Cómo funciona
El módulo implementa un sistema de traducción modular:

1. **I18n**: Clase principal que gestiona el idioma actual, las traducciones cargadas y la interpolación
2. **Loaders**: Cargadores de traducciones desde diferentes fuentes (JSON, API, etc.)
3. **Resolvers**: Estrategias para detectar el idioma preferido del usuario (Accept-Language, cookie, query param)
4. **Interpolación**: Reemplazo de variables en mensajes con formato y pluralización

## Componentes principales
- **src/i18n.ts**: Clase `I18n` que gestiona traducciones y cambio de idioma
- **src/interpolate.ts**: Funciones de interpolación y formateo
- **src/loaders/json-loader.ts**: Cargador de traducciones desde archivos JSON
- **src/resolvers/accept-language.ts**: Detector por header Accept-Language
- **src/resolvers/cookie.ts**: Detector por cookie
- **src/resolvers/header.ts**: Detector por header personalizado
- **src/resolvers/query.ts**: Detector por query parameter
- **src/types.ts**: Tipos compartidos (Translation, Locale, etc.)
- **src/index.ts**: Punto de exportación

## Uso básico
```typescript
import { I18n, JsonLoader, AcceptLanguageResolver } from '@jamx-framework/i18n';

// 1. Crear instancia de I18n
const i18n = new I18n({
  defaultLocale: 'en',
  fallbackLocale: 'en',
  loaders: [new JsonLoader('./locales')],
  resolvers: [new AcceptLanguageResolver()],
});

// 2. Cargar traducciones
await i18n.load('en', { welcome: 'Welcome' });
await i18n.load('es', { welcome: 'Bienvenido' });

// 3. Establecer idioma
i18n.setLocale('es');

// 4. Traducir
console.log(i18n.t('welcome')); // 'Bienvenido'

// 5. Interpolar variables
console.log(i18n.t('greeting', { name: 'Juan' })); // 'Hello, Juan' (en) / 'Hola, Juan' (es)
```

## Ejemplos
### Estructura de archivos de traducción
```
locales/
  en.json
  es.json
  fr.json
```

**en.json**:
```json
{
  "welcome": "Welcome, {{name}}!",
  "items": "{{count}} item",
  "items_plural": "{{count}} items"
}
```

**es.json**:
```json
{
  "welcome": "¡Bienvenido, {{name}}!",
  "items": "{{count}} artículo",
  "items_plural": "{{count}} artículos"
}
```

### Uso con interpolación y pluralización
```typescript
// Interpolación simple
i18n.t('welcome', { name: 'Ana' }); // '¡Bienvenido, Ana!'

// Pluralización
i18n.t('items', { count: 1 }); // '1 artículo' (es)
i18n.t('items', { count: 5 }); // '5 artículos' (es)

// Formato de fechas y números
i18n.formatDate(new Date(), { locale: 'es' }); // '15/03/2024'
i18n.formatNumber(1234.56, { style: 'currency', currency: 'EUR' }); // '1.234,56 €'
```

### Detección automática de idioma
```typescript
// Con Accept-Language header
const resolver = new AcceptLanguageResolver();
const locale = await resolver.resolve(req.headers['accept-language']);
// locale = 'es-ES,es;q=0.9,en;q=0.8'

// Con cookie
const cookieResolver = new CookieResolver('locale');
const locale = await cookieResolver.resolve(req.headers.cookie);
// locale = 'es'

// Con query param
const queryResolver = new QueryResolver('lang');
const locale = await queryResolver.resolve(req.query);
// locale = 'en'
```

### Middleware para Express/JAMX Server
```typescript
import { I18nMiddleware } from '@jamx-framework/i18n';

const i18nMiddleware = I18nMiddleware({
  defaultLocale: 'en',
  loaders: [new JsonLoader('./locales')],
  resolvers: [new AcceptLanguageResolver(), new CookieResolver('locale')],
});

server.use(i18nMiddleware);

// En el handler:
server.get('/hello', (req, res) => {
  const locale = req.locals.locale; // 'es', 'en', etc.
  const t = req.locals.t; // función de traducción
  
  res.json({ message: t('welcome', { name: 'User' }) });
});
```

### Carga perezosa (lazy) de traducciones
```typescript
// Cargar solo cuando se necesite
await i18n.loadIfNeeded('fr'); // Descarga fr.json si no está cargado

// Verificar si un idioma está cargado
if (i18n.isLoaded('de')) {
  console.log('Traducciones alemanas disponibles');
}
```

### Namespaces (módulos de traducción)
```typescript
// Cargar traducciones por namespace
await i18n.load('en', {
  auth: { login: 'Login', logout: 'Logout' },
  dashboard: { welcome: 'Welcome to dashboard' },
});

// Usar namespace
i18n.t('auth.login'); // 'Login'
i18n.t('dashboard.welcome'); // 'Welcome to dashboard'
```

### Cambio de idioma dinámico
```typescript
// Cambiar idioma en runtime
i18n.setLocale('fr');

// Escuchar cambios de idioma
i18n.onLocaleChange((newLocale) => {
  console.log(`Idioma cambiado a: ${newLocale}`);
  // Actualizar UI, recargar componentes, etc.
});
```

## Flujo interno
1. **Inicialización**: Se crea `I18n` con loaders, resolvers y configuración
2. **Detección**: Los resolvers examinan la request (headers, cookies, query) para determinar el idioma
3. **Carga**: Los loaders cargan traducciones desde archivos o APIs
4. **Cache**: Las traducciones se cachean en memoria para acceso rápido
5. **Interpolación**: `t()` reemplaza variables y aplica pluralización
6. **Formateo**: Funciones auxiliares para fechas, números, monedas
7. **Fallback**: Si una clave no existe, se busca en el idioma fallback

## API Reference (Resumen)
### I18n
- `constructor(config: I18nConfig)`
- `async load(locale: string, translations: Translation | Promise<Translation>): Promise<void>`
- `async loadIfNeeded(locale: string): Promise<boolean>`
- `setLocale(locale: string): void`
- `getLocale(): string`
- `t(key: string, params?: Record<string, any>): string`
- `has(key: string): boolean`
- `isLoaded(locale: string): boolean`
- `formatDate(date: Date, options?: Intl.DateTimeFormatOptions): string`
- `formatNumber(value: number, options?: Intl.NumberFormatOptions): string`
- `onLocaleChange(callback: (locale: string) => void): () => void`

### Loaders
- `JsonLoader(basePath: string)`
- `ApiLoader(endpoint: string)`
- `FileLoader(path: string)`

### Resolvers
- `AcceptLanguageResolver()`
- `CookieResolver(cookieName: string)`
- `HeaderResolver(headerName: string)`
- `QueryResolver(paramName: string)`

### I18nMiddleware
- `I18nMiddleware(config): Middleware`
- Añade `req.locals.locale` y `req.locals.t`

## Performance Considerations
- **Lazy loading**: Las traducciones se cargan solo cuando se necesitan
- **Caching**: Las traducciones se mantienen en memoria después de cargar
- **Tree-shaking**: Solo se incluyen los idiomas usados en el build
- **Compression**: Los archivos JSON de traducción pueden comprimirse

## Configuration
```typescript
const i18n = new I18n({
  defaultLocale: 'en',
  fallbackLocale: 'en',
  loaders: [new JsonLoader('./locales')],
  resolvers: [new AcceptLanguageResolver()],
  interpolation: {
    prefix: '{{',
    suffix: '}}',
  },
  missingKeyHandler: (key, locale) => {
    console.warn(`Missing translation: ${key} in ${locale}`);
    return key; // devolver la clave como fallback
  },
});
```

## Testing
Tests en `packages/i18n/tests/unit/`:

```bash
pnpm test
```

Cubre:
- Carga de traducciones desde JSON
- Detección de idioma por headers, cookies, query
- Interpolación de variables
- Pluralización
- Formateo de fechas y números
- Fallbacks y missing keys

## Compatibility
- Compatible con Node.js 18+ y navegadores
- Funciona con ICU MessageFormat para pluralización
- Soporta todos los idiomas de Unicode
- No requiere dependencias nativas

## CLI Integration
- `jamx i18n:extract`: Extrae claves de traducción del código fuente
- `jamx i18n:compile`: Compila archivos de traducción a formato optimizado
- `jamx i18n:add <locale>`: Añade nuevo idioma
- `jamx i18n:missing`: Lista claves faltantes por idioma

## Best Practices
1. **Usar keys descriptivas**: `auth.login.title` en lugar de `login_title`
2. **Mantener estructura plana**: Evitar anidación profunda en JSON
3. **Siempre tener fallback**: Configurar `fallbackLocale` para claves faltantes
4. **Extraer claves automáticamente**: Usar `jamx i18n:extract` para encontrar claves no traducidas
5. **Validar traducciones**: Revisar que todas las claves existan en cada idioma
6. **Usar pluralización correcta**: Definir formas singular y plural para cada clave
7. **No concatenar strings**: Usar interpolación en su lugar

This i18n module provides a robust, type-safe internationalization solution for JAMX applications, enabling developers to reach global audiences with proper language support, formatting, and cultural adaptation.