Skip to content

Instantly share code, notes, and snippets.

@zeroum
Created January 22, 2012 01:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zeroum/1654885 to your computer and use it in GitHub Desktop.
Save zeroum/1654885 to your computer and use it in GitHub Desktop.
L10n no VRaptor com message bundles em formato xml
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Properties;
import java.util.ResourceBundle;
public class messages extends ResourceBundle {
private Hashtable<String, String> table = new Hashtable<String, String>();
public messages() {
this(messages.class.getSimpleName() + ".xml");
}
public messages(String filename) {
Properties properties = new Properties();
try {
InputStream in = getClass().getResourceAsStream(filename);
properties.loadFromXML(in);
table = new Hashtable(properties);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public Enumeration<String> getKeys() {
return table.keys();
}
@Override
protected Object handleGetObject(String key) {
return table.get(key);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="is_not_a_valid_number">Não é um número válido.</entry>
<entry key="nome.tamanho.entre">O nome do produto deve ter entre {0} e {1} caracteres.</entry>
<entry key="descricao.vazia">A descrição do produto deve ser preenchida.</entry>
<entry key="preco.menorigual.zero">O preço do produto deve ser maior que zero.</entry>
</properties>
public class messages_en extends messages {
public messages_en() {
super(messages_en.class.getSimpleName() + ".xml");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
<properties>
<entry key="is_not_a_valid_number">Is not a valid number.</entry>
<entry key="nome.tamanho.entre">The product name must be {0} to {1} letters long.</entry>
<entry key="descricao.vazia">The product description must be filled.</entry>
<entry key="preco.menorigual.zero">The product price must be greater than zero.</entry>
</properties>
@zeroum
Copy link
Author

zeroum commented Jan 22, 2012

Prólogo

Seguindo convenções, a documentação do VRaptor fala que para realizar um L10N de uma aplicação web, deve-se colocar um arquivo messages.properties na raiz do projeto, e dele todas as mensagens serão traduzidas. Caso queria traduzir para inglês, o nome do arquivo é messages_en.properties, alemão seria messages_de, japonês messages_ja, assim em diante.

Na verdade essa convenção é baseada no método ResourceBundle.getBundle, que usa um formato nomeBase_linguagem_país_variante, que também está de acordo com o que foi definido na classe Locale do Java. Na convenção do Java, também usada pelo VRaptor, messages é o nome base.

Seguindo a documentação do getBundle, aprende-se que uma classe Java tem precedência a um arquivo .properties, o método irá carregar um ResourceBundle messages.java antes de um messages.properties.

Por quê utilizar XML, e não os Properties

Arquivos .properties, por definição da Sun, devem ser encodados em ISO 8859-1, e requerem escapar caracteres Unicode no formato \uXXXX. O JDK até vem com um utilitário native2ascii para fazer esses escapes pelo desenvolvedor. Arquivos XML, por sua vez, podem estar em qualquer encoding, desde que este esteja definido no cabeçalho do arquivo.

A partir do Java 5, definiram um formato XML para um arquivo de propriedades, e um método Properties.loadFromXML para deserializar o XML.
Com o Java 6, o ResourceBundle.getBundle foi atualizado para receber um parâmetro ResourceBundle.Control, permitindo implementar a própria lógica de carregamento de bundles.

Infelizmente em nenhuma das versões atualizaram o método para dar qualquer precedência a arquivos XML. Ou seja, caso não queira encher um arquivo de properties com escapes de XML, o deixando ilegível, faça como eu fiz e implemente uma classe Java para carregar o XML.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment