mpmp
mpmp

Reputation: 2459

Spring 3 Internationalization by folder

I want to use Spring's i18n utility in a manner that all languages are separated by folders. I plan to use this kind of folder structure to keep things more organized than having all in one folder:

Is this possible?

Upvotes: 3

Views: 816

Answers (1)

Bogdan
Bogdan

Reputation: 24590

Is this possible?

Yes it is.

A simple solution I initially thought of was to setup a message source with the basenames property, something like this:

<bean id="messageSource"
        class="org.springframework.context.support.ResourceBundleMessageSource">
    <property name="useCodeAsDefaultMessage" value="true" />
    <property name="basenames">
        <list>
            <value>i18n.en.messages</value>
            <value>i18n.en.application</value>
            <value>i18n.fr.messages</value>
            <value>i18n.fr.application</value>
        </list>
    </property>
</bean>

Giving it a second thought though, I realized the above won't work. Based on the ResourceBundles strategy to instantiate bundles, given a name for a bundle, the first name in the bundle list would resolve the bundle (e.g. looking for messages_fr.properties the strategy will look for i18n/en/messages_fr.properties and then get resolved to i18n/en/messages.properties as the default when messages_fr.properties is not found).

You will need something that discovers your bundles based on a custom folder configuration. You will have to write your own MessageSource implementation and use it in your application instead of the default ones provided by Spring. A basic implementation could look like this:

package pack.age;
import java.util.Locale;
import java.util.ResourceBundle;

import org.springframework.context.support.ResourceBundleMessageSource;

public class ByFolderResourceBundleMessageSource extends ResourceBundleMessageSource {
    private String rootFolder;

    @Override
    protected ResourceBundle getResourceBundle(String basename, Locale locale) {
        String langCode = locale.getLanguage().toLowerCase();
        String fullBaseName = this.rootFolder + "." + langCode + "." + basename;

        ResourceBundle bundle = super.getResourceBundle(fullBaseName, locale);
        if (bundle == null) {
            String defaultBaseName = this.rootFolder + ".Default." + basename;
            bundle = super.getResourceBundle(defaultBaseName, locale);
        }
        return bundle;
    }

    public void setRootFolder(String rootFolder) {
        this.rootFolder = rootFolder;
    }
}

Configuration like:

<bean id="messageSource" 
        class="pack.age.ByFolderResourceBundleMessageSource">
    <property name="useCodeAsDefaultMessage" value="true" />
    <property name="rootFolder" value="i18n" />
    <property name="basenames">
        <list>
            <value>messages</value>
            <value>application</value>
        </list>
    </property>
</bean>

And with a folder setup like:

i18n
  ├───Default
  │     ├─── application.properties
  │     └─── messages.properties
  │
  ├─── en
  │     ├─── application.properties
  │     └─── messages.properties
  │
  └─── fr
        ├─── application.properties
        └─── messages.properties

Upvotes: 1

Related Questions