Monday, February 6, 2012

How to use variables in Android internationalized message strings


This article explains how to include variables within internationalized message strings for Android applications.  It also explains how to specify an explicit locale (ie, language) for messages.

All secrets were gleaned from the references listed at bottom.

Prereqs

This article assumes you have:
- Set up the Android SDK and can build, install, and run an APK.
- Created a message file .../res/values/strings.xml
- Can access messages in the file using Context.getResources()...

Default locale messaging, no variables

In basic messaging, the simple Android method getString() may be used to get a message in the default locale.

In res/values/strings.xml:
    <string name="hello_message">Hello World</string>

In the java class:
    String message = myContext.getResources().getString(R.string.hello_message);

The resulting string 'message' is returned in the default locale:
    Hello World



Default locale messaging, 1 variable

To include a variable inside the message, Java formatting strings such as %d (int) and %s (string) may be included in strings.xml.  (See a full list of formatting strings in the references below.)

In res/values/strings.xml:
    <string name="ate_n_donuts">I ate %d donuts.</string>

In the java class:
    int numberDonuts = 12;
    String message = myContext.getResources().getString(R.string.ate_n_donuts, numberDonuts);

The resulting string 'message' is returned in the default locale:
    I ate 12 donuts.


Default locale messaging, multiple variables

Multiple variables in a string must be numbered with 1$, 2$, 3$.  These sequence numbers are embedded inside the formatting string, %s or %d, to appear as:  %1$s, %2$s, etc.  (very odd.)

Take note the sequence starts at 1, not zero.

The numbers correspond to the sequence of variables in the java method parameters.  This scheme allows translators to modify the sequence of variables to match the natural language style.  Example:

In res/values/strings.xml:
    <string name="game_results">The %1$s beat the %2$s in the %3$s.</string>

In your java class:
    String team1 = "New York Giants"
    String team2 = "New England Patriots"
    String gameName = "Super Bowl";
    String message = myContext.getResources().getString(R.string.game_results, team1, team2, gameName);

The resulting string 'message' is returned in the default locale:
    The New York Giants beat the New England Patriots in the Super Bowl.


Explicit locale messaging

The previous examples returned strings in the default locale of the mobile device automatically.  Messages displayed to the user should be presented this way.  However, for debug and servicability purposes, it may be useful to present messages in the language of the developer.  For example, I always want my log files in English.

To present a message in an explicit locale, the native Java formatter must be used.  In this last example, notice the variable is passed-in to the Java String.format() method, instead of to the Android getString() method.  Repeating the donut example...

In res/values/strings.xml:
    <string name="ate_n_donuts">I ate %d donuts.</string>

In the java class:
    int numberDonuts = 12;
    Locale logLocale = Locale.US;
    String messageEnglish = String.format(logLocale,
        myContext.getResources().getString(R.string.ate_n_donuts),
        numberDonuts);

The resulting string 'message' is returned in the explicitly-specified locale:
    I ate 12 donuts.


Really complex messaging

You now have all the secrets.  You can specify multiple variables in an internationalized message string.  You can get strings in the default locale and a specific locale.

And you can see that your code will get really complex and ugly fast.


Recommendations

I recommend you study the fine points in these examples.  Then write some helper methods to hide all these details from the main flow of your application.

Good luck!



Excellent References:

Bram's blog with comment from Romain Guy:
http://bvirtual.nl/2009/11/variable-in-androids-stringsxml.html

Official Android docs:
http://developer.android.com/reference/java/lang/String.html#format(java.lang.String, java.lang.Object...)
http://developer.android.com/reference/java/util/Formatter.html
http://developer.android.com/reference/android/content/Context.html#getString%28int,%20java.lang.Object...%29





No comments:

Post a Comment

Note: Only a member of this blog may post a comment.