For most of our cross-platform code our Gettext-based KF::I18n Framework takes care of translating user-readable texts on Android as well. It doesn’t cover Android-specific files and/or Android-native code though. Fortunately it’s not hard to integrate that with KDE’s translation infrastructure as well.

Marking strings for translation

For Android’s translation system all messages needing localization have to be put into the res/values/strings.xml file and are assigned translation ids there.

<?xml version='1.0' encoding='utf-8'?>
<resources>
    <string name="application_name_full">KDE Itinerary</string>
    <string name="application_name_short">Itinerary</string>
    <string name="shortcut_label_current_ticket_short">Current Ticket</string>
    ...
</resources>

Messages can then be referenced by their translation id, both in Java code and the various XML files including the Android manifest. The latter is probably the more commonly needed case for KDE’s apps, which have typically fairly little code written in Java directly.

In XML files those strings can then referenced using the @string/<translation_id> notation:

<application
    android:name="org.qtproject.qt5.android.bindings.QtApplication"
    android:label="@string/application_name_full"
    android:icon="@mipmap/ic_launcher">
    <activity android:name="org.kde.itinerary.Activity"
              android:label="@string/application_name_short">
    ...

In Java code, those messages are accessible via the getString method in android.content.Context and using the translation id constants R.string.<translation_id>.

Translation infrastructure integration

For KDE’s translation infrastructure to pick this up, a file named StaticMessages.sh is needed in the project root directory. It’s used by the nightly translation run to extract and merge translations that are stored in their own format rather than the usual Gettext catalogs.

Using the following template only two paths need to be adjusted to the respective project:

#!/usr/bin/env bash

# the name of catalog we create (without the.pot extension)
FILENAME="your-catalog-name"
# relative path to the Android resource folder
ANDROID_RES_DIR="src/app/android/res"

function export_pot_file
{
    mkdir outdir
    ANSI_COLORS_DISABLED=1 a2po export --android $ANDROID_RES_DIR --gettext outdir
    mv outdir/template.pot $1
    rm -rf outdir
    rm -f rc.cpp
}

function import_po_files
{
    podir=$1
    find "$podir" -type f -name "*@*.po" -delete
    find "$podir" -name '*.po' -exec msgattrib --no-obsolete -o {} {} \;
    ANSI_COLORS_DISABLED=1 a2po import --ignore-fuzzy --android $ANDROID_RES_DIR --gettext $podir
}

See e.g. KDE Itinerary’s StaticMessages.sh for a full example.

After adding that file you should see translated strings.xml variants starting to appear within a few days.