Cómo generar traducciones de forma sencilla desde un servidor Express/Apollo GraphQL.

Traducción de Inglés a Español de un interesantísimo artículo de Olivier Guimbal, Máster en Métodos Computacionales Avanzados para Aeronáutica, que nos explica como configurar un servidor Express/Apollo GraphQL para generar traducciones de forma sencilla y así lograr tus objetivos de internacionalización (i18n)

Apollo GraphqlExpresstraduccion software
12 marzo, 2022 Cómo internacionalizar y traducir con un servidor Express/Apollo
12 marzo, 2022 Cómo internacionalizar y traducir con un servidor Express/Apollo

Chema ha traducido este artículo sobre traducción de software, para el Blog de la agencia de traducción Ibidem Group.

Texto original escrito por Olivier Guimbal y publicado en dev.to

***

Índice de contenidos

  • El problema
  • Enfoque de smarloc
  • Express.js: ¿Cómo se configura?
  • Apollo GraphQL: ¿Cómo se configura?
  • Generación de traducciones
  • Conclusión

Digamos que tienes un servidor.
Digamos que estás utilizando un servidor Express.js y/o Apollo Graphql.
Digamos que tus usuarios hablan diferentes idiomas.
Digamos que vives en 2020, tu servidor es sólo un servidor api, y no te preocupan los procesadores de plantillas («template engines»).

🎉 Si es así este artículo es para tí.

He presentado otra biblioteca i18n que desarrollé para las necesidades de mi empresa y que (IMO) simplifica la creación de la implementación de servidores multi-idioma.

El problema

Cuando se escribe código en un manejador de ruta Express, se tiene acceso al objeto «request» original.

«bueno» se diría. Puedo acceder a «Cookies», a la cabecera «Accept-Languages», o a lo que sea que defina mi idioma de usuario, y traducir el contenido devuelto en base a eso.

A lo que yo respondería: De acuerdo, claro, pero ¿realmente quieres llevar tu objeto de petición como un argumento de algún tipo en toda tu base de código, sólo por conocer tu lenguaje de usuario?

¿No se siente un poco mal?

¿No estás cansado de llamar a métodos estáticos extraños con sintaxis extrañas para obtener una cadena traducida de tu código?

¿Realmente vas a refactorizar esos 500k archivos de código uni-lingüístico que ya escribiste sólo para añadir soporte de idiomas?

¿Cómo diablos se supone que se almacenan las cadenas traducibles?

Si, como yo, cree que esto está mal, siga leyendo…

El enfoque de smarloc.

Un buen ejemplo vale más que mil palabras:

// before
const myFunction = () => `Hello, it is now ${new Date()}`;
// after
const myFunction = () => loc`Hello, it is now ${new Date()}`;

¿Ves la diferencia? Sí, hay ‘loc’ delante de mi cadena.
Su función ya no devuelve una ‘cadena’, sino un objeto ‘LocStr’.

Aquí está el truco… no tienes que conocer tu idioma de usuario cuando emites la cadena que eventualmente tendrá que ser traducida. Puedes pasar este objeto por toda tu aplicación sin decirle al código que lo manipula que no es una cadena real.

 

latest

 

La traducción ocurrirá entonces en el último instante, cuando se serialice la respuesta json enviada a su cliente. Es entonces cuando se leerá la cabecera ‘Accept-Language’ o lo que sea, y cuando se traducirán realmente las instancias de las cadenas ‘LocStr’ en el json devuelto. En el último momento.

Express.js: ¿Cómo se configura?

expressjs

 

En primer lugar (esto debe hacerse antes de que cualquier código utilice smartloc), tendrás que decir en qué idioma escribes tus cadenas.

import {setDefaultlocale} from 'smartloc'; 

// lets say our developpers use english in code
setDefaultLocale('en');

A continuación, añadirás un middleware Express.js que traducirá el json devuelto sobre la marcha.

importar traductor de 'smartloc/express';

app.use(traductor());

Por defecto, buscará las traducciones que coincidan con la cabecera ‘Accept-Language’ de las peticiones entrantes, y por defecto utilizará el idioma por defecto que hayas proporcionado.

Ahora puedes usar smartloc así

import {loc} from 'smartloc';
app.get('/', (req, res) => {
// sends a JSON object containing text to translate,
// without bothering to translate it.
res.json({
// this string will get an automatic ID
hello: locHello !,
// notice that you can provide an ID like that // and use regular templating syntax: time: loc('myTime')`It is ${new Date()}, mate !`, });
});

Si ejecutas esto, notarás que tu api devolverá cosas como:

{
"hello": "Hello !",
"time": "It is , mate !"
}

De acuerdo, eso está bien, pero cómo eso no nos dice cómo proporcionar traducciones reales a las cadenas…

Sí, para eso tendrás que saltar a la sección de Generar traducciones 🙂 .

Una versión sencilla de este ejemplo se encuentra aquí (nb: proporciona traducciones codificadas, sin utilizar archivos de traducción)

Apollo GraphQL: ¿Cómo se configura?

graphql

 

Configurar un servidor Apollo GraphQL es casi lo mismo que configurar un servidor Express.js.

En resumen, es lo mismo que se describe en la sección anterior, salvo que no tendrá que utilizar el middleware traductor exprés.

En su lugar, tendrá que declarar en su esquema qué cadenas son traducibles utilizando el tipo ‘GLocString’ en lugar de ‘GraphQLString’, así:

import {GLocString} from 'smartloc/graphql';
//…
{
type: GLocString,
resolve: () => locHello ! // will be translated
}

Entonces construye tu servidor apollo así:

import {localizeSchema, localizedContext} from 'smartloc/graphql';
const apollo = new ApolloServer({
schema: localizeSchema(schema),
context: localizedContext(async http => {
// build your own context here as usual
return {};
})
});

Al hacerlo, todas las propiedades GLocString o JSOn de su esquema serán traducidas automáticamente cuando sus resolvedores devuelvan cosas que contengan instancias LocStr.

A continuación, al igual que en la explicación de Express.js, salta a la sección Generar traducciones para saber cómo refrescar tus traducciones 🙂 .

Una versión sencilla de este ejemplo se encuentra aquí (nb: proporciona traducciones codificadas, sin utilizar archivos de traducción)

Generación de traducciones

Si estás aquí, asumo que has leído una de las dos secciones anteriores.

Digamos que ahora quieres añadir soporte para el francés. En primer lugar, añada algo como esto en la sección «scripts» de su package.json:

{
"scripts": {
"collect": "smartloc collect --format=json --locales=fr-FR --defaultLocale=en-US --generateDefault"
}
}

Cuando ejecute npm run collect, se (re)generarán dos archivos en el directorio i18n:

  • en-us.json : Puedes olvidarte de este archivo, está aquí como referencia porque pusiste la opción –generateDefault en la línea de comandos, y puedes proporcionar traducciones en él (en cuyo caso la cadena real en código nunca llegará a tu cliente), pero puedes dejarlo como está.
  • fr-fr.json : Aquí es donde tendrás que poner tus traducciones.

En estos archivos, las traducciones se agrupan por el punto izquierdo de los ID de las cadenas.
Por ejemplo, si tienes:

locAutomatic ID;
loc('someId')Some ID string;
loc('someGroup.someId')Some grouped ID string;

Generará algo así:

{
"$default": {
"": { "source": "Automatic ID" },
"someId": { "source": "Some ID string" }
},
"someGroup": {
"someId": { "source": "Some grouped ID string" }
}
}

Sólo tienes que añadir un «objetivo» correspondiente a cada «fuente», y estarás listo. Por ejemplo:

{ 
"source": "Some grouped ID string",
"target": "Une chaine avec ID groupé"
}

Luego, al iniciar, sólo hay que decirle a smartloc dónde debe buscar las traducciones:

import {loadAllLocales} from 'smartloc';
import path from 'path';
// load all locales in the i18n directory
// … you could also use loadLocale() to only load one locale file.
loadAllLocales(path.resolve(__dirname, 'i18n'));

🎉 ¡Aquí está! Si tus archivos de traducción están bien, ¡tendrás un servidor de API multilingüe totalmente funcional!

Te dejaré adivinar cómo añadir más de una traducción 🙂

Conclusiones finales

Esta introducción es una muestra de lo que se puede hacer con esta biblioteca.

Llevamos meses usándolo @ justice.cool y debo decir que estoy bastante contento con él.

Antes de que alguien comente algo como «ya sabes, hay otras librerías que» … Sé que ya hay muchas otras librerías i18n, pero me apetecía desarrollar una más sencilla, que me pareciera bien. Si a ti no te funciona, pues… mala suerte compañero. Sigue usando esos monstruos que hay por ahí.

Para saber un poco más sobre los usos avanzados (transformar cadenas, almacenar cadenas traducibles, traducciones manuales, … consulta el repo de smartloc ), o abre un tema, estaré encantado de responder.

Rate this post

Articulos relacionados


Traducción de Inglés a Español de un interesantísimo artículo de Olivier Guimbal, Máster en Métodos Computacionales Avanzados para Aeronáutica, que nos explica como configurar un servidor Express/Apollo GraphQL para generar traducciones de forma sencilla y así lograr tus...

Traducción al español de un texto sobre aprendizaje, lenguaje, PNL, BERT, MT, PEMT.... By Sebastian Ruder

Traducción de Inglés a Español de un interesantísimo artículo de Olivier Guimbal, Máster en Métodos Computacionales Avanzados para Aeronáutica, que nos explica como configurar un servidor Express/Apollo GraphQL para generar traducciones de forma sencilla y así lograr tus...