C贸mo a帽adir internacionalizaci贸n b谩sica (i18n) a tu App 锘

Traducci贸n de un interesante art铆culo de Dana Woodman explicando c贸mo a帽adir traducciones y localizaci贸n sencilla a una app Svelte. El m茅todo se basa en un post de Matthias Stahl, pero Dana Woodman explica c贸mo hacerlo sin necesidad de crear un repositorio adicional para las traducciones.

i18ninternacionalizaciontraduccion app
10 diciembre, 2021 Internacionalizaci贸n de Apps Svelte
10 diciembre, 2021 Internacionalizaci贸n de Apps Svelte

Como experto en traducci贸n e internacionalizaci贸n de apps y software, nuestro traductor Chema ha querido traducir del Ingl茅s al Espa帽ol este interesante texto de Dana Woodman

Texto original escrito por Dana Woodman y publicado en
https://dev.to/danawoodman/svelte-quick-tip-adding-basic-internationalization-i18n-to-you-app-2lm

* * *

 

Svelte Quick Tips (6 Part Series)
1 馃殌 Svelte Quick Tip: Styling slot content with :global
2 馃殌 Svelte Quick Tip: Styling conditional named slots
3 馃殌 Svelte Quick Tip: Create a tooltip action using Tippy.js
4 馃殌 Svelte Quick Tip: Adding basic internationalization (i18n) to you app
5 馃殌 Svelte Quick Tip: Connect a store to local storage
6 馃殌 Svelte Quick Tip: Creating a toast notification system

馃憢 隆Hola, Mundo!

Hace poco me top茅 con un gran v铆deo del Dr. Matthias Stahl (tweet aqu铆, v铆deo de YouTube aqu铆, c贸digo aqu铆) en el canal de YouTube Svelte, que ide贸 un enfoque sencillo para a帽adir traducciones i18n b谩sicas a una aplicaci贸n Svelte.

Pens茅 que ser铆a divertido y 煤til recrearlo, y aprovechar para hacer algunas optimizaciones y mejoras menores por el camino… 馃

Queremos crear algo as铆:

translations in action

隆La mayor parte del cr茅dito en este post va a Matthias aqu铆, as铆 que aseg煤rate de echar un ojo a su trabajo y seguirle! 馃檱

馃搾 Nota: esta no es una soluci贸n de internacionalizaci贸n completa como i18next, por lo podr铆a no ser la soluci贸n perfecta para lo que est茅s buscando.

驴Impaciente? Consulta el REPL de Svelte con todo el c贸digo

 

El objeto de las traducciones

En el ejemplo de Matthias, utiliza un objeto profundamente anidado para almacenar las cadenas de traducci贸n. Esto funciona, pero es ligeramente ineficiente ya que tendr谩s que recorrer el objeto, especialmente si tienes m煤ltiples capas anidadas (piensa en app => page => section => component => label).

En su lugar, he optado por un objeto plano cuya clave es la subetiqueta de localizaci贸n de internacionalizaci贸n (por ejemplo, en y no en-US) y una cadena con espacios separados por puntos para los valores traducidos. Si tenemos que gestionar muchas traducciones, esto ser铆a una buena ventaja a nivel rendimiento.

Adem谩s, admitiremos variables incrustadas y HTML en nuestras cadenas de traducci贸n:

// translations.js
export default {
en: {
"homepage.title": "Hello, World!",
"homepage.welcome": "Hi <strong>{{name}}</strong>, how are you?", "homepage.time": "The current time is: {{time}}",
},
es: {
"homepage.title": "隆Hola Mundo!",
"homepage.welcome": "Hola, <strong>{{name}}</strong>, 驴c贸mo est谩s?",
"homepage.time": "La hora actual es: {{time}}",
},
};

Esto nos permitir谩 tener claves con espacios de nombres, as铆 como soportar formatos enriquecidos e inyectar valores (por ejemplo, cadenas, n煤meros, fechas, etc.).

 

El componente

Ahora crearemos nuestro componente Svelte, 隆huzzah! 馃憦

Este componente es bastante sencillo y consistir谩 en un desplegable de selecci贸n para elegir el idioma que el usuario desea utilizar, as铆 como en la visualizaci贸n de algunos textos de traducci贸n, 隆incluyendo uno con HTML y variables personalizadas!

 
<!-- App.svelte -->
<script>
import { t, locale, locales } from "./i18n";

// Create a locale specific timestamp
$: time = new Date().toLocaleDateString($locale, {
weekday: "long",
year: "numeric",
month: "long",
day: "numeric",
});
</script>

<main>
<p>
<select bind:value={$locale}>
{#each locales as l}
<option value={l}>{l}</option>
{/each}
</select>
</p>

<h1>{$t("homepage.title")}!</h1>
<p>{@html $t("homepage.welcome", { name: "Jane Doe" })}!</p>
<p>{$t("homepage.time", { time })}!</p>
</main>

Lo que estamos haciendo aqu铆 es conectar un elemento < select> a un almac茅n Svelte (que crearemos en un momento) y tambi茅n utilizar un m茅todo m谩gico $t() que nos permitir谩 hacer b煤squedas de traducci贸n.

Notar谩s que estamos creando una marca de tiempo espec铆fica de la localizaci贸n para mostrar al usuario usando toLocaleDateString a la que pasamos el valor de la tienda $locale.

Si esto a煤n no tiene sentido para t铆, no te preocupes, 隆sigue leyendo!

 

La tienda

Ahora viene la parte divertida, 隆vamos a crear nuestra tienda Svelte! 馃懐鈾傦笍

El repositorio es bastante simple: almacenamos primero el valor de la configuraci贸n regional (por ejemplo, en, es, etc) en un repositorio, y luego creamos un repositorio derivado de la configuraci贸n regional y el objeto de traducciones creado antes.

 
import { derived, writable } from "svelte/store";
import translations from "./translations";

export const locale = writable("en");
export const locales = Object.keys(translations);

function translate(locale, key, vars) {
// Let's throw some errors if we're trying to use keys/locales that don't exist.
// We could improve this by using Typescript and/or fallback values.
if (!key) throw new Error("no key provided to $t()");
if (!locale) throw new Error(`no translation for key "${key}"`);
// Grab the translation from the translations object.
let text = translations[locale][key];

if (!text) throw new Error(`no translation found for ${locale}.${key}`);
// Replace any passed in variables in the translation string.
Object.keys(vars).map((k) => {
const regex = new RegExp(`{{${k}}}`, "g");
text = text.replace(regex, vars[k]);
});

return text;
}

export const t = derived(locale, ($locale) => (key, vars = {}) =>
translate($locale, key, vars)
);

La mayor parte de la l贸gica est谩 en el m茅todo translate que busca las claves e inyecta las variables, si est谩n presentes.

El almac茅n derivado se mantendr谩 sincronizado con la configuraci贸n regional actual y por lo tanto nuestro m茅todo translate siempre recibir谩 la configuraci贸n regional actual cuando sea llamado. Cuando se actualice la configuraci贸n regional, las llamadas a $t() se volver谩n a calcular y as铆 se actualizar谩 todo nuestro texto en nuestro componente Svelte cuando el usuario cambie su configuraci贸n regional. 隆Genial! 馃槑

Esto se aleja un poco de la versi贸n de Matthias, ya que no requiere la creaci贸n de un repositorio adicional para la traducci贸n, algo que no es estrictamente necesario y es un poco m谩s eficiente si lo omitimos.

 

C贸mo montarlo todo

Ahora que tenemos nuestra tienda, tenemos todas las piezas para crear un sistema b谩sico de internacionalizaci贸n en Svelte, felicidades 馃帀

Si quieres ver este c贸digo en acci贸n, echa un vistazo al REPL de Svelte

 

馃洶 Para ir un poco m谩s all谩

Ahora bien, esta opci贸n no es adecuada para todo el mundo. Si est谩s construyendo una aplicaci贸n grande, robusta y con mucho contenido con muchas traducciones, entonces quiz谩s quieras considerar algo como Locize en combinaci贸n con i18next. Siempre puedes integrar sus librer铆as JS con Svelte de forma similar.

Tampoco estamos desinfectando el contenido HTML, as铆 que si est谩s inyectando datos suministrados por el usuario en tus cadenas de traducci贸n, tendr谩s que asegurarte de desinfectar/eliminar la entrada para no crear una vulnerabilidad XSS. 馃攼

Otro problema con este enfoque es que no se define un comportamiento alternativo para textos que no tienen traducci贸n (son carencias de este sistema que igual no quieres o铆r ahora…).

Dicho esto, una soluci贸n como 茅sta puede ser 煤til cuando no se necesita una plataforma de traducci贸n completa y bastan traducciones de cadenas relativamente b谩sicas.

Se podr铆a ampliar este ejemplo manteniendo el valor de la configuraci贸n regional en el almacenamiento local y por defecto en el idioma preferido del navegador, por ejemplo, utilizando la propiedad navigator.languages. Pero eso lo abordaremos en otro post..

 

馃幀 Fin

Valora este art铆culo