Ingeniería//13 min de lectura

Archivos de traducción JSON: Formatos, estructura y mejores prácticas para i18n

Eray Gündoğmuş
Compartir

Archivos de traducción JSON: Formatos, estructura y mejores prácticas para i18n

Casi todas las aplicaciones web que se publican en más de un idioma almacenan las traducciones en archivos JSON. El formato es omnipresente, pero las convenciones a su alrededor no son uniformes. Diferentes frameworks esperan diferentes estructuras: un objeto plano de clave-valor, un árbol de namespaces profundamente anidado, un mensaje con sintaxis ICU incrustada o un manifiesto de extensión de Chrome con su propia estructura de descriptores. Elegir el formato incorrecto al principio o migrar entre formatos más adelante conlleva costes reales.

Esta guía cubre los principales formatos de traducción JSON en uso hoy en día, cómo organizar archivos de traducción a escala, convenciones de nomenclatura de claves, patrones de pluralización, herramientas de validación y cómo moverse entre JSON y formatos alternativos como XLIFF y PO.


TL;DR / Conclusiones clave

  • JSON es el formato dominante para i18n web porque es nativo de JavaScript, legible por humanos y funciona bien con el control de versiones — pero no existe un único "formato JSON i18n". Cada biblioteca importante define sus propias convenciones.
  • Las variantes más comunes son: clave-valor plano (simple pero difícil de mantener a escala), anidado/con namespace (organizado pero verboso), i18next (con namespace y sufijos de clave plural integrados), FormatJS/react-intl (ICU MessageFormat en valores) y chrome.i18n (objetos descriptores con un campo message y description opcional).
  • La organización de archivos importa tanto como el formato: dividir las traducciones por namespace o dominio de funcionalidad mantiene los archivos pequeños, reduce los conflictos de fusión y permite la carga diferida.
  • La sintaxis de pluralización e interpolación de variables varía según la biblioteca — usar ICU MessageFormat en los valores ofrece la opción más portable y expresiva, pero requiere un runtime compatible.
  • La validación en CI — verificar claves faltantes, JSON malformado y cadenas sin traducir — es la forma más efectiva de evitar que traducciones rotas lleguen a producción.

¿Por qué JSON para traducciones?

Antes de comparar formatos, vale la pena entender por qué JSON se convirtió en el estándar para i18n web — y por qué esa elección no siempre es obvia.

Legible por humanos y amigable con diff. Un archivo de traducción JSON es legible sin herramientas. Un diff en un pull request muestra exactamente qué cadenas cambiaron, cuáles se agregaron y cuáles se eliminaron. Compara esto con XLIFF 2.0, donde el mismo cambio está enterrado en atributos XML en múltiples elementos, o con formatos binarios compilados donde los diffs son ilegibles.

Nativo de JavaScript. JSON.parse() está integrado en todos los runtimes de JavaScript. No hay dependencia de parseo que instalar, ni adaptador de formato que configurar. Cuando una aplicación Next.js agrupa traducciones para el navegador, envía JSON plano — sin overhead de serialización, sin parser personalizado.

Fácil de generar y consumir programáticamente. Todos los lenguajes tienen una biblioteca JSON. Generar archivos de traducción desde una base de datos, una exportación de hoja de cálculo o una API de sistema de gestión de traducción es una tarea directa de serialización JSON.

Funciona bien con control de versiones. Los archivos JSON son texto. Se fusionan limpiamente cuando los cambios están en claves diferentes, producen un historial de blame legible y funcionan con herramientas de diff estándar.

Alternativas y sus compensaciones

FormatoFortalezasDebilidades
XLIFF 2.0Metadatos ricos, notas de traductor, seguimiento de estado, estándar de la industriaXML verboso, mala legibilidad de diff, herramientas complejas
PO / GettextEcosistema maduro, el modelo msgid/msgstr admite contexto, formas plurales integradasRequiere parsers especializados, menos común en JavaScript
YAMLLegible, admite cadenas multilínea de forma naturalSensible a la indentación (propenso a errores), sin parser de navegador nativo
ARB (Application Resource Bundle)Nativo de Flutter/Dart, admite metadatos por claveEcosistema específico de Dart, herramientas web limitadas
JSONUbicuo, JavaScript nativo, excelentes herramientasSin metadatos integrados, el manejo de plurales varía según la biblioteca

