Ein Grundpfeiler unserer Dienstleistung ist die Entwicklung von Apps für iOS und Android. Die meisten Projekte entstehen zeitgleich für beide Plattformen. Eine Herausforderung hierbei ist die Lokalisierung von Texten bzw. deren Synchronisierung. Die Texte werden für iOS in einer Localizable.strings und für Android in einer strings.xml gehalten, wobei sich Format und Featureset grundlegend unterscheiden.

// iOS: Localizable.strings
"name" = "Name";
"placeholder" = "Placeholder: %@";

// Android: strings.xml
<resources>
    <string name="name">Name</string>
    <string placeholder="placeholder">Placeholder: %s</string>
</resources>

Wie die meisten Entwickler begannen wir mit einer nativen Implementierung der Texte von Hand, d.h. unabhängig von der jeweils anderen Plattform. Dies führte früher oder später zu Ungereimtheiten zwischen den Übersetzungen, weil Texte entweder unterschiedlich lokalisiert oder später nicht nachgezogen wurden. Dieses Problem haben wir mit einem Java-basierten Skript behoben, welches die Texte aus einer .csv Datei in die Localizable.strings bzw. strings.xml überführt. Dieses Skript wurde in jedes neue Projekt kopiert und üblicherweise im Repository des Android-Pendants gelagert. Für neue Texte wurde das Skript neu ausgeführt und die generierten Dateien entweder manuell (iOS) oder automatisch ins entsprechende Verzeichnis kopiert (Android).

Die bisher beschriebenen Lösungen sind aufwändig und eng an die Entwicklungsumgebung gebunden, weshalb dritte Personen ausgeschlossen sind. Unser nächster Schritt war also, diesen Prozess weiter zu automatisierten und an eine externe Plattform auszulagern. Externe Dienste wie lokalise oder applanga unterstützen Continuous Localization, heben sich im Preismodell oder ihrer Funktionalität mitunter jedoch stark von uns oder unseren Kunden ab.

Aus diesem Grund arbeiteten wir an einer weiteren In-House-Lösung und stießen bald auf einen Artikel namens “How We Deal with Localizing iOS and Android Apps”, in dem beschrieben wird, wie man Google Sheets als Repository für Lokalisierungen nutzt. Die Logik hierfür wird in einem Google Apps Script hinterlegt, welches man an die entsprechende Lokalisierungstabelle hängt. Auf Knopfdruck entstehen so die benötigten Localizable.strings und strings.xml, welche man nur noch ins lokale App Projekt kopieren braucht. Diese Lösung entkoppelt den Lokalisierungsmechanismus vom Quellcode der App Projekte und bietet jedem externen Übersetzer einfachen Schreib- und Lesezugriff auf die intern verwendeten Texte.

Es besteht noch ein einziger großer Nachteil: für Entwickler bleibt der Prozess aufwändig und über mehrere Anwendungen verteilt. Dieses Problem haben wir mit einem Plugin behoben, welches die Lokalisierungen über die Google Sheets API synchronisiert und die lokalen Textdateien ersetzt. Diese Lösung wurde als Java-Modul implementiert und erfolgreich via Gradle in das Buildskript für Android integriert. Für andere Plattformen sehen wir ein ebenso großes Potential, solange sich die entstandene .jar in den Buildprozess auf der entsprechenden Plattform integrieren lässt. Diese Lösung behebt auch das Problem der Codeduplikation, da das Skript nicht mehr wie zuvor für jedes Projekt kopiert werden muss, sondern als Abhängigkeit eingebunden werden kann.

 Icons made by  Smashicons  from  www.flaticon.com  is licensed by  CC 3.0 BY

Icons made by Smashicons from www.flaticon.com is licensed by CC 3.0 BY

Das Gradle Plugin erstellt einen Gradle Task, hinter dem sich der eigentliche Synchronisierungsalgorithmus verbirgt. Wenn ausgeführt, fordert dieser die Lokalisierungstabellen über die Google Sheets API an und übersetzt das erhaltene JSON in XML, welches in den lokalen strings.xml geschrieben bzw. überschrieben wird. Der Entwickler verlässt während des gesamten Prozesses nicht seine Entwicklungsumgebung und kann losgelöst vom Übersetzungsprozess arbeiten. Der Übersetzer wiederum arbeitet ausschließlich in den Tabellen von Google Sheets und benötigt weder Entwicklungsumgebung noch Kenntnisse in den Formaten der plattformspezifischen Textdateien.

Eine Herausforderung während der Entwicklung des Gradle Plugins war die Verwendung von Kotlin, dessen Klassen out-of-the-box nicht referenziert werden können (Class not found). Ein Workaround war das Verfassen der Einstiegspunkte in Java, bevor diese - dank der Interoperabilität beider Sprachen - auf den Rest des Projekts zugreifen. Wir sind jedoch guter Dinge, dass sich dieses Mysterium noch lösen lässt.

Mit den beschriebenen Lösungen haben wir unseren Lokalisierungsprozess kontinuierlich verbessert bis zu dem Punkt, an dem die Einrichtung eines neuen oder die Lokalisierung eines bestehenden Projekts nur wenige Sekunden in Anspruch nimmt. Jetzt gilt es noch, die Synchronisierung auf iOS zu übersetzen und den Mechanismus produktiv auszurollen. Was danach kommt, wird die Zukunft zeigen.