Ir al artículo
Aniq-UI

LearnioIdiomas

Idiomas

Cómo elige Learnio un idioma, dónde está cada traducción y cómo cambiar un texto o añadir un idioma nuevo a cada aplicación.

Para el paquete Full Stack

Los idiomas incluidos

Cada aplicación viene en inglés, el predeterminado, y en árabe, que se muestra de derecha a izquierda. Cada aplicación tiene sus propias traducciones:

AplicaciónArchivos de traducciónArchivos por idioma
Sitio para estudiantesfrontend/messages/<namespace>/<locale>.json22
Panel de administraciónadmin-dashboard/messages/<namespace>/<locale>.json24
APIback-end/src/i18n/translations/<locale>/<namespace>.json18

Un namespace es un área de la aplicación, como layouts, auth o courses. Algunos son carpetas anidadas, por ejemplo messages/dashboard/courses/en.json.

Cómo se elige el idioma

El idioma es la primera parte de la dirección: /en/courses o /ar/courses. No hay cookie de idioma ni detección desde el navegador.

  • Una dirección sin idioma se redirige al predeterminado, el inglés: /courses va a /en/courses. En el panel de administración, / va a /en/dashboard.
  • El selector de idioma abre la misma página con el otro prefijo.
  • Cada solicitud a la API lleva el idioma de la página en el encabezado Accept-Language, así que la API responde en ese idioma.

Para abrir en árabe por defecto, pon defaultLocale en "ar" en src/config/locales.ts en el sitio para estudiantes, y en src/proxy.ts en el panel de administración.

Cambia un texto

Cada palabra de la pantalla viene de un archivo de mensajes. Busca el texto que ves para encontrar su clave y luego cámbialo en todos los idiomas.

Terminalen frontend
grep -rn "All rights reserved" messages

Así se encuentra la línea de copyright del pie de página, con la clave footer.copyright en messages/layouts/en.json. Cambia la misma clave en ar.json:

frontend/messages/layouts/en.json
"footer": {
  "copyright": "© {year} Learnio. All rights reserved."
}
  • Conserva tal cual los marcadores como {year} y las etiquetas como <brand>. El código los rellena.
  • Cambia la clave en todos los archivos de idioma. Una clave que falta en un idioma muestra su ruta en lugar del texto.
  • yarn dev detecta el cambio. Una versión de producción incluye los mensajes, así que vuelve a construirla.

Con las notificaciones pasa lo mismo: la API solo guarda un tipo, como enrollment_created, y cada aplicación lo redacta a partir de sus propios archivos. En el panel de administración están en header.notifications.types en messages/dashboard/<locale>.json; en el sitio para estudiantes, en notifications.types en el mismo archivo.

Cursos, artículos y otros contenidos

El texto que escribes en el panel de administración, como los títulos de los cursos, las lecciones, las categorías, los artículos del blog y los perfiles de instructores, se guarda una sola vez con ambos idiomas, como un valor JSON con una clave en y una ar:

El nombre de una categoría en la base de datos
{ "en": "Project Management", "ar": "إدارة المشاريع" }
  • Los formularios del panel de administración muestran una pestaña en inglés y otra en árabe para cada uno de estos campos.
  • La API devuelve ambos valores y cada frontend muestra el del idioma de la página. Si ese está vacío, muestra el otro, así que un curso nunca se queda sin nombre.
  • La API ya devuelve resueltos los resultados de búsqueda, a partir del encabezado Accept-Language.
  • En los datos de demostración de yarn seed, las categorías, los artículos del blog, los perfiles de instructores, los cuestionarios y los títulos de las secciones de los cursos tienen texto en árabe. Los títulos y las descripciones de los cursos y los títulos de las lecciones llevan el texto en inglés en ambas claves, así que tradúcelos en el panel de administración.

El contenido tiene exactamente dos idiomas

La validación de la API espera un valor en y otro ar en estos campos y rechaza cualquier otra clave, y los editores del panel tienen dos pestañas. Añadir un tercer idioma de contenido implica cambiar las entidades y los DTO de la API, los campos multilingües del panel y su función auxiliar localizedText. La localizedText del sitio para estudiantes ya lee la clave que corresponde al idioma de la página. Sin esos cambios, una página en un nuevo idioma de interfaz muestra el contenido en inglés.

