1. Introdução

Para que uma aplicação web possua alcance global é necessário adaptá-la para que usuários de qualquer parte do mundo, ao acessarem, recebam o conteúdo de acordo com sua localização. O processo de transformar a aplicação web para que suporte mais que um idioma e formato de dados é conhecido como internacionalização, ou i18n. Já o processo de adaptar essa aplicação já internacionalizada para determinada região ou localidade é conhecido como localização, ou l10n.

Para internacionalizar uma aplicação são utilizados arquivos de propriedades, que contêm pares de chave-valor. Para cada localidade é criado um arquivo de propriedades, com a tradução correspondente. O conteúdo da página será exibido de acordo com o idioma configurado no navegador.

2. Classes de Localização da Plataforma Java

Na plataforma Java, a classe java.util.Locale representa uma região geográfica, politica ou cultural específica. A string de representação de um Locale consiste da abreviação padrão internacional de dois caracteres para idioma e país e uma variável opcional, todos separados pelo caractere underline(_). Alguns exemplos de strings de localidade são fr (francês), fr_CA (francês do Canadá), e en_US_POSIX (inglês em uma plataforma compatível com POSIX).

Dados que mudam de acordo com uma localidade são armazenados em java.util.ResourceBundle. Um resource bundle (pacote de recursos) contém pares de chave-valor, onde as chaves unicamente identificam um objeto de localidade específico em um pacote. Um pacote de recursos pode ser apoiado por um arquivo de texto (arquivo properties), ou uma classe (list) contendo os pares. Constrói-se uma instância de pacote de recursos concatenando uma string de localidade a um nome base.

Neste artigo são utilizados pacotes de recursos com o nome base messages.properties para as localidades pt (português), de (alemão), em (inglês) e fr (francês). A localidade padrão, pt (português), a qual é especificada no arquivo faces-config.xml, usa o pacote de recursos com o nome base messages.properties.

3. Fornecendo Mensagens Localizadas e Labels

Mensagens e labels devem ser adaptados de acordo com as convenções de idioma e região de um usuário. Há duas abordagens para fornecer mensagens localizadas e labels em uma aplicação WEB:

  • Fornecer uma versão da página web em cada uma das localidades de destino e ter um servlet controlador que despache a requisição para a página apropriada dependendo da localidade requisitada. Essa abordagem é útil se grandes quantidades de dados em uma página ou uma aplicação web inteira precisam ser internacionalizadas.
  • Isolar qualquer dado sensível à localidade em uma página nos pacotes de recursos, e acessar os dados de maneira que a mensagem correspondente traduzida é obtida automaticamente e inserida na página. Assim, ao invés de criar strings diretamente no seu código, cria-se um pacote de recursos que contém traduções e lê essas traduções daquele pacote usando a chave correspondente.

Este artigo segue a segunda abordagem. A Listagem 1 mostra o arquivo de propriedades messages.properties.

Listagem 1: Arquivo messages.properties

welcome=bom dia!
name= qual o seu nome?
age= qual a sua idade?
address = aonde você mora?
fone= qual o seu telefone?

4. Estabelecendo a Localidade

Para obter as strings corretas para determinado usuário, uma aplicação web ou recupera uma localidade (definida pelas preferências de idioma do navegador) da requisição usando o método getLocale(), ou permite ao usuário selecionar a localidade explicitamente. Um componente pode explicitamente definir a localidade utilizando a tag fmt:setLocale.

O elemento locale-config no arquivo de configuração (faces-config.xml) registra a localidade padrão e também registra outras localidades suportadas. Na Listagem 2 é definida a localidade padrão português e é indicado que alemão, inglês e francês são localidades suportadas.

Listagem 2: Configurando localidades

<locale-config>
	<default-locale>pt</default-locale>
	<supported-locale>de</supported-locale>
	<supported-locale>en</supported-locale>
	<supported-locale>fr</supported-locale>
</locale-config>

