IntlPull
Tutorial
18 min read

Cómo traducir una página web: La guía definitiva para desarrolladores (2026)

Guía paso a paso para verificar e implementar la traducción de sitios web. Desde widgets sencillos hasta sistemas i18n React, Next.js y Vue listos para producción.

IntlPull Team
IntlPull Team
03 Feb 2026, 11:44 AM [PST]
On this page
Summary

Guía paso a paso para verificar e implementar la traducción de sitios web. Desde widgets sencillos hasta sistemas i18n React, Next.js y Vue listos para producción.

Los niveles de la traducción de páginas web

Traducir un sitio web no es una sola cosa. Es un espectro que va del "hack rápido" al "sistema de internacionalización de grado de producción"

Esto es lo que parece:

| Nivel, esfuerzo, calidad, caso de uso |-------|--------|---------|----------| | 1. Widget de Google Translate | 5 minutos | Pobre | Temporal, prueba de demanda | | 2. Páginas estáticas manuales | 1-2 días | Bueno | Sitios pequeños (5-10 páginas) | **2 | 3. Archivos JSON + Biblioteca | 3-5 días | Genial | La mayoría de los sitios web | | 4. Integración CMS | 1-2 semanas | Genial | Sitios de marketing | | 5. Plataforma i18n completa | 2-4 semanas | Excelente | SaaS, sitios de alto tráfico | 6. Integración CMS | 1-2 semanas | Estupendo | Sitios de marketing | **7. Integración JSON

Esta guía cubre los cinco enfoques con ejemplos de código.

Nivel 1: Widget de Google Translate (El truco de 5 minutos)

Cuándo usar: Quieres probar si un mercado es viable antes de invertir en una traducción real.

Pros:

  • Cero código
  • Soporta más de 100 idiomas
  • Gratis

**Desventajas

  • La calidad de la traducción es mediocre
  • Sin valor SEO (los rastreadores ven el idioma original)
  • Aspecto poco profesional
  • Las traducciones no se almacenan en caché (lentas)

Implementación

Añade esto a tu <body>:

HTML
1<div id="google_translate_element"></div>
2
3<script type="text/javascript">
4  function googleTranslateElementInit() {
5    new google.translate.TranslateElement(
6      {
7        pageLanguage: 'en',
8        includedLanguages: 'es,fr,de,zh-CN,ja',
9        layout: google.translate.TranslateElement.InlineLayout.SIMPLE
10      },
11      'google_translate_element'
12    );
13  }
14</script>
15
16<script type="text/javascript" src="//translate.google.com/translate_a/element.js?cb=googleTranslateElementInit"></script>

Ya está. Los usuarios ven un menú desplegable para elegir idiomas.

Styling del widget:

CSS
1/* Hide Google's branding */
2.goog-te-banner-frame {
3  display: none !important;
4}
5
6/* Style the dropdown */
7.goog-te-combo {
8  padding: 8px 12px;
9  border: 1px solid #e2e8f0;
10  border-radius: 6px;
11  font-size: 14px;
12}

Why This Sucks for Production

  1. Desastre de SEO: Google indexa tu contenido original. Los usuarios hispanohablantes que busquen en español no encontrarán tu sitio.

  2. Sin control: No puedes arreglar las malas traducciones. "Banco" podría traducirse como "banco"

  3. Rendimiento: Cada carga de página golpea los servidores de Google. Añade latencia.

  4. Problemas de UX: El diseño de la página se rompe cuando el texto se expande (el alemán es un 30% más largo que el inglés).

Verdict: Bien para probar. No lo envíes a usuarios reales.

Nivel 2: Páginas estáticas manuales (el método de copiar y pegar)

Cuando usar: Sitio pequeño (menos de 10 páginas), raramente actualizado, presupuesto limitado.

Esfuerzo: 1-2 días por idioma.

Cómo funciona

Cree archivos HTML independientes para cada idioma:

/index.html           (English)
/es/index.html        (Spanish)
/fr/index.html        (French)
/de/index.html        (German)

Ejemplo de Estructura

Versión en inglés (/index.html):

HTML
1<!DOCTYPE html>
2<html lang="en">
3<head>
4  <link rel="alternate" hreflang="es" href="/es/" />
5  <link rel="alternate" hreflang="fr" href="/fr/" />
6  <title>Welcome to Our Product</title>
7</head>
8<body>
9  <nav>
10    <a href="/">English</a>
11    <a href="/es/">Español</a>
12    <a href="/fr/">Français</a>
13  </nav>
14
15  <h1>Welcome to Our Product</h1>
16  <p>Build amazing apps with our platform.</p>
17
18  <button>Get Started</button>
19</body>
20</html>

Versión en español (/es/index.html):

HTML
1<!DOCTYPE html>
2<html lang="es">
3<head>
4  <link rel="alternate" hreflang="en" href="/" />
5  <link rel="alternate" hreflang="fr" href="/fr/" />
6  <title>Bienvenido a Nuestro Producto</title>
7</head>
8<body>
9  <nav>
10    <a href="/">English</a>
11    <a href="/es/">Español</a>
12    <a href="/fr/">Français</a>
13  </nav>
14
15  <h1>Bienvenido a Nuestro Producto</h1>
16  <p>Construye aplicaciones increíbles con nuestra plataforma.</p>
17
18  <button>Comenzar</button>
19</body>
20</html>

Configuración SEO

Añade etiquetas hreflang para que Google sepa qué versión mostrar:

HTML
1<!-- In every page -->
2<link rel="alternate" hreflang="en" href="https://example.com/" />
3<link rel="alternate" hreflang="es" href="https://example.com/es/" />
4<link rel="alternate" hreflang="fr" href="https://example.com/fr/" />
5<link rel="alternate" hreflang="x-default" href="https://example.com/" />

Detección de idiomas

Redirección basada en el idioma del navegador:

JavaScript
1// Detect user's language and redirect
2const userLang = navigator.language || navigator.userLanguage;
3const supportedLangs = ['en', 'es', 'fr'];
4const lang = userLang.slice(0, 2);
5
6// Only redirect on homepage
7if (window.location.pathname === '/' && supportedLangs.includes(lang) && lang !== 'en') {
8  // Check if user has manually selected a language before
9  if (!localStorage.getItem('language_selected')) {
10    window.location.href = `/${lang}/`;
11  }
12}
13
14// Remember user's choice
15document.querySelectorAll('nav a').forEach(link => {
16  link.addEventListener('click', () => {
17    localStorage.setItem('language_selected', 'true');
18  });
19});

Pros

  • Control SEO completo
  • Traducciones perfectas (contrata a profesionales)
  • Rápido (sin llamadas a API externas)
  • Alojamiento sencillo (sólo archivos HTML)

Contras

  • Pesadilla de mantenimiento (actualizar 5 páginas por cada cambio)
  • No es escalable (100 páginas × 5 idiomas = 500 archivos)
  • Sin contenido dinámico

Verdict: Bien para páginas de aterrizaje, terrible para aplicaciones.

Nivel 3: Archivos JSON + Biblioteca (El enfoque estándar)

Cuándo usar: La mayoría de los sitios web. Este es el estándar de la industria.

Frameworks: React, Vue, Next.js, Svelte - todos soportan esto.

How It Works

  1. Extraer cadenas a archivos JSON
  2. Utilizar la biblioteca i18n para cargar las traducciones
  3. Sustituir texto codificado por claves de traducción

Ejemplo de React (react-i18next)

Instalar:

Terminal
npm install react-i18next i18next

Instalación (i18n.js):

JavaScript
1import i18n from 'i18next';
2import { initReactI18next } from 'react-i18next';
3
4import enTranslations from './locales/en.json';
5import esTranslations from './locales/es.json';
6import frTranslations from './locales/fr.json';
7
8i18n
9  .use(initReactI18next)
10  .init({
11    resources: {
12      en: { translation: enTranslations },
13      es: { translation: esTranslations },
14      fr: { translation: frTranslations }
15    },
16    lng: localStorage.getItem('language') || 'en',
17    fallbackLng: 'en',
18    interpolation: {
19      escapeValue: false // React already escapes
20    }
21  });
22
23export default i18n;

Archivos de traducción:

locales/en.json:

JSON
1{
2  "welcome": {
3    "title": "Welcome to Our Product",
4    "subtitle": "Build amazing apps with our platform",
5    "cta": "Get Started"
6  },
7  "nav": {
8    "home": "Home",
9    "pricing": "Pricing",
10    "docs": "Documentation"
11  }
12}

CÓDIGO_BLOQUE_36:

JSON
1{
2  "welcome": {
3    "title": "Bienvenido a Nuestro Producto",
4    "subtitle": "Construye aplicaciones increíbles con nuestra plataforma",
5    "cta": "Comenzar"
6  },
7  "nav": {
8    "home": "Inicio",
9    "pricing": "Precios",
10    "docs": "Documentación"
11  }
12}

Componente:

JSX
1import { useTranslation } from 'react-i18next';
2
3function HomePage() {
4  const { t, i18n } = useTranslation();
5
6  const changeLanguage = (lng) => {
7    i18n.changeLanguage(lng);
8    localStorage.setItem('language', lng);
9  };
10
11  return (
12    <div>
13      <nav>
14        <button onClick={() => changeLanguage('en')}>English</button>
15        <button onClick={() => changeLanguage('es')}>Español</button>
16        <button onClick={() => changeLanguage('fr')}>Français</button>
17      </nav>
18
19      <h1>{t('welcome.title')}</h1>
20      <p>{t('welcome.subtitle')}</p>
21      <button>{t('welcome.cta')}</button>
22    </div>
23  );
24}

Con variables:

JSX
1// Translation file
2{
3  "greeting": "Hello, {{name}}! You have {{count}} messages."
4}
5
6// Component
7<p>{t('greeting', { name: 'Sarah', count: 5 })}</p>
8// Output: "Hello, Sarah! You have 5 messages."

Con plurales:

JSON
1{
2  "messages": "{{count}} message",
3  "messages_plural": "{{count}} messages"
4}
JSX
<p>{t('messages', { count: 1 })}</p> // "1 message"
<p>{t('messages', { count: 5 })}</p> // "5 messages"

Next.js Ejemplo (next-intl)

Install:

Terminal
npm install next-intl

Estructura del archivo:

/app/[locale]/
├── layout.tsx
├── page.tsx
/messages/
├── en.json
├── es.json
├── fr.json

i18n.ts:

TypeScript
1import { getRequestConfig } from 'next-intl/server';
2
3export default getRequestConfig(async ({ locale }) => ({
4  messages: (await import(`./messages/${locale}.json`)).default
5}));

middleware.ts (detección de configuración regional):

TypeScript
1import createMiddleware from 'next-intl/middleware';
2
3export default createMiddleware({
4  locales: ['en', 'es', 'fr'],
5  defaultLocale: 'en'
6});
7
8export const config = {
9  matcher: ['/((?!api|_next|.*\..*).*)']
10};

Componente de página:

TSX
1import { useTranslations } from 'next-intl';
2
3export default function HomePage() {
4  const t = useTranslations('welcome');
5
6  return (
7    <div>
8      <h1>{t('title')}</h1>
9      <p>{t('subtitle')}</p>
10      <button>{t('cta')}</button>
11    </div>
12  );
13}

URLs:

  • /en → Inglés
  • /es → Español
  • /fr → Francés

Next.js gestiona el enrutamiento, el SEO y la detección de configuración regional automáticamente.

Vue Ejemplo (vue-i18n)

Install:

Terminal
npm install vue-i18n

Setup (main.js):

JavaScript
1import { createApp } from 'vue';
2import { createI18n } from 'vue-i18n';
3import App from './App.vue';
4
5import en from './locales/en.json';
6import es from './locales/es.json';
7
8const i18n = createI18n({
9  locale: localStorage.getItem('language') || 'en',
10  fallbackLocale: 'en',
11  messages: { en, es }
12});
13
14createApp(App).use(i18n).mount('#app');

Component:

VUE
1<template>
2  <div>
3    <select v-model="$i18n.locale" @change="saveLanguage">
4      <option value="en">English</option>
5      <option value="es">Español</option>
6    </select>
7
8    <h1>{{ $t('welcome.title') }}</h1>
9    <p>{{ $t('welcome.subtitle') }}</p>
10  </div>
11</template>
12
13<script>
14export default {
15  methods: {
16    saveLanguage() {
17      localStorage.setItem('language', this.$i18n.locale);
18    }
19  }
20};
21</script>

Gestión de traducciones

Problema: Ahora tiene archivos JSON. ¿Cómo:

  • ¿Los envías a los traductores?
  • ¿Hacer un seguimiento de lo traducido?
  • ¿Detectar las claves que faltan?

Opción 1: Manual (doloroso)

  1. Exportar JSON a Excel
  2. Email traductores
  3. Copiar y pegar

Opción 2: Utilizar un TMS (inteligente)

Terminal
1# IntlPull example
2npx @intlpullhq/cli init
3
4# Upload source strings
5npx @intlpullhq/cli upload --source locales/en.json
6
7# Translators translate in web UI
8
9# Download translations
10npx @intlpullhq/cli download
11# Creates locales/es.json, locales/fr.json, etc.

