Grav en varios idiomas

Soporte para múltiples idiomas en Grav

El soporte para múltiples idiomas en Grav es el resultado directo de un gran debate comunitario sobre el tema. Ahora desglosaremos esto y proporcionaremos ejemplos de cómo puedes configurar tu sitio Grav con múltiples idiomas.

Un solo idioma diferente al inglés

Si solo usas un idioma, activa las traducciones y añade tu código de idioma en el archivo user/config/system.yaml:

languages:
  supported:
    - fr

o en la configuración del Sistema en el Admin:

Configuración de Traducciones en Admin

Esto asegurará que Grav use las cadenas de idioma correctas en el frontend. Además, si el tema lo soporta, añadirá tu código de idioma a la etiqueta HTML.

Conceptos básicos de múltiples idiomas

Como ya deberías estar familiarizado con cómo Grav usa archivos markdown en carpetas para definir la estructura arquitectural así como configurar opciones importantes de página y contenido, no entraremos directamente en esos mecanismos. Sin embargo, ten en cuenta que por defecto Grav busca un único archivo .md en una carpeta para representar la página. Si no estás lo suficientemente familiarizado con este principio, por favor consulta la sección Tutorial Básico antes de continuar. Con el soporte multi-idioma activado, Grav buscará el archivo markdown nombrado apropiadamente para el idioma, por ejemplo default.en.md o default.fr.md.

Configuración de idioma

Para que Grav haga esto primero debes configurar algunas opciones básicas de idioma en tu archivo user/config/system.yaml (con comentarios para mejor legibilidad):

languages:
  supported: # Idiomas soportados:
    - en # Idioma inglés
    - fr # Idioma francés
  default_lang: en # Establece inglés como idioma por defecto
  include_default_lang: true # Si es true, usa /en/ruta en lugar de /ruta para el idioma inglés por defecto.
  include_default_lang_file_extension: true # Si es true, usa la extensión .en.md en lugar de .md para el idioma por defecto.
  content_fallback:
    en: ['en'] # Sin fallback para inglés.
    fr: ['fr', 'en'] # El francés recurre a la versión en inglés de la página.

Al proporcionar un bloque languages con una lista de idiomas supported, has habilitado efectivamente el soporte multi-idioma en Grav.

En este ejemplo puedes ver que se han descrito dos idiomas soportados (en y fr). Estos te permitirán soportar los idiomas inglés y francés.

Si no se solicita explícitamente un idioma (mediante la URL o por código), Grav usará el orden de los idiomas proporcionados para seleccionar el idioma correcto. Así que en el ejemplo anterior, el idioma por defecto es en o inglés. Si tuvieras fr primero, el francés sería el idioma por defecto.

Por defecto, todos los idiomas recurren al idioma por defecto. Si no quieres que haga eso, puedes sobrescribir los fallbacks de idioma usando content_fallback, donde la clave es el idioma y el valor es un array de idiomas.

Por supuesto puedes proporcionar tantos idiomas como quieras e incluso puedes usar códigos tipo locale como en-GB, en-US y fr-FR. Si usas esta nomenclatura basada en locale, tendrás que reemplazar todos los códigos cortos de idioma con las versiones de locale.

Páginas en múltiples idiomas

Por defecto en Grav, cada página está representada por un archivo markdown, por ejemplo default.md. Cuando activas el soporte multi-idioma, Grav buscará el archivo markdown nombrado apropiadamente. Por ejemplo, como el inglés es nuestro idioma por defecto, primero buscará default.en.md.

Si ese archivo no se encuentra, recurrirá al valor por defecto de Grav y buscará default.md para proporcionar información para la página.

Este comportamiento por defecto ha cambiado en Grav 1.7. En el pasado Grav mostraba la página en inglés no existente en francés, ahora todos los idiomas recurren solo al idioma por defecto si no se especifica lo contrario en content_fallback. Así que si la página no se encuentra en ninguno de los idiomas de fallback, se muestra en su lugar una Página de Error 404.

Si tuviéramos el sitio Grav más básico, con un solo archivo 01.home/default.md, podríamos empezar renombrando default.md a default.en.md, y su contenido podría verse así:

---
title: Página de inicio
---

¡Esta es mi página de inicio con Grav!

Luego podrías crear una nueva página ubicada en la misma carpeta 01.home/ llamada default.fr.md con el contenido:

---
title: Page d'accueil
---

Ceci est ma page d'accueil générée par Grav !

Ahora has definido dos páginas para tu página de inicio actual en múltiples idiomas.

Si estás convirtiendo un sitio existente para usar multi-idioma, puedes alternativamente establecer include_default_lang_file_extension: false para seguir usando la extensión de archivo simple .md para tu idioma principal. Leer más....

Idioma activo mediante URL

Como el inglés es el idioma por defecto, si apuntas tu navegador sin especificar un idioma obtendrías el contenido descrito en el archivo default.en.md, pero también podrías solicitar explícitamente inglés apuntando tu navegador a

http://tusitio.com/en

Para acceder a la versión en francés, por supuesto, usarías

http://tusitio.com/fr

Si prefieres no usar prefijo de idioma para el idioma por defecto, establece include_default_lang: false. Leer más....

Idioma activo mediante navegador

La mayoría de navegadores te permiten configurar qué idiomas prefieres ver en el contenido. Grav tiene la capacidad de leer estos valores http_accept_language y compararlos con los idiomas soportados actuales para el sitio, y si no se ha detectado un idioma específico, mostrarte contenido en tu idioma preferido.

Para que esto funcione debes habilitar la opción en tu archivo user/system.yaml en la sección languages::

languages:
  http_accept_language: true

Idioma activo basado en sesión

Si deseas recordar el idioma activo independientemente de la URL, puedes activar el almacenamiento del idioma activo basado en sesión. Para habilitar esto, debes asegurarte de tener session: enabled: true en el system.yaml. Luego necesitas habilitar la configuración de idioma:

languages:
  session_store_active: true

Esto almacenará entonces el idioma activo en la sesión.

Establecer locale al idioma activo

La configuración booleana establecerá el método PHP setlocale() que controla cosas como valores monetarios, fechas, comparaciones de cadenas, clasificaciones de caracteres y otras configuraciones específicas de locale al idioma activo. Esto es false por defecto, y entonces usará el locale del sistema, si estableces este valor a true sobrescribirá el locale con el idioma activo actual.

languages:
   override_locale: false

Prefijo de idioma por defecto

Por defecto, el código de idioma por defecto tiene prefijo en todas las URLs. Por ejemplo si tienes soporte para inglés y francés (en y fr), y el predeterminado es inglés. Una ruta de página podría verse como /en/mi-pagina en inglés y /fr/ma-page en francés. Sin embargo a menudo es preferible tener el idioma por defecto sin el prefijo, así que puedes simplemente establecer esta opción a false y la página en inglés aparecería como /mi-pagina.

languages:
    include_default_lang: false

[version=17]

Extensión de archivo por defecto

Si estás convirtiendo un sitio existente para usar multi-idioma, puede ser desalentador convertir todas las páginas existentes para usar la nueva extensión de archivo de idioma .en.md (si usas inglés). En este caso, puedes querer deshabilitar la extensión de idioma en tu idioma original.

languages:
    include_default_lang_file_extension: false

[/version]

Enrutamiento multi-idioma

Grav típicamente usa los nombres de las carpetas para producir una ruta URL para una página particular. Esto permite que la arquitectura del sitio sea fácilmente entendida e implementada como un conjunto anidado de carpetas. Sin embargo con un sitio multi-idioma puedes querer usar una URL que tenga más sentido en ese idioma particular.

Si tuviéramos la siguiente estructura de carpetas:

- 01.animals
  - 01.mammals
    - 01.bats
    - 02.bears
    - 03.foxes
    - 04.cats
  - 02.reptiles
  - 03.birds
  - 04.insets
  - 05.aquatic

Esto produciría URLs como http://tusitio.com/animals/mammals/bears. Esto es genial para un sitio en inglés, pero si quisieras tener una versión en francés preferirías que estas estuvieran traducidas apropiadamente. La forma más fácil de lograr esto es añadir un slug personalizado para cada uno de los archivos fr.md. Por ejemplo, la página de mamíferos podría verse algo así:

---
title: Mammifères
slug: mammiferes
---

Les mammifères (classe des Mammalia) forment un taxon inclus dans les vertébrés, traditionnellement une classe, définie dès la classification de Linné. Ce taxon est considéré comme monophylétique...

Esto combinado con sobreescrituras de slug apropiadas en los otros archivos debería resultar en una URL de http://tusitio.com/animaux/mammiferes/ours que se ve mucho más en francés.

Otra opción es hacer uso del soporte de rutas a nivel de página y proporcionar un alias de ruta completo para la página.

Página de inicio basada en idioma

Si sobreescribes la ruta/slug para la página de inicio, Grav no podrá encontrar la página de inicio como está definida por tu opción home.alias en tu system.yaml. Estará buscando /homepage y tu página de inicio en francés podría tener una ruta de /page-d-accueil.

Para soportar páginas de inicio multi-idioma Grav tiene una nueva opción que puede usarse en lugar de home.alias y es simplemente home.aliases y podría verse algo así:

home:
  aliases:
    en: /homepage
    fr: /page-d-accueil

De esta forma Grav sabe cómo enrutarte a la página de inicio si el idioma activo es inglés o francés.

Plantillas Twig basadas en idioma

Por defecto, Grav usa el nombre del archivo markdown para determinar la plantilla Twig a usar para renderizar. Esto funciona con multi-idioma de la misma manera. Por ejemplo, default.fr.md buscaría un archivo Twig llamado default.html.twig en las rutas de plantilla Twig apropiadas del tema actual y cualquier plugin que registre rutas de plantilla Twig. Con multi-idioma, Grav también añade el idioma activo actual a la estructura de rutas. Lo que esto significa es que si necesitas tener un archivo Twig específico para un idioma, puedes simplemente ponerlos en una carpeta de idioma a nivel raíz. Por ejemplo si tu tema actual está usando una plantilla ubicada en templates/default.html.twig puedes crear una carpeta templates/fr/, y poner tu archivo Twig específico para francés ahí: templates/fr/default.html.twig.

Otra opción que requiere configuración manual es sobreescribir la configuración template: en las cabeceras de página. Por ejemplo:

template: default.fr

Esto buscará una plantilla ubicada en templates/default.fr.html.twig

Esto te proporciona dos opciones para proporcionar sobreescrituras Twig específicas para idioma.

Si no se proporciona una plantilla Twig específica para un idioma, se usará la predeterminada.

Traducción mediante Twig

La forma más simple de usar estas cadenas de traducción en tus plantillas Twig es usar el filtro Twig |t. También puedes usar la función Twig t(), pero francamente el filtro es más limpio y hace lo mismo:

<h1 id="site-name">SITE_NAME</h1>
<section id="header">
    <h2>HEADER.MAIN_TEXT</h2>
    <h3>HEADER.SUB_TEXT</h3>
</section>

Usando la función Twig t() la solución es similar:

<h1 id="site-name">SITE_NAME</h1>
<section id="header">
    <h2>HEADER.MAIN_TEXT</h2>
    <h3>HEADER.SUB_TEXT</h3>
</section>

Otro nuevo filtro/función Twig te permite traducir desde un array. Esto es particularmente útil si tienes una lista de valores como meses del año, o días de la semana. Por ejemplo, digamos que tienes esta traducción:

en:
  GRAV:
    MONTHS_OF_THE_YEAR: [January, February, March, April, May, June, July, August, September, October, November, December]

Podrías obtener la traducción apropiada para el mes de una publicación con lo siguiente:

Mayo

También puedes usar esto como una función Twig con ta().

Traducciones con variables

También puedes usar variables en tus traducciones Twig usando la sintaxis sprintf de PHP:

SIMPLE_TEXT: Hay %d monos en el %s

Y luego puedes poblar esas variables con el Twig:

SIMPLE_TEXT

resultando en la traducción:

Hay 12 monos en el Zoológico de Londres

Traducciones complejas

A veces se requiere realizar traducciones complejas con reemplazo en idiomas específicos. Puedes utilizar todo el poder del método translate() de los objetos Language con el filtro/función tl. Por ejemplo:

SIMPLE_TEXT

Traducirá la cadena SIMPLE_TEXT y reemplazará los marcadores de posición con 12 y Zoológico de Londres respectivamente. También hay un array pasado con traducciones de idioma para probar en orden de primer-encontrado-primer-usado. Esto mostrará el resultado en francés:

Il y a 12 singes dans le Zoo de Londres

Traducciones PHP

Además del filtro y funciones Twig puedes usar el mismo enfoque dentro de tu plugin Grav:

$translation = $this->grav['language']->translate(['HEADER.MAIN_TEXT']);

También puedes especificar un idioma:

$translation = $this->grav['language']->translate(['HEADER.MAIN_TEXT'], ['fr']);

Para traducir un ítem específico en un array usa:

$translation = $this->grav['language']->translateArray('GRAV.MONTHS_OF_THE_YEAR', 3);

Traducciones de plugins y temas

También puedes proporcionar tus propias traducciones en plugins y temas. Esto se hace creando un archivo languages.yaml en la raíz de tu plugin o tema (ej. /user/plugins/error/languages.yaml, o user/themes/antimatter/languages.yaml), y debería contener todos los idiomas soportados prefijados por el código de idioma o locale:

en:
  PLUGIN_ERROR:
    TITLE: Error Plugin
    DESCRIPTION: The error plugin provides a simple mechanism for handling error pages within Grav.
fr:
  PLUGIN_ERROR:
    TITLE: Plugin d'Erreur
    DESCRIPTION: Le plugin d'erreur fournit un mécanisme simple de manipulation des pages d'erreur au sein de Grav.

La convención para plugins es usar PLUGIN_PLUGINNAME. como prefijo para todas las cadenas de idioma, para evitar cualquier conflicto de nombres. Los temas tienen menos probabilidades de introducir conflictos de cadenas de idioma, pero es una buena idea prefijar las cadenas añadidas en temas con THEME_THEMENAME.

Sobrescrituras de traducción

Si deseas sobrescribir una traducción particular, simplemente pon el par clave/valor modificado en un archivo de idioma apropiado en tu carpeta user/languages/. Por ejemplo un archivo llamado user/languages/en.yaml podría contener:

PLUGIN_ERROR:
  TITLE: Mi Plugin de Error

Esto asegurará que siempre puedas sobrescribir una cadena de traducción sin meterte con los plugins o temas mismos, y también evitará sobrescribir una traducción personalizada al actualizarlos.

Avanzado

Manejo de idioma basado en entorno

Puedes aprovechar la Configuración de Entorno de Grav para enrutar automáticamente a los usuarios a la versión correcta de tu sitio basado en la URL. Por ejemplo, si tuvieras una URL como http://french.misitio.com que fuera un alias para tu http://www.misitio.com estándar, podrías configurar una configuración de entorno:

/user/french.misitio.com/config/system.yaml

languages:
  supported:
    - fr
    - en

Esto usa un orden de idioma invertido así que el idioma por defecto es ahora fr así que el idioma francés se mostrará por defecto.

Rutas de alias de idioma

Debido a que cada página puede tener su propia ruta personalizada, sería difícil cambiar entre diferentes versiones de idioma de la misma página. Sin embargo, hay un nuevo método Page.rawRoute() en el objeto Page que obtendrá la misma ruta cruda para cualquiera de las varias traducciones de idioma de una sola página. Todo lo que necesitarías hacer es poner el código de idioma delante para obtener la ruta correcta a una versión de idioma específica de una página.

Por ejemplo, digamos que estás en una página en inglés con una ruta personalizada de:

/mi-pagina-inglesa-personalizada

La página en francés tiene la ruta personalizada de:

/ma-page-francaise-personnalisee

Podrías obtener la página cruda de la página en inglés y eso podría ser:

/blog/personalizada/mi-pagina

Luego solo añade el idioma que quieras y esa es tu nueva URL;

/fr/blog/personalizada/mi-pagina

Esto recuperará la misma página que /ma-page-francaise-personnalisee.

Soporte de traducción

Grav proporciona un mecanismo simple pero potente para proporcionar traducciones en Twig y también via PHP para usar en temas y plugins. Esto está habilitado por defecto, y usará el idioma en si no hay idiomas definidos. Para habilitar o deshabilitar traducciones manualmente, hay una configuración en tu system.yaml:

languages:
  translations: true

Las traducciones usan la misma lista de idiomas definida por languages: supported: en tu system.yaml.

El sistema de traducción funciona de forma similar a la configuración de Grav y hay varios lugares y formas en que puedes proporcionar traducciones.

El primer lugar donde Grav busca archivos de traducción es en la carpeta system/languages. Se espera que los archivos estén creados en el formato: en.yaml, fr.yaml, etc. Cada archivo yaml debe contener un array o arrays anidados de pares clave/valor:

SITE_NAME: Mi Sitio de Blog
HEADER:
    MAIN_TEXT: Bienvenido a mi nuevo sitio de blog
    SUB_TEXT: ¡Visita diariamente para las últimas noticias!

Para facilidad de identificación, Grav prefiere el uso de cadenas de idioma en mayúsculas ya que esto ayuda a determinar cadenas no traducidas y también hace más claro cuando se usan en plantillas Twig.

Grav tiene la capacidad de recurrir a través de los idiomas soportados para encontrar una traducción si no se encuentra una para el idioma activo. Esto está habilitado por defecto pero puede deshabilitarse via la opción translations_fallback:

languages:
  translations_fallback: true

Ayuda a Grav a llegar a una comunidad más amplia de usuarios proporcionando traducciones en tu idioma. Usamos la Plataforma de Traducción Crowdin para facilitar la traducción del Núcleo de Grav y el Plugin de Administración de Grav. ¡Regístrate y empieza a traducir hoy mismo!

Conmutador de idioma

Puedes descargar un simple plugin de Conmutador de Idioma via el plugin de Admin, o a través de GPM con:

bin/gpm install langswitcher

La documentación para configuración e implementación puede encontrarse en GitHub.

Configuración con dominios específicos de idioma

Configura tu sitio con Manejo de Idioma Basado en Entorno para asignar idiomas por defecto (el primer idioma) a dominios.

Asegúrate de que la opción

pages.redirect_default_route: true

esté establecida a true en tu system.yaml.

Añade lo siguiente a tu archivo .htaccess y adapta los slugs de idioma y nombres de dominio a tus necesidades:

# http://www.cheat-sheets.org/saved-copy/mod_rewrite_cheat_sheet.pdf
# http://www.workingwith.me.uk/articles/scripting/mod_rewrite

# manejar nivel superior ej. http://grav-site.com/de
RewriteRule ^en/?$ "http://grav-site.com" [R=302,L]
RewriteRule ^de/?$ "http://grav-site.de" [R=302,L]

# manejar sub páginas, excluir ruta admin
RewriteCond %{REQUEST_URI} !(admin) [NC]
RewriteRule ^en/(.*)$ "http://grav-site.com/$1" [R=302,L]
RewriteCond %{REQUEST_URI} !(admin) [NC]
RewriteRule ^de/(.*)$ "http://grav-site.de/$1" [R=302,L]

Si sabes cómo simplificar las reglas de reescritura, por favor edita esta página en GitHub haciendo clic en el enlace Editar en la parte superior de la página.

Aquí hay una versión simplificada del conjunto de reglas:

# http://www.cheat-sheets.org/saved-copy/mod_rewrite_cheat_sheet.pdf
# http://www.workingwith.me.uk/articles/scripting/mod_rewrite

# Redirigir URLs de nivel superior
RewriteRule ^en/?$ "http://grav-site.com" [R=302,L]
RewriteRule ^de/?$ "http://grav-site.de" [R=302,L]

# Redirigir sub-páginas, excluyendo la ruta admin
RewriteCond %{REQUEST_URI} !^/admin [NC]
RewriteRule ^(en|de)/(.*)$ "http://grav-site.$1/$2" [R=302,L]

Esta versión simplificada combina las reglas de reescritura para redirigir sub-páginas para "en" y "de" en una sola regla usando agrupación. Adicionalmente, consolida el RewriteCond para la ruta admin para reducir duplicación.

Asegúrate de añadir estas reglas antes de las reglas por defecto que vienen con Grav CMS.

Lógica de idioma en plantillas Twig

A menudo hay necesidad de acceder al estado y lógica de Idioma desde plantillas Twig. Por ejemplo si necesitas acceder a un cierto archivo de imagen que es diferente para un idioma particular y se nombra diferente (miimagen.en.jpg y miimagen.fr.jpg).

Para mostrar la versión correcta de la imagen necesitarías saber el idioma activo actual. Esto es posible en Grav accediendo al objeto Language via el objeto Grav, y llamando al método apropiado. En el ejemplo anterior esto podría lograrse con el siguiente código Twig:

La llamada getActive en el Twig está efectivamente llamando a Language->getActive() para retornar el código de idioma activo actual. Algunos métodos útiles de Language incluyen:

  • getLanguages() - Retorna un array de todos los idiomas soportados
  • getLanguage() - Retorna el idioma activo actual, sino retorna el idioma por defecto
  • getActive() - Retorna el idioma activo actual
  • getDefault() - Retorna el idioma por defecto (primero)

Para una lista completa de métodos disponibles, puedes mirar en el archivo <grav root>/system/src/Grav/Common/Language/Language.php.