Mensagens i18n no Controller do vRaptor 3

6 respostas
danieldestro

Olhei a documentação mas não achei nada direto que me explica como pegar uma mensagem i18n dentro de um Controller do vRaptor 3.

Só achei referência usando um Validator, que não é o meu caso.

Algo que eu possa injetar no Controller para me dar esta informação que configura no messages.properties?

6 Respostas

danieldestro

Bom, fiz uma gambiarra aqui e funcionou no meu caso.

package freeshop.i18n;
import br.com.caelum.vraptor.ioc.Component;
import br.com.caelum.vraptor.validator.Validations;

@Component
public class I18nMessages extends Validations {
	
	private MyValidations validations = new MyValidations();

	public String i18n(String key) {
		return validations.i18n(key);
	}

	private class MyValidations extends Validations {
		public String i18n(String key) { //torna método public
			return super.i18n(key);
		}
	};
}
public MeuController( I18nMessages msg ) {
   String label = msg.i18n("label.name");
}

Mas ainda procuro a solução correta.

cinei

assim ajuda, independente do VRaptor?

private void getMensagem(){
		ResourceBundle bundle;
		Locale locale = new Locale("pt","BR");
		bundle = ResourceBundle.getBundle("messages", locale);
		String s = bundle.getString("label.name");

		System.out.println("Valor: "+ s);
	}
G

Você pode injetar br.com.caelum.vraptor.core.Localization no seu controller, e ter acesso aos métodos localizados, por exemplo, getMessage(String, Object…)

guivirtuoso

Fala Daniel,

Eu achei a sua implementação muito legal e utilize junto com uma implementação sugerida pelo Lucas Cavalcanti.

o Lucas sugeriu a implementação de um CustomValidator, que retornaria uma chave Internacionalizada, no lugar apenas do nome da Field no caso do Hibernate Validator…

Dessa forma, a categoria estava ficando assim: “produto.nome” ao invés só de “nome”, como é o padrão.

Modelo:

@Entity
public class Produto {

           ......

	@NotEmpty(message = "{campo.obrigatorio}")
	private String nome;

           .....
}

CustomValidator.java

@Component
public class CustomValidator extends DefaultValidator {

    private List<BeanValidator> beanValidators;
    private final TypeNameExtractor extractor;

    public CustomValidator(Result result, ValidationViewsFactory viewsFactory, Outjector outjector, Proxifier proxifier,
            List<BeanValidator> beanValidators, Localization localization, TypeNameExtractor extractor) {
        super(result, viewsFactory, outjector, proxifier, beanValidators, localization);
        this.beanValidators = beanValidators;
        this.extractor = extractor;
    }

    @Override
    public void validate(Object object) {
        String prefix = extractor.nameFor(object.getClass()) + ".";
        for (BeanValidator validator : beanValidators) {
            List<Message> messages = validator.validate(object);
            for (Message message : messages) {
                String keyI18n = prefix + message.getCategory(); // Neste ponto tenho a chave entidade.atributo
                add(new ValidationMessage(message.getMessage(), keyI18n));
            }
        }
    }
}

Dai precisei pegar no meu até então ValidationMessages.properties o valor da chave e p/ isso tentei implementei a sua classe sugerida.

Porem p/ dar tudo certo tive que desmembrar meu arquivo properties, ficando:
:arrow: ValidationMessages_pt_BR.properties : Mensagens de validação

campo.obrigatorio=Este campo é obrigatório
campo.maiorQueZero=Este campo deve ser maior que zero

:arrow: messages.properties : Descrição dos atributos das entidades

#Produto.java
produto.nome=Nome
produto.descricao=Descrição
produto.preco=Preço

Sua Implementação:

**
 * 
 * @author Daniel Destro - Forum GUJ - 01/04/2011
 *
 */
@Component
public class I18nMessages extends Validations {

    private MyValidations validations = new MyValidations();

    public String i18n(String key) {
        return validations.i18n(key);
    }

    private class MyValidations extends Validations {

        public String i18n(String key) {   //torna método public 
            return super.i18n(key);
        }
    };
}

Classe CustomValidator com algumas alterações p/ receber a injeção de dependencia no I18nMessages

@Component
public class CustomValidator extends DefaultValidator {

    private List<BeanValidator> beanValidators;
    private final I18nMessages i18nMessages;
    private final TypeNameExtractor extractor;

    public CustomValidator(Result result, ValidationViewsFactory viewsFactory, Outjector outjector, Proxifier proxifier,
            List<BeanValidator> beanValidators, Localization localization, TypeNameExtractor extractor, I18nMessages i18nMessages) {
        super(result, viewsFactory, outjector, proxifier, beanValidators, localization);
        this.beanValidators = beanValidators;
        this.extractor = extractor;
        this.i18nMessages = i18nMessages;
    }

    @Override
    public void validate(Object object) {
        String prefix = extractor.nameFor(object.getClass()) + ".";
        for (BeanValidator validator : beanValidators) {
            List<Message> messages = validator.validate(object);
            for (Message message : messages) {
                String keyI18n = prefix + message.getCategory();
                String descAtributo = i18nMessages.i18n(keyI18n);
                add(new ValidationMessage(message.getMessage(), descAtributo));
            }
        }
    }
}

Dessa forma, tanto o nome do atributo como a mensagem utilizada na validação vem do arquivo properties.

Queria saber se existe uma forma mais usual de implementar esta solução ou se o caminho é por ai mesmo…

Vlw… :wink:

Lucas_Cavalcanti

não precisa disso tudo… pra pegar uma mensagem internacionalizada é só receber o Localization no construtor,
e usar:

localization.getMessage("chave", parametros);
guivirtuoso

Poiseh,

Acabei tirando a classe do nosso amigo Daniel, e utilizei diretamente a Localization que vem no construtor do CustomValidator.

:wink: vlw pelos toques…

Criado 1 de abril de 2011
Ultima resposta 23 de set. de 2011
Respostas 6
Participantes 5