XLIFF es la elección correcta cuando las traducciones pasan por una agencia de traducción profesional con herramientas CAT. PO es apropiado para proyectos que quieran aprovechar el ecosistema Gettext (Poedit, utilidades GNU gettext). Para la mayoría de las aplicaciones web creadas en React, Vue, Angular o Svelte, JSON es el estándar práctico.


Formatos de traducción JSON comunes

Clave-valor plano

El archivo de traducción JSON más simple posible es un objeto de un solo nivel donde cada clave es un identificador de cadena y cada valor es la cadena traducida.

{
  "welcome_message": "Bienvenido a nuestra plataforma",
  "login_button": "Iniciar sesión",
  "logout_button": "Cerrar sesión",
  "error_not_found": "Página no encontrada",
  "error_server": "Algo salió mal. Por favor, inténtalo de nuevo."
}

Este formato tiene curva de aprendizaje cero y funciona con cualquier parser JSON. El problema aparece a escala: un archivo plano con 500 claves para una aplicación grande se vuelve imposible de navegar. No hay agrupación visual, ninguna indicación de dónde se usa una cadena y ninguna manera de extraer un subconjunto de traducciones para carga diferida.

Mejor para: Proyectos pequeños, prototipos o aplicaciones con menos de 100 claves de traducción.

JSON anidado / con namespace

El JSON anidado organiza las claves en una jerarquía que refleja la estructura de la aplicación.

{
  "auth": {
    "login": {
      "title": "Inicia sesión en tu cuenta",
      "email_label": "Dirección de correo electrónico",
      "password_label": "Contraseña",
      "submit_button": "Iniciar sesión",
      "forgot_password": "¿Olvidaste tu contraseña?"
    },
    "logout": {
      "confirm": "¿Estás seguro de que quieres cerrar sesión?"
    }
  },
  "dashboard": {
    "greeting": "Buenos días, {{name}}",
    "stats": {
      "total_users": "Total de usuarios",
      "active_sessions": "Sesiones activas"
    }
  }
}

Bibliotecas como vue-i18n y angular/localize admiten JSON anidado de forma nativa. Se accede a la clave con notación de puntos: t('auth.login.title'). Esta estructura se corresponde naturalmente con las jerarquías de componentes y facilita identificar dónde se usa cada cadena.

La compensación es que los objetos profundamente anidados requieren una gestión de claves más cuidadosa y pueden producir rutas de acceso largas. La mayoría de los equipos se establece en dos o tres niveles de anidamiento como máximo práctico.

Formato i18next

i18next es la biblioteca i18n más utilizada en el ecosistema JavaScript y tiene sus propias convenciones construidas sobre JSON anidado. La más importante es su sistema de sufijos de clave plural.

{
  "common": {
    "save": "Guardar",
    "cancel": "Cancelar",
    "loading": "Cargando..."
  },
  "items": {
    "count_one": "{{count}} elemento",
    "count_other": "{{count}} elementos",
    "count_zero": "Sin elementos"
  },
  "notifications": {
    "new_one": "Tienes {{count}} nueva notificación",
    "new_other": "Tienes {{count}} nuevas notificaciones"
  }
}

i18next resuelve las formas plurales añadiendo un sufijo a la clave base. Los sufijos siguen las categorías de reglas plurales CLDR: zero, one, two, few, many, other. Para el español, aplican one y other. Para el árabe o el ruso, el conjunto completo importa.

i18next también admite namespacing a nivel de archivo: cada archivo JSON es un namespace. Cuando llamas a t('common:save'), i18next carga common.json para el locale activo. Esto permite la carga diferida a nivel de namespace en aplicaciones React que usan react-i18next.

{
  "title": "¡Bienvenido, {{name}}!",
  "description": "Te uniste el {{date, datetime}}",
  "price": "{{price, currency}}"
}

La sintaxis {{value, formatType}} activa el pipeline de formato de i18next, que se integra con la API Intl para fechas, números y moneda.

Formato FormatJS / react-intl

