Hello everyone š
As you might have noticed, I’ve recently decided to take a longer break in DSP competition. Few things to do, Easter in the meantime… but of course I didn’t give up and today I’m back š
In thisĀ post I’d like to show you how do we localize Android apps. Let’s see!
What is localization ?
Generally, localizationĀ is a process of adaptingĀ the product or application to specific markets by adjusting its language and cultural resourcesĀ accordingly.
People often think that localization is only a process of translating documentation and user interface into multiple languages, but in fact it may concern many other not less important topics, e.g. formats of numeric values or dates, currencies, numbers comparison/sorting methods, symbols, national flags or even country-specific law requirements.
Android supports app’s resources localization in pretty easy way. We can quite conveniently provide different versions of strings, images and layouts used in our application for different languages/regions. Let’s take a look atĀ the basics of Android app’s localization.
Android localization basics
InĀ every Android application, localization is based on the language userĀ has set on his/her device. The language can be changed in Settings -> Language & input. Changing the language in this place affects both user interface’s language and region-specific settings (e.g. dates formats).
To retrieve the current locale (constant/object representing selected language) in code the following statement can be used:
var currentLang = Resources.Configuration.Locale;In case user has Polish language set on his/her phone, currentLang variable would contain “pl_PL” locale symbol. For the full list of locales symbols, see for example this list.
Basically, everything that is placed under Resources folder in Android solution can be localized. All of you probably haveĀ values folder in Resources, which contains Strings.xml file. We’ll see more details about this file in a while, but to present the ease of localization to you, it’s enough to create another folder underĀ Resources called e.g.Ā values-pl, which makes retrieving strings from Strings.xml file located in this folder on devices with language set to Polish. Simple as that. The same can be done with every type of resource. It means we can create totally different layouts of our Activities or use different images (e.g. countries’ flags) depending on user’s device’s language.
Strings localization
Strings.xml file
To-be-localized strings (BTW, I think that we should do it straightaway with all strings we use in our app) should be put in values/Strings.xml file, which has the following structure:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="ApplicationName">MoneyBack</string> <string name="titleMenu">Menu:</string> <string name="btnPeople">People management</string> <string name="titleName">Name</string> <string name="titleLastName">Last name</string> <string name="titlePhoneNumber">Phone number</string> <string name="btnSavePerson">Save person</string> <string name="btnPeopleList">List of people</string> <string name="peopleListTitle">List of people</string> </resources> The file is built in accordance with standard XML rules. The name represents Android resource ID (cannot contain any spaces or dashes) to which we will refer from code and other places in order to retrieve the value of this resource, which is placed between “>” and “<” characters.
For instance, first resource from above-pastedĀ Strings.xml hasĀ nameĀ = “ApplicationName” and value = “MoneyBack”.
As mentioned in the previous paragraph, I also created Strings.xml file in values-pl folder, containing the same resources’ Polish translations. The contents of values-pl/Strings.xml file:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="ApplicationName">MoneyBack</string> <string name="titleMenu">Menu:</string> <string name="btnPeople">ZarzÄ dzaj osobami</string> <string name="titleName">ImiÄ</string> <string name="titleLastName">Nazwisko</string> <string name="titlePhoneNumber">Numer telefonu</string> <string name="btnSavePerson">Zapisz osobÄ</string> <string name="btnPeopleList">Lista osĆ³b</string> <string name="peopleListTitle">Lista osĆ³b</string> </resources> Usage in layout files
In our Activities’ layout files (AXML) we can retrieve resources’ values by using @string/id syntax. For example, TextView‘s text can be set in the following way:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<TextView android:text="@string/titleMenu" android:id="@+id/titleMenu" /> It can be used exactly the same way in the UI designer in Visual Studio.
Usage directly in code
In the code we can retrieve values of particular resources using Resources.GetTextĀ method giving it selected resource’s id asĀ Resource.String class’s property:
stringĀ titleMenuText = Resources.GetText(Resource.String.titleMenu);With all strings translated, I can see UI ofĀ MoneyBack translated when my device’s language is set to Polish:
Quantity strings
Very interesting concept are so called quantity strings. It allows to define differently formatted strings depending on a number of some elements determined at runtime. For instance, on the list of people we could have the following strings displayed depending on the number of people:
“There is 1 person in your database.”
“There are 2 people in your database.”
To declare such kind of quantity string, we’d add to Strings.xml the following section:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<plurals name="numberOfPeople"> <item quantity="one">There is %d person in your database.</item> <item quantity="other">There are %d people in your database..</item> </plurals> To illustrate: in order to retrieve and format appropriate string depending on value stored in numPeople variable, the following code might be used:
var text = Resources.GetQuantityString(Resource.Plurals.numberOfPeople, numPeople, numPeople);Second parameter passed is used to determine which string (plural) to use, and third parameter is the actual value passed to the final string (in the place of %d in that case).
TheĀ quantity of each plural can contain one of the following values:
- zero
- one
- two
- few
- many
- other
More details can be found here.
Application’s/Activity’s name
We can also localize the name of our app, by using string resource in the ActivityAttributeĀ defined on MainActivity:
[Activity(Label = "@string/ApplicationName", MainLauncher = true, Icon = "@drawable/icon")]The same can be done for any of our app’s activities. However, be careful here if you are referencing your main Android project from another one (e.g. from tests project) – I’ve experienced really annoying issue with that (more details below).
Other resources
As we already said,Ā not only strings can be localized. You can localize any kind of resources placed within ResourcesĀ folder, for example images or data files.
The file āobj\Debug\android\bin\packaged_resourcesā does not exist
Two weeks ago, when I finally decided to take a break in publishing DSP posts, I wanted to work onĀ MoneyBack a bit, however I encountered very frustrating issue, which I even described in this StackOverflow post. I’ve been fighting with that problem for few days and I still actually don’t know the real causeĀ of the issue.
Basically, when IĀ used resource string on my PeopleListActivity in order to translate its title:
[Activity(Label = "@string/peopleListTitle")]I couldn’t build my MoneyBack.Android.TestsĀ (yes, different project!) project. I was getting the following build error message:
I explored all existing forums threads on this topic and couldn’t resolve this issue. Finally,Ā by setting build output verbosity to
Diagnostic
in Tools -> Options -> Projects and Solutions -> Build and RunĀ I was able to see the detailed error my build process is giving. It was telling me thatĀ @string/peopleListTitleĀ doesn’t exist (or something similar). So when I changed theĀ Label‘s value inĀ ActivityAttribute to use a string directly (not taken as a resource), it worked fine and the build passed.Today I tried once more to use resource string, obviously getting the same error message. Then I realized that my MoneyBack.Android.Tests project is referencing Ā MoneyBack project in which I define those somehow missing strings:
so I removed that reference (commenting out my unit tests which use MoneyBack‘s logic) and the build worked fine. ApparentlyĀ when trying to build tests project, which references the main one, in which my strings are defined, it somehow needs those strings resources to be present in tests project’s output directory.Ā I have no idea why, because I’m not directly using those strings resources in my tests project.
Then I added the reference back and in MoneyBack.Android.Tests project I just created values folder and copy-pasted Strings.xml file to it from the MoneyBack project:
and it builds OK!
Does any of you have some idea why it may happen?Ā If you have a clue, you can answer here or even on SO.
For me it seems like a bug in the build process. I wanted to share it with you, because I wasted so much time because of this issue and maybe some of you will also find it useful.
BTW, I really recommend usingĀ Diagnostic verbosity of the build output for debugging such issues.
Summary
We’ve seen how Android application can be easily localized. I really recommend to put all strings visible for the end user from the beginning in Strings.xml file. Thanks to that, in case our application needs to be localized, we can even hire/ask some foreign languages’ interpreters to create country-specificĀ values folder and translate strings resources conveniently. This is even very common in mobile apps communities, that people who are non-technical can contribute to the project by translating the application into their own language.
I hope I won’t meet any other issues like the one I described today on my further DSP way š It wouldĀ allow me to write more stuff here and hopefully implement some usable app finally! Keep your fingers crossed š
PS: If I already mentioned taking breaks in DSP competition, I will also take one more during the first week of May (1-5.05.2017). In case anyone cares š
Hello Dawid,
To make Android app localization a more streamlined process, I warmly recommend you manage your projects with the localization platform https://poeditor.com
It’s a great collaborative tool with a clean interface and many possibilities to automate the l10n workflow (integrations with Github/Bitbucket/Gitlab, Translation Memory etc.)
Cheers,
Cosette
Hey Cosette,
thank you for this recommendation š Maybe if my app reaches enough popularity one day, I’ll think of making a use of it!
That only shows how important is localization and how community cares about it.
I’m glad I don’t have to care about localization in my current project ;)!
Did you manage to find the cause of the problem you describe at the end of your post?
Hey,
no, I didn’t find the reason behind that error. I don’t get why I cannot build a project, because of missing resources from another project which is only referenced. I will try to explore build’s output once more and if I don’t find anything more, I’ll report a bug to Xamarin, as it seems abnormal.
It is weird indeed. It would understand if you were having issues at runtime, as those resources may be required when the assembly is being loaded. But why it is required at build-time is a mystery. Unless there is a VS service running underneath that needs it for whatever other reason?
Maybe, but I couldn’t check it anyhow. I think I will just report it in some spare time š
I’m glad I don’t have to care about localization in my current project ;)!
Did you manage to find the cause of the problem you describe at the end of your post?
Hey,
no, I didn’t find the reason behind that error. I don’t get why I cannot build a project, because of missing resources from another project which is only referenced. I will try to explore build’s output once more and if I don’t find anything more, I’ll report a bug to Xamarin, as it seems abnormal.
It is weird indeed. It would understand if you were having issues at runtime, as those resources may be required when the assembly is being loaded. But why it is required at build-time is a mystery. Unless there is a VS service running underneath that needs it for whatever other reason?
Maybe, but I couldn’t check it anyhow. I think I will just report it in some spare time š
Hello Dawid,
To make Android app localization a more streamlined process, I warmly recommend you manage your projects with the localization platform https://poeditor.com
It’s a great collaborative tool with a clean interface and many possibilities to automate the l10n workflow (integrations with Github/Bitbucket/Gitlab, Translation Memory etc.)
Cheers,
Cosette
Hey Cosette,
thank you for this recommendation š Maybe if my app reaches enough popularity one day, I’ll think of making a use of it!
That only shows how important is localization and how community cares about it.