Most popular softwares are available in multiple languages, and that is awesome: you are a native Spanish speaker, you can use Microsoft PowerPoint in Spanish, that’s it. But when it’s your turn to deliver a new innovative software, you rarely think of the translation of its user interface as a primary goal. You focus on impacting features and working code. Indeed, this is what matters the most in the initial stages of the lifecycle. If the software is natively supporting English, it takes even longer to consider supporting other languages because its use is widespread.
English Localization
As UpSlide was first available in French, its growing success quickly required English support to expand abroad. The translation was thought to be a onetime effort and needed to be carried out swiftly with a low development cost.
At that time, strings were stored in the code in two different ways: one using fields, the second using ResX
resource files¹; and so, the translation was made in one of these formats without changing the architecture of the code.
For fields, the migration consisted in making their static constructors initialize strings to the relevant language on startup. It was quite straightforward, but a huge work, nonetheless.
public static class SettingsMessages
{
public static string WindowTitle { get; private set; }
public static void Localize(CultureInfo culture)
{
switch(culture)
{
case SupportedCultures.English:
WindowTitle = "Settings";
break;
case SupportedCultures.French:
WindowTitle = "Paramètres";
break;
default:
throw new ArgumentException($"Unknown culture: {culture}");
}
}
}
For ResX
files, it was even simpler. Thanks to its .NET
native internationalization support, it is possible to have multiple ResX
files with a language suffix such as Ribbon.en.resx
for a localization of Ribbon.resx
. The content of the English version is then stored in a satellite assembly and retrieved at runtime if the culture of the resource is set to en
or any region for this language, such as en-US
for instance.
public static class Resources
{
public static void Localize(CultureInfo culture)
{
Ribbon.Culture = culture;
}
}
French was kept as the default language to allow for incremental translation. The transition was thus an easy, but painstaking process of translations and reviews (our product team had professional proficiency in both languages).
The result worked wonders. It has supported the company's continuous success in expanding to other countries all over the world for about a decade. So, it could very much have been the end of the story.
German Office Called: Katastrophe…
But it was not going to be enough; English is not the only widespread professional language after all. According to a Babel article, less than 20% of the world speaks it. Some German clients even bought the solution under the assumption that the software would be available in German — this is because UpSlide also has an office in Germany. It seemed obvious to them but not us: the English translation had worked so well so far; we didn’t think it'd require further work.
Besides hindering future sales, missing a translated language could slow down product adoption in other countries as well. Indeed, although some French users can use English, they most often prefer to use the French version… The conclusion was simple: the software must be ready to be translated to other languages.
So far, only two languages were dealt with, and they were fairly similar. As a result, the methods used to add English would not necessarily be replicable, and translating to other, potentially very different, languages was unknown territory. In particular, pluralization and average word length could differ and impact both the code structure and the visual rendering. Also, it may not be spoken fluently by people in charge of string editions, namely product engineers and managers, so it was not very clear how the actual translation would take place.
Internationalization & Localization
According to Wikipedia, “Internationalization is the process of designing a software application so that it can be adapted to various languages and regions without engineering changes. Localization is the process of adapting internationalized software for a specific region or language by translating text and adding locale-specific components”.
Internationalization is complex because it has to bend a formal language to be able to display natural languages, with a common interface for all supported locales. It is also not just about the language in which an application is displayed but also involves reworking on the graphical user interface to accommodate for different writing directions, strings length, buttons’ locations, and color schemes.
GNU brilliantly solved part of the problem with gettext
for textual changes. One program extracts the strings in the default language from the code itself. Another manipulates those for each language. The last one retrieves the correct string depending on the localization at runtime. In particular, gettext
handles pluralization in a very smart and efficient way for any type of language, especially those for which more than two plural forms exist.
# Ukrainian has 3 plural forms:
# nplurals=3
# The plural form (the index in the msgstr array) is determined by the following expression:
# plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2)
msgid "%d constructor found\n" # Singular in English
msgid_plural "%d constructors found\n" # Plural in English (to indicate the pluralized content to the translator - 'constructors' here)
msgstr[0] "%d конструктор знайдено\n" # Singular nominative form for numbers ending in 1 (except 11)
msgstr[1] "%d конструктори знайдено\n" # Plural nominative form for numbers ending in 2, 3, and 4 (except 12, 13, and 14)
msgstr[2] "%d конструкторів знайдено\n" # Plural genetive form for all other numbers
Regarding graphical user interfaces, solutions are most commonly handcrafted depending on the application. However, WinForm
properties such as the size of graphical elements can be adjusted through properties defined in ResX
files. It is also possible to do the same for WPF
elements, even without using the designer.
Localization is challenging because it requires synchronisation between the product and developer teams. Many solutions exist to provide online localisation services supporting various input formats such as GNU gettext
and ResX
files. But a strong requirement, the code should not leave the company’s premises, removed almost all available solutions. Not to mention that they were also quite expensive. Weblate
on the other hand combines the advantages of being free and self-hosted. The code would not have to leave the premises, and support is affordable.
Remaining Pragmatic
There are a couple of NuGet packages out there to harness the cleverness of gettext
in .NET
. However, integration required additional dependencies, both for compilation and runtime, and resulted in a more complex and less stable build. The approach was thus deemed unfit for our .NET
Framework projects.
Besides technical challenges, the long-term target languages did not have more than two plural forms. These targeted languages were carefully identified with a high return on investment and limited expected graphical user interface modifications. To achieve the transition, all static strings had to be migrated to ResX
files and plurals had to be handled by a method similar to ngettext
.
Of course, this migration had a big impact. But it was still costly to add and edit strings both because the code had to be edited but also because product and developer teams needed synchronization. This is where Weblate
and continuous translation brought the solution to yet another level. It allows many within the company to engage in the translation process. All in a shared and constant environment. Translations can be peer-reviewed, and developers do not have to worry too much about them either, freeing up some time and reducing friction in the whole development process. Subcontractors can also be involved to translate to languages that are not mastered within the company.
Building on the previous success of the incremental translation to English, the migration is also incremental. The technical solution is ready, and we can already start translating to other languages. This makes the company a little more resilient against new language requirements and a little more ready for future challenges.
¹ A ResX file is an XML description of resources. Some, such as strings, are directly contained verbatim, while others are a pointer to any type of files, most notably icons, images, and audio files. Those files, along with an internal representation of the XML file, are embedded in the final assembly so that those resources can be retrieved in two convenient ways at run time. First, using a resource manager that loads the assembly, locates the resource and returns it. Second, having a single file generator wrap the resource file within a generated class with properties corresponding to each resource.
Top comments (0)