Software localization

Android Accessibility Tutorial for Multilingual Apps

Learn how to integrate Android accessibility services into your app internationalization process to cater to users with disabilities worldwide.
Software localization blog category featured image | Phrase

Globally, more than 2B people have a vision impairment. If you plan to launch an Android app for multiple markets, integrating accessibility features and services as early as possible into the Android localization process can help you increase your app's reach even more. This tutorial will show you how to make Android accessibility an inherent part of your app and cater to visually impaired users.

What is Android accessibility?

Android accessibility services require devices with at least Android 6.0 Marshmallow. They include Talkback, Accessibility Menu, Select to Speak, Switch Access, and CallApp.

In this tutorial, we'll focus on Talkback, the Google screen reader that gives eyes-free control of a mobile device.

Most original equipment manufacturers (OEMs) will have the service installed by default, but for some phones, you'll have to download Talkback manually from the Play Store and activate it via the following path: Settings > Accessibility > Talkback.

🗒 Note » You can also enable and disable Talkback via adb by using the following commands:

// disable

adb shell settings put secure enabled_accessibility_services com.android.talkback/com.google.android.marvin.talkback.TalkBackService

// enable

adb shell settings put secure enabled_accessibility_services com.google.android.marvin.talkback/com.google.android.marvin.talkback.TalkBackService

What is Talkback?

With the help of intelligent gestures, Talkback supports visually impaired users in navigating and interacting with a mobile screen without actually looking at it. It talks back to the user, telling all the appropriate information that the user might need from the app. In this article, we'll have a look at several ways to make Talkback announce localized text so we provide global audiences with accessible apps.

Navigating a screen with Talkback

Users browse a mobile app screen by swiping from left to right. Following each swipe, Talkback announces the items on the screen. When the user swipes from top to bottom, Talkback stays focused on that element and suggests actions related to it.

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-navigation.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-navigation.mp4" poster="https://phrase.com/wp-content/uploads/2022/03/image-from-ios-01.png"][/video]

Talkback also offers support for right-to-left (RTL) layouts, making touch gestures inverted:

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-rtl-navigation.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-rtl-navigation.mp4"][/video]

Remove hard-coded strings

Talkback automatically picks up the language set in Android OS to communicate with the user in the same language. If you use hard-coded strings in your app, Talkback will be forced to read out those strings instead of localized ones—rendering the app indiscernible.

Let's have a look at an example of TextView with hard-coded copy.

<!--    //Hardcoded TextView-->

<com.google.android.material.textview.MaterialTextView

  android:id="@+id/heading"

  style="?attr/textAppearanceHeadline2"

  android:layout_width="match_parent"

  android:layout_height="wrap_content"

  android:text="Hello"

  app:layout_constraintStart_toStartOf="parent"

  app:layout_constraintTop_toTopOf="parent" />

Since the text is hard-coded, Talkback will fail to localize the string and will announce it as "Hello" in all locales:

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-hard-coded-copy.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-hard-coded-copy.mp4"][/video]

To fix that, we need to remove all hard-coded strings. To do so, we'll create two strings.xml files, one for default and one for French locale.

<!--    Default string.xml file-->

<string name="greeting">Hello</string>

<!--    String.xml (fr) file -->

<string name="greeting">Bonjour</string>

🗒  Note » Learn more about creating different locale files.

Now, in TextView, pass the reference to the above resource Id.

<!--Dynamic TextView-->

 <com.google.android.material.textview.MaterialTextView

   android:id="@+id/heading"

   style="?attr/textAppearanceHeadline2"

   android:layout_width="match_parent"

   android:layout_height="wrap_content"

   android:text="@string/greeting"

   app:layout_constraintStart_toStartOf="parent"

   app:layout_constraintTop_toTopOf="parent" />

Talkback will now read out the localized string.

When the phone's language is set to French (any region), Talkback will use the string value corresponding to the French string resource file:

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-changing-locale-dynamically.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-changing-locale-dynamically.mp4"][/video]

For any other locale, Talkback will use the string from the default string.xml file:

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-default-locale.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-default-locale.mp4"][/video]

Internationalizing numbers

Talkback reads out numbers with different units depending on the locale and formatting of the number. We need to make sure that the numbers are formatted correctly for the Talkback service to read it out accurately.

For example, let's say we want to use the following set of digits in a TextView: 200000.

  • For English in the US (en_US), the number should be displayed as "200,000" and read out by Talkback as "two hundred thousand"
  • For Hindi in India (hi_IN), the number should be displayed as "2,00,000" and read out by Talkback as "two lakhs"

To make sure the number is formatted and read out correctly according to the locale, you need to use NumberFormat.

//Incorrect way to set numbers

    binding.textviewUnformattedOne.text = "200,000"

    binding.textviewUnformattedTwo.text = "10,000,000"

    //Correct way to set numbers Using NumberFormat

    val numberFormat = NumberFormat.getInstance()

    binding.textviewFormattedOne.text = numberFormat.format(200000);

    binding.textviewFormattedTwo.text = numberFormat.format(10000000);

As you can see in the mobile screen video below, for a phone whose locale is set to Hindi, numbers are formatted and read correctly:

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-number-formatting-for-the-hindi-locale.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-number-formatting-for-the-hindi-locale.mp4"][/video]

Internationalizing date formats

Talkback also has the ability to announce dates according to the phone's locale. However, for this to happen, it's key not to use hard-coded strings.

To take advantage of Talkback's localized dates, we'll use the DateTimeFormatter class.

val dateFormatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL)

    val dateOfBirth = LocalDate.of(1995, Month.OCTOBER, 7)

    val localizedDate = dateOfBirth.format(dateFormatter)

    binding.heading.text = localizedDate

When the phone's locale is set to en_US, the date is announced in English.

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-date-announced-in-english.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-date-announced-in-english.mp4"][/video]

If the phone's locale is set to hi_IN, the same date is localized and announced in Hindi, respecting the locale's date formatting and language.

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-date-announced-in-hindi.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-date-announced-in-hindi.mp4"][/video]

🔗 Resource » Our dedicated tutorial on localizing date and time formats in Android takes you through this process step-by-step.

Supporting multiple languages

Imagine you had a piece of text in your app, for example, an address or a name, which is fixed and should be shown in a specific locale, irrespective of the phone's set locale.

The latest version of Talkback is able to switch languages on the fly.

In the example below, Talkback can identify the language of the text, English ("Hello") and Hindi ("नमस्ते"), and is also able to announce the text accurately.

All you need to do is define the fixed text in the default strings.xml file.

<!--    Default string.xml file-->

       <!-- Text to be always read in English-->

          <string name="greeting_fixed_in_English">Hello</string>

       <!-- Text to be always read in Hindi-->

         <string name="greeting_fixed_in_hindi">नमस्ते</string>

🗒 Note » It's important to only define the strings in the default string.xml file and not in any other strings locale file as the strings are fixed and should be read as they are no matter the locale.

Check out the app screen below to see how Talkback can recognize different languages without explicitly defining them.

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-talkback-recognizing-locales-dynamically.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-talkback-recognizing-locales-dynamically.mp4"][/video]

Content descriptors

Android comes with certain accessibility APIs that help Talkback identify view elements and announce their type and description. In the following example, we've got two ImageViews—one for decorative purposes and the other, important one depicting New York's skyline—as well as a "Submit" button.

Android mobile app screen | Phrase

By default, Talkback will ignore the images and jump to announcing the "Submit" button. Nevertheless, we want Talkback to also announce a description for the important image while ignoring the decorative one as it serves no value to visually impaired users.

To solve this issue, you need to make the following changes to the XML file:

<!--    Setting content description to null for decorative image-->

    <ImageView

      android:id="@+id/decorativeImage"

      android:layout_width="wrap_content"

      android:layout_height="wrap_content"

      android:contentDescription="@null"

      app:layout_constraintEnd_toEndOf="parent"

      app:layout_constraintStart_toStartOf="parent"

      app:layout_constraintTop_toTopOf="parent"

      app:srcCompat="@android:drawable/btn_star_big_on" />

    <!--Setting content description for important image-->

    <ImageView

      android:id="@+id/importantImage"

      style="?attr/textAppearanceHeadline6"

      android:layout_width="wrap_content"

      android:layout_height="400dp"

      android:contentDescription="@string/image_description"

      app:layout_constraintStart_toStartOf="parent"

      app:layout_constraintTop_toBottomOf="@+id/decorativeImage"

      app:srcCompat="@drawable/newyork" />

    <!--Setting content description for delete button-->

    <ImageButton

      android:id="@+id/textview_unformatted_one"

      android:layout_width="200dp"

      android:layout_height="wrap_content"

      android:contentDescription="@string/delete_button"

      android:padding="20dp"

      android:src="@android:drawable/ic_menu_delete"

      android:textColor="@color/white"

      app:layout_constraintEnd_toEndOf="parent"

      app:layout_constraintStart_toStartOf="parent"

      app:layout_constraintTop_toBottomOf="@id/importantImage" />

🗒 Note » Remember to set the value of the content descriptor as resource Ids of a string rather than hardcoded strings because Talkback will automatically pick up the localized string.

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-announcing-content.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-announcing-content.mp4"][/video]

Supporting  layouts

Some languages, like Urdu, Hebrew, etc., are read from right to left. Talkback can automatically detect these languages and announce the view elements in the RTL instead of LTR direction.

However, we need to make sure that the layout supports RTL, or Talkback will fail. Currently, the TextViews are fixed to the left and right of the parent view.

<!--Key TextView-->

       <com.google.android.material.textview.MaterialTextView

          android:id="@+id/heading"

          style="?attr/textAppearanceHeadline6"

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:nextFocusRight="@id/value"

          android:text="@string/water_intake_key"

          app:layout_constraintLeft_toLeftOf="parent"

          app:layout_constraintTop_toTopOf="parent" />

        <!--    Value TextView-->

        <com.google.android.material.textview.MaterialTextView

          android:id="@+id/value"

          style="?attr/textAppearanceHeadline6"

          android:layout_width="wrap_content"

          android:layout_height="wrap_content"

          android:text="@string/water_intake_value"

          app:layout_constraintRight_toRightOf="parent"

          app:layout_constraintTop_toTopOf="parent" />

In English, Talkback will read out the content from left to right in the following sequence: "Water Intake" followed by "4 liters."

However, for any other language that uses the RTL layout, Talkback will read it in an incorrect order: "4 liters" followed by "Water Intake":

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-incorrect-announcing-of-rtl-content.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-incorrect-announcing-of-rtl-content.mp4"][/video]

To fix this, make the following changes to the previous code:

<com.google.android.material.textview.MaterialTextView

   android:id="@+id/heading"

   style="?attr/textAppearanceHeadline6"

   android:layout_width="wrap_content"

   android:layout_height="wrap_content"

   android:nextFocusRight="@id/value"

   android:text="@string/water_intake_key"

   **app:layout_constraintStart_toStartOf="parent"

   app:layout_constraintTop_toTopOf="parent" />

<com.google.android.material.textview.MaterialTextView

   android:id="@+id/value"

   style="?attr/textAppearanceHeadline6"

   android:layout_width="wrap_content"

   android:layout_height="wrap_content"

   android:text="@string/water_intake_value"

   **app:layout_constraintEnd_toEndOf="parent"

   app:layout_constraintTop_toTopOf="parent" />

Talkback will now announce the text in the correct order for all RTL layouts.

[video width="360" height="760" webm="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-correct-announcing-of-rtl-content.webm" mp4="https://phrase.com/wp-content/uploads/2022/03/android-accessibility-correct-announcing-of-rtl-content.mp4"][/video]

🗒 Note » To test this, go to Settings > Developer Options and enable "Force RTL Layout." This will let you mirror any language to an RTL layout to make it easier for testing.

Wrapping up our Android accessibility tutorial for global apps

In this tutorial, we learned how to use Android Accessibility's Talkback service in app internationalization. By doing so, we made sure that our app is accessible to people with disabilities across locales. Integrating accessibility features into your Android i18n process from the start can lead to higher exposure for our app and ultimately boost your global revenue.

🗒 Note » Learn how to internationalize accessibility features like VoiceOver for iOS apps as well.

As soon as you’ve got your app ready for localization, let your team of translators work with Phrase. The fastest, leanest, and most reliable software localization platform on the market will help you streamline the Android localization process with everything you need to reach a global user base. Sign up for a free 14-day trial and let the team know any questions you might have.

If you want to drill down on Android internationalization even more, we suggest the following guides: