Localization/Concepts/Non Text Resources
On Localization | Concepts |
Prerequisites | Subversion Ops |
Related Articles | Lbundle Checker |
External Reading | CMake Documentation |
Non-Text Resources To Localize?
In most introductory texts on localization, it will be noted that localization doesn't mean only translation of text, but that other resources too may need to be localized. Starting from KDE 4.1, any external content that a KDE application uses may be localized in a non-intrusive manner.
Typical candidate for localization is text embedded in images: on icons, splash screens, sidebars. Even when the image contains no text, it may be culturally geared towards English-speaking users, and a better locale analogy to achieve the same impact may exist.
Another example would be a set of sound files containing spoken English.
Localization Bundles
Think of an installed KDE application. Its resources that one may want to localize will probably reside in share/ directory of installation prefix. For example, the splash screen of KDingus may be installed like this:
/.../share/kdingus/
pics/
kdingus-splash.png
</syntaxhighlight>
Now, we have prepared the localized splash screen for language aa. Two things need to happen for the localized version to be shown to the user.
First, the localized splash must be installed in l10n/aa subdirectory of the directory where the original splash resides, and with the same name:
/.../share/kdingus/
pics/
kdingus-splash.png
l10n/
aa/
kdingus-splash.png
</syntaxhighlight>
Localized resources organized in this way are called localization bundles, or lbundles for short.
Second, KDingus' code has to fetch the splash screen in one of several standard ways. For example, if KStandardDirs::locate() is used, then it will automatically return the localized resource if there. If the code assembles the path to the resource manually, then passing the finalized path through KLocale::localizedFilePath() will achieve the same effect. (You are reading this in order to be able to point the programmer in the right way, should you discover that the resource is not localizable as is.)
Let's now see how lbundles are supposed to be organized in the repository, so that they get installed correctly.
Inside The Repository
KDE traditionally has two distinct ways of distributing localized data. For the core KDE modules, the localized data is installed by the respective language packs themselves, rather than bundled with the code (which is the case, e.g. for Gnome modules). For non-core modules, e.g. the extragear, applications themselves distribute the localized data, that is bundled with the code.
This dichotomy, which the translations (PO files) follow, necessarily reflects itself on non-text resources as well. Therefore, there are two organizational types of lbundles:
- out-of-source
- lbundles for core modules, residing in respective language directories, and installed by the language pack
- in-source
- lbundles for non-core modules, kept within the application directories and installed by the application itself
Out-of-Source Lbundles
With the current structure of l10n sections of KDE repository, out-of-source boundles are stored within each language's data subdirectory. It is totally up to the language pack how it wants to install the contained lbundles to match the requested installation structure, but the recommendation would be as follows.
Continuing with the KDingus example from above, assuming that it is an app within kdeutils module (i.e. one of the core modules, to which out-of-source lbundles apply). The location of its splash screen in the repository may be as follows:
/trunk/KDE/kdeutils/
kdingus/
CMakeLists.txt
pics/
CMakeLists.txt
kdingus-splash.png
</syntaxhighlight>
where CMakeLists.txt will contain the installation instructions for the splash image. Then, language aa could store the localized splash like this:
/trunk/l10n-kde4/aa/data/kdeutils/
CMakeLists.txt
kdingus/
CMakeLists.txt
pics/
CMakeLists.txt
l10n/
aa/
kdingus-splash.png
</syntaxhighlight>
Observe that the structure of aa/data/kdeutils follows that of the kdeutils module itself, only ending with an l10n/aa lbundle subdirectory. This has advantages that will become apparent later.
The CMakeLists.txt files in language subdirectory, except the last one, are there only to include their subdirs, so that all levels are "connected":
- aa/data/kdeutils/CMakeLists.txt
add_subdirectory(kdingus)
</syntaxhighlight>
and
- aa/data/kdeutils/kdingus/CMakeLists.txt
add_subdirectory(pics)
</syntaxhighlight>
The final CMakeLists.txt is the one that should really install the lbundle. It should match the installation instructions of the original resource, and some typicall examples are given below. Also, exactly which CMakeLists.txt is the final one (how deep in subdirectory structure), depends on exact installation instructions.
In-Source Lbundles
Apps outside of core modules have to fetch the PO files from language folders, because they must distribute them bundled with the application package. So far this has shown not to be quite straightforward for application maintainers. This is why the lbundles intended for these apps are to be kept within the app itself, i.e. in-source: non-text resources that need localization should be infrequent, so maintainers shouldn't be burdened by yet another set of protocols to follow wrt. l10n.
Assume now that KDingus is an extragear app, thus having this structure in the repository:
/trunk/extragear/utils/
kdingus/
CMakeLists.txt
pics/
CMakeLists.txt
kdingus-splash.png
</syntaxhighlight>
If the languages aa and bb have prepared localized splashes, the lbundle will be stored within KDingus' data like this:
/trunk/extragear/utils/
kdingus/
CMakeLists.txt
pics/
CMakeLists.txt
kdingus-splash.png
l10n/
aa/
kdingus-splash.png
bb/
kdingus-splash.png
</syntaxhighlight>
Before committing the localized data in this scenario, the language coordinator should inform the maintainer of KDingus. Especially when it is the first localized version of a particular original resource, i.e. there is a need to create the l10n/ subdirectory itself.
The installation instructions for the lbundle are now the responsibility of the app maintainer. But given that he knows his app's CMakeLists.txt files, it should be fairly straightforward for the maintainer to add additional instructions. Of course, a patch from a techy-minded translator will not hurt either.
CMake Installation Instructions
There are several characteristic ways in which KDE apps install their resources using CMake, the build system of KDE4. These are presented here, with the counterparts to install out-of-source or in-source lbundles.
Specific Files
Our KDingus may install its splash screen by specifically instructing the image file to be installed. The installation instruction would then reside in the CMakeLists.txt on the same level as the image file:
kdingus/
pics/
CMakeLists.txt
kdingus-splash.png
</syntaxhighlight>
and would contain something like:
install(FILES kdingus-splash.png
DESTINATION ${DATA_INSTALL_DIR}/kdingus/pics)
</syntaxhighlight>
In that case, the corresponding CMakeLists.txt for out-of-source lbundle (in aa language data directory), in the same relative position, would contain:
install(FILES l10n/aa/kdingus-splash.png
DESTINATION ${DATA_INSTALL_DIR}/kdingus/pics/l10n/aa)
</syntaxhighlight>
Complete Directories
If there are more images, KDingus may very well install the whole pics/ subdirectory using single install instruction in the CMakeLists.txt one level above:
kdingus/
CMakeLists.txt
pics/
kdingus-splash.png
kdingus-foo.png
kdingus-bar.png
...
</syntaxhighlight>
which would look like:
install(DIRECTORY pics
DESTINATION ${DATA_INSTALL_DIR}/kdingus
PATTERN .svn EXCLUDE)
</syntaxhighlight>
The corresponding CMakeLists.txt in out-of-source lbundle, again in same relative position, would then contain exactly the same instruction (providing the tree structure is as in the example for out-of-source lbundles).
Furthermore, if the lbundles are in-source and the complete directory is installed like this, then the application maintainer needn't modify existing CMakeLists.txt at all to accomodate installation of lbundles.
Icons
To install icons in full accordance with the specs is not exactly trivial, so KDE provides a custom CMake macro for application maintainers to use when installing icons. Such spec-conformant icons will look like:
kdingus/
icons/
CMakeLists.txt
hi16-app-kdingus.png
hi32-app-kdingus.png
hi48-app-kdingus.png
...
</syntaxhighlight>
and can be recognized by the initial prefix-size pattern. To install them, CMakeLists.txt will contain a terse instruction like this:
kde4_install_icons(${DATA_INSTALL_DIR}/kdingus/icons)
</syntaxhighlight>
which selects true installation paths and modifies icon file names when installed.
To properly install localized versions of such icons, the structure of the lbundle should be:
...
l10n/
CMakeLists.txt
aa/
CMakeLists.txt
hi16-app-kdingus.png
hi32-app-kdingus.png
hi48-app-kdingus.png
...
</syntaxhighlight>
regardless if out-of-source or in-source, and the final CMakeLists.txt should use the same instruction as for the original icons, but with language code as second argument:
kde4_install_icons(${DATA_INSTALL_DIR}/kdingus/icons aa)
</syntaxhighlight>
(the above-level CMakeLists.txt files just include their subdirectories for proper connection, as usual).
Keeping Localized Resources In Sync
To localize and prepare an lbundle for installation is the main part of the job, but same as with messages in PO files, at some point later the original resource may be modified, moved, or deleted. To be able to react accordingly, there is a special script on translator's disposal to track the state of lbundles against the original. Head to its article for further instructions.
Be sure to keep the "source" files for non-text resources in the repository too. For some resources, the source will be one of the files in the lbundle itself; e.g. for an icon, this is its scalable variant in SVG vector format (as opposed to different-sized bitmap PNGs), which is also installed. If this is not the case, keep the files needed to produce the final localized resource somewhere in the internal/ subdirectory of your language directory. This subdirectory is specifically excluded from packaging, so in it you can keep all internal files pertinent to localization effort of your team.