Update strings on the fly in mobile applications: part 1



    Introduction


    I will begin my article with a confession: I envy people a little, whose native language is English. In the modern world, it has become the language of international communication, an unwritten standard. Almost any popular application supports English. English-speaking people are unlikely to ever download the long-awaited game from the App Store and were disappointed to understand that it does not support their native language.

    Games and applications are more pleasant and easier to use in their native language, and for some people it is generally the only one available. That is why companies operating in the international market translate their applications into common languages.

    This article is for those developers who have already thought about localizing their application, took the first steps in this direction and stepped on their first rake. In today's article, I will briefly describe approaches to application localization, dwell on client-side localization in more detail, talk about the drawbacks of this approach and suggest a way around them. And in the next part, my colleagues will talk in more detail about the details of the implementation of our approach in mobile OS.

    We have already written about the localization of web applications here .



    Badoo language selection screen

    Localization methods


    Mobile applications from the point of view of the approach to storing strings to be translated can be divided into three groups:

    • all lines come from the server;
    • all lines are stored in the application itself;
    • some of the lines are stored in the application, some come from the server.

    The applications that we develop in Badoo belong to the third group, but the approaches discussed in the article can be successfully applied to the second, provided that the application still has a server part. Therefore, I will devote the article to just such applications.

    Popular mobile operating systems have built-in tools for localizing applications. For example, in Android, you can create a resource file with lines for each of the supported languages, and the OS will automatically select the values ​​for the lines first from the file corresponding to the current locale, and only if there is no such value there (or the file itself is not), it will be rolled back to default file:

    res/values-en-rGB/strings.xml → res/values-en/strings.xml → res/values/strings.xml

    ️ Later in the article I will illustrate what was said with examples for Android, although a similar scheme is used in iOS.

    This method is used in many applications due to its simplicity and convenience. But what is convenient for developers is not always convenient for copywriters and translators. It's hard to imagine a translator who will commit translation changes directly to Git. Therefore, many companies (including, of course, ours) invent their bike systems to simplify the life of translators.

    Advanced localization



    Screenshot from our translation management system

    Let's think about what we would like from such a system.

    • Developers can add new lines to the system in a convenient way for them to develop features.

      Two approaches are possible here: either the developer adds lines to the resource file (that is, directly to the source code), and the system automatically pulls this file to itself and adds the created lines to its database, or vice versa: the developer adds lines to the system database through a convenient interface , and the system then generates resource files for the application and adds them to the source code.
    • Translators in the system see the added lines and can translate them into various languages.

      It is desirable that translators understand the context in which the phrase is used. The best option is a screenshot of the application on which this phrase occurs.
    • The system can work with substitutions, as well as with strings depending on gender and numbers (“You have 1 friend” vs “You have 15 friends”).
    • Translated strings get into the application during the build process.

      Resource files with strings, one for each language (res/values-en-rXX/strings.xml), as well as the default resource file, are automatically generated from finished translations (res/values/strings.xml)- it contains strings that are not translated into any languages ​​in the form in which the developer added them.
    • By the time of release, features are already ready for translations into at least the main languages.

      This is achieved by parallelizing the work of translators and developers. Additional translations may be added in future releases.

    You can read more about our translation system here and here .

    Life after release


    The lines included in the application code have a significant minus: in order to update them, you have to release a new version of the application. Given that sometimes the approval process for a new version can take a week ( hi, Apple! ), This is not always a good option.

    Therefore, the product team needs a way to change text in applications without waiting for release. For example, before Valentine's Day, we changed the text in countries celebrating this day from “Looking for: dates” to “Looking for: Valentine's dates”.

    In addition, there are many other situations where you may need to urgently update translations. It happens that the translated phrase is too long and does not fit in the space allotted to it, because of which the interface partes or the phrase is truncated. Sometimes it happens that the translators misunderstand the context of the phrase, and the translated phrase looks inappropriate. Or, say, in some country a new law governing payments is issued, and you have to change the text on the service payment page.

    Well, it’s not without oddities: in one of our partner projects, during the redesign, we significantly increased the font size of the header for the notification window about a new contact, but did not manage to update the translation. The French word Connexion (Connection) over the image of the new contact was truncated to Con. Those who wish can search for a translation and imagine what the reaction of French users was.

    Of course, such linings require immediate intervention, and you can’t wait a week before the release.

    Applications that receive all the lines from the server instead of using local resources do not have such a problem, but it does not always make sense to drive kilobytes of text through the Network every time, especially if this text rarely changes. In addition, there are applications that should be able to work without being connected to the Network (many games, for example, belong to such applications).

    Hot Update Translation


    Of course, the idea to combine the approaches immediately comes to mind: use local translations stored in the application itself, but be able to update them in the background when there is an Internet connection.

    If you already have a translation system similar to the one I described above, then with minor modifications it can solve this problem. Here are the changes required:

    • The status of transfers at any time should be described by a certain version.
      Each change of translations should upgrade the version (we added a new line to version 25 - we believe that we now have version 26; we translated the line into Portuguese - we upgrade to 27; and so on). This is similar to the behavior of the version control system: changing translations is a commit. In practice, you can build a translation system on top of the version control system and get the described functionality out of the box.
    • The ability to mark versions as "ready for release in production."
      This is not a prerequisite, but very useful. For example, imagine that we decided in the game to rename the heroine: from Anna to make Elena. Obviously, you need to change all the lines where the name occurs, and only after that give the new version of the translation to the release, otherwise it may turn out that some application will receive a non-consistent version of the translation, where in the half of the plot Anna is found, and in the other half Elena . This can be avoided if you make changes to the translations in the general database not in atomic but in large pieces, but then the problem of conflict of changes arises if there are several translators (as it usually happens). On the other hand, a version control system may come in handy here as well.
    • The ability of the system to generate diff between two versions of translations.
      Diffs can be large, and their generation can take a lot of time, so it would be nice to turn up diffs and store ready-made diffs somewhere instead of having them counted on the fly every time.

    A mobile application must know the version of translations that it currently has, and be able to transfer this version to the server at the moment when it has an active connection.

    AppStartup {
        translation_version: , // текущая версия лексем на клиенте
        ... // другие параметры, необходимые на старте приложения
    }
    

    Having received the translation version from the mobile application, the server checks whether the new version is available. If a new version is available, the server checks to see if there is a ready diff between the two versions. If it is not, then a task is created in the diff generation queue (if there is no such task still in the queue, of course).

    When the diff is ready, the server notifies the application that a new version of translations is available. Now the application can request a diff and save it locally.


    Below is an example of what the server response might look like. It includes all the lines (we historically call them “tokens”, although this is not an absolutely correct use of the term), changed from the version that the application currently has.

    Lexemes {
        server_version: , // текущая версия лексем
        lexemes: [
            Lexeme { // простая лексама
                key: "badoocredits.profile.button.topup",
                mode: LEXEME_MODE_SIMPLE,
                value: LexemeValue {
                    text: "Пополнить баланс",
                }
            },
            Lexeme { // лексема, зависящая от числа
                key: "cmd.deleteselected",
                mode: LEXEME_MODE_NUM_DEPENDANT,
                value: LexemeValue {
                    plural_forms: [
                        PluralForm {
                            category: PLURAL_CATEGORY_ZERO,
                            text: "Выберите записи для удаления",
                        },
                        PluralForm {
                            category: PLURAL_CATEGORY_ONE,
                            text: "Удалить %d запись",
                        },
                        PluralForm {
                            category: PLURAL_CATEGORY_TWO,
                            text: "Удалить %d записи",
                        },
                        PluralForm {
                            category: PLURAL_CATEGORY_MANY,
                            text: "Удалить %d записей",
                        },
                    ]
                }
            }
        ]
    }
    

    As you can see, phrases can be simple, but can depend on the number. Number-dependent phrases can use wildcards. For number-dependent strings, we use six forms: zero, one, two, few, many, other.

    Here's how, for example, the phrase “N dogs, N cats” in Welsh (Wales, UK) looks like:



    As you can see, all six forms are used. Read more about this here .

    A / B testing


    The system of updating translations on the fly has another indisputable advantage. In addition to correcting translation errors and solving other problems with localization, we get the opportunity to conduct A / B testing of various translation options.

    Lexemes {
        server_version: , // текущая версия лексем
        lexemes: [
            Lexeme { // лексема с А/Б вариантами
                key: "popularity.share.title",
                mode: LEXEME_MODE_SIMPLE,
                value: LexemeValue { // вариант по-умолчанию
                    text: "Ты популярна!",
                },
                test_id: "popularity_test_android", // серверный id теста
                variations: [
                    LexemeVariation {
                        variation_id: "control",
                        value: LexemeValue {
                            text: "Ты популярна!",
                        }
                    },
                    LexemeVariation {
                        variation_id: "rock",
                        value: LexemeValue {
                            text: "Ты классная!",
                        }
                    },
                    LexemeVariation {
                        variation_id: "cool",
                        value: LexemeValue {
                            text: "Ты крутая!",
                        }
                    },
                ]
            }
        ]
    }

    In the above example, there is the phrase “You are popular!”, Which can be used, for example, as a text in a notification. In order to increase the click rate of this notification, our product team decided to conduct an A / B test and see how the changed text will affect the percentage of clicks on the notification. Without an update system on the fly, the developers of the application would have to set the task, then release a new version (another week of waiting) and only then test it. With the new system, analysts can conduct a test on their own, check the result, and in all applications replace the text with the winning option.

    Conclusion


    Briefly again: if you store translations in the application itself, you lose the ability to quickly change them. We propose the idea of ​​updating translations in the background, which allows you to quickly fix translation errors and test various phrases.

    If our approach interests you and you are already thinking about how to implement it in your application on iOS or Android, then the second part of the article, which we will publish in the near future, is for you. In it, we will tell you how to change your mobile application so that it can use the received diff, but at the same time avoid time-consuming and lengthy rewriting of all the places in the code where translations are used.

    Also popular now: