npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jamx-framework/i18n

v1.0.0

Published

JAMX Framework — Internationalization

Readme

@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

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:

{
  "welcome": "Welcome, {{name}}!",
  "items": "{{count}} item",
  "items_plural": "{{count}} items"
}

es.json:

{
  "welcome": "¡Bienvenido, {{name}}!",
  "items": "{{count}} artículo",
  "items_plural": "{{count}} artículos"
}

Uso con interpolación y pluralización

// 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

// 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

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

// 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)

// 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

// 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

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/:

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.