Lokalisierung von Anwendungen in iOS
Teil 1. Was haben wir?
Handbuch für lokalisierte Zeichenfolgenressourcen
Einführung
Vor einigen Jahren tauchte ich in die magische Welt der iOS-Entwicklung ein, die mir mit all ihrer Essenz eine glückliche Zukunft im Bereich der IT versprach. Als ich mich jedoch eingehend mit den Funktionen der Plattform und der Entwicklungsumgebung befasste, hatte ich viele Schwierigkeiten und Unannehmlichkeiten bei der Lösung scheinbar sehr trivialer Aufgaben: Apples „innovativer Konservatismus“ macht Entwickler manchmal sehr anspruchsvoll, um den ungezügelten „I WANT“ -Kunden zufrieden zu stellen.
Eines dieser Probleme ist das Problem der Lokalisierung der Zeichenfolgenressourcen der Anwendung. Ich möchte diesem Problem einige meiner ersten Veröffentlichungen über die Weiten von Habr widmen.
Anfangs hatte ich gehofft, meine Gedanken in einen Artikel zu integrieren, aber die Menge an Informationen, die ich präsentieren möchte, war ziemlich groß. In diesem Artikel werde ich versuchen, die Essenz von Standardmechanismen für die Arbeit mit lokalisierten Ressourcen aufzudecken, wobei einige Aspekte im Vordergrund stehen, die von den meisten Handbüchern und Tutorials vernachlässigt werden. Das Material richtet sich in erster Linie an Anfänger (oder diejenigen, die auf solche Aufgaben nicht gestoßen sind). Für erfahrene Entwickler sind diese Informationen möglicherweise nicht besonders wertvoll. Aber über die Unannehmlichkeiten und Nachteile, die in der Praxis auftreten können, werde ich in Zukunft berichten ...
Out of the Box. Wie die Speicherung von Zeichenfolgenressourcen in iOS-Anwendungen organisiert ist
Zunächst stellen wir fest, dass das Vorhandensein von Lokalisierungsmechanismen in der Plattform bereits ein großes Plus ist, weil Spart dem Programmierer zusätzliche Entwicklung und legt ein einziges Format für die Arbeit mit Daten fest. Und oft reichen die grundlegenden Mechanismen für die Umsetzung relativ kleiner Projekte aus.
Welche Möglichkeiten bietet uns Xcode "out of the box"? Schauen wir uns zunächst den Standard zum Speichern von Zeichenfolgenressourcen in einem Projekt an.
In Projekten mit statischem Inhalt können Zeichenfolgendaten direkt in der Benutzeroberfläche ( .storyboard
und .xib
Markup-Dateien, die wiederum XML-Dateien sind, die mit Interface Builder- Tools gerendert werden) oder im Code gespeichert werden. Der erste Ansatz ermöglicht es uns, den Prozess des Markierens von Bildschirmen und einzelnen Anzeigen zu vereinfachen und zu beschleunigen Der Entwickler kann den größten Teil der Änderung beobachten, ohne die Anwendung zu erstellen. In diesem Fall ist es jedoch nicht schwierig, auf Datenredundanz zu stoßen (wenn derselbe Text von mehreren Elementen verwendet wird, werden Anzeigen angezeigt). Der zweite Ansatz beseitigt lediglich das Problem der Datenredundanz, führt jedoch dazu, dass Bildschirme manuell IBOutlet
werden müssen (indem zusätzliche IBOutlet
und ihnen entsprechende IBOutlet
werden), was wiederum zu Code-Redundanz führt (natürlich in Fällen, in denen der Text dies IBOutlet
sollte) direkt durch den Anwendungscode installiert werden).
Darüber hinaus bietet Apple eine Standard-Dateierweiterung .strings
. Dieser Standard regelt das Format zum Speichern von Zeichenfolgendaten in Form eines assoziativen Arrays ( "-"
):
"key" = "value";
Der Schlüssel unterscheidet zwischen Groß- und Kleinschreibung und ermöglicht die Verwendung von Leerzeichen, Unterstrichen, Satzzeichen und Sonderzeichen.
Es ist wichtig zu beachten, dass Strings- Dateien trotz der einfachen Syntax regelmäßige Fehlerquellen beim Kompilieren, Zusammenstellen oder Betreiben einer Anwendung sind. Dafür gibt es mehrere Gründe.
Erstens Syntaxfehler. Fehlende Semikolons, Gleichheitszeichen, zusätzliche oder nicht angeführte Anführungszeichen führen unweigerlich zu einem Compilerfehler. Darüber hinaus zeigt Xcode auf die Datei mit dem Fehler, hebt jedoch nicht die Zeile hervor, in der etwas nicht stimmt. Das Auffinden eines solchen Tippfehlers kann einige Zeit in Anspruch nehmen, insbesondere wenn die Datei eine erhebliche Datenmenge enthält.
Zweitens die Vervielfältigung von Schlüsseln. Die Anwendung stürzt natürlich nicht ab, aber dem Benutzer werden möglicherweise falsche Daten angezeigt. Die Sache ist, dass beim Zugriff auf eine Zeile für Schlüssel der Wert, der dem letzten Vorkommen des Schlüssels in der Datei entspricht, abgerufen wird.
Ein einfaches Design erfordert daher, dass der Programmierer beim Füllen von Dateien mit Daten sehr gründlich und aufmerksam ist.
Sachkundig Entwickler können sofort ausrufen: "Aber was ist mit JSON und PLIST? Was haben sie nicht gefallen?" Erstens sind JSON
und PLIST
(in der Tat gewöhnliches XML
) universelle Standards, mit denen sowohl Zeichenfolgen als auch numerische, logische ( BOOL
), binäre Daten, Uhrzeit und Datum sowie Sammlungen gespeichert werden können - indiziert ( Array
) und assoziativ ( Dictionary
) Arrays. Dementsprechend ist die Syntax dieser Standards gesättigter und daher leichter zu knabbern. Zweitens ist die Verarbeitungsgeschwindigkeit solcher Dateien aufgrund der komplexeren Syntax etwas niedriger als die der Strings-Dateien. Dies ist nicht zu erwähnen, dass Sie eine Reihe von Manipulationen im Code vornehmen müssen, um mit ihnen zu arbeiten.
Lokalisiert, lokalisiert, aber nicht lokalisiert. Lokalisierung der Benutzeroberfläche
Nachdem die Standards herausgefunden wurden, wollen wir nun herausfinden, wie man alles benutzt.
Lass uns in Ordnung gehen. Erstellen Sie zunächst eine einfache Einzelansicht- Anwendung und fügen Sie dem Main.storyboard auf dem ViewController einige Textkomponenten hinzu .

