Previous Section  < Day Day Up >  Next Section

11.2 Handling Localized Application Input

The locale also plays a role when input is being processed. As I mentioned earlier, dates and numbers are written according to different rules in different parts of the world, so input must be parsed according to the rules for the current locale.

All JSF input components use the current locale when they parse input, so there's really nothing you need to do beyond what we've already covered. To verify this, let's use an internationalized version of the entry form area (Example 11-3) and see what happens.

Example 11-3. Internationalized version of the entry form area page (expense/stage5/entryFormArea.jsp)
<%@ page contentType="text/html" %>

<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>

<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>



<f:view locale="#{userProfile.locale}">

  <f:loadBundle basename="labels" var="labels" />

  <h:form>

    <h:outputText value="#{labels.reportTitleLabel}" />

    <h:inputText id="title" size="30" required="true"

      value="#{reportHandler.currentReport.title}" />

    <h:message for="title" />

    <br>

    <h:outputText value="#{labels.reportEntryLabel}" />

    <br>

    <h:outputText value="#{labels.entryDateLabel}" />

    <h:inputText id="date" size="10" required="true"

      value="#{entryHandler.currentEntry.date}">

      <f:convertDateTime datestyle="short" />

    </h:input_text>

    <h:message for="date" />

    <br>

    <h:outputText value="#{labels.entryTypeLabel}" />

    <h:selectOneMenu id="type" required="true"

      value="#{entryHandler.currentEntry.type}">

      <f:selectItems value="#{entryHandler.i18nChoices}"/>

    </h:selectOneMenu>

    <h:message for"type" />

    <br>

    <h:outputText value="#{labels.entryAmountLabel}" />

    <h:inputText id="amount" size="10" required="true"

      value="#{entryHandler.currentEntry.amount}">

      <f:convertNumber pattern="#,##0.00" />

      <f:validateDoubleRange minimum="1"/>

    </h:inputText>

    <h:message for="amount" />

    <br>

    <h:commandButton value="#{labels.addButtonLabel}"

      disabled="#{reportHandler.editDisabled}"

      action="#{entryHandler.add}" />

  </h:form>

  <h:messages globalOnly="true" />



  <%-- Loop to verify that it works --%>

  <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

  <ol>

    <c:forEach items="${reportHandler.currentReportEntries}" var="e">

      <li>Date: ${e.date}, Type: ${e.type}, Amount: ${e.amount}</li>

    </c:forEach>

  </ol>

</f:view>

This entry form area page is internationalized in exactly the same way as the pages we've worked with earlier. The only difference is that it contains input components in addition to the output components. The input component for the Date field is configured with a date/time converter, and the input component for the Amount field with a number converter.

If you use the preferences pages to switch between the English and the Swedish locale and then load the entry form area page, you'll see that the default values for the Date and Amount are formatted differently. In the English locale, the date is formatted as 1/30/04, but in the Swedish locale it's 2004-01-30. The difference between the number formats is subtle, but it's there. In the English locale, a dot separates the integer part from the fractional part, but in the Swedish locale, a comma is used as the separator.

The real thrill comes when you submit an entry. Because the converters are locale-sensitive, they interpret the date and number strings correctly no matter which locale you use. The simple loop at the end of the page writes out all entry values with their native Java formatting, so you can see that they are interpreted correctly.

Maybe you're curious about the localized Type selection menu values. I fixed that by implementing a new method in the EntryHandler class for getting the available choices with localized labels:

    public List getI18nChoices( ) {

        FacesContext context = FacesContext.getCurrentInstance( );

        Locale locale = context.getViewRoot( ).getLocale( );

        ResourceBundle bundle = 

            ResourceBundle.getBundle("entryTypes", locale);

        List i18nChoices = new ArrayList( );

        Iterator i = expenseTypes.entrySet( ).iterator( );

        while (i.hasNext( )) {

            Map.Entry me = (Map.Entry) i.next( );

            i18nChoices.add(new SelectItem(me.getValue( ),

                getResource(bundle, (String) me.getKey( ))));

        }

        return i18nChoices;

    }



    private String getResource(ResourceBundle bundle, String key) {

        key = key.replaceAll(" ", "_");

        String resource = null;

        try {

            resource = bundle.getString(key);

        }

        catch (MissingResourceException e) {

            resource = "???" + key + "???";

        }

        return resource;

    }

The getI18nChoices() method works the same as the other methods for getting the choices we've looked at earlier, except that it uses the Map keys as resource bundle keys to look up the localized value. Because the Map keys may contain spaces (e.g., "Rental Car") and spaces are not allowed in bundle keys, the getResource() helper method replaces all spaces in the key with underscore characters. It also catches the MissingResourceException and wraps the key with question marks if it's thrown, to mimic the behavior of the resource Map exposed by the <f:loadBundle> action.

    Previous Section  < Day Day Up >  Next Section