Skip to main content

Internacionalización

El portal está traducido a 7 idiomas con next-intl, sin prefijo de idioma en la URL (no usa el middleware de routing de next-intl, solo getRequestConfig).

1. Idiomas soportados

Definidos en app/constants/languages.ts:

CódigoIdiomaBandera
enEnglish🇬🇧
esEspañol🇪🇸
frFrançais🇫🇷
deDeutsch🇩🇪
itItaliano🇮🇹
ptPortuguês🇵🇹
elΕλληνικά🇬🇷

en es el idioma por defecto (defaultLanguage) y el fallback cuando una traducción remota no existe.

2. Resolución del idioma (i18n/request.tsx)

En cada petición, getRequestConfig resuelve el locale por orden de prioridad:

  1. Cookie app_custom_language — selección explícita del usuario en el portal.
  2. Cookie HW_preferred_locale — preferencia establecida por la web de Hawkers (SFCC); permite que un cliente que llega desde la tienda vea el portal en el mismo idioma.
  3. Cabecera Accept-Language (primer valor).
  4. en por defecto.

El valor resultante se recorta a dos letras en minúscula (es-ESes) y se cargan los mensajes con import('../messages/<language>.json').

caution

En este punto no se valida que el idioma esté entre los soportados. Un navegador que envíe, por ejemplo, Accept-Language: nl provocará el import de un fichero inexistente. Ver Notas técnicas.

3. Selector de idioma

SelectLanguage (en el Footer) escribe la cookie app_custom_language con cookies-next (path: '/') y hace window.location.reload(): al no haber routing por locale, el cambio de idioma requiere una recarga completa para que el servidor vuelva a resolver el locale y recargar los mensajes.

4. Ficheros de mensajes

messages/{de,el,en,es,fr,it,pt}.json102 claves en cada fichero (los siete están sincronizados). Namespaces de primer nivel:

NamespaceUso
brand, button, order, ErrorComunes: marca, botones, etiquetas y errores genéricos
Formlabel.*, placeholder.*, info.* y error.* de formularios
FormSearchOrder, FormRetrieveCaseTextos y errores de los dos formularios de entrada
Step2, Step3, Step4Títulos, introducciones, diálogos y errores por paso
ThankYouPagePantalla de confirmación
ReturnConditionsCondiciones de devolución (condition1, condition3condition7)
productPricesPanel explicativo del cálculo de precios
pdfTítulos dentro de los PDFs
SelectLanguage, FooterSelector de idioma y pie
next, total, subtotal, subtotalItems, free, shippingCostClaves sueltas de importes y navegación

Texto con formato

Las claves que contienen etiquetas (<p>, <strong>, <i>, <a>) se renderizan con el componente RichText, que las mapea a elementos React. Los enlaces se resuelven por índice mediante la prop links — así ReturnConditions puede inyectar la URL de contacto correcta según el idioma.

ReturnConditions además consulta tReturnConditions.raw('conditionN') para omitir condiciones vacías: una condición que no aplica a un mercado se deja como cadena vacía en su fichero de mensajes y desaparece de la lista.

5. Traducciones que no están en el repositorio

Parte del contenido visible no vive en messages/, sino que llega traducido desde robo-api en un campo translations indexado por código de idioma:

DatoOrigen
Título, descripción e instrucciones del método de devolución/return-method/searchmapReturnMethod()
Motivos de devolución/return-reason/infogetTranslation()
Estados de devolución y de línea/return-status/info, /return-line-status/info

Ese campo puede llegar como objeto o como string JSON, por lo que el código hace typeof translations === 'string' ? JSON.parse(...) : translations antes de usarlo. Si falta la traducción del idioma activo, se cae al valor de en (estados) o a cadena vacía (métodos y motivos).

tip

Para añadir un idioma nuevo hay que hacer las dos cosas: crear messages/<código>.json y añadir la entrada en app/constants/languages.ts, y dar de alta las traducciones correspondientes en robo-api (métodos, motivos y estados). Con solo lo primero, el portal se mostraría traducido pero con métodos y motivos vacíos.