Localization

In Java, any translatable text is generally stored in a set of localized property files called "resource bundles". The appropriate file is loaded at runtime for either the default locale or an explicitly selected non-default locale. While it is possible to use standard Java resource bundles in a Pivot application, Pivot adds support for JSON-based resource bundles that are slightly more flexible the built-in properties-based bundles. JSON resource bundles allow developers to more easily work with UTF-8 encoded resource strings, and also natively support hierarchical data, which can only be simulated when using properties files.

The following application provides a simple demonstration of localization in Pivot:

The following resource bundles are provided; if your default system locale is among these, you should see a localized version of the application. Otherwise, the default locale ("en") will be used:

  • Localization.json
  • Localization_cn.json
  • Localization_de.json
  • Localization_it.json
  • Localization_ph.json

The resource bundle for the default locale is shown below:

            
            {   firstName: "First name",
                lastName: "Last name",
                street: "Street",
                city: "City",
                state: "State",
                postalCode: "Zip",
                country: "Country"
            }
            
        

The BXML source for the application is as follows. Note the use of the "%" prefix in the form label attributes. This prefix is known as the "resource resolution operator" in BXML. As the BXML is read, attribute values that begin with the "%" character are replaced by the corresponding values defined in the resource bundle:

            
            <Window title="Localization" maximized="true"
                xmlns:bxml="http://pivot.apache.org/bxml"
                xmlns="org.apache.pivot.wtk">
                <windowStateListeners>
                    function windowOpened(window) {
                        window.requestFocus();
                    }
                </windowStateListeners>

                <Border styles="{padding:6}">
                    <Form>
                        <Form.Section>
                            <TextInput Form.label="%firstName"/>
                            <TextInput Form.label="%lastName"/>
                            <TextInput Form.label="%street"/>
                            <TextInput Form.label="%city"/>
                            <TextInput Form.label="%state" textSize="4"/>
                            <TextInput Form.label="%postalCode"/>
                            <TextInput Form.label="%country"/>
                        </Form.Section>
                    </Form>
                </Border>
            </Window>
            
        

The Java source for the application is shown below:

            
            package org.apache.pivot.tutorials.localization;

            import java.awt.Font;
            import java.awt.GraphicsEnvironment;
            import java.util.Locale;

            import org.apache.pivot.beans.BXMLSerializer;
            import org.apache.pivot.collections.Map;
            import org.apache.pivot.util.Resources;
            import org.apache.pivot.wtk.Application;
            import org.apache.pivot.wtk.DesktopApplicationContext;
            import org.apache.pivot.wtk.Display;
            import org.apache.pivot.wtk.Theme;
            import org.apache.pivot.wtk.Window;

            public class Localization implements Application {
                private Window window = null;

                public static final String LANGUAGE_KEY = "language";

                @Override
                public void startup(Display display, Map<String, String> properties) throws Exception {
                    String language = properties.get(LANGUAGE_KEY);
                    Locale locale = (language == null) ? Locale.getDefault() : new Locale(language);
                    Resources resources = new Resources(getClass().getName(), locale);

                    Theme theme = Theme.getTheme();
                    Font font = theme.getFont();

                    // Search for a font that can support the sample string
                    String sampleResource = (String)resources.get("firstName");
                    if (font.canDisplayUpTo(sampleResource) != -1) {
                        Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();

                        for (int i = 0; i < fonts.length; i++) {
                            if (fonts[i].canDisplayUpTo(sampleResource) == -1) {
                                theme.setFont(fonts[i].deriveFont(Font.PLAIN, 12));
                                break;
                            }
                        }
                    }

                    BXMLSerializer bxmlSerializer = new BXMLSerializer();
                    window = (Window)bxmlSerializer.readObject(Localization.class.getResource("localization.bxml"), resources);
                    window.open(display);
                }

                @Override
                public boolean shutdown(boolean optional) {
                    if (window != null) {
                        window.close();
                    }

                    return false;
                }

                @Override
                public void suspend() {
                }

                @Override
                public void resume() {
                }

                public static void main(String[] args) {
                    DesktopApplicationContext.main(Localization.class, args);
                }
            }
            
        

The following example shows the application localized in German. Note that the applet is signed to allow the code to set the "user.language" system property:

Notice that the startup() method includes code to search for a font that can display a sample set of characters obtained from the "firstName" resource. This is because all fonts are not guaranteed to include support for all possible Unicode characters. If the current theme font is not capable of displaying the sample string, this block of code attempts to identify and set one that can. This code must be executed prior to constructing any user interface elements so that the correct font will be used.

Next: Background Tasks