Los traductores trabajan en una interfaz web, sólo tienes que tirar de los archivos actualizados.

Nivel 4: Integración con CMS (sitios de marketing)

Cuándo usar: Sitios con mucho contenido (blogs, páginas de marketing).

Opciones de CMS: Contentful, Sanity, Strapi.

Cómo funciona

En lugar de archivos JSON, el contenido vive en un CMS. Los editores traducen allí.

Ejemplo: Next.js + Contentful

Esquema:

JavaScript
1// Contentful content type
2{
3  "name": "Blog Post",
4  "fields": [
5    { "id": "title", "type": "Text", "localized": true },
6    { "id": "body", "type": "RichText", "localized": true },
7    { "id": "slug", "type": "Text", "localized": true }
8  ]
9}

Fetching:

TypeScript
1import { createClient } from 'contentful';
2
3const client = createClient({
4  space: process.env.CONTENTFUL_SPACE_ID,
5  accessToken: process.env.CONTENTFUL_ACCESS_TOKEN
6});
7
8export async function getBlogPost(slug: string, locale: string) {
9  const entries = await client.getEntries({
10    content_type: 'blogPost',
11    'fields.slug': slug,
12    locale: locale // 'en-US', 'es', 'fr'
13  });
14
15  return entries.items[0];
16}

Componente:

TSX
1export default async function BlogPost({ params }) {
2  const { slug, locale } = params;
3  const post = await getBlogPost(slug, locale);
4
5  return (
6    <article>
7      <h1>{post.fields.title}</h1>
8      <div>{documentToReactComponents(post.fields.body)}</div>
9    </article>
10  );
11}

Rutas:

  • CÓDIGO_BLOQUE_92
  • CÓDIGO_BLOQUE_93
  • CÓDIGO_BLOQUE_94

Pros

  • Editores no técnicos pueden traducir
  • Texto enriquecido, imágenes, campos SEO todo traducido
  • Vista previa antes de publicar

Contras

  • El CMS cuesta dinero
  • Vendedor fijo
  • Configuración más compleja

Nivel 5: Plataforma i18n completa (escala de producción)

Cuándo utilizar: Productos SaaS, sitios de alto tráfico, actualizaciones frecuentes.

Plataformas: IntlPull, Lokalise, Phrase, Crowdin.

What You Get

  • Web UI para traductores (con contexto, capturas de pantalla)
  • CLI para desarrolladores (traducciones upload/download)
  • Integración con Git (sincronización bidireccional)
  • Traducción automática (DeepL, ChatGPT)
  • Actualizaciones "over-the-air" (cambia las traducciones sin desplegarlas)
  • Memoria de traducción (reutilización de traducciones anteriores)
  • Flujos de trabajo de revisión (aprobar/rechazar)

Ejemplo: Flujo de trabajo IntlPull

1. Configuración inicial:

Terminal
npm install @intlpullhq/react
npx @intlpullhq/cli init

2. Desarrollador añade cadenas en el código:

TSX
1import { useIntlPull } from '@intlpullhq/react';
2
3function App() {
4  const { t } = useIntlPull();
5
6  return (
7    <div>
8      <h1>{t('welcome.title')}</h1>
9      <button>{t('welcome.cta')}</button>
10    </div>
11  );
12}

3. Extraer y cargar:

Terminal
npx @intlpullhq/cli upload
# Scans code for t() calls
# Uploads new strings to platform

4. Traductores traducir (en la interfaz de usuario web, con capturas de pantalla y el contexto)

5. Descargar traducciones:

Terminal
npx @intlpullhq/cli download
# Downloads all translations
# Generates locale files

6. Desplegar:

Terminal
npm run build

7. Actualizaciones OTA (opcional):

Más tarde, arreglas una errata en español. En lugar de redistribuir:

Terminal
npx @intlpullhq/cli publish --ota

Los usuarios obtienen las traducciones actualizadas al instante.

Configuración de producción

Next.js + IntlPull:

TypeScript
1// intlpull.config.ts
2export default {
3  projectId: 'your-project-id',
4  sourceLanguage: 'en',
5  targetLanguages: ['es', 'fr', 'de', 'ja', 'zh'],
6  ota: {
7    enabled: true,
8    pollingInterval: 60000 // Check for updates every minute
9  },
10  translation: {
11    defaultEngine: 'deepl',
12    fallback: 'google'
13  }
14};

Component:

TSX
1'use client';
2
3import { IntlPullProvider, useIntlPull } from '@intlpullhq/react';
4
5export default function RootLayout({ children }) {
6  return (
7    <IntlPullProvider config={{ projectId: 'your-project-id' }}>
8      {children}
9    </IntlPullProvider>
10  );
11}

Avanzado: Memoria de traducción

Reutiliza automáticamente traducciones anteriores:

Terminal
1# String in app 1: "Save changes"
2# Translated to Spanish: "Guardar cambios"
3
4# Later, in app 2, you add "Save changes"
5# IntlPull suggests "Guardar cambios" (100% match)

Ahorra tiempo y garantiza la coherencia.

SEO para sitios traducidos

1. Etiquetas hreflang

Indican a Google en qué idioma está cada página:

HTML
1<link rel="alternate" hreflang="en" href="https://example.com/en/page" />
2<link rel="alternate" hreflang="es" href="https://example.com/es/page" />
3<link rel="alternate" hreflang="fr" href="https://example.com/fr/page" />
4<link rel="alternate" hreflang="x-default" href="https://example.com/en/page" />

2. URLs localizadas

Opción A: Subdirectorios (recomendado)

  • CÓDIGO_BLOQUE_127
  • CÓDIGO_BLOQUE_128
  • CÓDIGO_BLOQUE_129

Opción B: Subdominios

  • CÓDIGO_BLOQUE_130
  • CÓDIGO BLOQUE 131
  • CÓDIGO BLOQUE 132

Opción C: Diferentes dominios

  • example.com (Inglés)
  • example.es (Español)
  • example.fr (francés)

Los subdirectorios son más fáciles para SEO (toda la autoridad en un dominio).

3. Metadatos localizados

TSX
1// Next.js example
2export async function generateMetadata({ params }) {
3  const { locale } = params;
4  const titles = {
5    en: 'Best Translation Platform for Developers',
6    es: 'Mejor Plataforma de Traducción para Desarrolladores',
7    fr: 'Meilleure Plateforme de Traduction pour Développeurs'
8  };
9
10  return {
11    title: titles[locale],
12    description: t('meta.description'), // From translation file
13    openGraph: {
14      title: titles[locale],
15      locale: locale
16    }
17  };
18}

Optimización del rendimiento

1. División del código

Sólo carga el idioma actual:

JavaScript
1// ❌ Bad: Load all languages
2import en from './locales/en.json';
3import es from './locales/es.json';
4import fr from './locales/fr.json';
5
6// ✅ Good: Lazy load
7const loadTranslations = async (locale) => {
8  return await import(`./locales/${locale}.json`);
9};

2. Almacenamiento en caché

TypeScript
1// Cache translations in localStorage
2const cacheTranslations = (locale, data) => {
3  const cache = {
4    locale,
5    data,
6    timestamp: Date.now()
7  };
8  localStorage.setItem('translations', JSON.stringify(cache));
9};
10
11const getCachedTranslations = (locale) => {
12  const cached = localStorage.getItem('translations');
13  if (!cached) return null;
14
15  const { locale: cachedLocale, data, timestamp } = JSON.parse(cached);
16
17  // Invalidate after 24 hours
18  if (cachedLocale !== locale || Date.now() - timestamp > 86400000) {
19    return null;
20  }
21
22  return data;
23};

3. Tamaño del paquete

Los archivos de traducción pueden llegar a ser enormes. Comprímalos:

Terminal
1# Before
2locales/en.json: 450 KB
3
4# After gzip
5locales/en.json.gz: 85 KB

La mayoría de los servidores gzip automáticamente, pero verifique.

Errores comunes

1. Cadenas codificadas por todas partes

TSX
1// ❌ Found this in production code
2<button>Submit</button>
3<p>Welcome to our app</p>
4<div>Loading...</div>

Los traductores no pueden arreglar esto. Utilice un linter:

Terminal
npm install eslint-plugin-i18next

.eslintrc:

JSON
1{
2  "plugins": ["i18next"],
3  "rules": {
4    "i18next/no-literal-string": "error"
5  }
6}

Ahora ESLint te grita: "¡No hardcodees 'Submit'!"

2. Olvidar Imágenes/Iconos

El texto cambia, pero los iconos pueden no traducirse culturalmente:

  • Pulgar hacia arriba 👍 es ofensivo en algunos países de Oriente Medio
  • El gesto de OK 👌 es grosero en Brasil
  • Los colores tienen significados (blanco = luto en China)

Utiliza diferentes conjuntos de imágenes por localización cuando sea necesario.

3. Expansión del texto

El alemán es un 30% más largo que el inglés. Su interfaz de usuario se romperá.

Prueba con pseudo-localización:

JavaScript
// Expands English to simulate German
"Hello""Ĥéļļö [ẋẋẋẋ]"
"Submit""Śûƀɱîţ [ẋẋẋẋẋ]"

Si la interfaz de usuario se rompe con pseudo-localización, se romperá con el alemán.

4. Formato de fecha/número

No haga esto:

JavaScript
`${month}/${day}/${year}` // US-only format

Haz esto:

JavaScript
new Intl.DateTimeFormat(locale).format(date)

Lo mismo para números, monedas, etc. Utilice Intl API.

Desglose de costes

DIY (Nivel 3 - Archivos JSON):

  • Desarrollo: 3-5 días × $500/día = content: ,500-2,500
  • Traducción: 0,10 $/palabra × 5.000 palabras × 3 idiomas = 1.500 $
  • Mantenimiento: 2 horas/semana × 100 $/hora = 200 $/semana
  • Total año 1: ~14.000 dólares

Plataforma TMS (Nivel 5 - IntlPull):

  • Desarrollo: 1-2 días × $500/día = $500-1.000
  • Plataforma: 29 $/mes × 12 = 348 $
  • Traducción (con MT + revisión): 0,03 $/palabra × 5.000 × 3 = 450 $
  • Mantenimiento: 0.5 horas/semana × 100 $/hora = 50 $/semana
  • Total año 1: ~4.400 dólares

La plataforma ahorra 10.000 dólares en el primer año.

La matriz de decisión

SituaciónEnfoque recomendado
Comprobar la demanda del mercado Widget de Google Translate (Nivel 1)
Sitio de marketing de 5 páginas Páginas estáticas manuales (Nivel 2)
Aplicación React/Vue, 2-3 idiomas Archivos JSON + react-i18next (Nivel 3)
Next.js, 5+ idiomas Next-intl + TMS (Nivel 3 + 5)
Producto SaaS, actualizaciones frecuentes Plataforma i18n completa (Nivel 5)
Blog/sitio de contenidosIntegración CMS (Nivel 4)

Inicio rápido: React App en 30 minutos

Vamos a traducir una aplicación real desde cero.

Paso 1: Instalar

Terminal
npm install react-i18next i18next

**Paso 2: Crear archivos

src/i18n/index.js:

JavaScript
1import i18n from 'i18next';
2import { initReactI18next } from 'react-i18next';
3import en from './locales/en.json';
4import es from './locales/es.json';
5
6i18n.use(initReactI18next).init({
7  resources: { en: { translation: en }, es: { translation: es } },
8  lng: 'en',
9  fallbackLng: 'en'
10});
11
12export default i18n;

CÓDIGO_BLOQUE_176:

JSON
1{
2  "nav": { "home": "Home", "about": "About" },
3  "home": {
4    "title": "Welcome",
5    "cta": "Get Started"
6  }
7}

CÓDIGO_BLOQUE_180__:

JSON
1{
2  "nav": { "home": "Inicio", "about": "Acerca de" },
3  "home": {
4    "title": "Bienvenido",
5    "cta": "Comenzar"
6  }
7}

**Paso 3: Uso en componentes

CÓDIGO_BLOQUE_184__:

JSX
1import './i18n';
2import { useTranslation } from 'react-i18next';
3
4function App() {
5  const { t, i18n } = useTranslation();
6
7  return (
8    <div>
9      <nav>
10        <button onClick={() => i18n.changeLanguage('en')}>EN</button>
11        <button onClick={() => i18n.changeLanguage('es')}>ES</button>
12      </nav>
13      <h1>{t('home.title')}</h1>
14      <button>{t('home.cta')}</button>
15    </div>
16  );
17}

Listo. Su aplicación está traducida.


**¿Quieres saltarte el flujo de trabajo manual?

Pruebe IntlPull gratis. Empuje las cadenas de origen del código, los traductores trabajan en una interfaz web, tire de las traducciones antes de desplegar. Incluye actualizaciones OTA.

O hazlo tú mismo si te sientes cómodo gestionando archivos JSON y flujos de trabajo de traductores.

Tags
web-translation
i18n
react
nextjs
vue
website-localization
tutorial
IntlPull Team
IntlPull Team
Engineering

Building tools to help teams ship products globally. Follow us for more insights on localization and i18n.