Publi

Scripts multilingües en bash con gettext / Traducciones en scripts


Hace tiempo, empecé un proyecto en el que comparto algunos scripts que utilizo para hacerme la vida un poco más fácil. En esta colección, encontramos algunos scripts que ejecutaremos desde consola, y otros que, suelo tenerlos vinculados a una tecla rápida para ejecutarlos más rápidamente. El caso es que, los mensajes que se muestran en pantalla a través de diálogos suelo ponerlos en español, pero me gusta compartirlos con el mundo, y comprendo que cada uno quiera verlo en su idioma.

Bien, pues tal y como hacíamos en C y en PHP, ahora le toca el turno a nuestros scripts de Bash.

En este ejemplo, incluyo algunos consejos y soluciones a problemas que me he encontrado en el proceso.

Lo primero que se me ocurre

Bueno, lo primero que se nos pasa por la cabeza es meter los mensajes en variables, y, dependiendo del idioma cargar uno u otro archivo de mensajes:
es.sh

1
2
MENSAJE1="MENSAJE 1"
MENSAJE2="MENSAJE 2"

en.sh

1
2
MENSAJE1="MESSAGE 1"
MENSAJE2="MESSAGE 2"

test.sh

1
2
3
4
5
LCN=`locale | grep LC_NAME | cut -d'=' -f2 | cut -d'_' -f1`

. $LCN.sh

echo $MENSAJE1

El problema que tiene esto, es que, queda un poco como cogido con pinzas, parece que en cualquier momento va a fallar y no tiene pinta de ser muy estable. Además, el mantenimiento es incómodo, tienes que saber los nombres de las variables y luego tienes que hacer que se correspondan los mensajes.

Solución con gettext

La solución con gettext es mucho más larga, bueno, vamos a ver, es algo más larga pero mucho más fácil de mantener que la anterior. No tenemos que mantener los nombres de las variables, tenemos en cuenta directamente el mensaje y nos basamos en él.
Eso sí, tenemos que tener un fichero de traducciones aparte, bueno, antes teníamos ficheros sh, ahora tendrán una ruta y nombre específico; y en el resto del post veremos poco a poco cómo construirlo.
Aunque en posts anteriores he puesto alguna forma de hacerlo, aquí voy a empezar desde cero con un método nuevo (para que tengamos variedad, y para no hacer que nadie tenga que visitar otro post para conseguir una parte de la información y luego volver).

Nuestro programa: preparando el entorno

A la hora de crear nuestro programa, a mi me gusta crear un archivo «common.sh» (lo podéis llamar como queráis) situado en el mismo directorio del script, donde almacenamos funciones y variables que no tienen que ver con nuestro script propiamente dicho, son generales, en este caso, relativas a las traducciones (voy paso a paso, si sois impacientes, id al final del post, pero mientras voy poniendo experimentos):

common.sh

1
2
3
4
5
6
7
#!/bin/bash

function __()
{
    ARGS=$@
    echo "$ARGS"
}

multilin.sh

1
2
3
4
5
6
7
#!/bin/bash

SCRIPT_SOURCE=`dirname $BASH_SOURCE[0]`
. $SCRIPT_SOURCE/common.sh

echo $(__ "This is a message for you")
echo $(__ "This is another message for you")

¡Valiente tontería acabo de hacer! Pero quiero que esto vaya tomando forma. He creado una función __ que me servirá para introducir mensajes, y esta función se encargará de traducirlos. Todavía no, ahora mismo hace un echo y listo, ya llegaremos a las traducciones en el siguiente paso.

Por otra parte, en mi script, lo único que tendré que hacer es llamar al common.sh (las dos líneas nos servirán para ubicar el directorio donde se encuentra el archivo (y con ello, ubicar common.sh que está en el mismo directorio), e incluirlo en nuestro script.

Lo siguiente será que, cada vez que quiera escribir un mensaje, debo introducirlo entre $(__ mensaje), es decir, llamaré a la función que está en common que me devolverá la traducción.

Generando el archivo de mensajes

Ahora tenemos que generar un archivo que contenga todos los mensajes que se encuentran en nuestro proyecto. Lo primero es crear un directorio para esos mensajes (podemos usar directamente /usr/share/locale/) que es el directorio por defecto, pero prefiero no utilizar el usuario root para nada, por el momento. Así que crearemos un directorio, hijo del directorio donde se encuentran nuestros script:

mkdir -p locale/es/LC_MESSAGES

El directorio locale lo podemos llamar como queramos, por otro lado el directorio es corresponde al idioma de las traducciones, en este caso español, por ejemplo, Francés será fr_FR, alemán, de, etc. El directorio LC_MESSAGES hay que dejarlo como está, no nos queda otra, porque lo que vamos a modificar serán los mensajes del programa.

Bueno, a partir de ahora, podemos utilizar los comandos que voy a decir, o utilizar poedit, como en otros posts, que es una herramienta gráfica que nos permitirá hacerlo todo cómodamente.

Desde el directorio de nuestros scripts (por ejemplo), corremos el siguiente programa

$ xgettext -o multilin.pot –from-code=UTF-8 –keyword –keyword=__ *.sh

Nos creará un archivo .pot que podemos editar para rellenar los campos que consideremos oportunos (nombre del proyecto, e-mails, versiones, etc).

Entramos en LC_MESSAGES para crear un archivo de idioma español y ejecutamos:

$ msginit -i ../../../multilin.pot -l es_ES.UTF-8 -o multilin.po

A continuación, se habrá creado multilin.po , es un archivo de texto que podemos editar sin miedo, en el que pondremos los textos traducidos

# Spanish translations for PACKAGE package
# Traducciones al español para el paquete PACKAGE.
# Copyright (C) 2015 THE PACKAGE’S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Gaspar Fernández , 2015.
#
msgid «»
msgstr «»
«Project-Id-Version: PACKAGE VERSION\n»
«Report-Msgid-Bugs-To: \n»
«POT-Creation-Date: 2015-04-04 03:53+0200\n»
«PO-Revision-Date: 2015-04-04 04:18+0200\n»
«Last-Translator: Gaspar Fernández \n»
«Language-Team: Spanish\n»
«Language: es\n»
«MIME-Version: 1.0\n»
«Content-Type: text/plain; charset=UTF-8\n»
«Content-Transfer-Encoding: 8bit\n»
«Plural-Forms: nplurals=2; plural=(n != 1);\n»

#: multilin.sh:6
msgid «This is a message for you»
msgstr «Este es un mensaje para ti»

#: multilin.sh:7
msgid «This is another message for you»
msgstr «Este es otro mensaje para ti»

Y una vez generados todos los mensajes, debemos compilar este archivo, para ello, debemos ejecutar:

$ msgfmt -v multilin.po -o multilin.mo

Una modificación importante a common.sh

Nuestro common.sh quedará parecido a este:

1
2
3
4
5
6
7
8
9
#!/bin/bash

export TEXTDOMAINDIR=$SCRIPT_SOURCE/locale

function __()
{
    ARGS=$1
    gettext "multilin" "$ARGS"
}

En lugar de hacer echo directamente, he llamado a gettext con el dominio multilin (que es el que estamos usando para nuestros scripts.

En este momento cuando ejecutemos multilin.sh, lo que mostrará por pantalla será:

$ ./multilin.sh
Este es un mensaje para ti
Este es otro mensaje para ti

Bueno, ya tenemos la traducción automática, ya sólo nos queda mejorar esto un poco más.

Mejoras

common.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
GETTEXT=`which gettext`
DOMAIN="multilin"

if [ -z "`ls -R /usr/share/locale | grep $DOMAIN.mo`" ]; then
    export TEXTDOMAINDIR=$SCRIPT_SOURCE/locale
fi

function __()
{
    ARGS=$@

    if [ -z "$GETTEXT" ]; then
    printf "$ARGS"
    else
    LINE="$1"
    shift
    printf "$(gettext "$DOMAIN" "$LINE")" $@
    fi
}

Así quedaría mi common.sh, en este caso, miramos si tenemos la herramienta gettext disponible, porque es posible que el usuario final no la tiene instalada, y no podemos ponernos a mostrar fallos a cada mensaje en pantalla.

Lo siguiente es saber si el usuario ha instalado los idiomas de nuestra aplicación a nivel de sistema (si es así, esos archivos estarán en /usr/share/locale y usaremos estos. Si no, buscaremos en el directorio de nuestro script (SCRIPT_SOURCE lo definimos en el script multilin.sh).

Ahora, en la función __(), miramos si gettext está disponible, lo utilizamos para mostrar las traducciones (en lugar de usar DOMAIN, podemos utilizar TEXTDOMAIN, que es una variable de entorno de gettext y no tenemos que pasarle nada más, yo prefiero dejarlo así por si en mi proyecto incorporo varios dominios de traducciones.

Podéis ver que en lugar de echo, he usado printf. Y es para poder utilizar cadenas de formato con %s. Así un programa como:

1
2
3
4
5
6
#!/bin/bash

SCRIPT_SOURCE=`dirname $BASH_SOURCE[0]`
. $SCRIPT_SOURCE/common.sh

echo $(__ "You have %d apples and %d bananas" 12 30)

Daría una salida como:

You have 12 apples and 30 bananas

Y si en multilin.po lo traducimos como:

#: multilin.sh:8
msgid «You have %d apples and %d bananas»
msgstr «Tienes %d manzanas y %d plátanos»

Tendremos una salida como:

Tienes 12 manzanas y 30 plátanos

Lo que nos ayuda tremendamente a incrustar valores dentro de nuestras traducciones.

Instalar traducciones en el sistema

Si queremos instalar las traducciones a nivel de sistema, sólo tenemos que hacer esto:

$ sudo install locale/es/LC_MESSAGES/multilin.mo /usr/share/locale/es/LC_MESSAGES/multilin.mo

Así con cada idioma.

Actualización 30/11/2016 : Se añadió export antes de TEXTDOMAINDIR. Anteriormente funcionaba sin esto, pero ahora es obligatorio.

También podría interesarte....

There are 22 comments left Ir a comentario

  1. Pingback: Scripts multilingües en bash con gettext / Traducciones en scripts | PlanetaLibre /

  2. V /
    Usando Google Chrome Google Chrome 94.0.4606.114 en Linux Linux

    Bastante instructivo y útil por simplificar el asunto, gracias Gaspar!

    1. Gaspar Fernández / Post Author
      Usando Google Chrome Google Chrome 91.0.4472.27 en Linux Linux

      Gracias V ! 🙂

  3. WilliamSEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Your websites facilitate all the more each else volume is so engaging further serviceable It chooses me occur for withdraw reprise. I will in a split second snatch your rss channel to remain educated of any updates. pasar123 slot

  4. WilliamSEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Astounding, this is awesome as you need to take in more, I welcome to This is my page. 사설토토

  5. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    These web slots redefine the meaning of ‘big.’ Fantastic collection. สล็อตเว็บใหญ่

  6. WilliamSEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    On this page, you’ll see my profile, please read this data. 먹튀검증

  7. WilliamSEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    You should for the most part prevalent together with well-performing material, which implies that see it: Travel booking platform

  8. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    This is a reminder to always do thorough research before purchasing slots. เว็บตรง แตกง่าย

  9. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Can pleasantly compose on comparative themes! Welcome to here you’ll discover how it should look. แหล่งรวมสล็อตทุกค่าย

  10. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    I think this is an edifying post and it is incredibly useful and instructed. in like manner, I should need to thank you for the undertakings you have made in making this article. 대구맛집

  11. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    2up Sports Social Game APP is the newest type of sports social entertainment game in the world in 2020’s. 2up Sports adapts to the web3 era and the wave of mobile internet, oriented to the personality, health, fashion, popularity, new trend, all-day socialization concept of the young generation of 00’s. 2up

  12. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Trying to say thanks won’t simply be adequate, for the fantasti c clarity in your written work. I will immediately snatch your rss channel to remain educated of any updates. เว็บสล็อตโรม่า

  13. WilliamSEO /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    It should be seen that while asking for papers accessible to be acquired at paper creating organization, you can get unkind perspective. If you feel that the specialist is attempting to cheat you, don’t buy inquire about task from it. 토토사이트 모음

  14. jsimitseo /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Your websites facilitate all the more each else volume is so engaging further serviceable It chooses me occur for withdraw reprise. I will in a split second snatch your rss channel to remain educated of any updates. เกมป๊อกเด้งออนไลน์

  15. william SEO /
    Usando Mozilla Firefox Mozilla Firefox 122.0 en Windows Windows NT

    it’s to an extraordinary degree cool blog. Interfacing is unimaginably gainful thing.you have truly had any sort of impact photo booth rental

  16. Suman /
    Usando Google Chrome Google Chrome 120.0.0.0 en Windows Windows NT

    Escort in Goa these dazzling women have all the necessary experience to make your night extra special. The best thing about these women is that they are highly flexible and adaptable to different positions. This allows them to give their clients a high-quality experience, even when you’re on a tight budget.

  17. jsimitseo /
    Usando Google Chrome Google Chrome 121.0.0.0 en Windows Windows NT

    In this specific article, you will see a synopsis, fulfill peruse this post. concierge doctor naples

  18. JAKE /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    Thank you very much! I’m glad I could assist you, and please remember that I’m here whenever you need help or information in the future. If you have any questions or need assistance, don’t hesitate to reach out. Wishing you continued success, happiness, and fulfillment in all your endeavors as well. Take care, and have a fantastic day! I’m also looking forward to our next interaction. In 2024, men’s hair trends continue to evolve, offering a variety of colors, tips, and ideas to express individual style. Here are seven trending hair colors, tips, and ideas for men in 2024:tips and ideas for men/

  19. jessa /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    Thank you very much! I appreciate your kind words. I’m here to assist you whenever you need help or information in the future. If you have any questions or require assistance, please don’t hesitate to reach out. Wishing you continued success, happiness, and fulfillment in all your endeavors as well. Take care, and have a fantastic day! I’m also looking forward to our next interaction.

    VIP bodyguard services in New York City offer premium protection and personalized security solutions for high-profile individuals, celebrities, executives, dignitaries, and other VIPs. These services are designed to ensure the safety, privacy, and peace of mind of clients in a variety of settings and situations. Here are some key aspects of VIP bodyguard services in New York City:Personal Security Guard NYC

  20. jeni /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    Brothers [url=https://www.brothers-locksmith.com/]locksmith[/url] provides valuable 24/7 locksmith services near you we cover virtually all lock situations. These could be locks of residential, commercial or automotive properties.

  21. jeni /
    Usando Google Chrome Google Chrome 123.0.0.0 en Windows Windows NT

    Brothers locksmith provides valuable 24/7 locksmith services near you we cover virtually all lock situations. These could be locks of residential, commercial or automotive properties.

Leave a Reply to V Cancle Reply