Der Inhalt wird in diesem Fall direkt in der Schnittstelle gespeichert. Um es zu lokalisieren, müssen Sie Folgendes tun:
1) Gehen Sie zu den Projekteinstellungen

2) Dann - vom Ziel zum Projekt

3) Öffnen Sie die Registerkarte Info

Im Bereich Lokalisierungen sehen wir sofort, dass wir bereits den Eintrag "Englisch - Entwicklungssprache" haben . Dies bedeutet, dass Englisch als Entwicklungssprache (oder Standard) festgelegt ist.
Fügen wir jetzt eine weitere Sprache hinzu. Klicken Sie dazu auf " + " und wählen Sie die gewünschte Sprache aus (zum Beispiel habe ich Russisch gewählt). Caring Xcode bietet uns sofort die Möglichkeit, die zu lokalisierenden Dateien für die hinzugefügte Sprache auszuwählen.

Klicken Sie auf Fertig stellen , um zu sehen, was passiert ist. Im Projektnavigator wurden Schaltflächen zum Anzeigen der Verschachtelung in der Nähe der ausgewählten Dateien angezeigt. Wenn Sie darauf klicken, sehen Sie, dass die zuvor ausgewählten Dateien die erstellten Lokalisierungsdateien enthalten.

Beispielsweise ist Main.storyboard (Base)
die Standard-Schnittstellen-Markup-Datei in der Main.storyboard (Base)
, und beim Bilden der Lokalisierung wurde die zugehörige Main.strings (Russian)
paarweise erstellt - eine Zeichenfolgendatei für die russische Lokalisierung. Wenn Sie es öffnen, sehen Sie Folgendes:
/* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */ "tQe-tG-eeo.text" = "Label"; /* Class = "UITextField"; placeholder = "TextField"; ObjectID = "cpp-y2-Z0N"; */ "cpp-y2-Z0N.placeholder" = "TextField"; /* Class = "UIButton"; normalTitle = "Button"; ObjectID = "EKl-Rz-Dc2"; */ "EKl-Rz-Dc2.normalTitle" = "Button";
Hier ist im Allgemeinen alles einfach, aber der Klarheit halber werden wir dies genauer betrachten und dabei auf die Kommentare achten, die durch den fürsorglichen Xcode generiert werden:
/* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */ "tQe-tG-eeo.text" = "Label";
Hier ist eine Instanz der UILabel
Klasse mit dem Wert "Label"
für den UILabel
. ObjectID
- die Kennung des Objekts in der Markup-Datei - Dies ist eine eindeutige Zeile, die jeder Komponente zum Zeitpunkt der Platzierung auf dem Storyboard/Xib
zugewiesen wird. Aus der ObjectID
und dem Parameternamen des Objekts (in diesem Fall text
) wird der Schlüssel gebildet, und der Datensatz selbst kann formal wie folgt interpretiert werden:
Setzen Sie den Textparameter des tQe-tG-eeo-Objekts auf Label.
In diesem Datensatz kann sich nur der „ Wert “ ändern. Ersetzen Sie " Label " durch " Label ". Wir werden dasselbe mit anderen Objekten machen.
/* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */ "tQe-tG-eeo.text" = ""; /* Class = "UITextField"; placeholder = "TextField"; ObjectID = "cpp-y2-Z0N"; */ "cpp-y2-Z0N.placeholder" = " "; /* Class = "UIButton"; normalTitle = "Button"; ObjectID = "EKl-Rz-Dc2"; */ "EKl-Rz-Dc2.normalTitle" = "";
Wir starten unsere Anwendung.

