This codelab is part of the Advanced Android Development training course, developed by the Google Developers Training team. You will get the most value out of this course if you work through the codelabs in sequence.

For complete details about the course, see the Advanced Android Development overview.

Introduction

Users run Android devices in many different languages. To reach the most users, your app should handle text and layouts in ways appropriate for those languages.

An Android user can change the language for a device in the Settings app. As a developer, you should localize your app to support different languages in the locales in which your app is released.

In this chapter, you learn how to provide support for different languages using string resources and the Translations Editor in Android Studio.

What you should already know

You should be able to:

What you'll learn

What you'll do

In this lesson you work from a starter app called LocaleText_start, which is a simple app that uses the Basic Activity template. Its UI uses the default ConstraintLayout provided by the template. It has text, an image, and a floating action button that can make a phone call. The options menu has a single menu item, Help, that launches a second activity with help information.

This lesson demonstrates how you can localize an app for a locale, and provide translated text within your app for the other languages.

After adding an RTL language, you will use XML layout attributes to take advantage of the layout mirroring feature added to Android 4.2. Layout mirroring redraws the layout for a right-to-left orientation for RTL languages. As a result, the image, the TextView elements, the options menu, and the floating action button are all automatically moved to the opposite side of the screen as shown below. The app demonstrates the attributes you use for layout mirroring.

In this task you will learn the following key practices for adding different languages:

1.1 Examine the starter app's layout

To save you time, the LocaleText_start starter app has been prepared with a layout to show the effects of changing languages.

  1. Download the LocaleText_start app.
  2. Rename the LocaleText_start project folder to LocaleText, open it in Android Studio, and refactor it to use the name LocaleText.
  3. Run the app to see what it looks like.
  4. Examine the app's layouts in the Design tab.

The MainActivity layout (shown below) includes:

The HelpActivity layout includes:

1.2 Examine the starter app's resources

To prepare an app to be translated into another language, save all text strings as resources in strings.xml, including text from menu items such as the options menu, text on tabs, and any other navigation elements that use text.

To save time, the LocaleText_start starter app has been prepared with all text strings in strings.xml. Open strings.xml—known as the default strings.xml file because it is used for the default language—to see the string resources in the app. It includes every piece of text in the app including the action_help resource for the options menu item (Help). The file include comments that provide the context for the translator to translate your strings—such as the use of grammar structures and product terms.

<resources>
<!-- All comments are notes to translators. -->
<string name="app_name">LocaleText</string>

<!-- The Help option in the options menu, no more than 30 chars. -->
<string name="action_help">Help</string>
...
</resources>

Include comments in the strings.xml file to describe the context in which each string is used. If you use a translator to translate your strings, the translator will understand the context from the comments you provide, which will result in a better quality translation.

1.3 Add another language resource to the app

Use the Android Studio Translations Editor to create the string resources for each language.

  1. Open the strings.xml file, and click the Open editor link in the top right corner.

    The Translations Editor appears with a row for each resource key (such as action_help, app_name, and nougat). The Default Value column is the default value of the resource key in the default language.

  1. Click the globe button in the top left corner of the Translations Editor pane ("1" in the following figure), and select French in the dropdown menu:


After you choose a language, a new column with blank entries appears in the Translations Editor for that language, and the keys that have not yet been translated appear in red.

To show only the keys that require translation, check the Show only keys needing translation checkbox option at the top of the Translations Editor pane, next to the globe.

  1. Select a key (such as description). The Key, Default Value, and Translation fields appear at the bottom of the Translations Editor pane.
  2. Add the French translation for the key by selecting the key's cell in the column for the language (French), and entering the translation in the Translation field at the bottom of the pane as shown in the following figure.

1.4 Enter the translations for the strings

  1. Enter the translations in the French column for each key, as shown in the following figure:

  1. Click the Untranslatable checkboxes for the support_phone and dial_log_message keys; they change from red to black. Keys shown in black don't need to be translated, either because they've already been translated, or because you've indicated that they are untranslatable.

Since there is no translation for the support_phone and dial_log_message keys, the default values will be used in the layout no matter what language and locale the user chooses in the Settings app.

If you don't want to translate the app name, you can click the Untranslatable checkbox for it; however, you can also modify the app name for each language, as shown in the above figure. The choice of translating the app name is up to you. Many apps add translated names so that the users in other languages understand the app's purpose and can find the app in Google Play in their own languages.

  1. To see a preview of the layout in the new language, open content_main.xml in the Design tab, and choose the language you added from the Language menu at the top of the Layout Editor. The layout reappears with a preview of what it looks like in that language.

Changing the language can affect the layout. In this case, the headline in the previous figure, "Pacquet de bonbons de nougat," takes up two lines. To prepare for different languages, you need to create layouts that have enough room in their text fields to expand at least 30 percent, because a translated version of the text may take more room.

  1. Switch to Project: Project Files view, and expand the res directory. You see that the Translations Editor created a new directory for the French language: values-fr. The values directory is the default directory for colors, dimensions, strings, and styles, while for now, the values-fr directory has only string resources.

An app can include multiple values directories, each customized for a specific language and locale combination. When a user runs the app, Android automatically selects and loads the values directories that best match the user's chosen language and locale. For example, if the user chooses French as the language for the device in the Settings app, the French strings.xml file in the values-fr directory is used rather than the strings.xml file in the default values directory.

1.5 Run the app and switch languages

  1. Run the app on the emulator or on a device. The strings appear in the language used in the default strings.xml file (in this case, English). Click the options menu, which offers one option (Help). Click Help to see the second Activity.

  1. To switch the preferred language in your device or emulator, open the Settings app. If your Android device is in another language, look for the gear icon:
  2. Find the Languages & input settings in the Settings app, and choose Languages. Languages is the first choice on the Languages & input screen.

    Be sure to remember the globe icon for the Languages & input choice, so that you can find it again if you switch to a language you do not understand.



  1. For devices and emulators running a version of Android previous to Android 7, choose Language on the Languages & input screen, select Français (France).

In versions of Android previous to Android 7, users can choose only one language.

  1. For devices and emulators running Android 7 or newer, select Languages on the Languages & input screen. Click Add a language, select Français, and then select France for the locale. Use the move icon on the right side of the Language preferences screen to drag Français (France) to the top of the list.

In Android 7 and newer versions, users can choose multiple languages and arrange them by preference. The primary language is numbered 1, as shown in the following figure, followed by lower-preference languages.

  1. Run the app again. The app now appears in French:

If the user has chosen a language that your app does not support, the app displays the strings that are in the default strings.xml file. For example, if the user has chosen Spanish (or any other language which your app does not support), the app displays strings in English, which is the language used in the default strings.xml file for this app.

Note: Remember to include all the strings you need for the app in the default strings.xml file. If the default file is absent, or if it is missing a string that the app needs, the app may stop.

Some languages, such as English, are read from left to right (LTR), while others, such as Arabic or Hebrew, are read from right to left (RTL). While the text fields in an LTR language would be arranged in a layout from left to right, they should be reversed in a layout for an RTL language. Android 4.2 and newer versions provide full native support for RTL layouts so that you can use the same layout for both types of languages.

So far, the app uses two LTR languages: English (for the default) and French. In this task you add Hebrew, an RTL language.

2.1 Check for RTL support

Android provides the layout mirroring feature, which redraws the layout for RTL languages so that the image view, the text view, the options menu, and the floating action button are all automatically moved to the opposite side of the layout.

Open AndroidManifest.xml to check that the following attribute is part of the <application> element. This enables RTL layout mirroring:

android:supportsRtl="true"

Android Studio adds the above attribute to new projects. If you change true to false, RTL layout mirroring is not supported, and the views and other elements that use the RTL language appear as they would for an LTR language.

2.2 Add an RTL language

Add Hebrew to the LocaleText app:

  1. Open the LocaleText app from the previous task in Android Studio.
  2. Add Hebrew and translate the strings using the Translations Editor (see previous task for details). The translations appear in the new Hebrew (iw) column for the key.

  1. To see a preview of the layout in the new language, open content_main.xml, click the Design tab if it is not already selected, and choose Hebrew (iw) from the Language menu at the top of the Layout Editor. The layout reappears with a preview of what it will look like in Hebrew.

As shown in the figure, adding an RTL language can affect the layout, because Android Studio automatically supplies a declaration in the <application> element in the AndroidManifest.xml file that automatically turns on RTL layout support: android:supportsRtl="true". The RTL language characters are properly set from right to left, and the RTL text is justified to the right margin.

However, the UI elements—with the exception of the floating action button—are still in the same place in the layout, as if they were showing an LTR language. The floating action button moves to the opposite (left) side of the screen, as it should for an RTL language. But the ImageView is still constrained to the left margin, and the two TextView elements are constrained to the right side of the ImageView.

The ImageView and TextView elements should move to the opposite side of the screen, where a Hebrew reader would expect them to be. In the next step you will fix the layout to fully support an RTL language.

2.3 Modify the content layout for RTL languages

To adjust a layout so that it fully supports an RTL language, you need to add a "start" and "end" attribute for every "left" and "right" attribute in each layout. For example, if you use android:layout_marginLeft, add android:layout_marginStart:

  1. Open content_main.xml and look at the XML code.

Android Studio highlights "right" and "left" attributes (such as layout_marginLeft in the figure) and provides suggestions about including "start" and "end" attributes to better support right-to-left languages.

  1. Add a "start" attribute for every "left" attribute, and an "end" attribute for every "right" attribute. For example, add the android:layout_marginStart attribute to all uses of the layout_marginLeft attribute:
android:layout_marginLeft="@dimen/standard_margin"
android:layout_marginStart="@dimen/standard_margin"

The "start" attribute defines the start of the view, which is the same as the "left" attribute for an LTR language; however, in RTL languages, the start side is the right side.

The "end" attribute defines the end of the view, which is the same as the "right" attribute for an LTR language; however, in RTL languages, the end side is the left side.

Be sure to add "start" and "end" to the constraint attributes. For example:

app:layout_constraintLeft_toRightOf="@+id/product_image"
app:layout_constraintStart_toEndOf="@+id/product_image"
  1. To see a preview of the layout in the new language, click the Design tab, and choose Hebrew (iw) in the Language menu at the top of the Layout Editor. The layout reappears with a preview of what it will look like, now that you have added the "start" and "end" attributes.

Compare this layout preview with the layout preview in the previous task. As a result of adding the "start" and "end" attributes for margins and constraints, the layout now shows the image on the right side of the screen (the "start" side), and the TextView elements are constrained to its left ("end") side.

The following snippet is the revised XML code for the two TextView elements and the ImageView in content_main.xml:

<TextView
    android:id="@+id/heading"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:layout_marginLeft="@dimen/standard_margin"
    android:layout_marginStart="@dimen/standard_margin"
    android:layout_marginTop="@dimen/standard_margin"
    android:text="@string/nougat"
    android:textAppearance=
                    "@style/TextAppearance.AppCompat.Headline"
    app:layout_constraintHorizontal_bias="0.0"
    app:layout_constraintLeft_toRightOf="@+id/product_image"
    app:layout_constraintStart_toEndOf="@+id/product_image"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<ImageView
    android:id="@+id/product_image"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:srcCompat="@drawable/nougat"
    app:layout_constraintTop_toTopOf="parent"
    android:layout_marginTop="@dimen/standard_margin"
    android:layout_marginLeft="@dimen/standard_margin"
    android:layout_marginStart="@dimen/standard_margin"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintStart_toStartOf="parent"/>

<TextView
    android:id="@+id/description"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="@string/description"
    android:layout_marginTop="0dp"
    app:layout_constraintTop_toBottomOf="@id/heading"
    app:layout_constraintLeft_toRightOf="@id/product_image"
    app:layout_constraintStart_toEndOf="@id/product_image"
    android:layout_marginLeft="@dimen/standard_margin"
    android:layout_marginStart="@dimen/standard_margin"
    android:layout_marginRight="@dimen/standard_margin"
    android:layout_marginEnd="@dimen/standard_margin"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintHorizontal_bias="0.0" >
</TextView>

2.4 Modify the help layout for RTL languages

Modify the activity_help.xml layout for the RTL language: Add a "start" attribute for every "left" attribute, and an "end" attribute for every "right" attribute, as done previously for content.xml, for the two TextView elements and the floating action button. The following snippet shows the XML code for these elements in activity_help.xml:

<TextView
    android:id="@+id/help_title"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginLeft="@dimen/standard_margin"
    android:layout_marginStart="@dimen/standard_margin"
    android:layout_marginTop="@dimen/standard_margin"
    android:text="@string/action_help"
    android:textAppearance=
                "@style/TextAppearance.AppCompat.Headline"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintTop_toTopOf="parent" />

<android.support.design.widget.FloatingActionButton
    android:id="@+id/fab"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:clickable="true"
    app:fabSize="mini"
    app:srcCompat="@android:drawable/ic_menu_call"
    android:layout_marginLeft="@dimen/standard_margin"
    android:layout_marginStart="@dimen/standard_margin"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintStart_toStartOf="parent"
    android:layout_marginTop="@dimen/standard_margin"
    app:layout_constraintTop_toBottomOf="@+id/help_title" />

<TextView
    android:id="@+id/help_body"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:padding="@dimen/standard_margin"
    android:text="@string/help_text"
    android:textAppearance="@style/TextAppearance.AppCompat.Medium"
    android:layout_marginLeft="@dimen/standard_margin"
    android:layout_marginStart="@dimen/standard_margin"
    android:layout_marginRight="@dimen/standard_margin"
    android:layout_marginEnd="@dimen/standard_margin"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/help_title"
    app:layout_constraintLeft_toRightOf="@+id/fab"
    app:layout_constraintStart_toEndOf="@+id/fab"
    app:layout_constraintHorizontal_bias="1.0" >
</TextView>

To see the changes, run the app on the device or emulator, and then change the language to Hebrew and run the app again.

The image now appears on the right of the screen, at the start of the text in the main activity. The help activity's layout is also mirrored for the RTL language.

Note also that the app name, the Help title for HelpActivity, and the Up button for HelpActivity (shown on the right side of the figure) are also moved to the opposite side of the layout, which is proper for RTL languages.

Task 2 solution code

Android Studio project: LocaleText1

Would you like a quicker way than going back to the Settings app to change the language for testing this app? In this task, you add a Language option to the options menu in the LocaleText app. When tapped, this option uses an Intent to open the language list in the Settings app.

The Language menu option will make it easier for the user to open the language list without having to look for and launch the Settings app. The user can also immediately return to the LocaleText app and see the app in the new language by tapping the Back button.

3.1 Add the menu option

Open the LocaleText app project from the previous section (or download the LocaleText1 app project).

Add the Language item to menu_main.xml, using action_language as the id. Set the android:orderInCategory attribute value to a higher number than action_help so that it appears below the Help option in the menu.

<item
    android:id="@+id/action_language"
    android:orderInCategory="110"
    android:title="Language"
    app:showAsAction="never" >
</item>

Extract the string resource for the option's android:title attribute ("Language"). Use the Translations Editor to provide that string resource for French and Hebrew.

3.2 Modify onOptionsItemSelected()

In MainActivity, change the code in the onOptionsItemSelected() method to a switch block that handles both Help and Language:

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle options menu item clicks here.
    switch (item.getItemId()) {
        case R.id.action_help:
            showHelp();
            return true;
        case R.id.action_language:
            Intent languageIntent = new 
                             Intent(Settings.ACTION_LOCALE_SETTINGS);
            startActivity(languageIntent);
           return true;
        default:
           // Do nothing.
        }
    return super.onOptionsItemSelected(item);
}

The Language case uses an Intent with Settings.ACTION_LOCALE_SETTINGS to navigate directly to the language list.

Task 3 solution code

Android Studio project: LocaleText2

Challenge: Localize the UI elements of another app.

Developers often work in teams and are asked to update existing apps to localize them. In such cases you may not know everything about the code in the app, but you can apply localization best practices to update the code.

For this challenge, download the RecyclerView_start starter app, rename it to RecyclerView, and run the app. It shows a list of "Word" items. The floating action button adds a "Word" item each time you click it. Clicking on an item displays "Clicked!" with "Word" (as shown in the figure).

The following are the general steps for this challenge:

  1. Add string resources to the project with translations for French (or any LTR language) and Hebrew (or any RTL language).

The challenge requires you to support a RTL language. The number that appears after "Word" for an LTR language ("Word 20") should appear before "Word" ("20 מִלָה") for an RTL language. To control placement, use a string format with an argument for the number, as described in the Formatting and Styling section of String Resources.

  1. Open MainActivity, find the code In the onCreate() method that puts the initial data into the word list (shown in the comment below), and replace it with code to use the word string resource:
// Original code: mWordList.addLast("Word " + i)
mWordList.addLast(String.format(getResources()
                                 .getString(R.string.word, i));
  1. Within the onCreate() method, find the code for the floating action button in onClick() that adds a new word to the word list (shown in the comment below), and replace it to use the word string resource:
// Original code: mWordList.addLast("+ Word " + wordListSize)
mWordList.addLast("+ " +
               getResources().getString(R.string.word, wordListSize));
  1. Open WordListAdapter, and use the getString() method to replace the hardcoded "Clicked!" with R.string.clicked. In the WordViewHolder class within WordListAdapter, change the onClick() method to the following:
public void onClick(View v) {
    String clickOutput = v.getContext().getString(clicked) +
                    wordItemView.getText();
    wordItemView.setText(clickOutput);
}
  1. Run the app and click the floating action button twice to add two more entries: "+ Word 20" and "+ Word 21." Click the Word 16 item to ensure that it displays "Clicked! Word 16" as shown in the previous figure. Then change your device or emulator to another language, run the app, and perform the same steps.

Challenge solution code

Android Studio project: LocaleRecyclerView

The related concept documentation is in 5.1 Languages and layouts.

Android developer documentation:

Material Design: Usability - Bidirectionality

Android Developers Blog: Native RTL support in Android 4.2

Android Play Console: Translate & localize your app

Other:

This section lists possible homework assignments for students who are working through this codelab as part of a course led by an instructor. It's up to the instructor to do the following:

Instructors can use these suggestions as little or as much as they want, and should feel free to assign any other homework they feel is appropriate.

If you're working through this codelab on your own, feel free to use these homework assignments to test your knowledge.

Build and run an app

In the LocaleText1 app, make the following changes:

  1. Add Spanish for Mexico and Arabic for any region.
  2. Add translations for both languages.
  3. Test the app with both language choices.

Answer these questions

Question 1

Which of the following attributes should you add to the android:layout_marginLeft attribute to support an RTL language?

Question 2

Which of the following attributes should you add to the app:layout_constraintLeft_toRightOf attribute to support an RTL language?

Submit your app for grading

Guidance for graders

Check that the app has the following features:

To see all the codelabs in the Advanced Android Development training course, visit the Advanced Android Development codelabs landing page.