bookmark_border

Android Globalization Best Practices

Mohammad Shaddad,

I received a bug report from a friend of mine on an app I'm working on right now telling me that one screen was not showing text in proper Arabic format. And since I was building the app, with globalization as a key design factor, I was disappointed that we still slipped. So I decided to put together this guideline article to help me remember how things should be done. Hopefully, this will trigger some feedback from others to better optimize the practices on globalization.

First, what is Globalization?

Globalization, also referred to as Internationalization or the i18n standard; is the process of designing a software application so that it can potentially be adapted to various languages and regions without engineering changes.

It's a process that affects how you engineer the UX, UI and code of your application. It's not an easy process to cover all aspects, but once you get your application guidelines right, and build your design and engineering processes around it, you should be able to pull it through.

What about Localization?

Localization; also referred to as i10n, is different from Globalization. Localization requires you to add appropriate resources to your software to ensure that a given country, locale, language, or culture is supported. Or, its the process of adding another language to your app, which is hopefully designed for i18n!

All Text Must be Resource Based

Well, this is a basic thing, but it is important to highlight. Don't hardcode any strings either in your screen layouts nor in your application code; strings.xml is a key artifact in your application. If you mistakenly hardcode strings, it will be a costly process to fix.

Android Studio will warn you if you leave a string hardcoded, but I prefer to treat these as errors and log an issue when one is detected and fix prior to a release.

This is a bad idea

  1. <TextView
  2. android:layout_width="match_parent"
  3. android:layout_height="wrap_content"
  4. android:text="First Name" />

And will result in the warning shown below

Android Studio Hardcoded String Warning

Android Studio Hardcoded String Warning

Instead, use a proper resource string

  1. <TextView
  2. android:layout_width="match_parent"
  3. android:layout_height="wrap_content"
  4. android:text="@string/first_name" />



One Size Doesn't Fit All

This is a common pitfall that designers fall in. We usually design our layouts with a single language in mind; typically English, and assume that translations will fall into place; Unfortunately, not all languages are equal. You should always allow extra space in your layout for text to grow and shrink based on the language translation. Perhaps leave a 40-50% space to cater for that. In some cases, you might have to create separate layouts to cater for extreme cases.

The IBM Globalization Guidelines page has a good table that compares text size increase when translating from English.

Number of Characters in Text Additional Physical Space Required
Up to 10 100% to 200%
11 to 20 80% to 100%
21 to 30 60% to 80%
31 to 50 40% to 60%
51 to 70 31% to 40%
Over 70 30%

This calculation is based on the number of characters in the text string and includes the spaces and punctuation marks within the string. For example, the string "Hello World!" contains twelve characters.

Add Comments to String Resources

There are many cases where strings we use make sense in a one language but can't be translated directly to other languages. Especially if we use playful terms. In these cases, ensure your resource file has comments on the context of the messages to help your translators better understand the message you need to convey and provide proper translations in the target language; whether in a localized playful manner, or a more standard language.

  1. <!-- Used to to give user a sense of accomplishment for reaching a new level -->
  2. <string name="user_level_up_notification">Holy smokes! You've reached a new level!</string>

Imagine sending the above string to a translator to translate without providing them with comments or feedback on the context, what kind of translation will they provide?

Never, Ever Concatenate

We tend to fall into the temptation of concatenating strings to build dynamic messages, and we forget that word ordering is different across languages. Whether we are adding user names, amounts, we should always use string formatting.

For example, if you want to say Hello to a user, don't use this resource string

  1. <string name="hello">Hello </string>

with this code

  1. String welcomeMsg =
  2. getString(R.string.hello) + userProfile.getFirstname();

Instead, use this resource string

  1. <string name="hello">Hello %1s</string>

with this code

  1. String welcomeMsg =
  2. getString(R.string.hello, userProfile.getFirstname());



Use Proper Plural Strings

Don't try to build your quantity/amount texts in code by assigning plural nouns based on the value you have, as different languages will have different ways of representing amounts and quantities. So if you are trying to say: I ate 3 cookies, don't use the following resource strings

  1. <string name="cookie">cookie</string>
  2. <string name="cookies">cookies</string>

with this code

  1. String cookiesIAte = getString(R.string.cookie);
  2. if(cookieCount != 1) {
  3. cookiesIAte = getString(R.string.cookies);
  4. }

Instead,  use a plural resource string definition

<plurals name="cookie">
<item quantity="one">cookie</item>
<item quantity="other">cookies</item>
</plurals>

with this code

  1. String cookiesIAte = getResources()
  2. .getQuantityString(R.plurals.cookie, cookieCount);



Handle Dates Properly

Date formats vary across cultures, so make sure that your application uses the correct format for handling dates by using the DateUtils and DateFormat classes. Don’t use hardcoded date formats such as MM/dd/yyyy, you’ll just confuse everyone.

You can use DateUtils to show a relative timespan string

  1. dateView.setText(
  2. DateUtils.getRelativeTimeSpanString(
  3. transaction.getDate().getTime(),
  4. Calendar.getInstance().getTimeInMillis(),
  5. DateUtils.MINUTE_IN_MILLIS
  6. )
  7. );



It’s not only display that needs to be catered for. When you accept date values from users, or try to capture stamps, make sure you convert them to a standard culture-neutral format prior to storage. Otherwise, you won’t be able to analyze or render properly if a user switches cultures.

  1. Date timestamp = Calendar.getInstance().getTime();
  2. // This will result in inconsistent stored values across users
  3. //DateFormat storedDates = DateFormat.getDateInstance(DateFormat.FULL, Locale.getDefault());
  4. DateFormat storedDates = DateFormat.getDateInstance(DateFormat.FULL, Locale.ENGLISH);
  5. String toStoreStamp = storedDates.format(timestamp);


Dynamic Formatting

When you need to format or highlight part of the text you are showing (color, weight, etc.) don’t use index to manipulate a ForegroundColorSpan. This will get you in trouble with translated strings. Use HTML formatting instead within your resource strings.

  1. <string name="transferred_amount_confirmation">
  2. <![CDATA[
  3. You have successfully transferred <b>%1$s</b> to %2$s
  4. ]]>
  5. </string>

And from code, you can set text by using the Html.fromHtml method as follows

  1. transferConfirmation.setText(
  2. Html.fromHtml(
  3. getString(
  4. R.string.transferred_amount_confirmation,
  5. amount,
  6. transferredTo
  7. )
  8. )
  9. );



Colors

This is a frequently missed one. Colors have different meanings in different cultures. For example, while Green is used to indicate positive increase or trend; like in a stock price, in China, Red is used for that. You should also cater for this and support different colors for different cultures.

Chinese Stock Market App

Chinese Stock Market App Color Indicators

Integrate Globalization Tests in Your Automated Testing

While setting up a device in a different culture, and doing manual testing will allow you to verify your application for issues around clipped text, incorrect line wrapping or layout issues, you should also include testing your app across multiple cultures in your automated testing and continuous integration scripts. This will allow you to detect any issues with your code around parsing dates, inputs, etc. that may not be detectable from a UI focused test. Make sure you do this early in your development cycle and not wait till a later phase just before release.

Additional Resources

You can refer to the following Android documentation on how to implement the practices above

I hope you have found this list of Android Globalization Practices useful. If you have other practices you think might be helpful, please feel free to add them in the feedback section below. Or if you think that I have gotten some of these practices wrong, I'd love to hear your feedback as well.

androidlocalizationinternationalization

What level is this content for?

We've all had our humble beginnings, it's our hard learned experiences that got us to master our code. We will all learn something sharing our knowledge, leave a legacy and write a post now.
create Write post

About the author


Mohammad Shaddad
Mohammad Shaddad

Mohammad is a technology consultant and entrepreneur with big passion for technology and living systems; aka software communities. He enjoys mentoring other programmers and entrepreneurs, as well as creating new things. Mohammad is the founder of @barmijly and @nafaqati. He currently spends his time between Amman.JO and Dubai.AE.