FormatJS (que impulsa react-intl) usa sintaxis ICU MessageFormat incrustada directamente en los valores de cadena. Esto coloca toda la lógica de pluralización y variables dentro de la propia cadena del mensaje en lugar de en sufijos de clave.

{
  "welcome": "¡Bienvenido, {name}!",
  "item_count": "{count, plural, =0 {Sin elementos} one {# elemento} other {# elementos}}",
  "last_login": "Último acceso: {date, date, medium}",
  "account_status": "{gender, select, male {Él es} female {Ella es} other {Son}} miembro verificado.",
  "notification_badge": "{count, plural, =0 {} one {({count})} other {({count})}}"
}

ICU MessageFormat es la opción más expresiva disponible para reglas complejas de plural y concordancia de género. La palabra clave select maneja cadenas condicionales, plural maneja formas basadas en conteo y los tipos de formato (date, number, currency) delegan en la API Intl.

Las claves suelen ser cadenas planas, a menudo coincidiendo con la ruta del componente o un descriptor semántico. FormatJS desaconseja las estructuras profundamente anidadas en favor de claves planas descriptivas.

Uso con react-intl:

import { useIntl, FormattedMessage } from 'react-intl';

function ItemList({ count }) {
  const intl = useIntl();
  return (
    <p>
      <FormattedMessage id="item_count" values={{ count }} />
    </p>
  );
}

Formato chrome.i18n

Las extensiones de Chrome usan un formato JSON específico definido por la API chrome.i18n. Cada clave se corresponde con un objeto descriptor en lugar de una cadena plana.

{
  "extensionName": {
    "message": "Mi Extensión",
    "description": "El nombre de la extensión, mostrado en Chrome Web Store."
  },
  "welcomeMessage": {
    "message": "¡Hola, $USER$!",
    "description": "Saludo mostrado cuando se abre la extensión",
    "placeholders": {
      "user": {
        "content": "$1",
        "example": "Alice"
      }
    }
  },
  "itemCount": {
    "message": "$COUNT$ elementos seleccionados",
    "placeholders": {
      "count": {
        "content": "$1",
        "example": "3"
      }
    }
  }
}

El campo description no se muestra a los usuarios finales — es contexto para los traductores y el proceso de revisión de Chrome Web Store. Los marcadores de posición usan una convención $NOMBRE_MARCADOR$ con un objeto placeholders separado que define el contenido y un valor de ejemplo.

Este formato es obligatorio para las extensiones de Chrome. No es adecuado para i18n de aplicaciones web de propósito general.


Patrones de organización de archivos

Un archivo por locale

La organización más simple es un archivo JSON por locale que contiene todas las traducciones de la aplicación.

locales/
  en.json
  fr.json
  de.json
  ja.json
  es.json

Esto funciona para aplicaciones pequeñas pero crea problemas a escala: los archivos crecen, las funciones no relacionadas causan conflictos de fusión en el mismo archivo y no puedes cargar de forma diferida traducciones para secciones que el usuario no ha visitado.

División por namespace

El patrón más común para aplicaciones medianas y grandes es dividir las traducciones por namespace — un archivo JSON por área funcional por locale.

locales/
  en/
    common.json
    auth.json
    dashboard.json
    settings.json
    errors.json
  fr/
    common.json
    auth.json
    dashboard.json
    settings.json
    errors.json
  de/
    common.json
    auth.json
    dashboard.json
    settings.json
    errors.json

Cada archivo de namespace es pequeño y enfocado. El namespace common contiene cadenas usadas en toda la aplicación (etiquetas de botones, etiquetas de campos de formulario, mensajes de error genéricos). Los namespaces de funcionalidad contienen cadenas específicas de esa funcionalidad.

i18next y react-i18next usan este patrón de forma nativa: t('auth:login.title') carga auth.json para el locale activo. Las aplicaciones Next.js que usan next-i18next siguen esta estructura por convención.

División basada en funcionalidades

Para aplicaciones muy grandes, o monorepos donde cada paquete posee sus propias traducciones, una estructura basada en funcionalidades coloca los archivos de traducción junto al código que los usa.

src/
  features/
    auth/
      locales/
        en.json
        fr.json
      components/
        LoginForm.tsx
        SignupForm.tsx
    dashboard/
      locales/
        en.json
        fr.json
      components/
        DashboardHeader.tsx
    checkout/
      locales/
        en.json
        fr.json

