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.
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:
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:
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:
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:
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:
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:
More details can be found here.
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).
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.
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 😉