Tema XV - Departamento de Lenguajes y Sistemas Informáticos

Anuncio
Tema XV
Internacionalización (I18N)
(Revision : 1,4)
Herramientas de Programación.
19 de noviembre de 2004
Resumen
Internacionalización. Localización. Catalogos de mensajes.
Dpto. Lenguajes y Sistemas Informáticos
Universidad de Alicante
DLSI
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Preliminares: [I]
Entendemos por internacionalización al proceso por el que un programa o
conjunto de programas de un proyecto es capaz de soportar diversos lenguajes.
Generalización. I18n
Entendemos por localización al proceso por el que un conjunto de programas
ya ‘internacionalizados’ son capaces de adaptar su entrada y salida a un
determinado idioma y hábitos culturales. Particularización. L10n
DLSI
1
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Preliminares: [II]
A la descripción formal del conjunto de hábitos culturales de un paı́s junto con
las traducciones de los mensajes a un lenguaje nativo, se le llama locale, por
localización para un determinado paı́s e idioma.
Al conjunto de internacionalización y localización se le llama Soporte
de Lenguaje Nativo: NLS
A lo largo del tema nos ocuparemos de gettext como herramienta de ayuda
en la internacionalización .
DLSI
2
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext : [I]
La idea que hay detrás de gettext es muy sencilla. . .
Cualquier cadena del programa/librerı́a que pueda leer el usuario no se ‘imprime’
directamente. . .
Previamente se procesa con una función de la librerı́a gettext y el resultado
es lo que se muestra al usuario.
DLSI
3
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext : [II]
Y el proceso serı́a el siguiente
Se extraen todas las cadenas del código fuente a unos ficheros especiales.
xgettext .
Hay un fichero de éstos por cada idioma, y en él se acompaña cada cadena en
el idioma original por la cadena traducida al idioma destino.
DLSI
4
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext : [III]
Se procesan estos ficheros especiales —cada uno de un idioma— para optimizar
su lectura. msgfmt .
Se modifica el fuente de manera que cada cadena que aparecı́a en él, ahora es
el resultado de llamar a ‘gettext (cadena)’.
Se compila y enlaza el programa con la librerı́a gettext .
DLSI
5
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext : [IV]
En realidad es —sólo— un poco más complicado:
Original C Sources ---> PO mode ---> Marked C Sources ---.
|
.---------<--- GNU gettext Library
|
.--- make <---+
|
|
‘---------<--------------------+-----------’
|
|
|
.-----<--- PACKAGE.pot <--- xgettext <---’
.---<--- PO Compendium
|
|
|
^
|
|
‘---.
|
|
‘---.
+---> PO mode ---.
|
+----> msgmerge ------> LANG.pox --->--------’
|
|
.---’
|
|
|
|
|
‘-------------<---------------.
|
|
+--- LANG.po <--- New LANG.pox <----’
|
.--- LANG.gmo <--- msgfmt <---’
|
|
|
‘---> install ---> /.../LANG/PACKAGE.mo ---.
|
+---> "Hello world!"
‘-------> install ---> /.../bin/PROGRAM -------’
DLSI
6
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Archivos especiales: [I]
Los archivos especiales que hemos comentado antes usan la extensión .po por
Portable Object.
Son de texto, con un formato especial. Emacs dispone de un modo de edición
especı́fico para ellos.
msgfmt los transforma en archivos binarios, con extensión .mo por Machine
Object.
DLSI
7
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Archivos especiales: [II]
Ejemplo de archivo .po:
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR Free Software Foundation, Inc.
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"POT-Creation-Date: 2001-07-16 18:43+0200\n"
"PO-Revision-Date: 2001-07-16 19:00+0200\n"
"Last-Translator: Alfredo <[email protected]>\n"
"Language-Team: english <[email protected]>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=ISO-8859-1\n"
"Content-Transfer-Encoding: 8bit\n"
#: ../src/hola.c:31
msgid "Hola Mundo."
"\n"
msgstr "Hello World."
"\n"
DLSI
8
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [I]
Comenzaremos preparando el código fuente. . .
Para ello definiremos de este modo las siguientes macros del preprocesador:
#define
#define
#define
#define
DLSI
_(String) (String)
N_(String) (String)
textdomain(Domain)
bindtextdomain(Package, Directory)
9
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [II]
Y marcaremos las cadenas del código que se vayan a traducir con la macro:
(cadena): cout << (‘‘hola’’) << endl.
La macro N (cadena) sirve para marcar cadenas usadas en la iniciación de
vectores:
const char *strs[] = { N ("Cadena de iniciación") };
cout << (strs[0]) << endl;
DLSI
10
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [III]
Más tarde, cuando ya estemos listos para soportar completamente gettext ,
lo haremos ası́:
#include <libintl.h>
#define _(String) gettext (String)
#define gettext_noop(String) (String)
#define N_(String) gettext_noop (String)
Y al inicio del programa principal pondremos:
setlocale(LC_ALL,"");
bindtextdomain(PACKAGE, LOCALEDIR);
textdomain(PACKAGE);
DLSI
11
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [IV]
En ocasiones puede ser necesario reemplazar la llamada a
setlocale(LC ALL,)
por estas otras:
setlocale (LC_CTYPE, "");
setlocale (LC_MESSAGES, "");
DLSI
12
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [V]
PACKAGE es una macro con el nombre de nuestro programa.
LOCALEDIR es una macro que contiene el subdirectorio de inicio a partir del
cual se encuentra la ‘estructura’ de locales para los distintos idiomas.
DLSI
13
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [VI]
Suponiendo que LOCALEDIR sea igual a locale, a partir de él hay una
estructura de directorios ası́: locale/es/LC MESSAGES/aplicacion.mo.
locale----+
+----emacs.mo
|
+----gvim.mo
+---es/LC_MESSAGES---+----xterm.mo
|
|
+----emacs.mo
+---en/LC_MESSAGES---+----xterm.mo
|
+---ca/LC_MESSAGES---.........
DLSI
14
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [VII]
A continuación generaremos los ficheros .po a partir de los fuentes usando
xgettext ası́:
xgettext -k -kN hola.c -o hola.pot
La extensión .pot indica que es un ‘patrón’ de un fichero .po.
Duplicaremos este fichero por cada idioma al que queramos traducir la aplicación: en.po , ca.po , etc. . . y haremos las traducciones sobre ellos.
Finalmente los transformaremos a ficheros .mo usando msgfmt ası́:
msgfmt en.po -o en.mo.
DLSI
15
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [VIII]
¿Qué ocurre al ir modificando los fuentes en los que se basan los ficheros .po
que ya contienen traducciones?.
Van quedando desfasados. . . pero se pueden actualizar automáticamente.
Eso lo hace msgmerge def.po ref.po.
Donde def.po es un fichero de traducciones ya existente y ref.po es el último
fichero extraido de los fuentes con xgettext.
DLSI
16
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [IX]
En las cadenas de formato de printf puede alterarse el orden de los parámetros
en la traducción.
Por ejemplo, en la traducción al alemán de:
printf (gettext ("String ‘ %s’ has %d characters"), s, strlen (s));
podrı́a obtenerse esta cadena:
" %d Zeichen lang ist die Zeichenkette ‘ %s’".
Lo cual producirı́a. . . un error de ejecución .
msgfmt lo soluciona con la notación:
" %2$d Zeichen lang ist die Zeichenkette ‘ %1$s’".
DLSI
17
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
Uso de gettext : [X]
Finalmente queda enlazar1 con la librerı́a libintl.a.
Dar el valor del idioma elegido a una de estas variables de entorno que, por
prioridad decreciente, son: LANGUAGE, LC ALL , LC xxx —donde ‘xxx’
es el valor del locale elegido— y LANG .
Y poner en marcha el programa.
Por ejemplo: LANG=en GB hola
1
Sólo si fuera necesario, versiones recientes de la librerı́a gnu-libc no lo necesitan pues ya incluyen las funciones
comentadas.
DLSI
18
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [I]
automake y autoconf proporcionan soporte para el uso de gettext .
Estando en el directorio raı́z del proyecto, basta con seguir estos pasos:
• Ejecutamos el programa gettextize, el cual crea: ABOUT-NLS , po/ e
intl/ .
• El subdirectorio po contiene inicialmente el fichero Makefile.in.in —doble
sufijo—.
• En el subdirectorio po creamos el fichero POTFILES.in que contiene una
lista de los ficheros de código fuente con cadenas para traducir.
DLSI
19
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [II]
Ejemplo de fichero
POTFILES.in :
# List of source files containing translatable strings.
# Copyright (C) 1995 Free Software Foundation, Inc.
# Common library files
lib/my_error.c
lib/scan_text.c
# Package source files
src/process.c
src/main.c
DLSI
20
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [III]
En configure.ac añadimos las siguientes lı́neas:
ALL LINGUAS="de fr".
AM GNU GETTEXT.
AC OUTPUT([a~
nadimos... intl/Makefile po/Makefile.in]).
DLSI
21
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [IV]
Copiamos al directorio raı́z del proyecto los ficheros: config.guess y
config.sub.
Se pueden obtener de ftp://ftp.gnu.org/pub/gnu/config/, o de la distribución de automake o libtool que tengamos, pero —probablemente—
menos actualizados.
DLSI
22
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [V]
Añadimos al Makefile.in del directorio raı́z:
PACKAGE = @PACKAGE@ y VERSION = @VERSION@.
Añadimos ABOUT-NLS a la variable DISTFILES.
La variable SUBDIRS, valdrá algo parecido a :
SUBDIRS = doc intl lib src @POSUB@.
DLSI
23
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [VI]
Añadimos al Makefile.in del directorio con el código fuente:
PACKAGE = @PACKAGE@, VERSION = @VERSION@ y top srcdir = @top srcdir@.
Añadimos
datadir = @datadir@
localedir = $(datadir)/locale
DEFS = -DLOCALEDIR=’’$(localedir)’’ @DEFS@
LIBS = @INTLLIBS@ @LIBS@ .
DLSI
24
H.P.: Tema XV: Internacionalización (I18N) - Revision : 1,4
gettext y autotools : [VII]
El resto de acciones, tales como:
• La extracción de cadenas
• Traducción a diversos lenguajes de las mismas
la realizaremos tal y como ya sabemos.
DLSI
25
Descargar