Saltar al contenido

Idiomas y rutas

Idioma por defecto sin prefijo, rutas /en/… generadas, enlaces localizados, selector, hreflang y sitemap.

Idioma por defecto sin prefijo

Con strategy: 'prefix_except_default', la opción por defecto, las URL del idioma por defecto no cambian y cada otro idioma vive bajo su prefijo. El módulo genera las rutas /en/… a partir de las páginas existentes, con el mismo archivo, layouts y opciones: no hay que duplicar páginas.

meeko.config.ts ts
i18n: {
  defaultLocale: 'es',
  catalogs: { es: { common: 'app/locales/es/common.json' }, en: { common: 'app/locales/en/common.json' } },
  // Por defecto: es sin prefijo y en con /en/…
  strategy: 'prefix_except_default',
  // Sin versiones /en/… ni hreflang:
  exclude: ['/admin/*'],
  // Un idioma con traducción parcial sólo tiene estas rutas:
  partial: { ar: ['/playground'] },
}

// app/pages/guide.meeko        -> /guide y /en/guide
// app/pages/docs/[...slug].meeko -> /docs/… y /en/docs/…
// app/pages/en/legal.meeko     -> sustituye a la /en/legal generada

Una página del proyecto en la URL de otro idioma, como app/pages/en/legal.meeko, sustituye a la ruta generada: así se escribe la prosa de una página en cada idioma. exclude deja una ruta sin versiones y partial limita las de un idioma con traducción parcial. Una URL con el prefijo del idioma por defecto, como /es/guide, no existe.

meeko
<script lang="ts">
  const i18n = useI18n()
</script>

<template>
  <!-- /guide en español, /en/guide en inglés -->
  <a bind:href="i18n.localePath('/guide')">{i18n.t('nav.guide')}</a>
  <UILink bind:href="i18n.localePath('/docs/intro#setup')">Intro</UILink>
</template>

localePath añade el prefijo del idioma del documento, o del idioma que recibe, y conserva la búsqueda y el fragmento. Úsalo en los enlaces internos de la interfaz.

Selector de idioma

meeko
<script lang="ts">
  const i18n = useI18n()
</script>

<template>
  <nav aria-label="Idioma">
    <a
      each:of="i18n.pageLocales()"
      each:as="code"
      each:key="code"
      bind:href="i18n.switchLocalePath(code)"
      bind:hreflang="code"
      bind:lang="code"
      bind:aria-current="code === i18n.locale ? 'page' : undefined"
    >
      {i18n.localeName(code)}
    </a>
  </nav>
</template>

<!-- /playground?tab=demo#messages -> /en/playground?tab=demo#messages -->

switchLocalePath devuelve la ruta equivalente de la página actual en otro idioma y pageLocales los idiomas que tienen versión de ella. Usa enlaces reales: funcionan sin JavaScript y los buscadores los siguen. Cambiar de idioma es una navegación completa que guarda la elección en una cookie; switchLocale hace lo mismo desde un script.

hreflang y sitemap

html
<!-- /en/guide, con site: 'https://example.com' -->
<html lang="en" dir="ltr">
<link rel="alternate" href="https://example.com/guide" hreflang="es">
<link rel="alternate" href="https://example.com/en/guide" hreflang="en">
<link rel="alternate" href="https://example.com/guide" hreflang="x-default">

<!-- sitemap.xml (sitemap: true) -->
<url>
  <loc>https://example.com/en/guide</loc>
  <xhtml:link rel="alternate" hreflang="es" href="https://example.com/guide"/>
  <xhtml:link rel="alternate" hreflang="en" href="https://example.com/en/guide"/>
  <xhtml:link rel="alternate" hreflang="x-default" href="https://example.com/guide"/>
</url>

Cada página localizada declara lang, dir y un link rel="alternate" por idioma más x-default, con URL absolutas a partir de site. Con sitemap: true, el sitemap.xml de Meeko lista cada versión con sus alternativas.

Sugerir el idioma, sin redirigir

meeko
<script lang="ts">
  const i18n = useI18n()
  const suggestion = signal<string | undefined>(undefined)
  // Sólo en el navegador, después de hidratar: nunca redirige.
  onMounted(() => { suggestion.value = i18n.suggestedLocale() })
</script>

<template>
  <p if:when="suggestion.value" role="status">
    <a bind:href="i18n.switchLocalePath(suggestion.value!)">
      {i18n.localeName(suggestion.value!)}
    </a>
    <button type="button" on:click="() => { i18n.rememberLocale(i18n.locale); suggestion.value = undefined }">
      {i18n.localeName(i18n.locale)}
    </button>
  </p>
</template>

Las URL sin prefijo siempre muestran el idioma por defecto: el módulo nunca redirige según Accept-Language ni la cookie. Así cada URL tiene un único contenido que los buscadores pueden indexar y las cachés pueden compartir. suggestedLocale propone, sólo en el navegador, el idioma de la cookie o de navigator.languages para que muestres un aviso.

Utilidades de URL

Imports explícitos ts
import { localeOf, localizedPath, negotiateLocale, stripLocale } from '@meekojs/i18n'

const locales = ['es', 'en', 'ar']
localeOf('/en/playground', locales, 'es') // 'en'
localeOf('/playground', locales, 'es')    // 'es'
localizedPath('/playground?q=1#form', 'en', locales, 'es')
// '/en/playground?q=1#form'
localizedPath('/en/playground', 'es', locales, 'es') // '/playground'
stripLocale('/en/playground', locales)               // '/playground'
negotiateLocale('en-US,en;q=0.9,es;q=0.8', locales)  // 'en'

localeOf devuelve el idioma del primer segmento o el fallback recibido. localizedPath sustituye un prefijo conocido y omite el del idioma por defecto; negotiateLocale elige un idioma configurado a partir de una cabecera Accept-Language o de una lista de preferencias.

Probar cambio con query y fragmento

¿Te sirvió esta página?

Añadir un comentario

Se envía al elegir «Sí» o «No». Solo se guardan la página, tu respuesta y el comentario: ni cookies ni datos tuyos.

0 de 2000 caracteres