Qué traduce la API

  • Los mensajes de respuesta, como los textos de éxito y de error que el panel de administración muestra en sus alertas, vienen de src/i18n/translations/<locale>/<namespace>.json a través de I18nService en src/i18n/i18n.service.ts.
  • Los correos electrónicos se redactan en mail.json. Los correos de verificación y de restablecimiento de contraseña usan el idioma de la solicitud. Los recibos y las confirmaciones de inscripción usan el idioma en que se hizo el pedido. Los correos en árabe se muestran de derecha a izquierda.
  • Los nombres de los países están en countries.json.

El idioma se toma de la cabecera Accept-Language. Un código regional como ar-SA cuenta como ar. Una solicitud sin cabecera, o en un idioma que la API no admite, recibe el idioma por defecto. Una clave que falta en un idioma recurre a su texto en el idioma por defecto y, si no, a la propia clave.

  • El idioma por defecto es la entrada Default Language (default_locale) de la pestaña App Settings de Settings en el panel de administración, en en los datos iniciales. Un cambio se aplica a la siguiente solicitud, sin reiniciar. La API rechaza un valor que no sea uno de sus idiomas, así que una errata no puede dejarla respondiendo en un idioma sin traducciones.
  • La API lee sus archivos de traducción una sola vez, al iniciarse: reiníciala después de editar uno. yarn build los copia en dist/.

Añade un idioma al sitio para estudiantes

Los pasos usan el francés, fr, como ejemplo. Usa un código de dos letras en minúsculas: varios helpers reconocen el idioma como un primer segmento de dos letras en la dirección. Las rutas están dentro de frontend/.

  1. Añade el código a la lista de idiomas

    src/config/locales.ts es la única lista que lee el sitio para estudiantes: las rutas, la redirección, el cargador de mensajes, el script que define lang y dir antes del primer pintado, el selector de idioma, las solicitudes a la API, la redirección de inicio de sesión, los metadatos de las páginas, el mapa del sitio y cada número y fecha que formatea. Añade el código a locales y dale una entrada en los tres mapas de al lado. El compilador señala cualquiera que te falte.

    frontend/src/config/locales.ts
    export const locales = ["en", "ar", "fr"] as const;
    
    export const OG_LOCALES: Record<Locale, string> = { en: "en_US", ar: "ar_AE", fr: "fr_FR" };
    export const LOCALE_FLAGS: Record<Locale, FlagIconCode> = { en: "US", ar: "AE", fr: "FR" };
    export const LOCALE_FORMAT_TAGS: Record<Locale, string> = { en: "en-US", ar: "ar-EG", fr: "fr-FR" };
    EntradaQué define
    OG_LOCALESEl idioma de la tarjeta para compartir de la página (og:locale)
    LOCALE_FLAGSLa bandera que muestra el selector de idioma, como código de país
    LOCALE_FORMAT_TAGSCómo se escriben los números y las fechas. Usa una etiqueta con región, como fr-FR, para que las cifras y los nombres de los meses no dependan del navegador.
    RTL_LOCALESAñade el código si el idioma se escribe de derecha a izquierda.
    JOINING_SCRIPT_LOCALESAñade el código si su escritura une las letras, como la árabe. El logotipo de texto de la página de inicio se dibuja entonces como contornos, porque Safari deja esas letras sin unir en el texto SVG.
  2. Crea los archivos de mensajes

    Copia cada archivo en inglés a su lado con el nuevo código y luego traduce los valores. Conserva las claves.

    Terminalen frontend
    find messages -name en.json -exec sh -c 'cp "$1" "$(dirname "$1")/fr.json"' _ {} \;

    En PowerShell:

    Terminalen frontend
    Get-ChildItem messages -Recurse -Filter en.json | ForEach-Object { Copy-Item $_.FullName (Join-Path $_.DirectoryName 'fr.json') }
  3. Revisa las fuentes

    Inter se carga con el subconjunto latin en src/app/layout.tsx, que cubre el francés, el español o el alemán. Añade latin-ext para idiomas como el polaco, el checo o el turco. Para otro sistema de escritura, carga ahí una fuente para él y añade una regla para su lang en src/styles/base.css, como hace la árabe.

  4. Abre el nuevo idioma

    Reinicia yarn dev y abre localhost:3030/frLocal.

    Resultado esperado: La página muestra tu texto traducido, el selector incluye el nuevo idioma, y cada página lo nombra en sus alternativas hreflang y en el mapa del sitio.