Este patrón maximiza la cohesión: el archivo de traducción vive junto al componente que lo usa. El sistema de construcción o el cargador i18n fusiona los archivos de namespace en tiempo de ejecución o de construcción. La desventaja es que encontrar todas las traducciones para un locale dado requiere recorrer todo el árbol de fuentes, lo que complica el flujo de trabajo para traductores y sistemas de gestión de traducciones.

Recomendación: Usa la división por namespace para la mayoría de las aplicaciones. Usa la división basada en funcionalidades solo si tu equipo es lo suficientemente grande como para que diferentes equipos posean diferentes funcionalidades y necesiten evitar conflictos de fusión entre funcionalidades en los archivos de traducción.


Tabla comparativa de formatos de archivos de traducción

FormatoLegibilidadSoporte de herramientasSoporte de metadatosSoporte ICUCompatibilidad con diff
JSON (plano)AltaExcelenteNingunoNo (por defecto)Excelente
JSON (anidado)AltaExcelenteNingunoNo (por defecto)Excelente
JSON (FormatJS)MediaBuenoNingunoSí (nativo)Bueno
XLIFF 2.0BajaExcelente (herramientas CAT)Rico (estado, notas, traducciones alternativas)Pobre
PO / GettextMediaBueno (Poedit, Weblate)Medio (comentarios, contexto)ParcialMedio
YAMLAltaMedioNingunoNoBueno
ARBAltaBueno (Flutter)Metadatos por claveNoBueno

La ventaja de metadatos de XLIFF es significativa cuando se trabaja con agencias de traducción profesionales: el formato rastrea el estado de la traducción (nuevo, traducido, revisado, final), admite traducciones alternativas y es el formato nativo para la mayoría de las herramientas CAT profesionales como Phrase, memoQ y SDL Trados. Si tu flujo de trabajo de traducción implica entregas a agencias, generar XLIFF desde tu fuente JSON (en lugar de enviar JSON sin procesar) mejora la productividad del traductor y reduce errores.


Convenciones de nomenclatura de claves

La nomenclatura consistente de claves es la diferencia entre un archivo de traducción fácil de mantener y uno que se convierte en fuente de errores y confusión.

Notación de puntos vs. anidamiento

Las claves planas con puntos y los objetos genuinamente anidados representan ambos jerarquía, pero se comportan diferente. Una clave plana con puntos es una sola cadena — "auth.login.title". Un objeto anidado es una estructura de objeto real con la clave title dentro de login dentro de auth. La mayoría de las bibliotecas admiten ambos, pero mezclar los dos en el mismo archivo causa ambigüedad.

Recomendación: Usa anidamiento genuino en tus archivos JSON y notación de puntos solo en código al acceder a claves. No uses puntos en nombres de clave dentro del mismo nivel de anidamiento.

{
  "auth": {
    "login": {
      "title": "Iniciar sesión"
    }
  }
}

Accedido en código como t('auth.login.title') — la biblioteca maneja el recorrido.

snake_case vs. camelCase

Ambos son comunes. snake_case es más legible en archivos JSON porque las palabras no se mezclan visualmente. camelCase se alinea con las convenciones de JavaScript y es común en proyectos FormatJS.

{
  "submit_button": "Enviar",
  "error_message": "Ocurrió un error"
}
{
  "submitButton": "Enviar",
  "errorMessage": "Ocurrió un error"
}

Elige uno y aplícalo con un linter. La inconsistencia dentro de un proyecto es peor que cualquier elección.

Descriptivo vs. conciso

Las claves concisas son cortas pero pierden contexto rápidamente:

{
  "btn_sub": "Suscribirse",
  "btn_cncl": "Cancelar",
  "err_404": "Página no encontrada"
}

Las claves descriptivas comunican el propósito sin leer el valor:

{
  "newsletter_subscribe_button": "Suscribirse",
  "modal_cancel_button": "Cancelar",
  "error_page_not_found_title": "Página no encontrada"
}

Recomendación: Usa claves descriptivas que incluyan el contexto de la UI (tipo o ubicación del componente) y el tipo de contenido (botón, título, descripción, marcador de posición). Esto hace posible entender cómo se usa una clave sin leer el código del componente.

Agrupación jerárquica

Al usar JSON anidado, agrupa primero por área de UI, luego por componente o acción, y luego por tipo de elemento:

{
  "checkout": {
    "cart": {
      "title": "Tu carrito",
      "empty_message": "Tu carrito está vacío",
      "item_count_one": "{{count}} artículo",
      "item_count_other": "{{count}} artículos"
    },
    "payment": {
      "title": "Detalles de pago",
      "card_number_label": "Número de tarjeta",
      "expiry_label": "Fecha de vencimiento",
      "submit_button": "Pagar ahora"
    }
  }
}

Manejo de plurales y variables en JSON

ICU MessageFormat (FormatJS, vue-i18n, otros)

ICU MessageFormat es la sintaxis más expresiva y portable para plurales y variables. Es compatible de forma nativa con FormatJS y puede configurarse en vue-i18n y otras bibliotecas.

{
  "file_count": "{count, plural, =0 {Sin archivos} one {# archivo} other {# archivos}}",
  "upload_progress": "Subiendo {current} de {total} archivos",
  "last_seen": "Visto por última vez {time, date, relative}",
  "user_role": "{role, select, admin {Administrador} editor {Editor} other {Visualizador}}"
}

El símbolo # dentro de una rama plural se reemplaza por el conteo formateado. La palabra clave select ramifica en un valor de cadena en lugar de un número.

Convención de sufijo plural de i18next

i18next resuelve los plurales añadiendo un sufijo a la clave. Para el español:

{
  "message_count_one": "{{count}} mensaje",
  "message_count_other": "{{count}} mensajes",
  "message_count_zero": "Sin mensajes"
}

Llamado con t('message_count', { count: 5 }), i18next selecciona message_count_other e interpola count. Para idiomas con más formas plurales (el ruso tiene cuatro), se definen variantes de sufijo adicionales:

{
  "file_one": "{{count}} файл",
  "file_few": "{{count}} файла",
  "file_many": "{{count}} файлов",
  "file_other": "{{count}} файлов"
}

Las categorías de reglas plurales CLDR (zero, one, two, few, many, other) se corresponden con los sufijos que usa i18next.

Interpolación de variables

Cada biblioteca admite alguna forma de interpolación de variables. La sintaxis varía:

{
  "greeting_i18next": "¡Hola, {{name}}!",
  "greeting_icu": "¡Hola, {name}!",
  "greeting_vue": "¡Hola, {name}!",
  "greeting_angular": "¡Hola, {{ name }}!"
}

i18next usa llaves dobles por defecto. ICU usa llaves simples. El $localize de Angular usa un literal de plantilla etiquetado en el código en lugar de una sintaxis de interpolación en tiempo de ejecución en el valor JSON.

No mezcles sintaxis de interpolación en el mismo proyecto. Elige la sintaxis que coincida con tu biblioteca y aplícala en la validación de tu esquema JSON.


Herramientas y validación

JSON Schema para archivos de traducción

Una definición de JSON Schema te permite validar la estructura de archivos de traducción en pipelines de CI, editores y hooks pre-commit. Aquí hay un esquema mínimo para un archivo de traducción plano de clave-valor:

{
  "$schema": "http://json-schema.org/draft-07/schema#",
  "type": "object",
  "additionalProperties": {
    "type": "string"
  },
  "minProperties": 1
}

Para archivos anidados, el esquema se vuelve recursivo. La mayoría de los equipos usan una combinación de JSON Schema para validación estructural y una herramienta de linting i18n dedicada para verificaciones semánticas.

Linting para claves faltantes

El error de i18n en producción más común es una clave de traducción faltante — una clave presente en inglés pero ausente en un archivo de locale. Esto causa un fallback al nombre de la clave o una cadena vacía, lo que rompe la UI.

i18next-parser escanea tu código fuente en busca de llamadas t('key') y genera o valida archivos de traducción:

npx i18next-parser --config i18next-parser.config.js

eslint-plugin-i18n-json valida archivos de traducción JSON directamente:

npm install --save-dev eslint-plugin-i18n-json

Una configuración básica de ESLint para validación de archivos de traducción:

{
  "plugins": ["i18n-json"],
  "rules": {
    "i18n-json/valid-json": "error",
    "i18n-json/sorted-keys": ["warn", { "order": "asc" }],
    "i18n-json/identical-keys": [
      "error",
      { "filePath": "src/locales/en.json" }
    ]
  }
}

La regla identical-keys verifica que cada archivo de locale contenga el mismo conjunto de claves que el archivo de locale de referencia (típicamente inglés). Marca tanto las claves faltantes como las claves adicionales que no deberían existir.

Verificaciones de CI para completitud

Un paso de CI que bloquea las fusiones cuando un archivo de locale está incompleto previene la acumulación de deuda de traducción. Una verificación simple con script de shell:

#!/usr/bin/env bash
BASE="src/locales/en.json"
LOCALES=("fr" "de" "ja" "es")

for locale in "${LOCALES[@]}"; do
  FILE="src/locales/${locale}.json"
  BASE_KEYS=$(jq 'keys | length' "$BASE")
  LOCALE_KEYS=$(jq 'keys | length' "$FILE")

  if [ "$BASE_KEYS" != "$LOCALE_KEYS" ]; then
    echo "ERROR: ${FILE} tiene ${LOCALE_KEYS} claves, se esperaban ${BASE_KEYS}"
    exit 1
  fi
done

echo "Todos los archivos de locale están completos."

Para archivos anidados, se requiere el recorrido de ruta de jq. Plataformas como Better i18n usan JSON como su formato nativo y sincronizan traducciones mediante CLI, lo que significa que la verificación de completitud puede aplicarse en el lado de la plataforma antes de que se confirmen las traducciones, reduciendo la necesidad de verificaciones a nivel de CI en archivos incompletos.

Integración con el editor

Extensiones de VS Code como "i18n Ally" ofrecen vistas previas de traducción en línea, resaltado de claves faltantes y sugerencias de traducción automática directamente en el editor. Esto mueve la validación hacia la izquierda — los desarrolladores ven las traducciones faltantes mientras escriben código, en lugar de durante el CI.


Migración entre formatos

JSON a XLIFF

XLIFF es necesario cuando se envían traducciones a una agencia profesional. Convertir de JSON a XLIFF 2.0 implica mapear pares clave-valor a elementos <unit> con hijos <segment>.

La herramienta i18next-conv maneja la conversión bidireccional:

npm install -g i18next-conv

# JSON a XLIFF
i18next-conv -l en -s locales/en.json -t locales/en.xliff

# XLIFF a JSON
i18next-conv -l fr -s locales/fr.xliff -t locales/fr.json

Para proyectos FormatJS, @formatjs/cli proporciona exportación XLIFF:

npx formatjs compile-folder --ast src/locales/en.json > compiled/en.json

JSON a PO

El formato PO (Portable Object) es utilizado por el ecosistema Gettext y es compatible con herramientas como Poedit y Weblate. La herramienta i18next-conv también admite PO:

# JSON a PO
i18next-conv -l en -s locales/en.json -t locales/en.po

# PO a JSON
i18next-conv -l fr -s locales/fr.po -t locales/fr.json

Para proyectos vue-i18n, el @intlify/vue-i18n-loader admite archivos .po directamente como alternativa a JSON, lo que es útil cuando tu proyecto Vue comparte memoria de traducción con una aplicación del lado del servidor que usa Gettext.

Herramientas de conversión comunes

HerramientaConvierteNotas
i18next-convJSON ↔ PO, JSON ↔ XLIFF, JSON ↔ CSVMás completa para el formato i18next
@formatjs/cliFormatJS JSON → XLIFF, mensajes extraídos → archivos de localeRequerida para proyectos FormatJS/react-intl
gettext-converterPO ↔ JSON (plano)Simple, sin suposiciones de framework
xliff-simple-mergeFusión y división de XLIFFÚtil para proyectos Angular usando angular/localize
Editores XLIFF onlineXLIFF ↔ JSON (via UI)Phrase, Lokalise y Crowdin todos ofrecen importación/exportación

Al migrar entre formatos, valida la salida antes de confirmar. Las herramientas de conversión automatizada ocasionalmente pierden cadenas de contexto, eliminan comentarios o manejan incorrectamente las formas plurales para idiomas con reglas plurales no estándar.


