5

I followed some tutorials like this one:

http://www.concretepage.com/spring-4/spring-4-mvc-internationalization-i18n-and-localization-l10n-annotation-example

to get i18n work in my spring(boot) project. It's working so far, but I don't like it to always autowire the MessageSource bean to my current class, just to get some Strings translated.

My idea is a easy wrapper class with a static call like

I18n.translate("some.identifier") 

or

I18n.translate("some.identifier",param,param,param...).

But I can't inject the MessageSource into a class which is not handled by Spring, huh?

Any idea how to solve this?

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
Smoki
  • 551
  • 2
  • 9
  • 28
  • Why would you need the `MessageSource` anyway? When using JSP or Thymeleaf that integrates already with the I18N support the same for validation stuff that also integrates. So what is your usecase and why are you operating on a plain `MessageSource` anyway. I would say you don't need that hack if you use the framework correctly. – M. Deinum Oct 13 '15 at 13:58
  • 1
    I don't user JSP, I'm using Vaadin. I'm very open to any better way to get an !! easy to use !! i18n with Vaadin. – Smoki Oct 13 '15 at 14:33
  • Please add that specific part to your question as that really matters for the answer – M. Deinum Oct 14 '15 at 05:48
  • When using Spring Boot and the vaadin integration you can have your van components managed by Spring which should allow you to use the `MessageSource`. Also there is [vaadin4spring](https://github.com/peholmst/vaadin4spring/blob/master/addons/i18n/README.md) which already has something like that. – M. Deinum Oct 14 '15 at 05:56

6 Answers6

3

You could (not sure if you should) do something like this:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

@Component
public class StaticContextAccessor {

    private static StaticContextAccessor instance;

    @Autowired
    private ApplicationContext applicationContext;

    @PostConstruct
    public void registerInstance() {
        instance = this;
    }

    public static <T> T getBean(Class<T> clazz) {
        return instance.applicationContext.getBean(clazz);
    }

}

and then use it like this:

SomeOtherwiseAutowiredClass someObject = StaticContextAccessor.getBean(SomeOtherwiseAutowiredClass.class);
Kirill
  • 33
  • 1
  • 4
2

I had the same Idea as I develop also with Vaadin and the solution which works for me is to use a StaticContextInitializer Bean. Therefore do the following:

First make your field for the Message class static and provide the getter and setter methods:

private static MessageSource messageSource;

private TextSource() {
}

public static String getText(String key, Locale locale) {
    return messageSource.getMessage(key,null, ensureLocale(locale));
}



public static String getText(String key, Locale locale, Object[] parameter) {
    return messageSource.getMessage(key, parameter, ensureLocale(locale));
}

private static Locale ensureLocale(Locale locale) {
    if (locale == null)
        locale = Locale.getDefault();
    return locale;
}

Add the static setter method to the class:

public static void setMessageSource(MessageSource messageSource) {
    TextSource.messageSource = messageSource;
}

Write your StaticInitializer Bean with a @PostConstruct annotation and inject the MessageSource with @Autowired annotation.

@Component
public class FrontendStaticContextInitializer {

@Autowired
private MessageSource messageSource;

@PostConstruct
public void initialize() {
    TextSource.setMessageSource(messageSource);
}
}

After that you'll be able to call the class like that in your Views: TextSource.getText("login.textfield.placeholder.benutzername", getLocale())

the hand of NOD
  • 1,639
  • 1
  • 18
  • 30
0

You have two possibilities:

  1. Non-static setter for static property/field;
  2. Using org.springframework.beans.factory.config.MethodInvokingFactoryBean to invoke a static setter.

Examples you can find follow by link How to make spring inject value into a static field

P.S. What is problem with autowire MessageSource into your beans?

Community
  • 1
  • 1
grinder
  • 436
  • 1
  • 6
  • 10
  • 1
    Mhh maybe I'm a little spoiled, but it's really annoying to setup a bean for every GUI component I write with Vaadin. It's just,.. if i would do so,.. i have to autowire it to the most classes of the project... thats just stupid and annoying. I will try you hint as far as I#m back home again.thx – Smoki Oct 13 '15 at 14:37
0

Create a static message source wrapper, for example like https://github.com/chelu/jdal/blob/master/core/src/main/java/org/jdal/beans/StaticMessageSource.java

and declare it in bean configuration file:

<!-- Message Source -->
<bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="basenames" value="i18n/jdal,i18n/i18n" />
</bean>

<bean id="staticMessageSource" class="org.jdal.beans.StaticMessageSource">
        <constructor-arg ref="messageSource" />
</bean>

Note that you can use depend-on if you need that the wrapper is instantiated before some other bean.

Jose Luis Martin
  • 10,459
  • 1
  • 37
  • 38
0

Just implement MessageSourceAware and set it to the static variable. But, it will only work if spring.main.lazyInitialization is false.

@Component
public final class MessageUtils implements MessageSourceAware {

    private static MessageSource messageSource;

    @Override
    public void setMessageSource(MessageSource messageSource) {
        MessageUtils.messageSource = messageSource;
    }

    public static String getMessage(String key, String... params) {
        return messageSource.getMessage(key, params, new Locale("PT", "br"));
    }

}

If spring.main.lazyInitialization is true, will need to force the injection:

public class App {

    @Autowired
    private MessageUtils messageUtils;

    public static void main(String[] args) {
        SpringApplication.run(App .class, args);
    }

}

Spring will automatically inject, see class: ApplicationContextAwareProcessor.invokeAwareInterfaces(Object bean)

enter image description here

Marcus Voltolim
  • 413
  • 4
  • 12
0

here is a sample Utils, without DI concept, without Bean configuration:

import java.util.Locale;

import org.apache.commons.lang3.Validate;
import org.springframework.context.MessageSource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;

public class I18n {
    private static MessageSource MESSAGE_SOURCE;
    static {
        I18nUtils.MESSAGE_SOURCE = messageSource();
    }

    public static String translate(Locale locale, String key, Object... args) {
        Validate.notNull(locale, "locale require not null");
        Validate.notEmpty(key, "key require not empty");
        return MESSAGE_SOURCE.getMessage(key, args, locale);
    }

    private static MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.addBasenames("classpath:Messages");
        messageSource.setDefaultEncoding("UTF-8");
        return messageSource;
    }
}
chad chen
  • 472
  • 4
  • 10