Internacionalização e Localização: porque software livre é pra ser universal
Antonio S. de A. Terceiro
<terceiro@colibre.com.br>
Motivação
Uma das características mais empolgantes do software livre é sua universalidade.
No caso de vários softwares proprietários amplamente usados, para poder usar o
software na seu idioma nativo o usuário precisa baixar/comprar uma cópia do
software específica para o seu idioma. Além disso, a empresa fornecedora do
software proprietário tem que se convencer da necessidade de ter aquele
software traduzido para mais um idioma.
No software livre é diferente: para ter o software em seu idioma nativo, um usuário
tem muito mais facilidade. Pode ele próprio traduzir o software, pode contratar
alguém para fazer isso. Isso tudo sem nem ter que informar ao desenvolvedor original.
Por exemplo, em 25 de Julho de 2006 tínhamos os seguintes números sobre a
disponibilidade de alguns softwares livres e não-livres em diferentes idiomas:
Na
lista de idiomas suportados do Windows XP/2003 as variantes de espanhol são contadas várias vezes, ao
contrário dos softwares livres. Na área de editoração de imagens digitais,
o Gimp já supera o Adobe Photoshop em número de idiomas suportados.
Algo que está acima dos números é a autonomia das pessoas de se apoderarem
do software livre adaptando-o para sua cultura local. O Gnome, por exemplo,
tem uma
tradução parcial para Iorubá. A
tradução ainda é
muito incipiente, mas importante de se notar é que as
pessoas que falam Iorubá tem a
possibilidade de traduzir por elas próprias.
Eu duvido que algum dia exista uma tradução do Windows® para Iorubá, a não ser
que a Microsoft seja forçada a fazer isso.
No restante desse artigo, são apresentados sob um ponto de vista técnico,
diversos aspectos relacionados a internacionalização e localização.
Definições
Internacionalização é o processo de fazer com que um software tenha suporte a
usuários de diversas culturas. Isso inclui a tradução da interface de usuário,
mas não se limita a isso. Internacionalização é normalmente abreviada como
I18N
("I", seguido de 18 letras, seguido de "N", do inglês
internationalization).
Localização é o processo de adaptar um software que tenha internacionalização
para uma nova cultura. Por exemplo, traduzir a interface de usuário de uma
aplicação para o português do Brasil faz parte do processo de localização do
software para usuários brasileiros. Localização é normalmente abreviada como
L10N ("L", seguido de 10 letras, seguido de "N", do inglês
localization).
Locales: informações sobre a região do usuário
locales são informações que descrevem o ambiente para um determinada cultura.
Os
locales representam só informações sobre o idioma. Apesar de menos usadas, também estão disponíveis informações como separador de milhares ("ponto" em português, "vírgula" em inglês), separador de parte decimal ("vírgula" em português, "ponto" em "inglês"), caracteres maísculos e minúsculos, ordenação entre caracteres entre outros. Cada um desses tipos de informação é uma categoria de
locale.
Normalmente, define-se um único idioma para todas as categorias. Costumamos nos referir a essa configuração, genericamente, como
locale.
Normalmente o nome de um locale é o código de um idioma + o código do país. Por exemplo, o
locale para português brasileiro chama-se
pt_BR.
O português europeu, por sua vez, chama-se
pt_PT. Além do idioma, o nome do
locale pode conter também a codificação de caracteres utilizada.
Por exemplo, o
locale português brasileiro usando codificação
UTF-8 chama-se
pt_BR.utf8, já usando a codificação
ISO-8859-1,
pt_BR.iso88591. O nome do
locale pode conter ainda um modificador opcional como sufixo, no formato
@mod.
O comando
locale lista as informações sobre o ambiente
locale atual. Usado sem
nenhuma opção, são mostrados os valores das variáveis que definem cada categoria de
locale.
$ locale
LANG=pt_BR.utf8
LC_CTYPE="pt_BR.utf8"
LC_NUMERIC="pt_BR.utf8"
LC_TIME="pt_BR.utf8"
LC_COLLATE="pt_BR.utf8"
LC_MONETARY="pt_BR.utf8"
LC_MESSAGES="pt_BR.utf8"
LC_PAPER="pt_BR.utf8"
LC_NAME="pt_BR.utf8"
LC_ADDRESS="pt_BR.utf8"
LC_TELEPHONE="pt_BR.utf8"
LC_MEASUREMENT="pt_BR.utf8"
LC_IDENTIFICATION="pt_BR.utf8"
LC_ALL=
Cada uma dessa variáveis
LC_* corresponde a uma categoria de
locale.
LC_COLLATE, por exemplo, define qual idioma considerar para ordenação
de caracteres. Cada uma das categorias pode ser definida atribuindo-se
um valor à variável
LC_* correspondente. Por exemplo:
$ LC_COLLATE=C locale
LANG=pt_BR.utf8
LC_CTYPE="pt_BR.utf8"
LC_NUMERIC="pt_BR.utf8"
LC_TIME="pt_BR.utf8"
LC_COLLATE=C
LC_MONETARY="pt_BR.utf8"
LC_MESSAGES="pt_BR.utf8"
LC_PAPER="pt_BR.utf8"
LC_NAME="pt_BR.utf8"
LC_ADDRESS="pt_BR.utf8"
LC_TELEPHONE="pt_BR.utf8"
LC_MEASUREMENT="pt_BR.utf8"
LC_IDENTIFICATION="pt_BR.utf8"
LC_ALL=
Isso faz com que os programas que utilizam informação de
locale não considerem
a ordenação de caracteres do português, usando essas informações do locale
default
C.
A opção
-a lista os locales disponíveis.
$ locale -a
C
pt_BR
pt_BR.iso88591
pt_BR.utf8
Neste caso, o sistema possui os locales
C (
locale padrão),
pt_BR,
pt_BR.iso88591 e
pt_BR.utf8. Quando a codificação é omitida no nome do
locale, a escolha da codificação a ser usada é dependente do sistema.
Vamos alguns aspectos influenciados pela configuração de
locales.
Por enquanto, configure o seu terminal para codificação
ISO-8859-1.
Na seção seguinte você vai entender porquê.
Vamos escrever um pequeno programa em Perl que lê linhas da entrada padrão
e destaca todos os caracteres minúsculos:
#!/usr/bin/perl
use locale;
my $line;
while (defined($line = <STDIN>)) {
$line =~ s/[[:lower:]]/($&)/g;
print $line;
}
Suponha que esse programa chame-se
lower.pl. Veja o que acontece quando
ele é executado em diferentes contextos de
locale:
$ LANG=C perl lower.pl
asdasdáéíóúasdsadsa
(a)(s)(d)(a)(s)(d)áéíóú(a)(s)(d)(s)(a)(d)(s)(a)
$ LANG=pt_BR.iso88591 perl lower.pl
asdasdáéíóúasdsadsa
(a)(s)(d)(a)(s)(d)(á)(é)(í)(ó)(ú)(a)(s)(d)(s)(a)(d)(s)(a)
Note que só num locale onde os caracteres com acento fazem parte do "alfabeto"
eles são reconhecidos como caracteres minúsculos.
Agora vamos escrever um segundo programa, chamado
chars.pl. Ele vai imprimir todos
os caracteres considerados como alfanuméricos.
#!/usr/bin/perl
use locale;
print +(sort grep /\w/, map { chr } 0..255), "\n";
Note como o conceito de caracter alfanumérico varia a depender do
locale:
$ LANG=C perl chars.pl
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz
$ LANG=pt_BR.iso88591 perl chars.pl
µ_0123456789aAªáÁàÀâÂåÅäÄãÃæÆbBcCçÇdDðÐeEéÉèÈêÊëËfFgGhHiIíÍìÌîÎïÏjJkKlLmMnNñÑoOºóÓòÒôÔöÖõÕøØpPqQrRsSßtTuUúÚùÙûÛüÜvVwWxXyYýÝÿzZþÞ
Gerando locales
No Debian:
# dpkg-reconfigure locales
De forma genérica:
# edit /etc/locales.gen
# locale-gen
Lidando com diferentes codificação de caracteres
Ao transferir dados textuais entre computadores é preciso que haja um
consenso sobre como representar os elementos mais básicos do texto
em termos de bytes, que são afinal os menores elementos de informação
armazenáveis nos computadores atuais.
Segundo a Wikipedia,
Codificação de caracteres ou
conjunto de caracteres é um mapeamento
entre uma sequência de caracteres e um outro conjunto, normalmente um
dos números naturais.
Existem várias codificações atualmente em uso. A mais antiga delas é o
código ASCII. O código ASCII representa as letras
do alfabeto (
a a
z) maiúsculas e minúsculas, os numerais (
0 a
9),
diversos outros caracteres especiais e caracteres de controle, mapeando-os
nos números naturais entre 0 e 126. No código ASCII é representál através
de um único byte. De fato, um caracter ASCII só precisa de 7 bits para
ser representado, sobrando 1 bit num byte.
Uma clara limitação do código ASCII é que ele não representa caracteres
acentuados, impossibilitando a representação de textos em português,
espanhol, francês, etc. Dessa forma, uma codificação semelhante é
a
ISO-8819-1. É um superconjunto do código
ASCII que inclui o alfabeto latino, e representa 255 caracteres usando
os 8 bits de um byte.
Unicode é um padrão que visa representar todos os
caracteres utilizados nos sistemas de escrita do mundo. O Unicode associa
a cada caracter um código (chamado
codepoint). Por convenção, os primeiros
256
codepoints do Unicode correspondem aos 256 caracters do ISO 8859-1.
Os caracteres Unicode podem ser codificados usando um dos diferentes
formatos de transformação do Unicode (
Unicode Transformation Formats,
UTF).
UTF-8 é uma das codificações possíveis para o Unicode, que utiliza
de 1 a 4 bytes para codificar cada caracter. UTF-16 é uma codificação análoga
que usa 2 ou 4 bytes para codificar cada caracter. Outra codificação é UTF-32,
onde são usados 4 bytes para codificar cada caracter. UTF-8 é a codificação
mais popular entre estas.
A maioria dos emuladores de terminal suportam diferentes codificações. A
codificação selecionada será usada para transferir para as aplicações os
caracteres que são digitados pelo usuário. No GNOME Terminal, por exemplo,
você pode trocar a codificação utilizada através do menu "Terminal":
Quando o seu terminal está configurado para uma codificação e alguma aplicação
cospe dados em outra codificação, coisas estranhas acontecem. Você já deve ter
visto coisas assim.
Para os próximos exemplos, usaremos dois arquivos com o mesmo conteúdo, a linha:
vogais: áéíóú
. A única diferença entre eles é a codificação.
Se estamos com o terminal configurado para UTF-8 ...
$ cat utf8-data
vogais: áéíóú
$ cat latin1-data
vogais: □□□
Agora com o terminal em ISO-8859-1 (latin1) ...
$ cat utf8-data
vogais: áéÃóú
$ cat latin1-data
vogais: áéíóú
Como a maioria dos programas usa a informação do
locale para saber em que codificação
a informação deve ser apresentada, o normal é que o terminal sempre esteja configurado
para a
O mesmo tipo de problema acontece com páginas web. Atire a primeira pedra quem nunca
abriu uma página na qual os acentos estavam "desconfigurados"? Isso acontece porquê
quem fez a página não especificou corretamente qual codificação usada para o texto
daquela página.
Toda página web deve ter sua codificação informada de duas formas: a forma padrão é
através dos cabeçalhos HTTP (ex.
Content-Type: text/html;charset=utf-8).
A geração desse cabeçalho é simples para página dinâmicas (geradas por um script), mas
para páginas estáticas isso fica mais complicado. A solução é usar a tag
meta para
especificar o tipo do arquivo e de carona a codificação. Por exemplo, para páginas
codificadas em UTF-8, pode-se usar:
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
Existem diversas ferramentas para conversão de codificação. O
iconv é uma delas.
Com o
iconv selecionamos a codificação de origem de a de destino, usando as
opções
-f e
-t respectivamente.
Por exemplo, com o terminal configurado para UTF-8:
$ iconv -f iso-8859-1 -t utf-8 latin1-data
vogais: áéíóú
E com o terminal configurado para ISO-8859-1:
$ iconv -f utf-8 -t iso-8859-1 utf8-data
vogais: áéíóú
Também existem diversas biblioteca e módulos, em várias linguagens de programação,
para conversão de codificação. Em Perl, o módulo
Encode realiza essa tarefa. Como exemplo, vamos escrever um pequeno programa chamado
iconv.pl.
Nosso
iconv.pl é bastante limitado: ele só aceita com codificação de entrada ou saída
iso-8859-1 e
utf-8. Tanto o
iconv do sistema quanto o módulo Perl
Encode suportam vários outras codificações.
#!/usr/bin/perl
use Encode;
use Getopt::Long;
my $from = 'iso-8859-1';
my $to = 'utf-8';
GetOptions (
"from=s", \$from,
"to=s", \$to,
);
foreach my $choice ($from, $to) {
if ($choice ne 'iso-8859-1' && $choice ne 'utf-8') {
print "$choice encoding is not supported. Exiting.\n";
exit 1;
}
}
my $line, $text;
while (defined($line = <STDIN>)) {
$text = Encode::decode($from, $line);
print Encode::encode($to, $text);
}
Vamos testar nosso
iconv.pl. Com o terminal configurado para UTF-8:
$ cat latin1-data | perl iconv.pl
vogais: áéíóú
E com o terminal configurado para ISO-8859-1:
$ cat utf8-data | perl iconv.pl -f utf-8 -t iso-8859-1
vogais: áéíóú
Internacionalização de interface: inglês é só mais um idioma
Vamos ver agora como escrever um programa que suporte traduação da sua interface de usuário (janelas, menus, mensagens, etc).
TODO ...
#!/usr/bin/perl
use strict;
package Hello::I18N;
use base 'Locale::Maketext';
use Locale::Maketext::Lexicon {
'en' => ['Auto'],
'*' => [Gettext => '*.po'],
_auto => 1,
};
my $lh = Hello::I18N->get_handle() or die('What language?');
print($lh->maketext("Hello, world!\n"));
Na próxima sessão é descrito o processo de tradução propriamente dito, quando o template de mensagens é traduzido para cada idioma.
Localização de aplicações: traduzindo arquivos gettext
TODO ...
Estudo de caso: internacionalização da interface de usuário do TWiki
TODO ...
Para saber mais
Textos introdutórios, HOWTO's, etc:
Manuais de referência sobre
locales:
-
$man locale
-
$man locale.gen
-
$man locale-gen
Manuais de referência sobre codificação:
-
$man iconv (ferramenta iconv)
-
$man Encode (módulo Encode do Perl)
Slides
Slide 1: Internacionalização e Localização: porque software livre é pra ser universal
Antonio S. de A. Terceiro
<terceiro@colibre.com.br>
Slide 2: Roadmap
- Motivação
- I18N? e L10N?
- Locales
- Codificações de caracteres
- Internacionalização de interface → fazendo software traduzível
- Localização: traduzindo aplicações
- Estudo de caso: internacionalização de interface de usuário do TWiki
Slide 3: Motivação
Slide 4: Introdução
- I18N? : Internationalization → generalização
- L10N? : Localization →especialização
Slide 5: Locales
- Informações culturais
- listando locales disponíveis:
$ locale -a
- gerando locales:
$ locale-gen
Slide 6: Codificação de caracteres
↓
á
↑
| 1 |
1 |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
0 |
0 |
0 |
0 |
1 |
- Lidando com codificações diferentes
- conversão
Slide 7: Unicode
http://www.unicode.org/
* UTF-8, UTF-16, ...
Programando com I18N? !
Na prática ...
Extração de strings
Na prática ...
Tradução
Na prática ...
Acabou
Perguntas?
-- AntonioTerceiro - 25 Jul 2006