Skip to content

Localization in RescueMe

Kenneth Gulbrandsøy edited this page Aug 3, 2014 · 24 revisions

RescueMe is localized using the gettext extension. Gettext is a much-used and well-known method of localization, which depends on *.PO files. For compatibility reason, php-gettext is used in font of the raw gettext extension, which have the same API, and the ability to read MO files ("compiled" PO-files) even when gettext is not compiled in or when appropriate locale is not present on the system.

###Recommended editor

It is recommended that developers use the free and easy-to-use PoEdit to edit PO-files. Windows and OSX users can download the binaries from the PoEdit homepage. Linux users could install directly from source, or install any version available from upstream repositories.

PoEdit is able to analyze source code by looking for all occurrences from a given set of localization functions. The string argument to these functions are the words and sentences which should be localized into other languages. The editor is able to analyze these and present a list of unique words and sentences, which make maintenance easier. RescueMe source code is in English, so the default locale is en_US.

The editor stores all localized string and meta information in PO-files, one for each language. Each PO-file is maintained by PoEdit by recursively inspecting source code in at one or more folders relative to a base path. The base path is stored in each PO-file as a custom PO-file parameter, X-Poedit-Basepath.

Each time you change a localized string in a folder associated with the PO-file, you have to click Update in the editor. New or modified localized string (identifiers) are detected automatically, and if possible, translated automatically using already translated text. When you click Save in the editor. PoEdit generates a MO-file in same locating as the PO-file.

Important

There is however one unfortunate shortcoming. The editor only understands absolute base paths, which makes is a little cumbersome for several developers to maintain these files concurrently. Since base paths are stored in each PO-file, any developer attempting to update the PO-file first have to change the to a base path which matches the local repository location.

###File structure in ResuceMe

There are already hundred of single words and longer sentences in the source code. Words and sentences are added and modified continuously, which makes it a big job to maintain many languages. Even a change of case in a word, or comma in a sentence, produce a new text identifier, which in most cases breaks any former translations, forcing the system to default to en_US for that identifier. With the number of strings we have already, it is important to be able to prioritize between the important and less-important ones.

RescueMe is divided into two logically different parts, an admin interface (operations) and a trace interface (mobile being traced). Both interfaces share some common strings, but for the most part, strings are different. The number of strings in the admin interface greatly outnumbers the trace interface. On the other hand, the number of languages we ultimately need to support in each interface is opposite. We should ideally support all languages in the trace interface to ensure that every user mobile user in the world is able to understand the messages from RescueMe. But we do not need to do the same with the admin interface. If we chose to use only a single PO-file, it would become very cumbersome to maintain 150+ languages when only a small number of strings need translation to each language.

This distinction led to the following localization file structure:

RescueMe locale

src/locale/
├── domain
│   └── common.domain.php
├── locales
│   └── locales.php
└── nb_NO
    └── LC_MESSAGES
        ├── admin.mo
        ├── admin.po
        ├── common.mo
        ├── common.po
        ├── locales.mo
        ├── locales.po
        ├── sms.mo
        ├── sms.po
        ├── trace.mo
        └── trace.po

where nb_NO is the Norwegian translation of RescueMe.

Admin interface

src/admin/locale/
├── admin.domain.json
├── admin.domain.php
└── translate.json.php

Trace interface

src/trace/locale/
└── trace.domain.php

SMS messages

src/sms/locale/
└── sms.domain.php

Each domain contains all localized strings defined as constants. This simplifies the reuse of common words and sentences throughout the application. There are four domains in total

  • common: Domain shared by all other domains. This domain is loaded for all interfaces.
  • admin: Domain loaded for the admin interface.
  • trace: Domain loaded for the trace interface.
  • sms: Domain loaded for all interfaces.

Domains are loaded using the function set_system_locale(string $domain, string $locale), which loads the associated domain file(s).

###PO-files

There is one PO-file for each domain, and each PO-file is associated with a base path and one or several folders relative to this path.

File Folders
admin.po admin Admin interface
trace.po trace Trace interface
sms.po sms Shared SMS messages
common.po locale/domain Common to all domains
locales.po locale/locales Localized locale names