Aber was sehen wir? Die Anwendung verwendet die grundlegende Lokalisierung. Wie kann ich überprüfen, ob wir die Überweisung korrekt durchgeführt haben?
Hier lohnt es sich, einen kleinen Exkurs zu machen und ein wenig in Richtung der Funktionen der iOS-Plattform und der Anwendungsstruktur zu graben.
Ziehen Sie zunächst in Betracht, die Struktur des Projekts beim Hinzufügen der Lokalisierung zu ändern. So sieht das Projektverzeichnis aus, bevor die russische Lokalisierung hinzugefügt wird:

Und so danach:

Wie wir sehen können, hat Xcode ein neues Verzeichnis ru.lproj
, in dem die erstellten lokalisierten Zeichenfolgen abgelegt wurden.

Und wo ist die Struktur des Xcode-Projekts für die fertige iOS-Anwendung? Und trotz der Tatsache, dass dies hilft, die Funktionen der Plattform sowie die Prinzipien der Verteilung und Speicherung von Ressourcen direkt in der fertigen Anwendung besser zu verstehen. Unter dem Strich überträgt die Umgebung beim Zusammenstellen eines Xcode-Projekts zusätzlich zum Generieren einer ausführbaren Datei Ressourcen (Layoutdateien der Storyboard / Xib- Schnittstelle, Bilder, Zeilendateien usw.) an die fertige Anwendung, wobei die in der Entwicklungsphase angegebene Hierarchie beibehalten wird.
Um mit dieser Hierarchie arbeiten zu können, stellt Apple die Bundle(NSBundle)
Klasse Bundle(NSBundle)
( kostenlose Übersetzung ) zur Verfügung:
Apple verwendet das Bundle
, um Zugriff auf Anwendungen, Frameworks, Plugins und viele andere Arten von Inhalten zu gewähren. Bundles organisieren Ressourcen in klar definierten Unterverzeichnissen, und Bundle-Strukturen variieren je nach Plattform und Typ. Mit dem bundle
können Sie auf die Ressourcen eines Pakets zugreifen, ohne dessen Struktur zu kennen. Bundle
ist eine einzige Schnittstelle für die Suche nach Elementen unter Berücksichtigung der Paketstruktur, der Benutzeranforderungen, der verfügbaren Lokalisierungen und anderer relevanter Faktoren.
Suche und Entdeckung einer Ressource
Bevor Sie mit einer Ressource arbeiten, müssen Sie deren bundle
angeben. Die Bundle
Klasse hat viele Konstruktoren, aber main wird am häufigsten verwendet. Bundle.main
bietet einen Pfad zu Verzeichnissen, die den aktuellen ausführbaren Code enthalten. Auf diese Weise bietet Bundle.main
Zugriff auf die von der aktuellen Anwendung verwendeten Ressourcen.
Betrachten Sie die Bundle.main
Struktur mithilfe der FileManager
Klasse:

Basierend auf dem Vorstehenden können wir schließen: Wenn die Anwendung geladen wird, wird ihre Bundle.main
gebildet, die aktuelle Bundle.main
(Systemsprache), Anwendungslokalisierung und lokalisierte Ressourcen werden analysiert. Anschließend wählt die Anwendung aus allen verfügbaren Lokalisierungen diejenige aus, die der aktuellen Sprache des Systems entspricht, und ruft die entsprechenden lokalisierten Ressourcen auf. Wenn keine Übereinstimmungen vorliegen, werden Ressourcen aus dem Standardverzeichnis verwendet (in unserem Fall die englische Lokalisierung, da Englisch als Entwicklungssprache definiert wurde und die Notwendigkeit einer zusätzlichen Lokalisierung von Ressourcen vernachlässigt werden kann). Wenn Sie die Gerätesprache in Russisch ändern und die Anwendung neu starten, entspricht die Schnittstelle bereits der russischen Lokalisierung.

Bevor Sie jedoch das Thema der Lokalisierung der Benutzeroberfläche über den Interface Builder schließen , sollten Sie einen anderen bemerkenswerten Weg beachten. Beim Erstellen von Lokalisierungsdateien (durch Hinzufügen einer neuen Sprache zum Projekt oder im Inspektor für lokalisierte Dateien) ist leicht zu erkennen, dass Xcode die Möglichkeit bietet, den zu erstellenden Dateityp auszuwählen:

Anstelle einer Zeilendatei können Sie problemlos ein lokalisiertes Storyboard/Xib
erstellen, in dem alle Markups der Basisdatei gespeichert werden. Ein großes Plus dieses Ansatzes besteht darin, dass der Entwickler sofort sehen kann, wie der Inhalt in einer bestimmten Sprache angezeigt wird, und das Layout des Bildschirms sofort korrigieren kann, insbesondere wenn die Textmenge unterschiedlich ist oder eine andere Richtung des Textes verwendet wird (z. B. auf Arabisch, Hebräisch) und so weiter . Gleichzeitig erhöht das Erstellen zusätzlicher Storyboard / Xib- Dateien die Größe der Anwendung selbst erheblich (String-Dateien benötigen jedoch viel weniger Speicherplatz).
Daher sollte bei der Auswahl der einen oder anderen Methode zur Schnittstellenlokalisierung berücksichtigt werden, welcher Ansatz in einer bestimmten Situation geeigneter und praktischer ist.
Mach es selbst. Arbeiten mit lokalisierten Zeichenfolgenressourcen im Code
Hoffentlich ist bei statischen Inhalten alles mehr oder weniger klar. Aber was ist mit dem Text, der direkt im Code festgelegt ist?
Die Entwickler des iOS-Betriebssystems haben sich darum gekümmert.
Um mit lokalisierten NSLocalizedStrings
arbeiten zu können, stellt das Foundation-Framework die Methodenfamilie NSLocalizedStrings
in Swift NSLocalizedStrings
NSLocalizedString(_ key: String, comment: String) NSLocalizedString(_ key: String, tableName: String?, bundle: Bundle, value: String, comment: String)
und Makros in Objective-C
NSLocalizedString(key, comment) NSLocalizedStringFromTable(key, tbl, comment) NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment)
Beginnen wir mit dem Offensichtlichen. Der key
ist der Zeichenfolgenschlüssel in der Zeichenfolgendatei. val
(Standardwert) - Der Standardwert, der verwendet wird, wenn sich der angegebene Schlüssel nicht in der Datei befindet. comment
- (weniger offensichtlich) eine kurze Beschreibung der lokalisierten Zeichenfolge (tatsächlich enthält sie keine nützliche Funktionalität und soll den Zweck der Verwendung einer bestimmten Zeichenfolge erläutern).
Die Parameter tableName
( tbl
) und bunble
sollten genauer betrachtet werden.
tableName
( tbl
) ist der Name der String-Datei (um ehrlich zu sein, ich weiß nicht, warum Apple sie als Tabelle bezeichnet), die die Zeile enthält, die wir für den angegebenen Schlüssel benötigen. Bei der Übertragung wird die Erweiterung .string
nicht angegeben. Durch die Möglichkeit, zwischen Tabellen zu navigieren, können Sie Zeichenfolgenressourcen nicht in einer Datei speichern, sondern nach eigenem Ermessen verteilen. Auf diese Weise können Sie die Überlastung von Dateien beseitigen, die Bearbeitung vereinfachen und das Risiko von Fehlern minimieren.
Der bundle
Parameter erweitert die Ressourcennavigation noch weiter. Wie bereits erwähnt, ist Bundle ein Mechanismus für den Zugriff auf Anwendungsressourcen, dh wir können die Ressourcenquelle unabhängig bestimmen.
Ein bisschen mehr. Wir werden direkt zur Stiftung gehen und die Deklaration von Methoden (Makros) für ein klareres Bild betrachten, weil Die überwiegende Mehrheit der Tutorials ignoriert diesen Punkt einfach. Das Swift- Framework ist nicht sehr informativ:
/// Returns a localized string, using the main bundle if one is not specified. public func NSLocalizedString(_ key: String, tableName: String? = default, bundle: Bundle = default, value: String = default, comment: String) -> String
"Das Hauptpaket gibt eine lokalisierte Zeichenfolge zurück" - alles, was wir haben. Objective-C ist etwas anders.
#define NSLocalizedString(key, comment) \ [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil] #define NSLocalizedStringFromTable(key, tbl, comment) \ [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)] #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \ [bundle localizedStringForKey:(key) value:@"" table:(tbl)] #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \ [bundle localizedStringForKey:(key) value:(val) table:(tbl)]
Hier können Sie bereits deutlich sehen, dass kein anderes als bundle
(in den ersten beiden Fällen mainBundle
) mit String-Ressourcendateien funktioniert - genau wie bei der Schnittstellenlokalisierung. Natürlich könnte ich dies sofort sagen, wenn man die Bundle
Klasse ( NSBundle
) im vorherigen Absatz betrachtet, aber zu diesem Zeitpunkt waren diese Informationen nicht von besonderem praktischem Wert. Im Zusammenhang mit der Arbeit mit Zeilen im Code kann dies jedoch nicht gesagt werden. Tatsächlich sind die von der Foundation bereitgestellten globalen Funktionen nur Wrapper für die Standard-Bundle-Methoden, deren Hauptaufgabe darin besteht, den Code präziser und sicherer zu gestalten. Niemand verbietet es, das bundle
manuell zu initialisieren und in seinem Namen direkt auf Ressourcen zuzugreifen, aber auf diese Weise scheint (wenn auch eine sehr, sehr geringe) Wahrscheinlichkeit der Bildung von Zirkelverbindungen und Speicherlecks zu bestehen.
In den folgenden Beispielen wird beschrieben, wie Sie mit globalen Funktionen und Makros arbeiten.
Mal sehen, wie das alles funktioniert.
Erstellen Sie zunächst eine String-Datei, die unsere String-Ressourcen enthält. Nennen Sie es Localizable.strings * und fügen Sie es hinzu.
"testKey" = "testValue";
(Die Lokalisierung von String-Dateien erfolgt genauso wie bei Storyboard / Xib , daher werde ich diesen Prozess nicht beschreiben. Wir werden " testValue " in der russischen Lokalisierungsdatei durch " test value *" ersetzen .)
Wichtig! In iOS ist eine Datei mit diesem Namen die Standard-String-Ressourcendatei, d. H. Wenn Sie den Tabellennamen tableName
( tbl
) nicht angeben, tableName
die Anwendung automatisch auf Localizable.strings
.
Fügen Sie unserem Projekt den folgenden Code hinzu
//Swift print("String for 'testKey': " + NSLocalizedString("testKey", comment: ""))
und führen Sie das Projekt aus. Nach dem Ausführen des Codes wird eine Zeile in der Konsole angezeigt
String for 'testKey': testValue
Alles funktioniert richtig!
Ändern Sie in ähnlicher Weise am Beispiel der Lokalisierung der Schnittstelle die Lokalisierung und führen Sie die Anwendung aus. Das Ergebnis der Codeausführung ist
String for 'testKey':
Versuchen wir nun, den Wert über den Schlüssel abzurufen, der sich nicht in der Datei Localizable.strings
:
//Swift print("String for 'unknownKey': " + NSLocalizedString("unknownKey", comment: ""))
Das Ergebnis der Ausführung eines solchen Codes wird sein
String for 'unknownKey': unknownKey
Da die Datei keinen Schlüssel enthält, gibt die Methode den Schlüssel selbst als Ergebnis zurück. Wenn ein solches Ergebnis nicht akzeptabel ist, ist es besser, die Methode zu verwenden
//Swift print("String for 'testKey': " + NSLocalizedString("unknownKey", tableName: nil, bundle: Bundle.main, value: "noValue", comment: ""))
wo es einen Wertparameter gibt ( Standardwert ). In diesem Fall müssen Sie jedoch die Quelle der Ressourcen angeben - bundle
.
Lokalisierte Zeichenfolgen unterstützen den Interpolationsmechanismus, ähnlich wie Standard-iOS-Zeichenfolgen. Fügen Sie dazu der Zeichenfolgendatei einen Datensatz mit Zeichenfolgenliteralen ( %@
, %li
, %f
usw.) hinzu, zum Beispiel:
"stringWithArgs" = "String with %@: %li, %f";
Um eine solche Zeile auszugeben, müssen Sie einen Code des Formulars hinzufügen
//Swift print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "some", 123, 123.098 ))
Aber wenn Sie solche Designs verwenden, müssen Sie sehr vorsichtig sein! Tatsache ist, dass iOS die Anzahl, Reihenfolge der Argumente und die Entsprechung ihrer Typen zu den angegebenen Literalen streng überwacht. Wenn Sie beispielsweise die Zeichenfolge anstelle des ganzzahligen Werts als zweites Argument einsetzen
//Swift print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "some", "123", 123.098 ))
dann ersetzt die Anwendung den Ganzzahlcode der Zeichenfolge "123" anstelle der Nichtübereinstimmung
"String with some: 4307341664, 123.089000"
Wenn Sie es überspringen, bekommen wir
"String with some: 0, 123.089000"
Wenn Sie jedoch das Objekt überspringen, das %@
in der Argumentliste entspricht
//Swift print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "123", 123.098 ))
Dann stürzt die Anwendung zum Zeitpunkt der Codeausführung einfach ab.
Drück mich, Baby! Lokalisierung von Benachrichtigungen
Eine weitere wichtige Aufgabe bei der Arbeit mit lokalisierten Zeichenfolgenressourcen, über die ich kurz sprechen möchte, ist die Lokalisierung von Benachrichtigungen. Das Fazit ist, dass die meisten Tutorials (sowohl zu Push Notifications
als auch zu Localizable Strings
) dieses Problem häufig vernachlässigen und solche Aufgaben nicht so selten sind. Wenn der Entwickler zum ersten Mal damit konfrontiert wird, kann er daher eine vernünftige Frage haben: Ist dies im Prinzip möglich? Ich werde den Apple Push Notification Service
des Apple Push Notification Service
hier nicht berücksichtigen, insbesondere da ab iOS 10.0 UserNotifications
und lokale Benachrichtigungen über dasselbe Framework implementiert werden - UserNotifications
.
Bei der Entwicklung mehrsprachiger Client-Server-Anwendungen muss ein ähnliches Problem auftreten. Als mich eine solche Aufgabe zum ersten Mal konfrontierte, fiel mir als erstes ein, das Problem der Nachrichtenlokalisierung auf der Serverseite zu beseitigen. Die Idee war sehr einfach: Die Anwendung sendet die aktuelle Lokalisierung beim Start an das Backend , und der Server wählt beim Senden des Push die entsprechende Nachricht aus. Das Problem trat jedoch sofort auf: Wenn sich die Lokalisierung des Geräts geändert hat und die Anwendung nicht neu gestartet wurde (die Daten in der Datenbank wurden nicht aktualisiert), hat der Server den Text gesendet, der der letzten "registrierten" Lokalisierung entspricht. Und wenn die Anwendung auf mehreren Geräten mit unterschiedlichen Systemsprachen gleichzeitig installiert ist, funktioniert die gesamte Implementierung wie die Hölle, weiß was. Da mir eine solche Lösung sofort als die wildeste Krücke erschien, suchte ich sofort nach geeigneten Lösungen (lustig, aber in vielen Foren rieten die "Entwickler", die Pushies genau im Backend zu lokalisieren).
Die richtige Entscheidung war schrecklich einfach, wenn auch nicht ganz offensichtlich. Anstelle des vom Server auf APNS gesendeten Standard- JSON
"aps" : { "alert" : { "body" : "some message"; }; };
müssen JSON des Formulars senden
"aps" : { "alert" : { "loc-key" : "message localized key"; }; };
Dabei wird der loc-key
verwendet, um den lokalisierten String-Schlüssel aus der Datei Localizable.strings
. Dementsprechend wird die Push-Nachricht entsprechend der aktuellen Lokalisierung des Geräts angezeigt.
Der Mechanismus zum Interpolieren lokalisierter Zeichenfolgen in Push- Benachrichtigungen funktioniert auf ähnliche Weise:
"aps" : { "alert" : { "loc-key" : "message localized key"; "loc-args" : [ "First argument", "Second argument" ]; }; };
Der Schlüssel loc-args
übergibt ein Array von Argumenten, die in den lokalisierten Benachrichtigungstext eingebettet werden müssen.
Zusammenfassend ...
Und was haben wir am Ende:
- Standard zum Speichern von String-Daten in speziellen
.string
Dateien mit einfacher und zugänglicher Syntax; - die Fähigkeit, die Schnittstelle ohne zusätzliche Manipulationen im Code zu lokalisieren;
- schneller Zugriff auf lokalisierte Ressourcen über Code;
- automatische Generierung von Lokalisierungsdateien und Strukturierung der Ressourcen des Projektverzeichnisses (Anwendung) mithilfe von Xcode-Tools;
- die Möglichkeit, den Benachrichtigungstext zu lokalisieren.
, Xcode , .
.