Traducir tu app Vue.js es esencial para llegar a una audiencia global. vue-i18n es el plugin oficial de internacionalización para Vue.js, proporcionando una solución potente y flexible para gestionar traducciones. Esta guía te guiará a través del proceso de traducir una app Vue.js usando vue-i18n.
Entendiendo la Localización de Vue.js con vue-i18n
vue-i18n es la biblioteca estándar de internacionalización para Vue.js. Proporciona componentes Vue, directivas y una API de composición para manejar traducciones, pluralización y formateo de fechas, números y monedas.
Paso 1: Instalar Dependencias
Para Vue 3:
npm install vue-i18n@9
Para Vue 2:
npm install vue-i18n@8
O con yarn:
yarn add vue-i18n@9 # Vue 3
yarn add vue-i18n@8 # Vue 2
Paso 2: Crear Archivos de Traducción
Crea un directorio locales en tu carpeta src y agrega archivos de traducción para cada idioma:
src/locales/en.json (Inglés - por defecto):
{
"app": {
"welcome": "Welcome to our app!",
"title": "My Vue.js App"
},
"button": {
"submit": "Submit",
"cancel": "Cancel",
"delete": "Delete"
},
"error": {
"network": "Network error. Please try again.",
"notFound": "Page not found"
},
"items": {
"count": "{count} items",
"count_zero": "No items",
"count_one": "{count} item",
"count_other": "{count} items"
},
"user": {
"greeting": "Hello, {name}! You have {count} messages.",
"greeting_zero": "Hello, {name}! You have no messages.",
"greeting_one": "Hello, {name}! You have {count} message.",
"greeting_other": "Hello, {name}! You have {count} messages."
}
}
src/locales/es.json (Español):
{
"app": {
"welcome": "¡Bienvenido a nuestra aplicación!",
"title": "Mi Aplicación Vue.js"
},
"button": {
"submit": "Enviar",
"cancel": "Cancelar",
"delete": "Eliminar"
},
"error": {
"network": "Error de red. Por favor, inténtalo de nuevo.",
"notFound": "Página no encontrada"
},
"items": {
"count": "{count} elementos",
"count_zero": "No hay elementos",
"count_one": "{count} elemento",
"count_other": "{count} elementos"
},
"user": {
"greeting": "¡Hola, {name}! Tienes {count} mensajes.",
"greeting_zero": "¡Hola, {name}! No tienes mensajes.",
"greeting_one": "¡Hola, {name}! Tienes {count} mensaje.",
"greeting_other": "¡Hola, {name}! Tienes {count} mensajes."
}
}
src/locales/fr.json (Francés):
{
"app": {
"welcome": "Bienvenue dans notre application!",
"title": "Mon Application Vue.js"
},
"button": {
"submit": "Soumettre",
"cancel": "Annuler",
"delete": "Supprimer"
},
"error": {
"network": "Erreur réseau. Veuillez réessayer.",
"notFound": "Page non trouvée"
},
"items": {
"count": "{count} éléments",
"count_zero": "Aucun élément",
"count_one": "{count} élément",
"count_other": "{count} éléments"
},
"user": {
"greeting": "Bonjour, {name}! Vous avez {count} messages.",
"greeting_zero": "Bonjour, {name}! Vous n'avez aucun message.",
"greeting_one": "Bonjour, {name}! Vous avez {count} message.",
"greeting_other": "Bonjour, {name}! Vous avez {count} messages."
}
}
Paso 3: Configurar vue-i18n (Vue 3)
Crea un archivo de configuración i18n:
src/i18n.js:
import { createI18n } from 'vue-i18n';
import en from './locales/en.json';
import es from './locales/es.json';
import fr from './locales/fr.json';
const messages = {
en,
es,
fr
};
const i18n = createI18n({
locale: 'en', // Locale por defecto
fallbackLocale: 'en', // Locale de respaldo
messages,
legacy: false, // Usar modo Composition API
globalInjection: true // Habilitar $t global
});
export default i18n;
O con TypeScript (src/i18n.ts):
import { createI18n } from 'vue-i18n';
import en from './locales/en.json';
import es from './locales/es.json';
import fr from './locales/fr.json';
const messages = {
en,
es,
fr
} as const;
const i18n = createI18n({
locale: 'en',
fallbackLocale: 'en',
messages,
legacy: false,
globalInjection: true
});
export default i18n;
Paso 4: Inicializar i18n en tu App (Vue 3)
src/main.js:
import { createApp } from 'vue';
import App from './App.vue';
import i18n from './i18n';
const app = createApp(App);
app.use(i18n);
app.mount('#app');
O con TypeScript (src/main.ts):
import { createApp } from 'vue';
import App from './App.vue';
import i18n from './i18n';
const app = createApp(App);
app.use(i18n);
app.mount('#app');
Paso 5: Configurar vue-i18n (Vue 2)
Para Vue 2, la configuración es ligeramente diferente:
src/i18n.js:
import Vue from 'vue';
import VueI18n from 'vue-i18n';
import en from './locales/en.json';
import es from './locales/es.json';
import fr from './locales/fr.json';
Vue.use(VueI18n);
const messages = {
en,
es,
fr
};
const i18n = new VueI18n({
locale: 'en',
fallbackLocale: 'en',
messages
});
export default i18n;
src/main.js (Vue 2):
import Vue from 'vue';
import App from './App.vue';
import i18n from './i18n';
new Vue({
i18n,
render: h => h(App)
}).$mount('#app');
Paso 6: Usar Traducciones en Plantillas
Usa la función $t en plantillas:
Antes:
<template>
<h1>Welcome to our app!</h1>
</template>
Después:
<template>
<h1>{{ $t('app.welcome') }}</h1>
</template>
Paso 7: Usar Traducciones en Script (Composition API - Vue 3)
Usa el composable useI18n:
<template>
<h1>{{ t('app.welcome') }}</h1>
</template>
<script setup>
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
</script>
Paso 8: Usar Traducciones en Script (Options API)
<template>
<h1>{{ welcomeMessage }}</h1>
</template>
<script>
export default {
computed: {
welcomeMessage() {
return this.$t('app.welcome');
}
}
};
</script>
Paso 9: Interpolación de Cadenas con Variables
Pasa variables a las traducciones:
translation.json:
{
"user": {
"greeting": "Hello, {name}!"
}
}
Componente:
<template>
<p>{{ $t('user.greeting', { name: userName }) }}</p>
</template>
<script setup>
import { ref } from 'vue';
const userName = ref('John');
</script>
O con Composition API:
<template>
<p>{{ t('user.greeting', { name: userName }) }}</p>
</template>
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const userName = ref('John');
</script>
Paso 10: Pluralización
vue-i18n soporta pluralización usando claves especiales:
translation.json:
{
"items": {
"count": "{count} items",
"count_zero": "No items",
"count_one": "{count} item",
"count_other": "{count} items"
}
}
Componente:
<template>
<p>{{ $t('items.count', count, { count }) }}</p>
</template>
<script setup>
import { ref } from 'vue';
const count = ref(5);
</script>
O con Composition API:
<template>
<p>{{ t('items.count', count, { count }) }}</p>
</template>
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { t } = useI18n();
const count = ref(5);
</script>
Paso 11: Formatear Fechas
Usa la función $d o el método d:
Plantilla:
<template>
<p>{{ $d(date, 'long') }}</p>
</template>
<script setup>
import { ref } from 'vue';
const date = ref(new Date());
</script>
Composition API:
<template>
<p>{{ d(date, 'long') }}</p>
</template>
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { d } = useI18n();
const date = ref(new Date());
</script>
Configurar formatos de fecha en i18n:
const i18n = createI18n({
locale: 'en',
messages,
datetimeFormats: {
en: {
short: {
year: 'numeric',
month: 'short',
day: 'numeric'
},
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
}
},
es: {
short: {
year: 'numeric',
month: 'short',
day: 'numeric'
},
long: {
year: 'numeric',
month: 'long',
day: 'numeric',
weekday: 'long'
}
}
}
});
Paso 12: Formatear Números
Usa la función $n o el método n:
Plantilla:
<template>
<p>Número: {{ $n(number) }}</p>
<p>Moneda: {{ $n(amount, 'currency') }}</p>
</template>
<script setup>
import { ref } from 'vue';
const number = ref(1234.56);
const amount = ref(1234.56);
</script>
Composition API:
<template>
<p>Número: {{ n(number) }}</p>
<p>Moneda: {{ n(amount, 'currency') }}</p>
</template>
<script setup>
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
const { n } = useI18n();
const number = ref(1234.56);
const amount = ref(1234.56);
</script>
Configurar formatos de número en i18n:
const i18n = createI18n({
locale: 'en',
messages,
numberFormats: {
en: {
currency: {
style: 'currency',
currency: 'USD'
}
},
es: {
currency: {
style: 'currency',
currency: 'EUR'
}
}
}
});
Paso 13: Cambiar Idioma Programáticamente
Permite a los usuarios cambiar idiomas:
Composition API:
<template>
<div>
<button @click="changeLanguage('en')">English</button>
<button @click="changeLanguage('es')">Español</button>
<button @click="changeLanguage('fr')">Français</button>
</div>
</template>
<script setup>
import { useI18n } from 'vue-i18n';
const { locale } = useI18n();
const changeLanguage = (lang) => {
locale.value = lang;
localStorage.setItem('language', lang);
};
</script>
Options API:
<template>
<div>
<button @click="changeLanguage('en')">English</button>
<button @click="changeLanguage('es')">Español</button>
<button @click="changeLanguage('fr')">Français</button>
</div>
</template>
<script>
export default {
methods: {
changeLanguage(lang) {
this.$i18n.locale = lang;
localStorage.setItem('language', lang);
}
}
};
</script>
Paso 14: Detección de Idioma y Persistencia
Carga la preferencia de idioma guardada al iniciar la app:
src/i18n.js:
import { createI18n } from 'vue-i18n';
import en from './locales/en.json';
import es from './locales/es.json';
import fr from './locales/fr.json';
const messages = {
en,
es,
fr
};
// Obtener idioma guardado o detectar idioma del navegador
const getInitialLocale = () => {
const saved = localStorage.getItem('language');
if (saved && messages[saved]) return saved;
const browserLang = navigator.language.split('-')[0];
return messages[browserLang] ? browserLang : 'en';
};
const i18n = createI18n({
locale: getInitialLocale(),
fallbackLocale: 'en',
messages,
legacy: false,
globalInjection: true
});
export default i18n;
Paso 15: Manejar Idiomas de Derecha a Izquierda (RTL)
Para idiomas RTL como árabe y hebreo:
<template>
<div :dir="textDirection" :lang="currentLocale">
<!-- Contenido de tu app -->
</div>
</template>
<script setup>
import { computed, watch } from 'vue';
import { useI18n } from 'vue-i18n';
const { locale } = useI18n();
const currentLocale = computed(() => locale.value);
const isRTL = computed(() => ['ar', 'he', 'fa'].includes(locale.value));
const textDirection = computed(() => isRTL.value ? 'rtl' : 'ltr');
watch(locale, (newLocale) => {
document.documentElement.dir = isRTL.value ? 'rtl' : 'ltr';
document.documentElement.lang = newLocale;
}, { immediate: true });
</script>
Mejores Prácticas
1. Usar Claves de Traducción Descriptivas
Malo:
{
"msg1": "Submit"
}
Bueno:
{
"button": {
"submit": "Submit"
}
}
2. Organizar por Característica
{
"auth": {
"login": "Login",
"logout": "Logout"
},
"dashboard": {
"title": "Dashboard"
}
}
3. Usar Namespaces
Para apps grandes, divide las traducciones en namespaces:
i18n.js:
import commonEN from './locales/en/common.json';
import authEN from './locales/en/auth.json';
const messages = {
en: {
common: commonEN,
auth: authEN
}
};
Uso:
<template>
<p>{{ $t('auth.login') }}</p>
</template>
4. Proporcionar Fallbacks
const i18n = createI18n({
fallbackLocale: 'en',
missingWarn: false, // Deshabilitar advertencias en producción
fallbackWarn: false
});
5. Usar Formateo de Texto Enriquecido
<template>
<p v-html="$t('welcome', { link: '<a href="/about">here</a>' })"></p>
</template>
Nota: Ten cuidado con v-html por seguridad. Sanitiza la entrada del usuario.
6. Probar Longitudes de Cadenas
Algunos idiomas son más largos que otros. Diseña tu UI para acomodar:
- Alemán y finlandés: 30-50% más largo que inglés
- Idiomas asiáticos: Pueden necesitar más espacio vertical
Errores Comunes
1. Olvidar Instalar vue-i18n
Siempre instala la versión correcta:
npm install vue-i18n@9 # Vue 3
npm install vue-i18n@8 # Vue 2
2. No Usar Modo Composition API (Vue 3)
Para Vue 3, usa legacy: false:
const i18n = createI18n({
legacy: false, // Importante para Vue 3
// ...
});
3. Codificar Cadenas de Formato Directamente
Malo:
<p>${{ amount.toFixed(2) }}</p>
Bueno:
<p>{{ $n(amount, 'currency') }}</p>
4. No Manejar Traducciones Faltantes
Proporciona fallbacks y maneja claves faltantes con gracia.
Avanzado: Carga Perezosa de Traducciones
Carga traducciones bajo demanda:
const loadLocaleMessages = async (locale) => {
const messages = await import(`./locales/${locale}.json`);
i18n.global.setLocaleMessage(locale, messages.default);
return messages.default;
};
// Uso
await loadLocaleMessages('es');
i18n.global.locale.value = 'es';
Avanzado: Soporte TypeScript
Para mejor soporte TypeScript:
src/types/vue-i18n.d.ts:
import { DefineLocaleMessage } from 'vue-i18n';
declare module 'vue-i18n' {
export interface DefineLocaleMessage {
app: {
welcome: string;
title: string;
};
button: {
submit: string;
cancel: string;
delete: string;
};
// ... otros tipos de mensaje
}
}
Avanzado: Usar con Vue Router
Integra con Vue Router para routing basado en locale:
import { createRouter, createWebHistory } from 'vue-router';
import { useI18n } from 'vue-i18n';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/:locale?',
component: Layout,
children: [
{
path: '',
name: 'home',
component: Home
}
]
}
]
});
router.beforeEach((to, from, next) => {
const locale = to.params.locale || 'en';
const { locale: i18nLocale } = useI18n();
if (i18nLocale.value !== locale) {
i18nLocale.value = locale;
}
next();
});
Avanzado: Usar con Pinia (Gestión de Estado)
Almacena locale en Pinia:
import { defineStore } from 'pinia';
import { useI18n } from 'vue-i18n';
export const useLocaleStore = defineStore('locale', {
state: () => ({
currentLocale: 'en'
}),
actions: {
setLocale(locale) {
this.currentLocale = locale;
const { locale: i18nLocale } = useI18n();
i18nLocale.value = locale;
localStorage.setItem('language', locale);
}
}
});
Usar con Nuxt.js
Para aplicaciones Nuxt.js, vue-i18n está integrado:
nuxt.config.js:
export default {
modules: ['@nuxtjs/i18n'],
i18n: {
locales: ['en', 'es', 'fr'],
defaultLocale: 'en',
vueI18n: {
fallbackLocale: 'en',
messages: {
en: require('./locales/en.json'),
es: require('./locales/es.json'),
fr: require('./locales/fr.json')
}
}
}
};
Conclusión
Localizar tu app Vue.js con vue-i18n es sencillo cuando sigues estos pasos:
- Instalar
vue-i18n(versión 9 para Vue 3, versión 8 para Vue 2) - Crear archivos JSON de traducción para cada idioma
- Configurar vue-i18n con tus mensajes
- Usar
$ten plantillas ouseI18nen Composition API - Manejar pluralización con claves especiales
- Formatear fechas y números usando formateadores integrados
- Permitir a los usuarios cambiar idiomas
- Probar exhaustivamente en todos los idiomas soportados
Siguiendo estas prácticas, crearás una app que proporciona una experiencia nativa para usuarios en todo el mundo, expandiendo significativamente tu base de usuarios potencial.
Optimiza tu Flujo de Trabajo de Localización Vue.js
Gestionar traducciones para múltiples idiomas puede volverse complejo a medida que tu app crece. Considera usar una plataforma de gestión de traducciones para:
- Colaborar con traductores
- Mantener traducciones sincronizadas con tu código base
- Automatizar el flujo de trabajo de traducción
- Mantener consistencia en todos los idiomas
- Generar archivos de traducción automáticamente
¿Listo para llevar tu app Vue.js a nivel global? Explora la plataforma de localización de AZbox y optimiza tu flujo de trabajo de traducción: