jacekn
jacekn

Reputation: 1541

Internationalized drop downs using Spring 3

Story

I have a select control that represents user access level. I'm looking for a way to internationalize it. The label should be loaded from a message resource and the value should be used as is. I prepare all my drop down lists in controllers using a simple SelectOption class that has a label and a value properties. This way, my select's look consistent accross all jsp's.

Problem

I've found some examples but they are based on logic within jsp. Developer loops through his labels and manually constructs the option tag using a message resource. While this works, there just has to be a better way. I've also found some comments that Spring 3 will have support for internationalizing option labels but I can't find anything concrete on that.

Controller logic

Collection<SelectOption> optionList = new ArrayList<SelectOption>();
optionList.add(new SelectOption("-SELECT-", "-"));  
optionList.add(new SelectOption("Administrator", "ADMIN"));
optionList.add(new SelectOption("Editor", "EDIT"));
bean.setFilterUserAccessLevelOptionList(optionList);

JSP logic

<form:select path="filterUserAccessLevel"  items="${bean.filterUserAccessLevelOptionList}" itemLabel="label" itemValue="value"/>

Questions

  1. I would like to add options in my controller in this way: optionList.add(new SelectOption("userAccessLevelAdministratorLabel", "ADMIN")); and have Spring convert userAccessLevelAdministratorLabel to a value from a message resource. Is this possible?
  2. If Spring 3 cannot do this for me, how else can this be achieved without manually constructing the option tag within jsp?

=== 2012-01-15 ==============================================================

Still trying to work out a solution using aweigold's idea.

Controller

@Controller
public class UserController {
@Autowired
private UserService userService;

@Autowired
SelectOptionListBuilder listBuilder;

    @RequestMapping("/userIndex/{pageNumber}")
public ModelAndView getUserList(@PathVariable Integer pageNumber, @ModelAttribute("userIndexBean") UserIndexBean phantomBean, Locale locale, Model model) {

    UserIndexBean bean = new UserIndexBean();

    // prepare filter form
    Collection<SelectOption> optionList = listBuilder.getUserAccessLevelOptionList(true, SortOrder.NONE, locale);
    bean.setFilterUserAccessLevelOptionList(optionList);

SelectOptionListBuilderImpl

@Component
public class SelectOptionListBuilderImpl implements SelectOptionListBuilder, MessageSourceAware {

private MessageSource messageSource;

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


@Override
public List<SelectOption> getUserAccessLevelOptionList(boolean addSelectPrompt, SortOrder sortOrder, Locale locale) {
    List<SelectOption> optionList = new ArrayList<SelectOption>();

    if(addSelectPrompt) {
        optionList.add(new SelectOption(messageSource.getMessage("common.selectPromptLabel", null, locale), "-"));
    }

messageSource mapping

<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">    
<property name="basename" value="/WEB-INF/i18n/messages" />
<property name="defaultEncoding" value="UTF-8"/>
<property name="UseCodeAsDefaultMessage" value="true"/>
</bean>

Exception

org.springframework.context.NoSuchMessageException: No message found under code 'common.selectPromptLabel' for locale 'en_CA'

Upvotes: 1

Views: 2326

Answers (2)

Ralph
Ralph

Reputation: 120851

Have a look at a spring roo project. They managed this kind of problem by creating tagx tags. This tags do what you already descibed (it contains a litte logic to load the messages from ressources and build the option tags). But because the logic is witten once and you can use this tags like normal tags in you jspx files, it feels like a tag that do what you want to have.

Upvotes: 1

aweigold
aweigold

Reputation: 6889

When I need to do operations like this in a Controller outside of a jsp, I've been making my Controllers MessageSourceAware. Spring will then inject a new MessageSource when they are swapped, and you can interrogate it much like Spring does. In your example, you would do something like this:

@Controller
public class someController implements MessageSourceAware {
    private MessageSource messageSource;

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

    @RequestMapping
    // Pass in the locale from the LocaleResolver
    public void someMapping(Locale locale){
        optionList.add(new SelectOption(
           messageSource.getMessage("userAccessLevelAdministratorLabel", null, locale),
           "ADMIN"))
    }
}

Upvotes: 1

Related Questions