# Internacionalización

Flarum cuenta con un potente sistema de traducción (basado en el traductor de Symfony (opens new window)) que permite que la interfaz muestre información en prácticamente cualquier idioma. Deberías considerar aprovechar el traductor de Flarum mientras desarrollas tu extensión, incluso si no tienes intención de usarla en más de un idioma.

Por un lado, este sistema le permitirá cambiar la información mostrada por su extensión sin editar el código real. También le proporcionará las herramientas necesarias para tratar eficazmente fenómenos como la pluralización y la concordancia de género. Y nunca se sabe: puede ser útil más adelante si decide que quiere añadir más idiomas y hacer que su extensión esté disponible para usuarios de todo el mundo.

Esta guía le mostrará cómo crear un archivo de configuración regional que contenga recursos lingüísticos para su extensión, y cómo usar el traductor para acceder a esos recursos desde su código. Aprenderás a tratar con traducciones más complejas que implican variables y etiquetas HTML, así como pluralización y género.

También describiremos el formato estándar que debe seguirse al desarrollar recursos lingüísticos para Flarum, y ofreceremos algunos consejos que pueden ayudarte a que tus recursos lingüísticos sean más fáciles de localizar. Pero primero, comencemos con una visión general de cómo Flarum prioriza los recursos cuando muestra la salida para una extensión de terceros.

# Cómo traduce Flarum

A diferencia de las extensiones incluidas en Flarum, que se traducen utilizando recursos añadidos por paquetes de idiomas, una extensión de terceros tiene que proporcionar todas sus propias traducciones. Como desarrollador de Flarum, dependerá de ti obtener y mantener los recursos para cada idioma que quieras que soporte tu extensión.

Por regla general, un sitio de Flarum sólo puede mostrar las traducciones correspondientes a los paquetes de idiomas que se han instalado en ese sitio. Pero Flarum hará todo lo posible — dentro de esta limitación — para renderizar la salida de su extensión en algún tipo de lenguaje legible para el usuario:

  1. Comenzará buscando una traducción en el idioma de visualización preferido por el usuario.
  2. Si no encuentra ninguna, buscará una traducción en el idioma por defecto del foro.
  3. Como último esfuerzo, buscará una traducción "genérica" al inglés de la salida.
  4. Si ninguna de las anteriores está disponible, se rendirá y mostrará una clave de traducción.

Dado que las traducciones al inglés podrían ser lo único que se interponga entre los usuarios del foro y las antiestéticas claves de traducción, recomendamos encarecidamente incluir un conjunto completo de recursos en inglés con cada extensión. (También tendrá que incluir recursos en inglés si desea listar su extensión en el Mercado de Flarum).

# Archivo de localización

Los recursos lingüísticos de Flarum utilizan el formato de archivo YAML (opens new window). Los archivos de localización de una extensión de terceros deben almacenarse en la carpeta locale de la extensión. Cada archivo de configuración regional debe nombrarse utilizando el código ISO 639-1 (opens new window) del idioma que contiene. Por ejemplo, un archivo que contenga traducciones al francés debe llamarse "fr.yml".

TIP

Si desea proporcionar soporte para una localización específica, puede añadir un guión bajo seguido de un código de país ISO 3166-1 alpha-2 (opens new window); el nombre de archivo para el francés hablado en Canadá, por ejemplo, sería "fr_CA.yml". Pero debe asegurarse de incluir un archivo de configuración regional que contenga traducciones "genéricas" para el mismo idioma, de modo que Flarum tenga algo a lo que recurrir en caso de que un usuario especifique una configuración regional que usted no haya previsto.

El esqueleto de la extensión incluye una plantilla locale/en.yml donde puedes poner las traducciones al inglés de tu extensión. Si quieres añadir recursos para otro idioma o localización, simplemente duplica la plantilla y dale un nombre de archivo apropiado. A continuación, abre el archivo y empieza a añadir tus traducciones.

# Añadir claves

Cada traducción en el archivo de configuración regional debe ir precedida de una clave, que se utilizará como identificador para esa traducción. La clave de identificación debe estar en snake_case y seguida de dos puntos y un espacio, como se muestra a continuación:

sample_key: This is a sample translation.

También puede utilizar claves para espaciar el nombre de sus traducciones. Para empezar, la primera línea del archivo de configuración regional debe consistir en una única clave que reúna todas las traducciones de su extensión en un único espacio de nombres. Esta clave debe coincidir exactamente con el nombre de la carpeta en la que se encuentra la extensión, kebab-case y todo eso.

Se pueden utilizar claves adicionales para dividir el espacio de nombres de la extensión en grupos. Esto es muy útil cuando quieres organizar tus traducciones de acuerdo con el lugar donde aparecen en la interfaz de usuario, por ejemplo. Estas claves intermedias de espaciado de nombres deben estar siempre en snake_case.