Preguntas frecuentes

¿Qué formato JSON debo usar para un nuevo proyecto React?

Si usas react-i18next (que es la elección más común), comienza con JSON anidado dividido por namespace siguiendo las convenciones de i18next. Si usas react-intl o una configuración basada en FormatJS, usa claves planas con sintaxis ICU MessageFormat en los valores. La biblioteca que elijas determina el formato — elige primero la biblioteca según los requisitos de tu proyecto, luego sigue sus convenciones documentadas.

¿Mis claves JSON deben ser la cadena inglesa en sí misma o un identificador semántico?

Los identificadores semánticos (como auth.login.submit_button) son preferibles para la mayoría de las aplicaciones. Usar la cadena inglesa como clave (estilo Gettext: t('Submit')) funciona para proyectos pequeños pero crea problemas a escala: no puedes tener dos botones "Enviar" diferentes con diferente contexto en el mismo namespace, y cambiar el texto en inglés requiere actualizar todas las referencias de clave en el código.

¿Cómo manejo las traducciones faltantes en tiempo de ejecución sin romper la UI?

Cada biblioteca i18n importante recurre a un locale predeterminado configurado cuando falta una clave. Configura tu biblioteca para usar el archivo de locale en inglés como fallback, lo que significa que una traducción francesa faltante mostrará la cadena en inglés en lugar del nombre de la clave. Registra las claves faltantes en desarrollo (la mayoría de las bibliotecas admiten un callback missingKeyHandler) para que sean visibles durante las pruebas.

¿Es seguro usar comentarios en archivos de traducción JSON?

El JSON estándar no admite comentarios. Algunas herramientas admiten JSON5 o JSONC (JSON con comentarios) como extensión, pero esto rompe la compatibilidad con parsers JSON estándar. Si necesitas anotar cadenas con contexto para traductores, usa un campo de descripción separado a nivel de clave (como hace chrome.i18n) o mantén un archivo de metadatos separado. Un enfoque más simple: usa nombres de clave descriptivos que comuniquen el contexto sin necesitar comentarios en línea.

¿Cómo debo manejar los idiomas de derecha a izquierda (RTL) en mis archivos JSON?

La estructura JSON para idiomas RTL (árabe, hebreo, persa) es idéntica a los idiomas LTR — el formato del archivo no cambia. El soporte RTL es una preocupación de CSS y diseño, no de archivos de traducción. Tu biblioteca i18n proporciona una manera de detectar la dirección del texto del locale activo (típicamente a través de la API Intl.Locale o un objeto de metadatos de locale), y tu aplicación aplica dir="rtl" al documento o componente según corresponda. Mantén el CSS específico de RTL en tus hojas de estilo, no en tus valores de traducción.


Conclusión

Los archivos de traducción JSON no siguen un único estándar universal — siguen las convenciones de la biblioteca que los lee. Entender qué formato espera tu biblioteca y por qué fue diseñada de esa manera es más útil que buscar un enfoque "correcto".

La guía práctica es esta: usa JSON anidado con convenciones de i18next si estás creando una aplicación React, Vue o Node.js y quieres el mayor ecosistema de herramientas y ejemplos. Usa ICU MessageFormat en tus valores si tu aplicación debe manejar plurales complejos, concordancia de género o formato enriquecido en muchos locales y quieres que las expresiones sean lo más portables posible. Usa claves planas para proyectos pequeños o prototipos rápidos donde la sobrecarga cognitiva importa más que la estructura organizativa.

La organización de archivos, la nomenclatura de claves y la validación en CI importan tanto como la elección del formato. Un archivo plano con nomenclatura consistente y verificaciones de completitud automatizadas servirá mejor a un equipo pequeño que una estructura cuidadosamente organizada en namespaces sin herramientas ni aplicación.

La deuda de traducción se acumula silenciosamente — una clave faltante aquí, una cadena obsoleta allá — hasta que los usuarios localizados encuentran cadenas de UI rotas. Los equipos que evitan este resultado tratan los archivos de traducción igual que cualquier otro artefacto de código: revisados en pull requests, validados en CI y organizados con futuros mantenedores en mente.


Referencias


Última actualización: marzo de 2026

Comments

Loading comments...