Saltar al contenido principal
01:43 AM
Volver al blog
astroi18ntypescriptsvelteislands-architecture

Islas i18n en Astro: Pasar el Locale al Límite Cliente

Un bug histórico de i18n llevó a este portfolio a pasar el locale desde Astro hacia Svelte en lugar de leer estado del navegador durante la inicialización.

·5 min
Editor de código con TypeScript

Este portfolio tiene pares de rutas localizadas como /en/projects y /es/proyectos. Astro conoce el locale al generar cada página, pero una isla hidratada puede sobrevivir a la navegación cliente. Eso crea una frontera: el locale inicial proviene del documento y el estado persistente del navegador debe responder a los cambios de ruta.

El Fallo Histórico

Un helper anterior leía window.location durante la inicialización de un componente Svelte. Se presentaba como seguro porque supuestamente el componente omitiría el código dependiente del navegador durante el render del servidor. La suposición era incorrecta: el código de inicialización puede ejecutarse mientras Astro prerenderiza una isla, donde window no existe.

Un fallback como typeof window !== 'undefined' ? locale : 'en' evita la excepción, pero puede renderizar rutas en español con estado inicial en inglés. Oculta el crash en lugar de definir un flujo de datos confiable.

El repositorio todavía conserva helpers legados sin consumidores para componentes React y Svelte anteriores. Su presencia es residuo histórico, no la arquitectura actual de las páginas públicas.

El Contrato Actual

Astro obtiene el locale desde la ruta y localiza los datos de colección antes de renderizar la isla:

---
const lang = getLangFromUrl(Astro.url);
const entries = await getCollection('projects');
const projects = entries.map((entry) => mapProjectEntry(entry, lang));
---

<StickerAlbum {projects} {lang} client:load />

El componente Svelte recibe lang como entrada obligatoria. No intenta adivinar el locale inicial desde un global del navegador:

<script lang="ts">
  interface Props {
    projects: ProjectForCard[];
    lang: 'en' | 'es';
  }

  let { projects, lang }: Props = $props();
</script>

Así, HTML generado, hidratación, labels, filtros y formato de fechas usan el mismo locale desde el primer render.

La Navegación Cliente Requiere Otra Regla

El escritorio retro conserva intencionalmente algunas ventanas durante las view transitions de Astro. El locale forma parte del contrato de ventanas persistentes, no solo de las props de página. Después de astro:after-swap, el shell lee la nueva ruta, actualiza el contenido localizado y conserva únicamente el estado seguro entre rutas equivalentes EN y ES.

El registro central de rutas entrega esas equivalencias. Los componentes no mantienen sus propias tablas about ↔ acerca-de o player ↔ reproductor.

La Lección General

La disponibilidad del navegador y la identidad del locale son problemas distintos. Un guard de ciclo de vida puede proteger una API del navegador, pero no garantiza el idioma inicial correcto. El orden robusto es:

  1. obtener el locale en Astro;
  2. localizar datos estáticos antes de hidratar;
  3. pasar el locale explícitamente a las islas interactivas;
  4. resincronizar estado persistente después de navegación cliente;
  5. probar EN → ES → EN con la UI afectada ya abierta.

El flujo de datos explícito más pequeño es más seguro que un hook conveniente que infiere estado global.