Difference between revisions of "Gettext izar en "C""

From Proxecto Trasno
(Nova páxina: "==Gettex_izar aplicacións en "C" == [http://gruvi.galpon.org/index.php/Gettext_izar_en_%22C%22 Este COMO en castellano] Un agradecemento especial a '''Martin Vazquez''' (GLUG) e a …")
 
m (Modificar a orde das variables)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
==Gettex_izar aplicacións en "C" ==
+
==Gettex_izar aplicativos en "C" ==
 
[http://gruvi.galpon.org/index.php/Gettext_izar_en_%22C%22 Este COMO en castellano]
 
[http://gruvi.galpon.org/index.php/Gettext_izar_en_%22C%22 Este COMO en castellano]
  
Line 10: Line 10:
  
 
===Preparación/adaptación dos ficheiros===
 
===Preparación/adaptación dos ficheiros===
Esta preparación ou adaptación deberemos realizala en todos os ficheiros que conteñan cadeas de texto traducibles, considerando como tales aquelas que a aplicación utiliza como elemento de comunicación ou información co/ao usuario. Non se consideran cadeas traducibles aquelas que pertencen a notas do desenvolvedor, comentarios internos, etc...
+
Esta preparación ou adaptación deberemos realizala en todos os ficheiros que conteñan cadeas de texto traducibles, considerando como tales aquelas que o aplicativo utiliza como elemento de comunicación ou información co/ao usuario. Non se consideran cadeas traducibles aquelas que pertencen a notas do desenvolvedor, comentarios internos, etc...
 
   
 
   
 
Utilizando <font color="#0000FF">gettext("cadea_de_texto_orixinal")</font>
 
Utilizando <font color="#0000FF">gettext("cadea_de_texto_orixinal")</font>
Line 73: Line 73:
 
NOTAS IMPORTANTES:
 
NOTAS IMPORTANTES:
  
Os "include" de bibliotecas que se indican son os específicos para utilizar gettext, deben engadirse aos que teña a aplicación. Así mesmo necesita doutras bibliotecas que adoitan formar parte das aplicacións, en todo caso non está de máis comprobar que estean xa "incluídas" e se non o están incluílas.
+
Os "include" de bibliotecas que se indican son os específicos para utilizar gettext, deben engadirse aos que teña o aplicativo. Así mesmo necesita doutras bibliotecas que adoitan formar parte dos aplicativos, en todo caso non está de máis comprobar que estean xa "incluídas" e se non o están incluílas.
 
  #include <stdio.h>
 
  #include <stdio.h>
 
  #include <stdlib.h>
 
  #include <stdlib.h>
Line 89: Line 89:
 
  ...
 
  ...
  
Tamén deberemos ter en conta que algunhas aplicacións, ao ser compiladas, instálansenos en "/usr/locale/bin". Neste caso deberemos ter en conta que a ruta que indiquemos en "bindtextdomain"debe ser a "usr/local/share/locale" xa que será aquí onde busque de forma predeterminada.
+
Tamén deberemos ter en conta que algúns aplicativoss, ao seren compilados, instálansenos en "/usr/locale/bin". Neste caso deberemos ter en conta que a ruta que indiquemos en "bindtextdomain"debe ser a "usr/local/share/locale" xa que será aquí onde busque de forma predeterminada.
 
     bindtextdomain( "absvolume", "/usr/local/share/locale" );
 
     bindtextdomain( "absvolume", "/usr/local/share/locale" );
  
Line 137: Line 137:
 
====Creando (compilando) o ficheiro binario ".mo" que lerá o executable====
 
====Creando (compilando) o ficheiro binario ".mo" que lerá o executable====
 
  msgfmt -c -v -o po/<font color="#0000FF">nome_executable</font>.mo po/es.po
 
  msgfmt -c -v -o po/<font color="#0000FF">nome_executable</font>.mo po/es.po
Normalmente o ficheiro ".mo" leva o mesmo nome que a aplicación, sempre deberá ser o mesmo que definamos nas liñas
+
Normalmente o ficheiro ".mo" leva o mesmo nome que o aplicativo, sempre deberá ser o mesmo que definamos nas liñas
 
     bindtextdomain( "<font color="#0000FF">nome_executable</font>", "/usr/share/locale" );
 
     bindtextdomain( "<font color="#0000FF">nome_executable</font>", "/usr/share/locale" );
 
     textdomain( "<font color="#0000FF">nome_executable</font>" );
 
     textdomain( "<font color="#0000FF">nome_executable</font>" );
Line 169: Line 169:
 
  Escrito ás  25/7/2009 do dia 7:30
 
  Escrito ás  25/7/2009 do dia 7:30
 
Para solucionalo deberemos ter en conta a orde das variables e modificalo engadindolle un valor "ordinal" 1, 2, etc... antes do tipo de dato
 
Para solucionalo deberemos ter en conta a orde das variables e modificalo engadindolle un valor "ordinal" 1, 2, etc... antes do tipo de dato
  msgstr "Escrito ás %2$s do día «%1$\n"
+
  msgstr "Escrito ás %$2s do día «%$1s»\n"
  
 
===Xeración/modificación do procedemento xeral de compilación===
 
===Xeración/modificación do procedemento xeral de compilación===
para que compile toda a aplicación e sitúe correctamente os ficheiros ".mo"  
+
para que compile todo o aplicativo e sitúe correctamente os ficheiros ".mo"  
  
 
====Dependencias====
 
====Dependencias====
 
Loxicamente necesitamos ter instalado "gettext" e para poder compilar necesitaremos ter instaldos automake gcc e as cabeceiras (header) -En Ubuntu é "build-essentials"-
 
Loxicamente necesitamos ter instalado "gettext" e para poder compilar necesitaremos ter instaldos automake gcc e as cabeceiras (header) -En Ubuntu é "build-essentials"-
 
  apt-get install gettext automake build-essentials
 
  apt-get install gettext automake build-essentials
E segundo o tipo de aplicación deberemos ter instaladas as bibliotecas das que dependa.
+
E segundo o tipo de aplicativo deberemos ter instaladas as bibliotecas das que dependa.
  
 
Exemplos de avisos ao traballar con GRandR
 
Exemplos de avisos ao traballar con GRandR
Line 192: Line 192:
 
  configure: erro: C compiler cannot create executables
 
  configure: erro: C compiler cannot create executables
 
  See `config.log' for more details.
 
  See `config.log' for more details.
Cando nos faltan librerias particulares da aplicación
+
Cando nos faltan librerias particulares do aplicativo
 
  Non package 'gtk+-2.0' found
 
  Non package 'gtk+-2.0' found
 
  Non package 'gconf-2.0' found
 
  Non package 'gconf-2.0' found
Line 202: Line 202:
  
 
=====Procedemento "gettextize"=====
 
=====Procedemento "gettextize"=====
Sempre dentro do directorio/cartafol da aplicación
+
Sempre dentro do directorio/cartafol do aplicativo
 
  cd /Ruta/a/o/cartafol/do/proxecto
 
  cd /Ruta/a/o/cartafol/do/proxecto
 
Aplicamos a orde
 
Aplicamos a orde
Line 240: Line 240:
  
 
  nano po/POTFILES.in
 
  nano po/POTFILES.in
engadimos o que sexa preciso en función da aplicación:
+
engadimos o que sexa preciso en función do aplicativo:
 
  # List of source files containing translable strings.
 
  # List of source files containing translable strings.
 
   
 
   
Line 274: Line 274:
 
*Árbore de ficheiros
 
*Árbore de ficheiros
 
  ./                                ./
 
  ./                                ./
   |----aplicación                   |----aplicación
+
   |----aplicativon                   |----aplicativo
 
       |                                |
 
       |                                |
 
       |----src/                        |----src/
 
       |----src/                        |----src/
Line 283: Line 283:
 
       |----po/                          |----po/
 
       |----po/                          |----po/
 
       |    |                            |    |  
 
       |    |                            |    |  
       |    |----aplicación.pot          |    |----aplicación.pot
+
       |    |----aplicativo.pot          |    |----aplicativo.pot
 
       |    |----es.po                  |    |----es.po
 
       |    |----es.po                  |    |----es.po
 
       |    |----gl.po                  |    |----gl.po       
 
       |    |----gl.po                  |    |----gl.po       
Line 325: Line 325:
  
 
====Corrección final====
 
====Corrección final====
Nas aplicacións que de forma predeterminada instálansenos en "/usr/local/bin/XXXX" e os ficheiros de idioma ".mo" en "/usr/local/share/locale" pero queremos forzar a instalación en "/usr/bin/XXXX" e os ficheiros de idioma en "/usr/share/local", teremos que facer a configuración coa instrución:
+
Nos aplicativos que de forma predeterminada instálansenos en "/usr/local/bin/XXXX" e os ficheiros de idioma ".mo" en "/usr/local/share/locale" pero queremos forzar a instalación en "/usr/bin/XXXX" e os ficheiros de idioma en "/usr/share/local", teremos que facer a configuración coa instrución:
 
  ./configure --prefix=/usr
 
  ./configure --prefix=/usr
 
Asegurandonos de antemán que a ruta en "bindtextdomain" é:
 
Asegurandonos de antemán que a ruta en "bindtextdomain" é:

Latest revision as of 13:15, 24 October 2010

Gettex_izar aplicativos en "C"[edit]

Este COMO en castellano

Un agradecemento especial a Martin Vazquez (GLUG) e a Cesar Mauri (eViacam) que case ao mesmo tempo detectaron unha trapallada miña que levaba retrasando o resultado durante máis dunha semana

Xeral[edit]

Este proceso é o que se define como "i18n" ou "internacionalización" (segundo a Wikipedia):

A internacionalización é o proceso de deseñar software de xeito tal que poida adaptarse a diferentes idiomas e rexións sen a necesidade de realizar cambios de enxeñería nin no código.

Preparación/adaptación dos ficheiros[edit]

Esta preparación ou adaptación deberemos realizala en todos os ficheiros que conteñan cadeas de texto traducibles, considerando como tales aquelas que o aplicativo utiliza como elemento de comunicación ou información co/ao usuario. Non se consideran cadeas traducibles aquelas que pertencen a notas do desenvolvedor, comentarios internos, etc...

Utilizando gettext("cadea_de_texto_orixinal")

/* includes para localizar con gettext */
#include <libintl.h>
#include <locale.h>

// Definición de ficheiros e rutas para gettext
trans_text(void)
{
    setlocale( LC_ALL, "" );
    bindtextdomain( "nome_executable", "/usr/share/locale" );
    bind_textdomain_codeset ( "nome_executable", "UTF-8" );
    textdomain( "nome_executable" );
}

Orixinal:

void create_file_selection(void) 
{
    // file_selection_box = gtk_file_selection_new("Select MIXER application");
    file_selection_box = gtk_file_chooser_dialog_new("Select MIXER application", NULL,
    ...

Modificado:

void create_file_selection(void) 
{
    // file_selection_box = gtk_file_selection_new("Select MIXER application");
    file_selection_box = gtk_file_chooser_dialog_new(gettext("Select MIXER application"), NULL,
    ...

Utilizando _("cadea_de_texto_orixinal")

/* includes e define para localizar con gettext */
#include <libintl.h>
#include <locale.h>

#define _(String) gettext(String)    // cadeas traducibles
#define N_(String) (String)          // cadeas non traducibles

// Definición de ficheiros e rutas para gettext
trans_text(void)
{
    setlocale( LC_ALL, "" );
    bindtextdomain( "nome_executable", "/usr/share/locale" );
    bind_textdomain_codeset ("nome_executable", "UTF-8");
    textdomain( "nome_executable" );
}

Orixinal:

void create_file_selection(void) 
{
    // file_selection_box = gtk_file_selection_new("Select MIXER application");
    file_selection_box = gtk_file_chooser_dialog_new("Select MIXER application", NULL,
    ...

Modificado:

void create_file_selection(void) 
{
    // file_selection_box = gtk_file_selection_new("Select MIXER application");
    file_selection_box = gtk_file_chooser_dialog_new(_("Select MIXER application"), NULL,
    ...

NOTAS IMPORTANTES:

Os "include" de bibliotecas que se indican son os específicos para utilizar gettext, deben engadirse aos que teña o aplicativo. Así mesmo necesita doutras bibliotecas que adoitan formar parte dos aplicativos, en todo caso non está de máis comprobar que estean xa "incluídas" e se non o están incluílas.

#include <stdio.h>
#include <stdlib.h>

Usar LC_ALL en "setlocale" podería non ser apropiado. LC_ALL inclúe todas as categorias de localización (locale), especialmente LC_CTYPE, responsable de determinar as clases de carácteres nunha serie de funcións de "ctype.h" o cal podería producir unha saída incorrecta. Ademais, algúns sistemas teñen problemas procesando números usando as funcións scanf cando se utiliza LC_ALL. É por iso que normalmente é necesario substituír a liña que fai referencia a LC_ALL por unha secuencia de liñas setlocale:

setlocale(LC_TIME, "");
setlocale(LC_MESSAGES, "");

No mesmo ficheiro, debemos buscar a chamada a "main()"

main (int argc, char *argv[])

e ao principio facer unha chamada a "trans_text()"

main (int argc, char *argv[])
{
  trans_text();
...

Tamén deberemos ter en conta que algúns aplicativoss, ao seren compilados, instálansenos en "/usr/locale/bin". Neste caso deberemos ter en conta que a ruta que indiquemos en "bindtextdomain"debe ser a "usr/local/share/locale" xa que será aquí onde busque de forma predeterminada.

    bindtextdomain( "absvolume", "/usr/local/share/locale" );

Creación dos ficheiros de tradución[edit]

Extracción de textos a unha plantilla .pot "nome_executable.pot"[edit]

Utilizando gettext("cadea_de_texto_orixinal")
xgettext -d nome_executable -s -o po/nome_executable.pot src/main.c
Utilizando _("cadea_de_texto_orixinal") debe engadirse a opción -k_
xgettext -k_ -kN_ -d nome_ejecutable -s -o po/nome_executable.pot src/main.c

Se hai que extraer as cadeas de máis dun ficheiro, o primeiro será crear un ficheiro nome_executable.pot

touch po/nome_executable.pot

agora extraemos as cadeas coa opción "-j" (--join-existing)

xgettext -k_ -kN_ -d grandr -s -o po/nome_executable.pot -j src/*.c

Desta forma extraemos as cadeas de todos os ficheiros ".c" en "./src", existen máis opcións, como excluír ficheiros etc...

man xgettext
 ...
   Operation mode:
      -j, --join-existing
             join messages with existing file

Xeración de ficheiro de tradución "nome_executable.po"[edit]

Desprazámonos ao cartafol "po" ( $ cd po )

No mesmo "locale" (idioma) do noso sistema[edit]
msginit -o po/es.po -i po/nome_executable.pot

Devólvenos a seguinte mensaxe:

O novo catálogo de mensaxes debería conter a súa dirección de correo 
electrónico, de tal forma que os usuarios poidan retroalimentalo sobre
as traducións, e o persoal de mantemento poida contactalo 
en caso de ter problemas técnicos inesperados.

Is the following your email address?
  manolito@maquina 
Please confirm by pressing Return, or enter your email address.

Introducimos o noso correo-e e pódenos devolver algo como isto:

If you want to create a new translation team for gl, please visit
  http://www.iro.umontreal.ca/contrib/po/HTML/teams.html
  http://www.iro.umontreal.ca/contrib/po/HTML/leaders.html
  http://www.iro.umontreal.ca/contrib/po/HTML/index.html

Noutro "locale" (idioma) distinto ao do noso sistema[edit]
msginit -l gl -o gl.po -i nome_executable.pot

Se nos fixamos, a diferenza está na opción "-l" e no parámetro do idioma, ter en conta que é costume que o ficheiro ".po" resultante leve por nome o código do idioma ao que corresponde xa que desta forma, calquera que o vexa saberá que é.

Creando (compilando) o ficheiro binario ".mo" que lerá o executable[edit]

msgfmt -c -v -o po/nome_executable.mo po/es.po

Normalmente o ficheiro ".mo" leva o mesmo nome que o aplicativo, sempre deberá ser o mesmo que definamos nas liñas

   bindtextdomain( "nome_executable", "/usr/share/locale" );
   textdomain( "nome_executable" );

senon o executable non saberá como buscalo.

Casos especiais[edit]

Engadir comentarios para os tradutores[edit]

Colocar comentarios antes das cadeas para dar instrucións ou axudas aos tradutores

/// TRANSLATORS: Please leave %s as it is, because it is needed by the program.
/// Thank you for contributing to this project.
printf(_("My name is %s.\n"), my_name);

Neste caso iníciase o comentario con /// e debe terse en conta á hora de construír a plantilla .pot a fin de que poida extraer estes comentarios.

xgettext --add-comments=///

O ficheiro .pot terá este aspecto

#. TRANSLATORS: Please leave %s as it is, because it is needed by the program.
#. Thank you for contributing to this project. 
#: src/name.c:36
msgid "My name is %s.\n"
msgstr ""
Modificar a orde das variables[edit]

Este é un erro moi frecuente nas traducións

Frase exemplo

printf (gettext ("Written on `%s' at %s\n"), s, strlen (s));

Na plantilla verémolo así:

msgid "Written on `%s' at %s\n"

Traducímolo literalmente por msgstr

"Escrito o «%s» ás %s\n"

Como nos gusta máis dicir "Escrito ás %s do día «%s»" traducímolo así e o resultado será algo como:

Escrito ás  25/7/2009 do dia 7:30

Para solucionalo deberemos ter en conta a orde das variables e modificalo engadindolle un valor "ordinal" 1, 2, etc... antes do tipo de dato

msgstr "Escrito ás %$2s do día «%$1s»\n"

Xeración/modificación do procedemento xeral de compilación[edit]

para que compile todo o aplicativo e sitúe correctamente os ficheiros ".mo"

Dependencias[edit]

Loxicamente necesitamos ter instalado "gettext" e para poder compilar necesitaremos ter instaldos automake gcc e as cabeceiras (header) -En Ubuntu é "build-essentials"-

apt-get install gettext automake build-essentials

E segundo o tipo de aplicativo deberemos ter instaladas as bibliotecas das que dependa.

Exemplos de avisos ao traballar con GRandR

Cando non existe "automake"

**Error**: You must have `autoconf' installed.
Download the appropriate package for your distribution,
or get the source tarball at ftp://ftp.gnu.org/pub/gnu/

**Error**: You must have `automake' installed.

Cando non existe gcc, etc...

checking for gcc... gcc
checking for C compiler default output file name... 
configure: erro: C compiler cannot create executables
See `config.log' for more details.

Cando nos faltan librerias particulares do aplicativo

Non package 'gtk+-2.0' found
Non package 'gconf-2.0' found
Non package 'xrandr' found
sudo apt-get install libgtk2.0-dev libgconf2-dev libxrandr-dev

Procedemento[edit]

Procedemento "gettextize"[edit]

Sempre dentro do directorio/cartafol do aplicativo

cd /Ruta/a/o/cartafol/do/proxecto

Aplicamos a orde

gettextize

Invocando esta orde non se copia o directorio ./intl polo que deberemos invocalo no ficheiro "configure.ac" (ou en configure.in) coa seguinte liña

AM_GNU_GETTEXT([external])

Recomendo que se inclúa o directorio ./intl a fin de que nas fontes xa vaian incluídos os "cabeceiras" para a compilación, ademais para previr calquera fallo bobo, é preferible aplicar a orde completa

gettextize --copy --force --intl

Devólvenos a seguinte mensaxe:

Please use AM_GNU_GETTEXT([external]) in order to cause autoconfiguration
to look for an external libintl.

Please create po/Makevars from the template in po/Makevars.template.
You can then remove po/Makevars.template.

Please fill po/POTFILES.in as described in the documentation.

Please run 'aclocal -I m4' to regenerate the aclocal.m4 file.
You need aclocal from GNU automake 1.9 (or newer) to do this.
Then run 'autoconf' to regenerate the configure file.

You will also need config.guess and config.sub, which you can get from the CVS
of the 'config' project at http://savannah.gnu.org/. The commands to fetch them
are
$ wget 'http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess'
$ wget 'http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub'

You might also want to copy the convenience header file gettext.h
from the /usr/share/gettext directory into your package.
It is a wrapper around <libintl.h> that implements the configure --disable-nls
option.

Press Return to acknowledge the previous 6 paragraphs.

Abrimos outra terminal e imos facendo cada un dos pasos que se nos indican

cp po/Makevars.template po/Makevars
nano po/POTFILES.in

engadimos o que sexa preciso en función do aplicativo:

# List of source files containing translable strings.

src/main.c
src/interface.c
src/callbacks.c
src/outro_ficheiro
src/ ...

Situar só os ficheiros que teñen cadeas traducibles por gettext

Aínda que non nolo di na mensaxe de saída de "gettextize", agora deberemos crear o Ficheiro "LINGUAS" que é unha listaxe dos idiomas que vai procesar durante a compilación

nano po/LINGUAS

e nel engadimos os idiomas separados por un espazo ou, se nos gusta máis, un en cada liña

es gl

ou

es
gl

Seguimos co que nos indica gettextize na mensaxe e executamos:

aclocal -I m4
autoconf
wget http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess

wget http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub
cp /usr/share/gettext/gettext.h .

Opcionalmente

cp -r /usr/share/gettext/intl/ .
  • Árbore de ficheiros
./                                ./
 |----aplicativon                   |----aplicativo
      |                                 |
      |----src/                         |----src/
      |    |                            |    | 
      |    |---- ...                    |    |---- ...
      |    |---- ...                    |    |---- ...
      |                                 |
      |----po/                          |----po/
      |    |                            |    | 
      |    |----aplicativo.pot          |    |----aplicativo.pot
      |    |----es.po                   |    |----es.po
      |    |----gl.po                   |    |----gl.po      
      |    |---- ...                    |    |---- ...
      |                                 |
      |---- ...                         |----intl/
      |---- ...                         |    | 
                                        |    |---- ... 
                                        |
                                        |---- ...

Compilación final[edit]

./configure
make
make install

Construír un ".deb"[edit]

Como isto é tema doutro manual e hai bastantes e bos na rede, deixo as ligazóns:

Un metodo sinxelo que permite controlar algunhas variables é "checkinstall"

E aínda que con poucas posibilidades de control é moi sinxelo utilizar o script "autodeb"

Como crear paquetes ".deb" con "checkinstall"[edit]
Como crear paquetes ".deb" con AutoDeb[edit]

Descargamos o script

e dámoslle os permisos necesarios:

chmod +x autodeb.sh

executamos o script:

# (ou sudo) ./autodeb.sh

Se executamos

# (ou sudo) ./autodeb.sh --gnome

Autodeb execútase en modo gráfico e traballa sobre o ficheiro comprimido -tarball- (tgz, tar.gz, etc...)

Corrección final[edit]

Nos aplicativos que de forma predeterminada instálansenos en "/usr/local/bin/XXXX" e os ficheiros de idioma ".mo" en "/usr/local/share/locale" pero queremos forzar a instalación en "/usr/bin/XXXX" e os ficheiros de idioma en "/usr/share/local", teremos que facer a configuración coa instrución:

./configure --prefix=/usr

Asegurandonos de antemán que a ruta en "bindtextdomain" é:

bindtextdomain( "absvolume", "/usr/share/locale" );

Referencias[edit]

http://www.gnu.org/software/gettext/manual/gettext.html

http://www.alu.ua.es/p/psp4/Documentacion/Febrero_2002/gettext2.html

http://www.escomposlinux.org/lfs-es/lfs-es-6.3/chapter06/gettext.html

http://www.alu.ua.es/p/psp4/Documentacion/Febrero_2002/gettext.html