El pago necesita que la API conozca el idioma

El pago envía el idioma de la página con el pedido, y la API solo acepta ahí los idiomas de su propia lista. Hasta que el código se añada también a la API (Añadir un idioma a la API), una compra hecha desde una página en el nuevo idioma se rechaza.

Añade un idioma al panel de administración

El panel de administración guarda su lista de idiomas en tres archivos. Los pasos usan fr; usa un código de dos letras en minúsculas. Las rutas están dentro de admin-dashboard/.

  1. Añade el código a las tres listas

    • locales en src/config/i18n.ts, que carga los mensajes.
    • locales en src/proxy.ts, que redirige las direcciones sin idioma.
    • locales en src/app/[locale]/layout.tsx, que decide qué direcciones existen.
  2. Crea los archivos de mensajes

    Copia cada archivo en inglés con el nuevo código y luego traduce los valores.

    Terminalen admin-dashboard
    find messages -name en.json -exec sh -c 'cp "$1" "$(dirname "$1")/fr.json"' _ {} \;
  3. Actualiza los helpers

    • src/hooks/locale/useLocale.ts acepta en, fr, es y ar. Añade tu código si no es uno de ellos.
    • src/hooks/locale/useDirection.ts solo trata ar como de derecha a izquierda. Amplía la comprobación para otro idioma de derecha a izquierda.
    • src/lib/api/client-utils/locale.ts y src/lib/api/client-utils/auth.ts solo reconocen en y ar en la dirección. Añade tu código.
  4. Añádelo al selector de idioma

    En src/components/LanguageSwitcher.tsx, importa la bandera de country-flag-icons/react/3x2 y añade una entrada a languages.

    admin-dashboard/src/components/LanguageSwitcher.tsx
    import { US, SA, FR } from "country-flag-icons/react/3x2";
    
    const languages = [
      { code: "en", country: "US" as const, Flag: US },
      { code: "ar", country: "SA" as const, Flag: SA },
      { code: "fr", country: "FR" as const, Flag: FR },
    ];
  5. Revisa las fuentes

    Las fuentes se cargan en src/app/layout.tsx, y src/styles/base.css cambia a la fuente árabe para html[lang="ar"]. Un idioma con otro sistema de escritura necesita su propia fuente y una regla equivalente.

Los nombres de la marca en src/config/brand.config.ts solo tienen valores en y ar, y el inglés se muestra para cualquier otro idioma.

Añade un idioma a la API

Las rutas están dentro de back-end/.

  1. Copia la carpeta de traducciones

    Después, traduce los 18 archivos que contiene.

    Terminalen back-end
    cp -R src/i18n/translations/en src/i18n/translations/fr

    En PowerShell:

    Terminalen back-end
    Copy-Item -Recurse src/i18n/translations/en src/i18n/translations/fr
  2. Añade el código a la lista de idiomas admitidos

    SUPPORTED_LOCALES en src/i18n/locales.ts es la única lista de la API. La leen las traducciones, la validación del pago, el idioma fijado en cada pedido, las páginas de pago, los emails y sus enlaces a los dos frontends. Hasta que el código esté ahí, las solicitudes en el nuevo idioma reciben el idioma por defecto.

    back-end/src/i18n/locales.ts
    export const SUPPORTED_LOCALES = ['en', 'ar', 'fr'] as const;
  3. Revisa los dos lugares que comprueban el árabe

    src/modules/mail/templates/layout.ts maqueta un email de derecha a izquierda solo para ar; amplíalo para otro idioma que se escriba de derecha a izquierda. Las dos búsquedas, src/modules/search/search.service.ts y src/modules/public/student-search.service.ts, leen un título guardado solo en árabe o en inglés, porque el contenido tiene dos idiomas. Encuéntralas:

    Terminalen back-end
    grep -rn "=== 'ar'" src
  4. Reinicia la API

    Lee los archivos de traducción al iniciarse. Para producción, yarn build los copia en dist/.

¿Te atascaste en un paso?

Busca una solución antes de empezar de nuevo.

Solución de problemas

Preferencias de Cookies

Utilizamos cookies para mejorar tu experiencia de navegación, analizar el tráfico del sitio y personalizar el contenido. Al hacer clic en "Aceptar Todo", consientes nuestro uso de cookies para análisis y publicidad personalizada.