i18n

12 minuto(s) de lectura

Soporte de internacionalización (i18n) y localización (i10n) en adJ

Comparación con OpenBSD

  • Desde adJ 5.5 la librería de C soporta formatos para fecha y hora particulares para cada país (categoria LC_TIME del locale) y tablas para todos los países de latinoamérica y otros soportados por OpenBSD. También soporta xlocale completo. La mejora de LC_TIME se aportó a OpenBSD desde que preparaba la versión 5.6, pero no ha sido integrada.
  • Desde adJ 5.4 la librería de C soporta formatos numéricos particulares de cada país (categoria LC_NUMERIC del locale) y tablas para todos los países de latinoamérica y otros soportados por OpenBSD. También soporta las funciones de xlocale relacionadas. Esta mejora se aportó a OpenBSD desde que preparaba la versión 5.5, pero no ha sido integrada.
  • Desde adJ 5.4 la librería de C soporta cantidades monetarias particulares de cada país (categoria LC_MONETARY del locale) y tablas para todos los países de latinoamérica y otros soportados por OpenBSD. También soporta las funciones de xlocale relacionadas. Esta mejora se aportó a OpenBSD desde cuando se preparaba la versión 5.5, pero no ha sido integrada.
  • Desde adJ 5.2 la librería de C soporta cotejación (collation o categoria LC_COLLATE) o ordenamiento alfabético en el idioma nativo con base en la implementación de FreeBSD, así como el programa colldef para generar tablas de cotejación. Esta mejora se ha aportado a OpenBSD y se espera que en futuras versiones la integre (desde OpenBSD 5.3 no la incluyen aunque ayudamos desde esa versión y algunas posteriores para que las incluyeran).
    Agradecemos una revisión para OpenBSD por parte de Stephan Sperling –todas sus sugerencias se incluyeron desde adJ 5.3.
  • Desde adJ 5.5 implementa todas las funciones del API xlocale para la librería de C. Esta mejora se ha aportado a cada versión que se prepara de OpenBSD.
  • Desde adJ 5.2 en las funciones strcasecmp y wcscasecmp emplea la categoria LC_CTYPE del locale actual (como POSIX 2008 lo requiere aunque de forma ambigua), por lo que operan mejor para español y otros idiomas diferente al inglés –por ejemplo ñ y Ñ con estas funciones son equivalentes en adJ 5.2 mientras que no lo son en OpenBSD 5.4. Agradecemos una revisión por parte de Stephan Sperling y Matthew Dempsky, desarrolladores de OpenBSD.
  • Desde adJ 5.2 replica el locale (identificaciones culturales y de idioma para un área geográfica) para España de OpenBSD y la tabla de cotejación para España de FreeBSD para todos los paises de Latinoamérica y de habla hispana. Esta mejora se aportó a OpenBSD y generó expectativa de la comunidad que trajo solución en OpenBSD 5.4 (con especial atención a paises hispanohablantes en la utilidad locale).
  • Desde adJ 5.2 está configurado por defecto para emplear el locale es_CO.UTF-8 y la zona horaria America/Bogota, e incluye zonas horarias más recientes.
  • Desde adJ 5.2 incluye un porte de PostgreSQL que soporta cotejaciones en idioma nativo, con este por ejemplo sus consultas a la base de datos ordenando por nombre podrán estar ordenadas en español (y no con las palabras que comienzan con tilde o ñ al final que ocurre si usa cotejación en inglés). Esta mejora podrá aportarse al porte oficial una vez OpenBSD incluya cotejación (podría ser en 5.6 o posterior).
  • Desde adJ 5.2 incluye un porte de xfe modificado para soportar cotejación en el idioma nativo (y mostrar listados de archivos en el orden correcto de acuerdo al locale), así como una nueva traducción a es_CO. Esta mejora se ha aportado a xfe y fue integrada en 1.37.
  • Desde adJ 5.3 incluye tablas ctype actualizadas de NetBSD para varios locales (incluyendo los basados en UTF-8) –no ha sido posible la integración de esta mejora en OpenBSD propuesta desde que se preparaba la versión 5.4.
  • Hemos aportados correcciones a fallas relacionadas con el locale a OpenBSD, por ejemplo !MB_CUR_MAX en OpenBSD 5.4 (resuelta en adJ 5.3).

Comparación con FreeBSD

  • La implementación de xlocale de FreeBSD es segura en programas con hilos –multi-thread–, esto debido a que la implementación de pthreads en OpenBSD no soporta _Thread_local.
  • La implementación de xlocale en FreeBSD no soporta en strcoll ni en strxfrm codificaciones multibyte, mientras que la implementación en adJ 5.2 parcialmente (por ahora UTF-8 cuando se codifica ISO-8859-1). Esta mejora se aportó a OpenBSD desde que se preparaba la versión 5.4
  • La implementación de cotejación basada en la de FreeBSD fue enviada y auditada en la lista de OpenBSD. Agradecemos a Stephan Sperling con cuya ayuda prácticamente se reescribió. adJ emplea las tablas de cotejación de FreeBSD, pero la de español es mejorada pues en FreeBSD la ñ y la n son equivalentes, mientras que en adJ la ñ está entre la n y la o.
  • Desde adJ 5.2 se prepararon pruebas de regresión para las implementaciones de LC_COLLATE y de xlocale, y desde adJ 5.4 para `LC_MONETARY y LC_NUMERIC. Esta mejora se aportó a OpenBSD desde que se preparaba la versión 5.4.
  • FreeBSD sólo incluye tablas con formatos monetarios, numéricos y de tiempo para España pero no para los demás países de habla hispana.
    En adJ hemos incluido estos datos para todos los paises de habla hispana con base en Unicode ( http://unicode.org/cldr/trac/browser/tags/release-1-9/posix/ ) , Wikipedia, glibc (particularmente el locale de Cuba que no está en POSIX), y hemos hecho consultas privadas a personas de otros paises y públicas en listas de correo de Internet.
  • En OpenBSD cada categoria para un locale de la forma idioma_territorio.codificacion (e.g es_CO.UTF-8) se busca primero como idioma_territorio.codificacion, después como idioma.codificación y después como codificacion. En FreeBSD sólo se busca idioma_territorio.codificacion. Esto permite que adJ (y OpenBSD en el caso de LC_CTYPE) tengan menos enlaces entre locales iguales y de valores por defecto más aproximados cuando no cuenta con datos de algún territorio o idioma.
  • FreeBSD incluye una extensión en nl_langinfo !D_MD_ORDER que retorna "dm" si en el locale el día va antes del mes o "md" si primero va el mes. Para soportarla incluye en las tablas de LC_TIME y en la estructura lc_time_T de libc un campo md_order que incluye esta cadena.
    Consideramos que esto es redundante por cuanto las mismas tablas incluyen x_fmt que para todo locale tiene %d (o %e) y %m (o %b) y el orden en el que aparecen definen si va primero el dia o el mes.
    En esta lógica consideramos que hay errores en las tablas de FreeBSD para he_IL.UTF-8.src y lv_LV.UTF-8.src que definen x_fmt en %d/%m/%y pero definen md_order en md. Aunque nos parece buena la extensión !D_MD_ORDER en nl_langinfo, para evitar redundancia y errores en adJ preferimos eliminar de las tablas de LC_TIME el campo md_order.

Otras Innovaciones

  • Desde adJ 5.3 se incluyen las funciones strcasecoll, strcasecoll_l, wcscasecoll y wcscasecoll_l para comparar con cotejación de acuerdo al locale e ignorando mayúsculas y minúsculas. Se trata de una extensión a POSIX 2008, incluida con otros nombres en otros sistemas operativos, aunque se propuso para OpenBSD no fue aceptada.

En adJ muchos programas populares (e.g. chrome, pidgin, libreoffice) emplean el locale que haya configurado para presentar información ordenada, así que notará la diferencia. Por ejemplo en la captura de pantalla siguiente puede ver el ordenamiento correcto en canales de Pidgin (note primero á), en el diálogo para guardar una página de chrome (note la á antes de la D) y en el PostgreSQL incluido en adJ 5.2 (note ACHÍ antes de ACHIOTE). En las otras 2 terminales notará caracteres en griego en vim y una forma fresca de ver el spam desde mutt :)

[http://aprendiendo.pasosdejesus.org/sites/APRENDIENDO.PASOSDEJESUS.ORG/spages/cotejaci%C3%B3n.png]

Así como se adaptó el porte de PostgreSQL, otros portes pueden requerir activar el soporte de locale_t, así mismo muchas utilidades del sistema base (empezando por ls) aún no emplean las funciones de cotejación.
Puede ayudar aportando parches para las fuentes y dialogando en https://groups.google.com/forum/?fromgroups#!forum/OpenBSD-Colombia

Resumen del Uso

Un locale define una codificación y formas de presentar información típicas de una región geográfica (números, valores monetarios, fechas, horas, idioma y cotejación u ordenamiento lexicográfico del mismo). adJ viene configurado por defecto con el locale es-CO.UTF-8 es decir en español, para Colombia y con codificación UTF-8.

Puede examinar otros locales con

% locale -a

Los paises iberoaméricanos y sus respectivos locale que opera en adJ son (en lugar de UTF-8 también puede usar ISO-8859-1 e ISO-8859-15).

País locale
Argentina es_AR.UTF-8
Brazil pt_BR.UTF-8
Bolivia es_BO.UTF-8
Chile es_CL.UTF-8
Colombia es_CO.UTF-8
Costa Rica es_CR.UTF-8
Ecuador es_EC.UTF-8
El Salvador es_SV.UTF-8
España es_ES.UTF-8
Guinea Ecuatorial es_GQ.UTF-8
Guatemala es_GT.UTF-8
Hispanohablantes de Estados Unidos es_US.UTF-8
Honduras es_HN.UTF-8
México es_MX.UTF-8
Nicaragua es_NI.UTF-8
Panama es_PA.UTF-8
Perú es_PE.UTF-8
Puerto Rico es_PR.UTF-8
Paraguay es_PY.UTF-8
República Dominicana es_DO.UTF-8
Uruguay es_UY.UTF-8
Venezuela es_VE.UTF-8

En UTF-8 puede codificarse UNICODE, que a su vez permite representar todos los lenguajes escritos –la mayoría de lenguajes occidentales, incluyendo el español, también puede codificarse con ISO8859-1, ISO8859-15 (con euro). Elija el locale más apropiado para su país. Recomendamos que emplee codificación UTF-8 y que establezca el locale en sus archivos ~/.fluxbox/startup y ~/.profile agregando o cambiando la línea:

export LANG=es_CO.UTF-8

Los programas estándares emplearan esta variable (y otras asociadas) para determinar el locale y modificaran la forma de presentar:

  • Los mensajes, menús y ayudas para que sean en su idioma.
    En adJ esto se soporta via el porte gettext.
  • La codificación de caracteres para que sea la que prefiere. En adJ se emplea el soporte de LC_CTYPE de OpenBSD que entre otros es suficiente para ISO-8859-1/15 y UTF-8.
  • Los ordenamientos alfabéticos serán apropiados para su idioma (por ejemplo en español la á lexicograficamente equivale a la a, y la ñ está entre la n y la o). En adJ se emplea una implementación mejorada sobre la de FreeBSD que es suficiente para el español en codificaciones ISO-8859-1, ISO-8859-15 y UTF-8 (aunque no basta para otros lenguajes soportados por UNICODE).
  • La forma de presentar números será la particular de la región geográfica elegida. Por ejemplo el número 1000000.2 de acuerdo al país se presenta así:
Países Número
Argentina, Bolivia, Brazil, Chile, Colombia, Ecuador, España, Guatemala, Honduras, Nicaragua, Panama, Paraguay, Peru, Republica Dominicana, Uruguay, Venezuela 1.000.000,2
Costa Rica, El Salvador, Honduras, México, Puerto Rico e hispanohablantes de Estados Unidos 1,000,000.2
Cuba 1 000 000,2
  • Los valores monetarios se presentan con las convenciones de la categoría LC_MONETARY del locale desde adJ 5.4. Por ejemplo el número -3456.78 como cantidad monetaria en cada locale de iberoamérica es:
locale Cantidad Observaciones
es_AR -$ 3.456,78  
es_BO -$b 3.456,78  
es_CL -$ 3.456,78  
es_CO -$ 3.456,78  
es_CR -₡ 3 456,78 Con ISO8859-1 se usa ¢ en lugar de ₡
es_DO -RD$ 3,456.78  
es_EC -$ 3.456,78  
es_ES -3.456,78 € Con ISO8859-1 se usa Eu en lugar de €
es_GQ -FCFA 3.457  
es_GT -Q 3,456.78  
es_HN -L 3,456.78  
es_MX -$ 3,456.78  
es_NI -C$ 3,456.78  
es_PA -B/. 3,456.78  
es_PE -S/. 3,456.78  
es_PR -$ 3,456.78  
es_PY -Gs 3.456,78  
es_SV -US$ 3,456.78  
es_UY -$ 3.456,78  
es_US -$3,456.78  
es_VE -Bs 3.456,78  
pt_BR -R$3.456,78  
  • También la forma de presentar fecha y hora se ve afectada por el locale así como por la zona horaria. La zona horaria se establece enlazando /etc/localtime con una de las zonas del directorio /usr/share/zoneinfo, en adJ se establece por defecto en America/Bogota. El formato de fecha presentado por el comando date varía al cambiar el locale –aunque es común para todos los países de habla hispana:
locale date
es mié oct 1 18:17:34 COT 2014
pt_BR Qua Out 1 18:18:54 COT 2014
zh 三 10 1 18:19:38 COT 2014
ja 水 10月 1 18:20:25 COT 2014
ru ср окт 1 18:20:45 COT 2014
he ד’ אוק 1 18:21:11 COT 2014

xterm

Puede iniciar una terminal que soporte codificación UTF-8 y que lea la configuración de .profile con:

xterm -en utf8 -e /bin/ksh -l

tmux

Soporta la codificación de la terminal.

vim

Puede establecerse el idioma de los mensajes que vim presenta con el comando :language, por ejemplo para establecer español de Colombia:

:language es_CO

Puede establecer esta configuración por defecto agregando el comando al archivo ~/.vimrc.

vim puede emplear codificaciones diferentes para la terminal y para los archivos, ambos se establecen con la variable encoding (o enc) y cada uno en particular con termencoding (o tenc) y fileencoding (o fenc).
La forma recomendada es hacer que vim emplee la variable de ambiente LANG (o LC_ALL y los tipos particulares), agregando esta configuración a su archivo ~/.vimrc:

set encoding&           " terminal charset: follows current locale but still not working so:                                                               
set termencoding=                                                            
set fileencodings=      " charset auto-sensing: disabled                
set fileencoding&       " auto-sensed charset of current buffer   

mutt

Si la terminal lo soporta, mutt puede emplear codificación UTF-8, y enviar correos con esta codificación, agregando las siguientes líneas a su archivo ~/.muttrc (que se espera codificado en UTF-8):

set config_charset=utf-8                                                        
set locale=es_CO.UTF-8                                                          
my_hdr Content-Type: text/plain\; charset=UTF-8\; format=flowed                 
my_hdr Content-Transfer-Encoding: 8bit                                          

PostgreSQL

En la versión 9.1, puede examinar las cotejaciones disponibles ingresando al interprete psql y ejecutando:

SELECT * FROM pg_collation;

Puede crear una cotejación (digamos es_co_utf_8 pues deben ser nombres en minúsculas) para un locale soportado por el sistema operativo (digamos es_CO.UTF-8) con:

CREATE COLLATION es_co_utf_8 (LOCALE='es_CO.UTF-8');

Una vez creada puede realizar operaciones empleándola por ejemplo:

SELECT 'Á' < 'B' COLLATE "es_co_utf_8";
?column? 
----------
t
(1 row)
...
SELECT nombre FROM clase ORDER BY nombre COLLATE "es_co_utf_8";
...

Puede crear columnas de tablas especificando el tipo de cotejación por defecto para operaciones con esa columna.

CREATE TABLE ejc (
nombre VARCHAR(100) COLLATE "es_co_utf_8"
);

o cambiar las existentes:

ALTER TABLE clase ALTER nombre TYPE VARCHAR(500) COLLATE "es_co_utf_8";

También podrá renombrar cotejaciones que haya creado asi como borrarlas, ver más en http://www.postgresql.org/docs/9.1/static/collation.html

Variables de entorno relacionadas con el locale

El locale consta de varias categorias, todas ellas se establecen en conjunto con la variable de entorno LANG o bien con LC_ALL. Puede establecer unas particulares con:

  • LC_MESSAGE idioma y codificación de mensajes, menús y en general todo escrito que un programa presente al usuario
  • LC_NUMERIC valores numéricos
  • LC_MONETARY valores monetarios
  • LC_COLLATE cotejamiento
  • LC_CTYPE Codificación y clasificación (e.g minúsuclas, mayúsculas)
  • LC_TIME hora y fecha

En lenguaje de programación C

LC_NUMERIC: La bandera ‘ de la función printf presentará valores numéricos de acuerdo a la categoria LC_NUMERIC del locale. Por ejemplo

setlocale(LC_ALL, "es_CO.UTF-8"); 
printf("%'f", 1000000.2)

Establece todas las categorias de locale, incluyendo LC_NUMERIC en es_CO.UTF-8 e imprime el número como: 1.000.000,200000. Puede examinar el locale numérico con la función localeconv y nl_langinfo.

LC_MONETARY: La función strfmon dará formato a un número como cantidad monetaria de acuerdo a la categoria LC_MONETARY del locale. Por ejemplo llamando el siguiente programa como ejfmon.c:

#include <locale.h>
#include <monetary.h>
#include <stdio.h>
int main() {
  char col![512]; 
  setlocale(LC_ALL, "es_CO.UTF-8"); 
  strfmon(col, sizeof(col), "%n", -3456.781); 
  printf("%s\n", col); 
  return 0;
}

Y compilando con

% cc -o ejfmon ejfmon.c

Al ejecutarlo con ./ejfmon establecerá todas las categorias de locales, incluyendo LC_MONETARY, en es_CO.UTF-8 e imprimirá -$ 3.456,78. Puede examinar el locale monetario con la función localeconv.

LC_TIME: define como la función date interpreta sus especificadores de conversión, así como la operación de las funciones strftime, wcsftime, strptime y nl_langinfo. Su operación puede verificarse con el comando date.

Otras lecturas

Actualizado: