Skip to content

Tutorial: useLocales y Traducciones

El proyecto tiene dos sistemas de i18n que coexisten:

SistemaArchivoUso
vue-i18n (useI18n)i18n/es.json, en.json, pt-BR.jsonStrings cortas: botones, labels, mensajes de error
useLocalesapp/locales/inspiria/{lang}/{page}.jsonContenido de páginas completas: títulos, secciones, textos largos

useLocales<T>('webinars')
1. Detecta idioma actual (useI18n().locale ó languageStore)
2. import(`~/locales/inspiria/${lang}/webinars.json`)
3. import(`~/locales/inspiria/es/webinars.json`) ← siempre carga fallback
4. mergeWithFallback(data, fallbackData) ← merge profundo
5. return { data: T }
<script setup lang="ts">
interface WebinarsPage {
title: string
subtitle: string
filters: { label: string; value: string }[]
}
const { data: pageData } = await useLocales<WebinarsPage>('webinars')
</script>
<template>
<h1>{{ pageData.title }}</h1>
<p>{{ pageData.subtitle }}</p>
</template>

El composable useLocales implementa mergeWithFallback() que resuelve traducciones parciales:

// locales/inspiria/es/webinars.json (fallback - completo)
{
"title": "Webinars",
"subtitle": "Formación en directo",
"filters": [
{ "id": 1, "label": "Todos" },
{ "id": 2, "label": "Próximos" },
{ "id": 3, "label": "Grabados" }
]
}
// locales/inspiria/en/webinars.json (parcial - solo title traducido)
{
"title": "Webinars",
"subtitle": "",
"filters": [
{ "id": 1, "label": "All" },
{ "id": 2, "label": "" }
]
}

Resultado del merge (lo que recibe el componente):

{
"title": "Webinars", // ← inglés (tiene valor)
"subtitle": "Formación en directo", // ← español (inglés está vacío)
"filters": [
{ "id": 1, "label": "All" }, // ← inglés
{ "id": 2, "label": "Próximos" }, // ← español (inglés vacío)
{ "id": 3, "label": "Grabados" } // ← español (no existe en inglés)
]
}
CasoResultado
Campo con valor en ambosUsa el idioma primario
Campo vacío/null en primarioUsa el fallback (español)
Array con objetos que tienen idMerge por ID (no por posición)
Array sin IDsMerge por posición (índice)
Objeto falta en primarioUsa el del fallback completo
Archivo entero falta en primarioUsa fallback completo

Necesitas…Usa
Label de botón (“Comprar”, “Cancel”)useI18n() → t('common.buy')
Mensaje de error genéricouseI18n() → t('errors.network')
Contenido completo de una páginauseLocales<T>('pageName')
Datos que podrían no estar traducidosuseLocales (tiene fallback)
Texto en un componente reutilizableuseI18n()

  1. Crea el JSON en español (es el fallback y debe estar completo):

    app/locales/inspiria/es/mi-pagina.json
  2. Crea versiones para otros idiomas (pueden estar parcialmente traducidas):

    app/locales/inspiria/en/mi-pagina.json
    app/locales/inspiria/pt-BR/mi-pagina.json
  3. Usa en el componente:

    const { data } = await useLocales<MiPaginaData>('mi-pagina')