Cada clave de espaciado de nombres debe ir seguida de dos puntos. Las claves deben anidarse según el formato de esquema de YAML, añadiendo dos espacios de sangría por cada nivel de la jerarquía. Poniendo todo esto junto, el archivo de configuración regional para el tutorial de inicio rápido podría ser algo así:

acme-hello-world:                # Namespacing for the extension; unindented.
  alert:                         # Namespacing for alerts; indented 2 spaces.
    hello_text: "Hello, world!"  # Identifier/translation; indented 4 spaces.

Una vez que tengas esta información, puedes formar la clave de traducción completa que utilizarás para acceder a una traducción enumerando sus claves en orden desde el espacio de nombres de extensión hasta un identificador, con puntos como delimitadores. Por ejemplo, la clave de traducción completa para la traducción "Hello, world!" sería:

'acme-hello-world.alert.hello_text'

Eso es todo lo que necesitas saber sobre la mecánica de la creación de claves. Sin embargo, ten en cuenta que hay un formato estándar que los desarrolladores deben seguir al crear recursos lingüísticos para Flarum. Las reglas para traducciones de namespacing y naming ID keys se pueden encontrar en el Apéndice A.

# Añadir traducciones

Los ejemplos de la sección anterior ya le han dado lo básico: usted escribe una clave de identificación — seguida de dos puntos y un espacio — luego escribe la traducción. Así de fácil. Aquí sólo queremos añadir algunos detalles que le ayudarán a tratar con traducciones más largas y complejas.

Comillas

Habrás notado que sólo una de las dos traducciones de ejemplo de la sección anterior iba entre comillas. Por lo general, no es necesario delimitar las traducciones de este modo. Sin embargo, debe utilizar comillas dobles para encerrar cualquier traducción que incluya uno o más de los siguientes caracteres:

`  !  @  #  %  &  *  -  =  [  ]  {  }  |  :  ,  <  >  ?

Dado que Flarum utiliza corchetes y paréntesis angulares para denotar marcadores de posición para [variables] (#including-variables) y etiquetas HTML, respectivamente, no hace falta decir que cualquier traducción que incluya dichos marcadores de posición también deberá ir entre comillas dobles.

Además, debe utilizar comillas simples para encerrar cualquier traducción que incluya uno o más caracteres de comillas dobles (") o barras invertidas (\). Esta regla tiene prioridad. Así que si una traducción incluyera tanto comillas dobles como uno o más caracteres de la lista anterior — como lo hace este ejemplo, en el que un marcador de posición de una variable está delimitado por comillas — tendría que encerrarlo entre comillas simples.

# Bloques literales

Cuando necesite que una traducción aparezca como más de una línea de texto, la traducción debe añadirse como un bloque literal. Introduzca un carácter de barra vertical (|) en el lugar en el que normalmente comenzaría la traducción, y luego añada la traducción debajo de la clave de identificación, sangrado cada línea con dos espacios adicionales:

literal_block_text: |
  Estas líneas se mostrarán como se muestra aquí, con saltos de línea y todo.

      También se conserva la sangría adicional: ¡esta línea tendrá una sangría de 4 espacios!

  Las comillas son innecesarias, incluso cuando el bloque contiene caracteres especiales.

El bloque literal termina con la última línea con una sangría de al menos dos espacios más que la clave de identificación. Las comillas no son necesarias porque el bloque está efectivamente delimitado por estos dos espacios extra de sangría.

Los recursos lingüísticos básicos de Flarum emplean bloques literales principalmente para el contenido del cuerpo del correo electrónico.

# Referencias clave

No es raro utilizar el mismo trozo de texto en más de un lugar o contexto. Supongamos que quieres que tu extensión muestre la frase "Editar cosas" en dos lugares de la interfaz de usuario:

  • Como un botón en el que los usuarios pueden hacer clic cuando quieren editar algunas cosas
  • Como el título de un cuadro de diálogo que se muestra cuando los usuarios hacen clic en ese botón

Tu instinto podría ser el de añadir una única traducción — llamémosla "edit_stuff" — y utilizar esa clave de identificación dos veces en tu código. Este enfoque es eficiente, pero carece de flexibilidad: en algunos idiomas, puede que no sea posible utilizar la misma frase tanto para el botón como para el título del diálogo. Una forma mejor sería definir dos claves para su uso en el código, y luego establecer que ambas hagan referencia a la misma traducción, de esta manera:

edit_stuff_button: => edit_stuff    # Se utiliza en el código que crea el botón.
edit_stuff_title: => edit_stuff     # Se utiliza en el código que crea el diálogo.

edit_stuff: Edit Stuff              # No se utiliza en el código.

Puede establecer que una clave haga referencia a otra sustituyendo su traducción por un signo de igualdad (=), un signo de mayor que (>) y un espacio, seguido de la clave de traducción completa a la que se hará referencia. Al instalar la extensión, el compilador de Flarum resolverá estas referencias para crear un conjunto completo de traducciones que pueda utilizar.

Hay más cosas que decir sobre las referencias; para empezar, ¡hemos ignorado totalmente el tema del espaciado de nombres en el ejemplo anterior! Y puede que se pregunte por qué sugerimos crear tres claves cuando dos serían suficientes. Para una explicación, vea las reglas para reutilizar traducciones en el Apéndice A.

# Uso del traductor

Una vez que hayas añadido una traducción a tu archivo de configuración regional, con el espaciado de nombres y las claves de identificación apropiadas, puedes utilizar el método app.translator.trans() para hacer referencia a esa traducción en tu código. Por ejemplo, el archivo js/forum/src/index.js para el tutorial de inicio rápido podría tener este aspecto:

app.initializers.add('acme-hello-world', function() {
  alert(app.translator.trans('acme-hello-world.alert.hello_text'));
});

Esto muestra el método de traducción básico, sin campanas ni silbidos. A continuación encontrará ejemplos de traducciones más complejas que incluyen cosas como variables y etiquetas HTML. (Tenga en cuenta que hemos omitido el espaciado de nombres en los siguientes ejemplos para mantenerlos simples; si mira el código real, encontrará que las traducciones están debidamente espaciadas por nombres según el formato estándar.)

# Inclusión de variables

Puedes incluir variables en las traducciones. Como ejemplo, veamos el código que crea el primer elemento del desplegable de resultados de búsqueda (opens new window) de Flarum. Este botón cita la consulta de búsqueda introducida por el usuario — información que se pasa al traductor junto con la clave de traducción, como parámetro adicional:

{LinkButton.component({
  icon: 'search',
  children: app.translator.trans('all_discussions_button', {query}),
  href: app.route('index', {q: query})
})}

Un marcador de posición coincidente en la traducción permite al traductor saber dónde debe insertar la variable:

all_discussions_button: 'Search all discussions for "{query}"'

Dado que se utilizan corchetes para indicar el marcador de posición, la traducción en su conjunto debe ir entre comillas. Normalmente, se utilizarían comillas dobles; pero como esta traducción en particular utiliza comillas dobles para definir la consulta de búsqueda, la regla de las comillas simples tiene prioridad.

# Añadir etiquetas HTML

Abstraer las traducciones del HTML puede suponer un reto único: ¿cómo tratar los elementos del HTML que afectan sólo a una parte de la frase? Afortunadamente, Flarum le ofrece una forma de añadir etiquetas a sus traducciones.

Comienza añadiendo una clave al argumento de los parámetros para cada elemento que quieras que el traductor maneje. El siguiente fragmento — del modal Editar grupo (opens new window) de la interfaz de administración — muestra una clave de traducción acompañada de un objeto de parámetros con un elemento.

<div className="helpText">
  {app.translator.trans('icon_text', {
    a: <a href="https://fortawesome.github.io/Font-Awesome/icons/" tabindex="-1"/>
  })}
</div>

Tenga en cuenta que cada parámetro se define utilizando una sola etiqueta HTML, con una barra inclinada añadida antes del paréntesis angular de cierre. A continuación, puede utilizar etiquetas de apertura y cierre de estilo HTML en su archivo de configuración regional para especificar a qué parte de la traducción afecta cada elemento. Una vez más, las comillas dobles son necesarias. Puede ver que no se pasan todas las etiquetas como argumento, sólo las que tienen atributos.

icon_text: "Introduce el nombre de cualquier clase de icono <a>FontAwesome</a>, <em>sin</em> el prefijo <code>fa-</code>."

Por supuesto, puedes dar a un parámetro el nombre que quieras — ¡podrías usar <fred> y </fred> para encerrar el texto de tu enlace si realmente quisieras! Pero le recomendamos que se ciña lo más posible a las etiquetas HTML que se están representando, para que sus localizadores puedan entender lo que está pasando.

Los localizadores pueden reordenar los elementos según sea necesario, e incluso optar por omitir las etiquetas si así lo desean. Pero no pueden añadir ninguna etiqueta propia: el traductor simplemente ignorará cualquier etiqueta de estilo HTML que no se corresponda con un parámetro correctamente definido en el código.

# Manejo de la pluralización

En ocasiones, puede ser necesario proporcionar versiones alternativas de una traducción para acomodar la pluralización de una palabra o frase. Esto se hace utilizando el método app.translator.transChoice() para pasar la clave de traducción — junto con una variable que establece las condiciones para la pluralización — al traductor.

const remaining = this.minPrimary - primaryCount;
return app.translator.transChoice(
  'choose_primary_placeholder',
  remaining,
  { count: remaining }
);

Este ejemplo es del modal Choose Tags (opens new window) de la extensión Tags, donde se indica al usuario cuántas etiquetas primarias más puede seleccionar. Nótese que la variable remaining se pasa al traductor dos veces. Primero, aparece como ella misma, para condicionar la pluralización de la palabra "tags". Luego aparece de nuevo como el valor del parámetro count, que el traductor puede utilizar para insertar ese valor en la traducción.

Cuando se llama al método app.translator.transChoice(), el traductor explora la traducción en busca de una variante que coincida con el tipo de pluralización requerido por el valor de la variable. Estas variantes tienen que ser listadas en serie — la forma singular primero, luego las formas plurales en orden de magnitud creciente — y separadas usando el carácter de línea vertical (|). Esta es la traducción al inglés del código anterior:

choose_primary_placeholder: "Choose a primary tag|Choose {count} primary tags"

Por supuesto, el inglés sólo tiene dos variantes: singular o plural. Tendrá que proporcionar variantes adicionales cuando cree traducciones para un idioma que tenga más de una forma plural. Si necesita información detallada sobre el número de variantes necesarias para un idioma — o el orden en el que deben aparecer — puede consultar directamente las reglas de pluralización (opens new window) que utiliza Flarum para asignar la variable a las formas plurales.

# Tratamiento del género

El soporte para el género gramatical se añadirá en una futura versión de Flarum. Se proporcionarán instrucciones detalladas aquí una vez que esa funcionalidad esté disponible.

# Traducción del lado del servidor

La traducción es generalmente manejada por el cliente front-end de Flarum. Sin embargo, puedes usar traducciones en tu código PHP si lo necesitas.

Primero, necesitará obtener una instancia de la clase Flarum\Locale\Translator. Esto se puede hacer de varias maneras:

$translator = app('translator');
$translator = app('Flarum\Locale\Translator');
$translator = app(Translator::class); // para ello deberá importar la clase con 'use'.

Entonces, la API es similar a la clase Traductor de JavaScript. Puedes usar $translator->trans como usarías app.translator.trans en JavaScript. Puedes aprender más sobre los métodos del traductor en los documentos de Symfony's Translator (opens new window), que el Translator de Flarum extiende.

# Registrando las Localidades

Hay una última cosa que debe hacer antes de que Flarum pueda utilizar sus traducciones. Necesitas registrarlas. Afortunadamente, Flarum hace esto bastante fácil. Añade lo siguiente a tu extend.php:

new Extend\Locales(__DIR__ . '/locale'),

# Apéndice A: Formato de clave estándar

Las siguientes directrices fueron creadas para su uso en el núcleo de Flarum y en las extensiones incluidas. Su propósito es asegurar que las claves de traducción estén organizadas y nombradas de manera consistente, de manera que los localizadores de Flarum puedan crear y mantener paquetes de idiomas de alta calidad con un mínimo de dificultad.

Se espera que los desarrolladores que deseen contribuir al desarrollo de Flarum sigan estas directrices. Los desarrolladores de terceros también pueden seguirlas, por lo que los localizadores experimentados de Flarum que se encarguen de la traducción de extensiones de terceros se encontrarán trabajando en un entorno familiar.

# Namespacing en las traducciones

Todas las traducciones deben organizarse en categorías, utilizando claves de espaciado de nombres dispuestas en hasta tres niveles. Cada nivel proporciona a los localizadores una información importante sobre donde se utiliza la traducción:

# ➡ La clave de nivel superior indica qué componente utiliza la traducción.

El espacio de nombres para las claves de traducción utilizadas en los componentes oficiales de Flarum, incluidas las extensiones incluidas, debe coincidir con el nombre del archivo de configuración regional del paquete de idiomas para el componente en cuestión. Los espacios de nombres para los componentes de Flarum que no son extensiones se fijan como se muestra a continuación:

core:        # Traducciones utilizadas por el núcleo de Flarum
validation:  # Traducciones utilizadas por el validador de Laravel

Las claves de traducción usadas en una extensión, incluyendo cualquier extensión de terceros, deben tener un espacio de nombre usando el nombre de la extensión en formato vendor-package, donde los prefijos flarum- y flarum-ext- se eliminan del package (por ejemplo, flarum-tags para la extensión Tags y foo-bar para una extensión foo/flarum-ext-bar).

Sólo debe haber un prefijo de primer nivel en cualquier archivo de configuración regional; debe ser la primera línea del archivo de configuración regional.

# ➡ La clave de segundo nivel indica qué interfaz utiliza la traducción.

Como Flarum no tiene muchas interfaces, hemos creado una pequeña lista de claves de segundo nivel para que puedas elegir. Hemos incluido las más usadas en la plantilla del archivo locale creado con el esqueleto de la extensión. A continuación encontrará la lista completa, con explicaciones:

admin:       # Translations used by the admin interface.
forum:       # Translations used by the forum user interface.
lib:         # Translations used by either of the above.
views:       # Translations used outside the normal JS client.
api:         # Translations used in messages output by the API.
email:       # Translations used in emails sent by Flarum.

Las primeras cuatro claves corresponden aproximadamente a los directorios que contienen el código donde se utilizarán las traducciones en ese espacio de nombres. (La mayoría de sus claves probablemente irán en admin o forum.) Las dos claves restantes son un poco diferentes: el espacio de nombres api es para las traducciones utilizadas en los mensajes emitidos por la API, mientras que el espacio de nombres email contiene los recursos para todos los correos electrónicos enviados por el foro.

ref:         # Translations referenced by more than one key.
group:       # Translations used as default group names.

Estas dos claves no corresponden a interfaces; son para traducciones que requieren un manejo especial. Explicaremos cómo utilizar el espacio de nombres ref cuando hablemos de reutilizar traducciones. El espacio de nombres group contiene los nombres de los grupos por defecto, que son traducidos por el servidor en lugar de en el front-end.

# ➡ La clave de tercer nivel indica qué parte de la interfaz de usuario utiliza la traducción.

Las claves de este nivel no están definidas de forma tan rígida. Su propósito principal es dividir la interfaz de usuario en partes manejables, de modo que los localizadores puedan encontrar las traducciones y ver por sí mismos cómo las utiliza el software. (Las claves de tercer nivel no se utilizan en los espacios de nombres ref y group, que no necesitan ser cortados).

Si estás modificando una localización existente — para añadir un nuevo ajuste a la página de Configuración, por ejemplo — deberías copiar nuestro namespacing para que los localizadores experimentados de Flarum sepan de un vistazo exactamente dónde se muestran las nuevas traducciones. Consulte los archivos de localización en Inglés (opens new window) para conocer los detalles de nuestro esquema de espaciado de nombres.

Si su extensión agrega una nueva ubicación — como un nuevo cuadro de diálogo — debería sentirse libre de crear una nueva clave de tercer nivel para espaciar por nombres las traducciones que van allí. Tómese un par de minutos para familiarizarse con el espaciado de nombres en los archivos de configuración regional enlazados anteriormente, y luego cree una nueva clave que se ajuste a ese esquema.

Como regla general, las claves de tercer nivel deben ser cortas — no más de una o dos palabras — y expresadas en snake_case. Deben ser descriptivas de los lugares donde se utilizan las traducciones.

# Cómo nombrar las claves de los identificadores

Al igual que las claves de espacio de nombres de tercer nivel, las claves de identificador deben expresarse en snake_case. Las claves de identificador deben estar organizadas en orden alfabético dentro de cada espacio de nombres, para que sean fáciles de encontrar para los desarrolladores. (¡Hay una excepción a esta regla! Las claves de identificación en el espacio de nombres email deben ser listadas tal y como aparecen en su cliente de correo: subject primero, luego body).

La clave de identificación típica consta de dos partes: una raíz y un sufijo; cada una de las cuales puede omitirse en determinadas circunstancias. Al igual que las claves de espaciado de nombres indican a los localizadores dónde se utiliza la traducción, cada parte de la clave ID proporciona un poco más de información sobre la traducción:

# ➡ El sufijo indica cómo se utiliza la traducción.

Empezaremos con el sufijo porque es la parte más importante del nombre de la clave. Indica a los localizadores qué tipo de objeto deben buscar cuando tratan de encontrar la traducción en la interfaz. Por ejemplo, los sufijos de la siguiente lista se utilizan para objetos de la interfaz gráfica de usuario más o menos relacionados con las operaciones del usuario:

_button:        # Used for buttons (including dropdown menu items).
_link:          # Used for links that are not shown graphically as buttons.
_heading:       # Used for headings in tables and lists.
_label:         # Used for the names of data fields, checkbox settings, etc.
_placeholder:   # Used for placeholder text displayed in fields.

Estos sufijos se utilizan para elementos de texto informativos o descriptivos:

_confirmation:  # Used for messages displayed to confirm an operation.
_message:       # Used for messages that show the result of an operation.
_text:          # Used for any text that is not a message, title, or tooltip.
_title:         # Used for text displayed as the title of a page or modal.
_tooltip:       # Used for text displayed when the user hovers over something.

Y hay dos sufijos que se utilizan sólo en el espacio de nombres email:

_body:          # Used for the content of the email message.
_subject:       # Used for the subject line of the email message.

Lo anterior es una lista completa de los sufijos disponibles para su uso en los archivos de localización. Deberías tener cuidado de usarlos de forma consistente, ya que esto facilitará la vida de los localizadores. Si crees que falta algo en la lista, por favor, presenta un problema a los desarrolladores; consideraremos la posibilidad de añadir un nuevo sufijo si la situación lo justifica.

Los sufijos deben ser omitidos de las claves de identificación para traducciones reutilizadas en el espacio de nombres ref:. Esto se debe a que no se puede asegurar que estas traducciones se vayan a utilizar siempre en el mismo contexto. Añadir un nuevo contexto significaría cambiar el nombre de la clave en todos los lugares a los que se hace referencia … así que es mejor mantener estas traducciones genéricas.

# ➡ La raíz indica lo que dice la traducción.

En otras palabras, debe ser un breve resumen del contenido de la traducción. Si la traducción es una frase muy corta, de no más de unas pocas palabras, puede utilizarla textualmente (en snake_case, por supuesto). En cambio, si es muy larga, hay que intentar reducirla al máximo.

En algunos casos, el resumen puede ser sustituido por una descripción de la función del objeto. Esto se ve comúnmente en los botones. El botón que envía un formulario debe identificarse como submit_button independientemente de que la traducción diga "OK" o "Save Changes". Del mismo modo, el botón que descarta un cuadro de diálogo o mensaje es siempre un dismiss_button, incluso si en realidad dice "OK" o "Cancel".

La raíz también puede ser omitida en ciertos casos — normalmente cuando el sufijo por sí solo es suficiente para identificar la traducción. Por ejemplo, es poco probable que una página o cuadro de diálogo tenga más de un título … y como no, ¡el contenido del título ya se da en el espaciado de nombres de tercer nivel! Así que el sufijo puede ser independiente.

Los sufijos también son suficientes para identificar los componentes del asunto y del cuerpo de un mensaje de correo electrónico, ya que cada correo electrónico sólo tendrá un asunto y un cuerpo. Tenga en cuenta que el guión bajo inicial se omite en estos casos: se utilizaría simplemente title, subject o body como clave de identificación.

# Reutilización de traducciones

Las referencias a claves únicas de Flarum cumplen la misma función que los anclajes YAML, pero son mejores en un aspecto: ¡incluso puedes referenciar claves en un archivo diferente! Por esta razón, es necesario utilizar la clave de traducción completa cuando se hace referencia. Este es un ejemplo más realista de cómo funciona la referenciación, con espaciado de nombres:

core:

  forum:
    header:
      log_in_link: => core.ref.log_in

    log_in:
      submit_button: => core.ref.log_in
      title: => core.ref.log_in

  ref:
    log_in: Log In

Como puede ver, queremos reutilizar una única traducción en tres contextos diferentes (incluyendo dos localizaciones): (1) como un enlace que se muestra en la cabecera del sitio, (2) como un botón que se muestra en el modal de Inicio de Sesión, y (3) como el título de ese modal. Por lo tanto, estas tres claves se han configurado para que hagan referencia a la misma clave de traducción completa.

La traducción reutilizada se identifica con una clave que omite el sufijo — como se especifica arriba — y se coloca en el espacio de nombres ref. Esta última medida es necesaria para evitar los conflictos que pueden producirse si una traducción reutilizada recibe el mismo nombre que una clave de segundo nivel de namespacing. (Las claves email son un ejemplo de ello).

El espacio de nombres ref también facilita el seguimiento de la reutilización de traducciones. Imagínate lo que pasaría si establecieras los escalares para el botón y el título para hacer referencia a core.forum.header.log_in_link en su lugar:

core:

  forum:
    header:
      log_in_link: => Log In

    log_in:
      submit_button: => core.forum.header.log_in_link  # No hay que hacer referencia a las claves
      title: => core.forum.header.log_in_link          # que no están en "ref"

Sería muy fácil cambiar la traducción del enlace de la cabecera sin darte cuenta de que también estás cambiando cosas en el modal de Log In — ¡por no hablar de las extensiones que también podrían estar haciendo referencia a esa clave! Este tipo de cosas será menos probable que ocurran si mantiene sus traducciones reutilizadas en el espacio de nombres ref.

Por esta razón, cualquier referencia a una clave en el core resources (opens new window) debe apuntar a claves en el espacio de nombres core.ref. Las referencias a claves en los recursos de las extensiones agrupadas pueden apuntar a cualquiera de las dos ubicaciones:

  • Las traducciones específicas de la extensión deben ir en el espacio de nombres ref del archivo de configuración regional de la extensión.

  • Las traducciones utilizadas tanto por la extensión como por el núcleo deben ir en el espacio de nombres core.ref.

Las extensiones de terceros son bienvenidas a referenciar claves en el espacio de nombres core.ref, pero tenga en cuenta que no podemos añadir traducciones a este espacio de nombres basado en la reutilización en extensiones de terceros. Un desarrollador de terceros que quiera reutilizar una traducción de un espacio de nombres que no sea core.ref tendrá que añadir una traducción duplicada con la clave adecuada al archivo de configuración regional de la extensión.

Ninguna extensión debería hacer referencia a una clave de otra extensión, ya que al hacerlo se produciría una dependencia.

Una última advertencia: las claves de traducción en el espacio de nombres ref no deberían nunca insertarse directamente en el código. Esto se debe a que los localizadores pueden acabar creando una traducción para reemplazar cada referencia a una clave de traducción reutilizada; en cuyo caso estarían en su derecho de eliminar esa clave del archivo de localización. Si dicha clave se utilizara en el código, ¡terminaría sin un recurso que la tradujera!

# Añadir comentarios

Los comentarios (y las líneas vacías) deben añadirse a los archivos de localización para que los localizadores los encuentren más fáciles de navegar.

Hemos incluido algunos comentarios de bloque en la plantilla del archivo de localización incluida en el esqueleto de la extensión. Están ahí para recordar a los desarrolladores algunos conceptos básicos: las claves de traducción no deben usarse en más de un lugar; las claves para traducciones reutilizadas nunca deben insertarse directamente en el código; etc.

Debe añadir líneas de comentario sobre cada clave de segundo o tercer nivel de espaciado de nombres, para dar a los localizadores una descripción más completa de la ubicación cubierta por ese espacio de nombres. Al copiar claves existentes, asegúrese de copiar también el comentario (y modificarlo si es necesario). Si añade una nueva clave de tercer nivel, recuerde precederla de un comentario para explicar la localización que se añade.

También puede añadir comentarios en línea después de una traducción específica para proporcionar a los localizadores más información sobre esa traducción (como el hecho de que una traducción puede ser pluralizada si es necesario).

# Apéndice B: Codificación para el mundo

En este apéndice, nos gustaría ofrecer algunos consejos que pueden ayudarle a evitar algunos de los escollos más comunes en el proceso de internacionalización. Abstraer el lenguaje del código es fácilmente una de las tareas más aburridas con las que tiene que lidiar un programador, pero si no se presta la debida atención a las sutilezas implicadas, es probable que acabe creando a sus localizadores un dolor de cabeza innecesario o dos.

Por supuesto, no se trata sólo de facilitar la vida a los localizadores. Porque cuando tengan dolores de cabeza, acudirán a ti para que les ayudes, a menudo meses (o incluso años) después de que hayas dejado atrás el proyecto y hayas pasado a otra cosa. Es el tipo de situación en la que una o dos onzas de prevención pueden valer varias libras de cura más adelante … para todos los implicados.

Probablemente sea imposible evitar por completo los problemas de localización; hay demasiadas variables. Pero si se siguen unas cuantas pautas sencillas, se podrán evitar muchos problemas antes de que se produzcan.

# ¡Elimine todo el texto codificado!

Esto probablemente no hace falta decirlo. Al fin y al cabo, si vas a tomarte la molestia de extraer las traducciones, más vale que termines el trabajo, ¿no? Pues sí, pero es más fácil decirlo que hacerlo. Es muy raro encontrar un programa que no tenga al menos algunos fragmentos de texto codificado flotando en alguna parte.

Incluso pequeños fragmentos de texto pueden causar problemas a los localizadores. Una coma por aquí, dos puntos por allá … tal vez un par de paréntesis insertados para hacer la página más legible: estas cosas pueden causar y causan problemas a los localizadores. Al fin y al cabo, no todos los idiomas utilizan los mismos glifos para estas cosas. Un solo espacio codificado puede ser un problema para alguien que intente traducir la interfaz a un idioma que no utilice espacios para separar las palabras.

En general, cualquier texto mostrado que no sea suministrado por una variable o el resultado de un cálculo debe ser incluido en los archivos de configuración regional. Esto es fácil de decir, pero hacerlo realmente requiere un poco de perseverancia.

# ¡Evite la sintaxis codificada!

El texto codificado no es la única forma en que el código puede crear problemas para los localizadores. Los problemas de sintaxis codificada ocurren cuando el código fuerza las palabras en un orden específico que simplemente no funciona en otros idiomas. Suelen ser el resultado de utilizar dos traducciones cuando una sola sería más apropiada.

Por ejemplo, veamos la línea de texto que se imprime cerca de la parte inferior del modal Log In (opens new window):

Don't have an account? Sign Up

Originalmente, codificamos esta línea como dos traducciones, que estaban separadas por un espacio en blanco:

before_sign_up_link: "Don't have an account?"
sign_up: Sign Up

Había buenas razones para hacerlo así. Por un lado, facilitaba la conversión de la segunda parte en un enlace. Y como la segunda traducción se reutiliza en otras partes, mantenerla separada parecía una obviedad.

Pero este enfoque planteaba problemas. El espacio codificado parecía que podía plantear problemas a algunos localizadores, como ya se ha mencionado. Además, dividir este texto en dos cadenas haría imposible representar la línea como una sola frase con el enlace incrustado en el medio:

If you don't have an account yet, you can sign up instead!

Como parecía posible que un localizador necesitara este tipo de flexibilidad, optamos por abstraer la línea como una sola traducción, utilizando etiquetas de estilo HTML para encerrar el texto del enlace:

sign_up_text: "Don't have an account? <a>Sign Up</a>"

Esto coloca el espacio (antes codificado) en la traducción, de modo que los localizadores que no lo necesitan pueden eliminarlo. Además, las etiquetas pueden colocarse libremente dentro de la traducción, lo que hace que este enfoque sea mucho más flexible.

La moraleja de esta historia es: cuando tenga dos trozos de texto adyacentes que parezcan estar relacionados entre sí gramaticalmente — o incluso semánticamente — debería pensar en encontrar una manera de incorporar ambos en una sola traducción. Es posible que sus localizadores se lo agradezcan.

También podríamos llegar a la conclusión de que la presencia de pequeños fragmentos de texto codificado — como el espacio codificado en este ejemplo — puede ser una especie de code smell (opens new window) que indica la presencia de un problema más profundo. No siempre es así, pero es una posibilidad que merece la pena tener en cuenta.

# ¡No pierda de vista los plurales!

Son sorprendentemente fáciles de pasar por alto. Por supuesto, la necesidad de apoyar la pluralización es bastante obvia aquí:

A Toby le gusta esto. Te gusta esto. A Toby y Franz les gusta esto.

Y la situación se complica por la presencia del pronombre de segunda persona, ya que siempre toma la forma plural en inglés, incluso cuando se trata de una sola persona. Por eso la llamada a app.translator es tan complicada en el código que produce las frases anteriores para la extensión Likes (opens new window).

Ahora mira este conjunto de frases similares, producidas por un código similar en la extensión Mentions (opens new window):

Toby respondió a esto. Tú respondiste a esto. Toby y Franz respondieron a esto.

En inglés, el tiempo pasado simple no se ve afectado por la pluralización. Como la frase verbal es siempre la misma, sería bastante fácil ignorar los plurales y utilizar el método app.translator.trans() para producir la única traducción necesaria. Por supuesto, eso no funcionaría para el localizador francés, que necesita inflexionar el verbo de forma diferente en cada una de las tres frases anteriores.

Este es el tipo de situación en la que la tarea rutinaria de la abstracción lingüística requiere un poco más de cuidado y atención. Recuerda preguntarte si cada sustantivo (o pronombre) puede pluralizarse. Si puede, asegúrese de utilizar el método app.translator.transChoice() y pasar una variable apropiada al traductor. Por supuesto, no es necesario proporcionar ninguna variante de traducción en los recursos en inglés …

mentioned_by_text: "{users} replied to this."       # Se puede pluralizar...
mentioned_by_self_text: "{users} replied to this."  # Se puede pluralizar...

… pero sería una muy buena idea añadir un comentario después de las traducciones en cuestión, para alertar a los localizadores del hecho de que el código soportará la adición de tales variantes, en caso de que sean necesarias.

# Reutilizar las traducciones, ¡no las claves!

Si las claves de espaciado de nombres se combinan para formar una especificación completa de dónde se utiliza una traducción, y la clave de identificación especifica exactamente cómo se utiliza la traducción y lo que dice, entonces es lógico que cada clave de traducción completa debe ser única. En otras palabras: nunca debe utilizarse la misma clave más de una vez.

Aunque esto pueda parecer ineficiente, hay una buena razón para hacer las cosas de esta manera: es la forma más fácil de garantizar que los localizadores tengan la flexibilidad que necesitan. Si reutiliza claves en su código, acabará encontrando un obstáculo. Tus localizadores serán incapaces de encontrar una única expresión que se ajuste a todos los contextos en los que hayas utilizado alguna clave u otra … y entonces empezarán a molestarte para que arregles tu código.

Afortunadamente, puedes evitar muchos de estos problemas si simplemente tienes cuidado de namespace translations correctamente, name your ID keys apropiadamente, y siempre reuse translations en lugar de claves. Aunque pueda parecer una molestia, a la larga, el formato estándar hará que la localización sea mucho más fácil para todos.