Cambio de idioma
Implementa selectores de idioma para permitir que los usuarios cambien su idioma preferido.
Implementación básica
Usa el hook useLingoContext para obtener la configuración regional actual y una función para cambiarla:
"use client"; // For Next.js
import { useLingoContext } from "@lingo.dev/compiler/react";
export function LanguageSwitcher() {
const { locale, setLocale } = useLingoContext();
return (
<select value={locale} onChange={(e) => setLocale(e.target.value)}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="de">Deutsch</option>
<option value="fr">Français</option>
</select>
);
}
Cuando se llama a setLocale():
- El nuevo idioma se persiste (mediante un resolver personalizado o cookie por defecto)
- La página se recarga para aplicar el nuevo idioma
Interfaz personalizada
Menú desplegable con banderas
"use client";
import { useLingoContext } from "@lingo.dev/compiler/react";
const locales = [
{ code: "en", name: "English", flag: "🇺🇸" },
{ code: "es", name: "Español", flag: "🇪🇸" },
{ code: "de", name: "Deutsch", flag: "🇩🇪" },
{ code: "fr", name: "Français", flag: "🇫🇷" },
];
export function LanguageSwitcher() {
const { locale: currentLocale, setLocale } = useLingoContext();
return (
<div className="relative">
<select
value={currentLocale}
onChange={(e) => setLocale(e.target.value)}
className="px-4 py-2 border rounded-md"
>
{locales.map((locale) => (
<option key={locale.code} value={locale.code}>
{locale.flag} {locale.name}
</option>
))}
</select>
</div>
);
}
Grupo de botones
"use client";
import { useLingoContext } from "@lingo.dev/compiler/react";
export function LanguageSwitcher() {
const { locale, setLocale } = useLingoContext();
const locales = ["en", "es", "de", "fr"];
return (
<div className="flex gap-2">
{locales.map((loc) => (
<button
key={loc}
onClick={() => setLocale(loc)}
className={`px-3 py-1 rounded ${
locale === loc ? "bg-blue-500 text-white" : "bg-gray-200"
}`}
>
{loc.toUpperCase()}
</button>
))}
</div>
);
}
Menú desplegable
"use client";
import { useState } from "react";
import { useLingoContext } from "@lingo.dev/compiler/react";
export function LanguageSwitcher() {
const { locale, setLocale } = useLingoContext();
const [isOpen, setIsOpen] = useState(false);
const locales = [
{ code: "en", name: "English" },
{ code: "es", name: "Español" },
{ code: "de", name: "Deutsch" },
{ code: "fr", name: "Français" },
];
const currentLocaleName = locales.find((l) => l.code === locale)?.name;
return (
<div className="relative">
<button
onClick={() => setIsOpen(!isOpen)}
className="px-4 py-2 border rounded-md flex items-center gap-2"
>
<span>{currentLocaleName}</span>
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 9l-7 7-7-7" />
</svg>
</button>
{isOpen && (
<div className="absolute top-full mt-2 bg-white border rounded-md shadow-lg">
{locales.map((loc) => (
<button
key={loc.code}
onClick={() => {
setLocale(loc.code);
setIsOpen(false);
}}
className={`block w-full text-left px-4 py-2 hover:bg-gray-100 ${
locale === loc.code ? "bg-blue-50" : ""
}`}
>
{loc.name}
</button>
))}
</div>
)}
</div>
);
}
Persistencia
Por defecto, setLocale() usa la persistencia de idioma configurada (cookie por defecto).
Persistencia personalizada
Implementa persistencia personalizada mediante resolvers de idioma personalizados:
// .lingo/locale-resolver.client.ts
export function persistLocale(locale: string): void {
// Custom logic: localStorage, URL params, API call, etc.
localStorage.setItem("locale", locale);
window.location.reload();
}
setLocale() llama automáticamente a tu función persistLocale().
Evitar la recarga de página
Por defecto, setLocale() recarga la página para aplicar el nuevo idioma. Para evitar la recarga:
- Usa gestión de estado del lado del cliente
- Precarga las traducciones para todos los idiomas
- Cambia las traducciones sin recargar la página
Nota: Esto requiere una implementación personalizada; el comportamiento por defecto del compilador recarga la página por simplicidad.
Cambio de idioma basado en URL
Para enrutamiento de idioma basado en URL (/en/about, /es/about):
"use client";
import { useRouter, usePathname } from "next/navigation";
export function LanguageSwitcher() {
const router = useRouter();
const pathname = usePathname();
// Extract current locale from path: /es/about → es
const currentLocale = pathname.split("/")[1];
function switchLocale(newLocale: string) {
// Replace locale in path: /es/about → /de/about
const newPath = pathname.replace(`/${currentLocale}`, `/${newLocale}`);
router.push(newPath);
}
return (
<select value={currentLocale} onChange={(e) => switchLocale(e.target.value)}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="de">Deutsch</option>
</select>
);
}
Cambio basado en subdominio
Para enrutamiento basado en subdominio (es.example.com):
"use client";
export function LanguageSwitcher() {
const currentLocale = window.location.hostname.split(".")[0];
function switchLocale(newLocale: string) {
const host = window.location.hostname;
const domain = host.split(".").slice(1).join(".");
const newHost = `${newLocale}.${domain}`;
window.location.href = `${window.location.protocol}//${newHost}${window.location.pathname}`;
}
return (
<select value={currentLocale} onChange={(e) => switchLocale(e.target.value)}>
<option value="en">English</option>
<option value="es">Español</option>
<option value="de">Deutsch</option>
</select>
);
}
Nombres de idiomas nativos
Muestra los nombres de los idiomas en su idioma nativo para una mejor experiencia de usuario:
const locales = [
{ code: "en", name: "English" },
{ code: "es", name: "Español" },
{ code: "de", name: "Deutsch" },
{ code: "fr", name: "Français" },
{ code: "ja", name: "日本語" },
{ code: "zh", name: "中文" },
{ code: "ar", name: "العربية" },
{ code: "ru", name: "Русский" },
];
Accesibilidad
Haz que tu selector de idioma sea accesible:
const { locale, setLocale } = useLingoContext();
<div role="group" aria-label="Language selector">
<label htmlFor="language-select" className="sr-only">
Choose language
</label>
<select
id="language-select"
value={locale}
onChange={(e) => setLocale(e.target.value)}
aria-label="Select language"
>
{locales.map((loc) => (
<option key={loc.code} value={loc.code}>
{loc.name}
</option>
))}
</select>
</div>
Patrones comunes
Integración en la barra de navegación
export function Navbar() {
return (
<nav className="flex items-center justify-between p-4">
<Logo />
<div className="flex items-center gap-4">
<NavLinks />
<LanguageSwitcher />
</div>
</nav>
);
}
Integración en el pie de página
export function Footer() {
return (
<footer className="p-4 border-t">
<div className="flex justify-between items-center">
<p>© 2024 Your Company</p>
<LanguageSwitcher />
</div>
</footer>
);
}
Menú móvil
export function MobileMenu() {
return (
<div className="mobile-menu">
<NavLinks />
<div className="border-t pt-4 mt-4">
<p className="text-sm text-gray-500 mb-2">Language</p>
<LanguageSwitcher />
</div>
</div>
);
}
Pruebas
Prueba el cambio de idioma en desarrollo:
- Añade el componente selector de idioma
- Ejecuta el servidor de desarrollo
- Haz clic para cambiar de idioma
- Verifica que la página se recargue con el nuevo idioma
- Comprueba que las traducciones se actualicen
Con el pseudotraductor habilitado, verás traducciones falsas inmediatamente.
Preguntas frecuentes
¿Por qué se recarga la página? El compilador recarga la página para aplicar el nuevo idioma. Esto garantiza que todos los componentes de servidor y metadatos se actualicen correctamente.
¿Puedo evitar la recarga? Sí, pero requiere una implementación personalizada. Precarga todas las traducciones y gestiona el estado del lado del cliente manualmente.
¿Necesito envolver LanguageSwitcher en Suspense?
No. useLingoContext es síncrono, no se necesita suspense.
¿Puedo detectar automáticamente el idioma del navegador del usuario? Sí. Impleméntalo en resolvedores de locale personalizados:
export function getClientLocale(): string {
return navigator.language.split("-")[0] || "en";
}
¿Debo mostrar todos los locales compatibles o solo algunos? Muestra todos en un menú desplegable. Si hay muchos locales, agrúpalos por región o usa una interfaz de búsqueda/filtro.
Próximos pasos
- Resolvedores de locale personalizados — Personaliza la persistencia
- Integración de frameworks — Patrones de enrutamiento específicos del framework
- Mejores prácticas — Recomendaciones de UX para el cambio de idioma