peeter_joot@vnet.ibm.com
Traducción por Juan José López
Mellado,laveneno@hotmail.com
Esto es realmente una descripción de cómo hice para tener localedef instalado, compilar algunas localidades, y cómo probarlas. Lo hago solo por entretenimiento, y pensando que alguien podría estar interesado en probarlo por si mismo. Una vez esté configurado usted podrá usar aplicaciones con NLS activado y con la localidad que desee. De aquí a poco tiempo, el soporte a las localidades será una parte de las distribuciones estándar, por lo que gran parte de este mini-HOWTO será redundante.
Locales encapsula varias de las características específicas de la lengua y la cultura que no puede ser codificada directamente en sus programas. Si tiene varias localidades instaladas en su ordenador entonces puede seleccionar a través de las correspondientes variables de entorno como se de sensitivo a su localidad debe ser un programa. Las localidades por defecto son las de C, o las POSIX locale las cuales se encuentran codificadas en libc.
Selecciona la localidad, pero puede ser superpuesta por cualquier otra variable de entorno de las LC_xxxx.
Método de ordenamiento.
Definiciones de caracteres, mayúsculas, minúsculas, ... Son usadas por funciones como toupper, tolower, islower, isdigit, ...
Contiene la información necesaria para el formato monetario. Contiene definiciones de cosas como el separador de millares, el separador decimal, y el símbolo monetario junto con la posición que ocupa.
Separadores de millares y decimal, y la agrupación numérica esperada.
Como especificar la hora y la fecha. Contiene cosas como los días de la semana, y los meses del año en forma abreviada y completa.
Expresiones Sí, y No.
Activa la localidad, y se superpone a cualquier otra variable de entorno LC_xxxx.
Algunas localidades son las siguientes, y existen muchas más.
Inglés Canadiense.
Inglés Estadounidense.
Alemán de Alemania.
Francés de Francia.
Español de España.
Si está escribiendo un programa, y espera que sea usado de manera internacional debe usar las localidades. La razón más evidente para ello es porque no todo el mundo va a usar el mismo código y páginas de caracteres que usted. Vaya con cuidado de no incorporar en su programa código como el siguiente:
/* aceptar caracteres alfabéticos */
if ( (( c >= 'a') && ( c <= 'z' )) ||
(( c >= 'A') && ( c <= 'Z' )) ) { ... }
Si escribe este tipo de código está asumiendo en su programa que el
usuario/fichero/... usa ASCII y nada más que ASCII, y no estará respetando la
página de códigos de la localidad del usuario. Por ejemplo está rechazando
caracteres como la a acentuada del entorno Español (N. del T. el ejemplo ha
sido convenientemente modificado para la localidad Española). Lo que debe
hacer en vez de aquello es usar funciones que tengan en cuenta la localidad
como isalpha(). Si su programa requiere necesariamente del uso del alfabeto
US-ASCII, utilice de todas maneras la función isalpha(), pero antes debería
hacer setlocale(LC_CTYPE,"C")
o definir las variables de entorno
LANG
, LC_CTYPE
, o LC_ALL
al valor "C".
Locales permite un gran grado de flexibilidad y hace que ciertas presunciones que un programador hacía en programas C basados en ASCII sean incorrectas. Por ejemplo, no puede asumir la posición de los caracteres dentro del código. Nada le prohibe el hacer un fichero de mapa de caracteres que defina la posición del carácter 'A' como 0xC1 en vez de 0x41. Este es en realidad el código de mapeo para la 'A' en la página de códigos 37 de IBM, usada en los mainframes, mientras que el primero es el usado por US-ASCII, iso8859-x, y otros. La idea básica es que la gente que habla en lenguas diferentes, esperan ordenaciones de caracteres diferentes, usan páginas de códigos diferentes, y viven en diferentes paises. Las localidades y los programas sensitivos a la localidad dan a uno la capacidad de respetar estas cosas, y manejarlas de forma correcta. No es mucho más el trabajo que debe realizarse, solo se necesita una manera diferente de pensar al escribir los programas.
ftp.tu-clausthal.de:/pub/linux/SLT/nls
contiene una versión a.out de
locale o localedef (en el fichero nlsutils-0.5.tar.gz), por si no dispone de un
sistema ELF, o no quiere una copia que lo use. Probablemente haya una copia del
paquete nlsutils en otros sitios, pero no los he buscado. No se si era una
versión completa e independiente de locale y localedef, ni que tipo de librería
libc necesitaba tener instalada. Por este motivo un buen trozo de este HOWTO es
solo un recordatorio de lo que necesité hacer para actualizar libc y familia.
Si lo hace, como hice yo, necesitará un sistema ELF corriendo, o actualizarse a
uno al activar las localidades.
Es necesario bajarse algunas cosas de varios sitios. Todo lo que aparece
aquí exceptuando los ficheros fuentes de locale puede obtenerse de
sunsite.unc.edu
, tsx-11.mit.edu
, o, preferiblemente, un sitio
espejo de estos. Cuando hice esto originalmente use libc-5.2.18, la cual está
bastante actualizada. La actual versión de libc es la 5.4.17, y más abajo se
han hecho las correspondientes sustituciones. De todas maneras, libc 5.4.17,
estará probablemente anticuada cuando realice estos cambios, así que use la
última versión de que disponga. Debería considerar el usar glibc (gnu libc) en
vez de libc 5 de Linux para cualquier trabajo de
internacionalización.Actualmente está disponible glibc 2.0.4 (gnu libc) pero
ninguna distribución la ha comenzado a utilizar como su librería estándar libc
(al menos para las distribuciones de Linux para Intel). Además de ser
completamente reentrante y tener soporte para hilos (N. del T.
threads), glibc está completamente internacionalizada y tiene un excelente
soporte para la internacionalización en la programación. La mayoría de la
internacionalización hecha en libc 5 se ha obtenido de glibc. Si opta por usar
glibc entonces puede ignorar este mini-howto. Incluir el añadido de locale en
la compilación e instalación de glibc es trivial, y está cubierto por la
documentación de instalación de glibc. ¡ Debe advertirse que una actualización
completa no es un trabajo trivial ! Estoy esperando a que redhat (la cual uso)
tenga pronto una distribución basada en glibc, ya que no deseo tener que
recompilar completamente mi sistema.
locale, y los fuentes de charmap
--- Esto es lo que usted
compila usando localedef.
libc-5.4.17.bin.tar.gz
--- las
librerías compartidas ELF para el C y librerías matemáticas. Nótese que el
programa localefef precompilado para libc 5.4.17 es aparentemente incorrecto y
crea un LC_CTYPE con un número mágico incorrecto. Esto probablemente signifique
que un localedef más antiguo se utilizó para hacerla distribución binaria.
libc-5.4.17.tar.gz
--- el código fuente para las librerías
compartidas ELF. Lo necesitará para compilar localedef.
make-3.74.tar.gz
--- necesitará compilar make para incorporar un
parche para arreglar el fallo de dirent
.
release.libc-5.2.18
--- Estas notas tienen el parche para hacer
el make. Hace bastante que este fallo del make apareció, y probablemente no
necesite preocuparse por el. ld.so-1.7.12+
--- el enlazador
dinámico. ELF gcc-2.7.2+
--- para compilar cosas :-)
a el kernel ELF ( ej. 2.0.xx )
--- para compilar cosas.
binutils 2.6.0.2+
--- para compilar cosas. Hay probablemente un montón se sitios con los fuentes de locale. He encontrado fuentes de locale y de mapas de caracteres de dominio público en dkuug.dk:/i18n/WG15-collection/localesy dkuug.dk:/i18n/WG15-collection/charmaps respectivamente.
Esto es lo que hice para instalar todo. Disponía de un sistema ELF (compilador, kernel, ...) instalado antes de hacer todo esto.
tar xzf binutils-2.6.0.2.bin.tar.gz -C /
tar zxf ld.so-1.7.12.tar.gz -C /usr/src
cd /usr/src/ld.so-1.7.12
sh instldso.sh
release.libc-5.4.17
para más instrucciones al respecto.
rm -f /usr/lib/libc.so /usr/lib/libm.so
rm -f /usr/include/iolibio.h /usr/include/iostdio.h
rm -f /usr/include/ld_so_config.h /usr/include/localeinfo.h
rm -rf /usr/include/netinet /usr/include/net /usr/include/pthread
tar -xzf libc-5.4.17.bin.tar.gz -C /
ldconfig
para que se encuentren las
nuevas librerías compartidas. ldconfig -v
.
tar zxf make-3.74.tar.gz -C /usr/src
cd /usr/src/make-3.74
patch < /donde_sea_que_lo_puso/release.libc-5.4.17
configure --prefix=/usr
sh build.sh
./make install
cd ..
rm -rf make-2.74
mkdir /usr/src/libc
tar zxf libc-5.4.17.tar.gz -C /usr/src/libc
cd /usr/src/libc
cd include
ln -s /usr/src/linux/include/asm .
ln -s /usr/src/linux/include/linux .
cd ../libc
./configure
# No estoy seguro de que estos dos makes sean necesarios, pero mejor
asegurarse: make clean ; make depend
cd locale
make programs
mv localedef /usr/local/bin
mv locale /usr/local/bin
localedef
los pueda
encontrar. En este punto uso los mapas de caracteres y fuentes de locale que
bajé desde dkuug.dk
ftp como charmaps.tar
, ylocales.tar
respectivamente. La versión antigua de localedef (5.2.18)
buscaba los fuentes de los mapas de caracteres en
/usr/share/nls/charmap
, pero ahora localedef busca en
/usr/share/i18n/charmaps
y /usr/share/i18n/locales
por
defecto en busca de los fuentes de los mapas de caracteres y los fuentes de
locale:
mkdir /usr/share/i18n
mkdir /usr/share/i18n/charmaps
mkdir /usr/share/i18n/locales
tar xf charmaps.tar -C /usr/share/i18n/charmaps
tar xf locales.tar -C /usr/share/i18n/locales
El nuevo localedef (5.4.17) se ha hecho más inteligente y buscará otros ficheros fuente de locale cuando esté trabajando con el comando 'copy', mientras que el antiguo localedef necesitaba tener los objetos locale creados de antemano para poder hacer el comando copy. Esta lista de comandos tiene las dependencias ordenadas y pueden usarse para generar todos los objetos locales indiferentemente de la versión de libc que esté usando, pero puede crear solo aquellos que desee.
localedef -ci en_DK -f ISO_8859-1:1987 en_DK
localedef -ci sv_SE -f ISO_8859-1:1987 sv_SE
localedef -ci fi_FI -f ISO_8859-1:1987 fi_FI
localedef -ci sv_FI -f ISO_8859-1:1987 sv_FI
localedef -ci ro_RO -f ISO_8859-1:1987 ro_RO
localedef -ci pt_PT -f ISO_8859-1:1987 pt_PT
localedef -ci no_NO -f ISO_8859-1:1987 no_NO
localedef -ci nl_NL -f ISO_8859-1:1987 nl_NL
localedef -ci fr_BE -f ISO_8859-1:1987 fr_BE
localedef -ci nl_BE -f ISO_8859-1:1987 nl_BE
localedef -ci da_DK -f ISO_8859-1:1987 da_DK
localedef -ci kl_GL -f ISO_8859-1:1987 kl_GL
localedef -ci it_IT -f ISO_8859-1:1987 it_IT
localedef -ci is_IS -f ISO_8859-1:1987 is_IS
localedef -ci fr_LU -f ISO_8859-1:1987 fr_LU
localedef -ci fr_FR -f ISO_8859-1:1987 fr_FR
localedef -ci de_DE -f ISO_8859-1:1987 de_DE
localedef -ci de_CH -f ISO_8859-1:1987 de_CH
localedef -ci fr_CH -f ISO_8859-1:1987 fr_CH
localedef -ci en_CA -f ISO_8859-1:1987 en_CA
localedef -ci fr_CA -f ISO_8859-1:1987 fr_CA
localedef -ci fo_FO -f ISO_8859-1:1987 fo_FO
localedef -ci et_EE -f ISO_8859-1:1987 et_EE
localedef -ci es_ES -f ISO_8859-1:1987 es_ES
localedef -ci en_US -f ISO_8859-1:1987 en_US
localedef -ci en_GB -f ISO_8859-1:1987 en_GB
localedef -ci en_IE -f ISO_8859-1:1987 en_IE
localedef -ci de_LU -f ISO_8859-1:1987 de_LU
localedef -ci de_BE -f ISO_8859-1:1987 de_BE
localedef -ci de_AT -f ISO_8859-1:1987 de_AT
localedef -ci sl_SI -f ISO_8859-2:1987 sl_SI
localedef -ci ru_RU -f ISO_8859-5:1988 ru_RU
localedef -ci pl_PL -f ISO_8859-2:1987 pl_PL
localedef -ci lv_LV -f BALTIC lv_LV
localedef -ci lt_LT -f BALTIC lt_LT
localedef -ci iw_IL -f ISO_8859-8:1988 iw_IL
localedef -ci hu_HU -f ISO_8859-2:1987 hu_HU
localedef -ci hr_HR -f ISO_8859-4:1988 hr_HR
localedef -ci gr_GR -f ISO_8859-7:1987 gr_GR
Después de hacer todo este trabajo usted debe poder utilizar las localidades que han sido creadas. Aquí puede ver un simple programa de ejemplo.
/* test.c : una simple prueba para ver si las localidades pueden ser
cargadas y usadas */ #include <locale.h> #include <stdio.h> #include <time.h> main(){ time_t t; struct tm * _t; char buf[256]; time(&t); _t = gmtime(&t); setlocale(LC_TIME,""); strftime(buf,256,"%c",_t); printf("%s\n",buf); }
Puede usar el programa locale
para ver cual es su actual entorno
local de variables de entorno relacionadas.
$ # compile el programa de prueba anterior, y ejecútelo con
$ # diferentes localidades $ gcc -s -o Test test.c $ # vea que localidad está activada en este momento: $ locale LANG=POSIX LC_COLLATE="POSIX" LC_CTYPE="POSIX" LC_MONETARY="POSIX" LC_NUMERIC="POSIX" LC_TIME="POSIX" LC_MESSAGES="POSIX" LC_ALL= $ # Esto... estamos usando la localidad de C (bastante
$ # aburrida) cambiemoslo al Inglés Canadiense: $ export LC_TIME=en_CA $ Test Sat 23 Mar 1996 07:51:49 PM $ # Probemos con el Francés Canadiense: $ export LC_TIME=fr_CA $ Test sam 23 mar 1996 19:55:27
Instalando las localidades se arregla un fallo (¿característica?) que hay
en el comando catopen de libc de Linux. Digamos que usted crea un programa que
usa catálogos de mensajes, y crea un catálogo en Alemán y lo pone en
/home/peeter/catalogs/de_DE
. Ahora haciendo lo que sigue, sin la
localidad de_DE instalada:
export LC_MESSAGES=de_DE
export NLSPATH=/home/peeter/catalogs/%L/%N.cat:$NLSPATH
el catálogo de mensajes en Alemán no se abre, y los mensajes por defecto son los que se usan en las llamadas a catgets. Esto es así porque catopen hace una llamada a setlocale para obtener la categoría correcta de mensajes, setlocale falla aunque las variables de entorno estén activadas. Entonces catopen intenta cargar el catálogo de mensajes sustituyendo "C" por todas las "%L" en NLSPATH. Puede seguir usando su catálogo de mensajes sin instalar la localidad, pero debe añadir explícitamente la parte "%L" en NLSPATH como
export NLSPATH=/home/peeter/catalogs/de_DE/%N.cat:$NLSPATH
, pero esto va en contra del propósito general de las variables de entorno de categorías de localidad.
Esta sección podría crecer hasta un FAQ, pero todavía no lo es.
Soy un usuario de LINUX, y he escrito el siguiente programa de prueba:
--------------------------------------------------------------------
#include <stdio.h>
#include <locale.h>
#include <features.h>
#include <nl_types.h>
main(int argc, char ** argv)
{
nl_catd catd;
setlocale(LC_MESSAGES, "");
catd = catopen("msg", MCLoadBySet);
fprintf(stderr,catgets(catd, 1, 1, "locale message fail\n"));
catclose(catd);
}
--------------------------------------------------------------------
$ msg.m
$set 1
1 locale message pass
--------------------------------------------------------------------
Si uso un camino absoluto como catopen("/etc/locale/msg.cat",MCLoadBySet);
, entonces obtengo el resultado correcto. Pero si uso el ejemplo anterior,
catopen devuelve un -1 (error).
Esta pregunta ha sido casi contestada en la sección anterior, pero aquí se añade información adicional. Hay un número de lugares válidos donde puede poner sus catálogos de mensajes. Aun así, no debe tener explícitamente definida NLSPATH en su entorno porque está definido en libc como sigue:
$ strings /lib/libc.so.5.4.17 | grep locale | grep %L
/etc/locale/%L/%N.cat:/usr/lib/locale/%L/%N.cat:/usr
/lib/locale/%N/%L:/usr/share/locale/%L/%N.cat:/usr/
local/share/locale/%L/%N.cat
asíarriba que si ha hecho algo de esto :
$ export LC_MESSAGES=en_CA
$ export LC_ALL=en_CA
$ export LANG=en_CA
Con la NLSPATH de arriba y el entorno especificado, la llamada
catopen("msg", MCLoadBySet);
debería funcionar si su catálogo de
mensajes se ha copiado en alguno de estos lugares:
/etc/locale/en_CA/msg.cat
/usr/lib/locale/en_CA/msg.cat
/usr/lib/locale/msg/en_CA
/usr/share/locale/en_CA/msg.cat
/usr/local/share/locale/en_CA/msg.cat
Esto, de todas maneras, no funcionará si no tiene la localidad en_CA instalada porque el setlocale fallará, y "C" será sustituido por "%L" en la rutina catopen (en vez de "en_CA").
Esto es todo. Espero que esta guía le haya sido útil. Debe haber probablemente un montón de sitios donde pueda buscar información adicional sobre la escritura de programas sensibles a la localidad, y documentos sobre internacionalización, y localización en general. Apuesto que si busca por la Web un poco será capaz de encontrar un montón de información. Ulrich Drepper que fue quien implementó la mayor parte del código de internacionalización y localización de GNU tiene alguna información en su página personal y puede hecharle un vistazo para comenzar. También hay alguna información en las páginas de información de libc, y por supuesto, también hay páginas de manual.