A classe RecuperaLocalidade utiliza o método getLocale() para recuperar a localidade e o método toString() para retornar uma tradução localizada baseada na localidade. Um exemplo é mostrado na Listagem 3.

Listagem 3: Recuperando a localidade

package resources;
miport java.util.Locale;

public class RecuperaLocalidade{
	private FacesContext contexto = FacesContext.getCurrentInstace();
private Locale locale;

//Cria uma nova instância de RecuperaLocalidade
public RecuperaLocalidade(){
	locale = contexto.getViewRoot().getLocale();
}

public String getLocalizedStatus(StatusType tatus){
	return status.toString(locale);
}
}

5. Definindo o Pacote de Recurso

O pacote de recurso é definido com o elemento resource-bundle no arquivo de configurações. A Listagem 4 mostra um exemplo de definição de pacote de recurso.

Listagem 4: Definindo pacote de recursos

<resource-bundle>
	<base-name>i18n.messages</base-name>
	<var>bundle</var>
</resource-bundle>

Após definir a localidade, o controlador de uma aplicação web poderia recuperar um pacote de recurso para aquela localidade e salvá-lo como um atributo de sessão para ser usado por outros componentes ou simplesmente ser usado para retornar uma string de texto apropriada para a localidade selecionada. A Listagem 5 apresenta um exemplo de como recuperar um pacote de recursos.

Listagem 5: Recuperando pacote de recursos

public String toString(Locale locale){
	ResourceBundoe res = ResourceBundle.getBundle("i18n.messages", locale);
	return res.getString(name() + ".string");
}

Alternativamente, uma aplicação poderia utilizar a tag f:loadBundle para definir o pacote de recurso. Essa tag carrega o pacote de recurso correto de acordo com a localidade armazenada no FacesContext. A Listagem 6 mostra como definir um pacote de recursos através da tag f:loadBundle.

Listagem 6: Definindo pacote de recurso

<f:loadBundle basename="i18n.messages" var="bundle"/>

Pacotes de recursos contêm mensagens que são explicitamente referenciadas a partir de um atributo de tag JavaServer Faces usando uma value expression e devem ser registrados utilizando o elemento resource-bundle do arquivo de configuração.

6. Recuperando Mensagens Localizadas

Um componente web escrito na linguagem de programação Java recupera o pacote de recurso a partir da sessão. Isso é mostrado na Listagem 7.

Listagem 7: Recuperando pacote de recursos

ResourceBundle messages = (ResourceBundle)session.getAttribute("messages");

Em seguida ele procura a string associada com a chave welcome como pode ser visto na Listagem 8.

Listagem 8: Recuperando string

messages.getString("welcome");

É possível utilizar uma tag message ou messages para mostrar mensagens que estão na fila para um componente como resultado de um conversor ou validador que está sendo registrado no componente. O exemplo a seguir mostra uma tag de mensagem, que exibe a mensagem de erro que está em fila no componente de entrada userNO, se o validador registrado no componente falha em validar o valor que o usuário informa no componente. A Utilização da tag message é mostrada na Listagem 9.

Listagem 9: Usando a tag message

<h:inputText id="userNo" value="#{UserNumberBean.userNumber}">
<f:validateLongRange minimum="0" maximum="10/>
...
<h:message style="color:red; text-decoration:overline" id="errors1" for="userNo"/>

Mensagens que não estão em fila em um componente e, portanto não são carregadas automaticamente são referenciadas usando uma value expression. Pode-se referenciar uma mensagem localizada a partir de praticamente qualquer atributo de tag JavaServer Faces.

A value expression que referencia uma mensagem tem a mesma notação se o pacote de recurso foi carregado com a tag loadBundle ou registrado com o elemento resource-bundle no arquivo de configurações.

A notação value expression é var.message, em que var corresponde ao atributo var da tag loadBundle ou o elemento var definido no elemento resource-bundle do arquivo de configurações, e message corresponde a chave message contida no pacote de recursos, referido pelo atributo var.

7. Formatando Data e Número

Programas Java usam o método DateFormat.getInstance(int, locale) para converter e formatar datas que mudam de acordo com uma localidade. Programas Java usam o método NumberFormat.getXXXInstance(locale) onde XXX pode ser Currency, Number ou Percent para converter e formatar valores numéricos que mudam de acordo com uma localidade.

Uma aplicação pode usar data/hora e conversores de números para formatar datas e números que mudam de acordo com uma localidade. Por exemplo, uma data de expedição poderia ser convertida da maneira que é mostrado na Listagem 10.

Listagem 10: Convertendo uma data

<h:outputText value="#{cashier.shipDate}">
	<f:convertDateTime dateStyle="full"/>
</h:outputText>

8. Conjunto de Caracteres

Um conjunto de caracteres é um conjunto de texto e símbolos gráficos, cada um dos quais é mapeado para um conjunto de números inteiros não negativos.

O primeiro conjunto de caracteres usado na computação foi o US-ASCII. Ele é limitado na medida em que pode representar apenas inglês americano. US-ASCII contém alfabeto latino maiúsculo e minúsculo, números, pontuação, um conjunto de código de controle, e alguns símbolos diversos.

Unicode define um conjunto universal padronizado de caracteres que pode ser estendido para acomodar combinações de caracteres. Quando a codificação do arquivo fonte do programa Java não suporta Unicode, pode-se representar caracteres Unicode como sequências de escape usando a notação \uXXXX, onde XXXX é a representação em 16bits do caractere em hexadecimal. Pode-se verificar um exemplo na Listagem 11

Listagem 11: Representando caracteres Unicode através de sequência de escape

main=P\u00e1gina Principal
adm=Administraci\u00f3n

9. Codificação de Caracteres

Uma codificação de caracteres mapeia um conjunto de caracteres para unidades de uma largura específica e define serialização de bytes e regras de ordenação. Muitos conjuntos de caracteres têm mais que uma codificação. Por exemplo, programas Java podem representar conjuntos de caracteres Japoneses usando as codificações EUC-JP ou Shift-JS, entre outras. Cada codificação tem regras para representar e serializar um conjunto de caracteres.

A série ISO 8859 define 13 codificações de caracteres que podem representar textos em dezenas de idiomas. Cada codificação de caracteres ISO 8859 pode ter até 256 caracteres. ISO-8859-1(Latin-1) inclui o conjunto de caracteres ASCII, caracteres com acentos e cedilhas, circunflexos, entre outros, além dos símbolos adicionais.

UTF-8 (Unicode Transformation Format, 8-bit form) é uma codificação de caracteres de largura variável que codifica caracteres Unicode de 16-bit com um de 4 bytes. Um byte em UTF-8 é equivalente a 7-bit ASCII se o bit de alta ordem é zero, caso contrário, o caractere é composto por um número variável de bytes.

UTF-8 é compatível com a maior parte do conteúdo existente da WEB e fornece acesso ao conjunto de caracteres Unicode. As versões atuais de navegadores e clientes de e-mail suportam UTF-8. Além disso, muitos novos padrões WEB especificam UTF-8 como sua codificação de caracteres. Por exemplo, UTF-8 é uma das duas codificações requeridas para documentos XML (a outra é UTF-16).

Componentes da WEB geralmente usam PrintWriter para produzir respostas, pois ele codifica automaticamente usando o ISO-8859-1. Servlets também podem gerar dados binários usando classes OutputStream, que realizam nenhuma codificação. Uma aplicação que usa um conjunto de caracteres que não podem utilizar a codificação padrão deve definir explicitamente uma codificação diferente.

10. Conclusão

Internacionalizar e localizar uma aplicação WEB permite que a aplicação tenha um alcance global, sendo que cada usuário recebe os dados formatados de acordo com a sua localidade.

Referências

Internationalizing and Localizing Web Applications - The Java EE 6 Tutorial.
Disponível em http://docs.oracle.com/javaee/6/tutorial/doc/bnaxu.html
Acesso em 26 de Abril de 2012 às 22h18min.