Lokalisierung von Anwendungen in iOS. Teil 1. Was haben wir?

Published on August 02, 2018

Lokalisierung von Anwendungen in iOS. Teil 1. Was haben wir?

IOS-Anwendungslokalisierung


Teil 1. Was haben wir?


Handbuch zu lokalisierten Zeichenfolgenressourcen


Einleitung


Vor einigen Jahren stürzte ich mich in die magische Welt der iOS-Entwicklung, die mir mit ihrem ganzen Wesen eine glückliche Zukunft in der IT versprach. Als ich mich jedoch mit der jeweiligen Plattform und Entwicklungsumgebung befasste, hatte ich viele Schwierigkeiten und Unannehmlichkeiten bei der Lösung scheinbar sehr trivialer Aufgaben: Apples „innovativer Konservativismus“ macht Entwickler manchmal sehr anspruchsvoll, um den ungezügelten „WANT“ des Kunden zu befriedigen.


Eines dieser Probleme ist das Problem der Lokalisierung von Zeichenfolgenressourcen der Anwendung. Diesem Problem möchte ich einige meiner ersten Veröffentlichungen im Freiraum von Habr widmen.


Изначально я рассчитывал уместить свои мысли в одной статье, но объем той информации, которую хотелось бы изложить, оказался достаточно большим. В этой статье я попытаюсь раскрыть суть стандартных механизмов работы с локализованными ресурсами с акцентом на некоторые аспекты, которыми пренебрегают большинство гайдов и туториалов. Материал ориентирован прежде всего на начинающих разработчиков (или тех, кто с такими задачами не сталкивался). Для опытных девелоперов данная информация может не нести особо ценности. А вот о неудобствах и недостатках, с которыми можно столкнуться на практике, я расскажу в дальнейшем...


Из-под коробки. Как организовано хранение строковых ресурсов в iOS-приложениях


Для начала отметим, что наличие в платформе механизмов локализации уже является огромным плюсом, т.к. избавляет программиста от дополнительной разработки и задает единый формат работы с данными. Да и зачастую, базовых механизмов хватает для реализации относительно небольших проектов.


И так, какие же возможности предоставляет нам Xcode "из-под коробки"? Для начала давайте разберемся со стандартом хранения строковых ресурсов в проекте.


In Projekten mit statischem Inhalt können Zeichenfolgendaten direkt in der Schnittstelle (Markup-Dateien .storyboardund .xibXML-Dateien, die mit Interface Builder gerendert werden ) oder in Code gespeichert werden. Der erste Ansatz ermöglicht es uns, den Prozess der Kennzeichnung von Bildschirmen und einzelnen Displays zu vereinfachen und zu beschleunigen, weil Ein Entwickler kann die meisten Änderungen beobachten, ohne eine Anwendung zu erstellen. In diesem Fall ist es jedoch nicht schwierig, auf Datenredundanz zu stoßen (wenn derselbe Text von mehreren Elementen verwendet wird, Zuordnungen). Der zweite Ansatz beseitigt lediglich das Problem der Datenredundanz, führt jedoch zu der Notwendigkeit, die Bildschirme manuell auszufüllen (indem zusätzliche Einstellungen vorgenommen werden)IBOutlet-ows und Zuweisen geeigneter Textwerte), was wiederum zu Code-Redundanz führt (natürlich außer in Fällen, in denen der Text direkt durch den Anwendungscode festgelegt werden muss).


Darüber hinaus stellt Apple eine Standarddatei mit der Erweiterung zur Verfügung .strings. Diese Norm regelt das Speicherformat von Zeichenfolgendaten in Form eines assoziativen Arrays ( "ключ-значение"):


"key" = "value";

Bei der Eingabe muss die Groß- und Kleinschreibung beachtet werden, Leerzeichen, Unterstriche, Interpunktion und Sonderzeichen werden berücksichtigt.


Es ist wichtig zu beachten, dass Strings- Dateien trotz ihrer einfachen Syntax regelmäßige Fehlerquellen beim Kompilieren, Zusammenstellen oder Ausführen der Anwendung sind. Dafür gibt es mehrere Gründe.


Erstens Syntaxfehler. Fehlende Semikolons, Gleichheitszeichen, zusätzliche oder ungeschirmte Anführungszeichen führen zwangsläufig zu einem Compilerfehler. Und Xcode zeigt auf die Datei mit einem Fehler, hebt jedoch nicht die Zeile hervor, in der etwas nicht stimmt. Das Auffinden eines solchen Tippfehlers kann viel Zeit in Anspruch nehmen, insbesondere wenn die Datei eine erhebliche Datenmenge enthält.



Zweitens die Vervielfältigung von Schlüsseln. Die Anwendung wird natürlich nicht dadurch beeinträchtigt, aber dem Benutzer werden möglicherweise falsche Daten angezeigt. Wenn der Schlüssel auf die Zeichenfolge zugreift, wird der Wert abgerufen, der dem letzten Vorkommen des Schlüssels in der Datei entspricht.


Infolgedessen erfordert eine einfache Struktur, dass ein Programmierer beim Füllen von Dateien mit Daten sehr gründlich und vorsichtig ist.


SachkundigEntwickler können sofort ausrufen: "Aber was ist mit JSON und PLIST? Als hätten sie nicht gefallen?" Nun, erstens JSONund PLIST(in der Tat, gewöhnlich XML) sind universelle Standards, mit denen sowohl Zeichenfolgen als auch numerische, logische ( BOOL), binäre Daten, Uhrzeit und Datum sowie Arrays mit Index ( Array) und Assoziativ ( Dictionary) gespeichert werden können. Dementsprechend ist die Syntax dieser Standards gesättigter, und daher ist es einfacher, sie in sie einzufügen. Zweitens ist die Verarbeitungsgeschwindigkeit solcher Dateien aufgrund der komplexeren Syntax geringfügig 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 verschoben. Lokalisierung der Benutzeroberfläche


Nachdem wir die Standards herausgefunden haben, wollen wir nun herausfinden, wie wir alles nutzen können.


Gehen wir in Ordnung. Zuerst erstellen wir eine einfache Single View-Anwendung und fügen im Main.storyboard auf dem ViewController einige Textkomponenten hinzu.




Der Inhalt wird in diesem Fall direkt in der Oberfläche 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 standardmäßig) festgelegt ist.


Fügen wir jetzt eine weitere Sprache hinzu. Klicken Sie dazu auf " + " und wählen Sie die gewünschte Sprache aus (ich habe beispielsweise Russisch gewählt). Caring Xcode fordert uns sofort auf, auszuwählen, welche Dateien für die hinzugefügte Sprache lokalisiert werden müssen.




Klicken Sie auf Fertig stellen , um zu sehen, was passiert ist. Im Projektnavigator wurden neben den ausgewählten Dateien Schaltflächen zum Anzeigen von Sammelformen angezeigt. Wenn Sie darauf klicken, sehen Sie, dass die zuvor ausgewählten Dateien erstellte Lokalisierungsdateien enthalten.




Zum Beispiel Main.storyboard (Base)- ist es auf der Standard - Interface Markup - Language - Datei auf einem grundlegendes Design erstellt und Lokalisierung in der Bildung in einem Paar ihm wurde von einem Mitarbeiter erstellt Main.strings (Russian)- Strings für russische Lokalisierung Datei. 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 sollten wir uns die Kommentare des fürsorglichen Xcodes genauer ansehen:


/* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */
"tQe-tG-eeo.text" = "Label";

Hier ist eine Instanz der Klasse UILabelmit dem Wert "Label"für den Parameter text. ObjectID- Die Objektkennung in der Markup-Datei ist eine eindeutige Zeichenfolge, die jeder Komponente zum Zeitpunkt der Platzierung zugewiesen wird Storyboard/Xib. Aus dem ObjectIDNamen des Objektparameters (in diesem Fall text) wird der Schlüssel gebildet, und der Datensatz selbst kann formal interpretiert werden als:


Setzen Sie den Parameter "text" des Objekts "tQe-tG-eeo" auf den Wert "Label".


In diesem Datensatz kann sich nur der " Wert " ändern . Ersetzen Sie " Label " durch " Inscription ". 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" = "Кнопка";

Führen Sie unsere Anwendung aus.




Aber was sehen wir? Die Anwendung verwendet die grundlegende Lokalisierung. Wie kann man überprüfen, ob wir die Übersetzung gemacht haben?


Hier lohnt es sich, einen kleinen Exkurs zu machen und sich ein wenig mit den Funktionen der iOS-Plattform und der Struktur der Anwendung auseinanderzusetzen.


Berücksichtigen Sie zunächst die Änderung in der Projektstruktur beim Hinzufügen der Lokalisierung. So sieht das Projektverzeichnis vor dem Hinzufügen der russischen Lokalisierung aus:




Und so nach:




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




Und hier ist die Struktur des Xcode-Projekts zur fertigen iOS-Anwendung? Und das trotz der Tatsache, dass es 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 Erstellen des Xcode-Projekts nicht nur die ausführbare Datei, sondern auch Ressourcen ( Storyboard / Xib- Schnittstellen-Markup-Dateien , Bilder, Zeilendateien usw.) in die fertige Anwendung, wobei die in der Entwurfsphase festgelegte Hierarchie beibehalten wird.


Apple stellt eine Klasse Bundle(NSBundle)( kostenlose Übersetzung ) zur Verfügung, um mit dieser Hierarchie zu arbeiten :


Apple Bundleermöglicht den Zugriff auf Anwendungen, Frameworks, Plugins und viele andere Arten von Inhalten. Bundle-y organisiert Ressourcen in genau definierten Unterverzeichnissen, und die Bündelstrukturen variieren je nach Plattform und Typ. Mit bundlekönnen Sie auf die Paketressourcen zugreifen, ohne deren Struktur zu kennen. BundleEs ist eine einzige Oberfläche für die Suche nach Artikeln unter Berücksichtigung der Paketstruktur, der Benutzeranforderungen, der verfügbaren Lokalisierungen und anderer relevanter Faktoren.
Suchen und Öffnen einer Ressource
Bevor Sie mit einer Ressource arbeiten können, müssen Sie sie angeben bundle. Die Klasse Bundlehat viele Konstruktoren, aber am häufigsten wird main verwendet .Bundle.mainStellt Pfade zu Verzeichnissen bereit, die den aktuellen ausführbaren Code enthalten. Auf diese Weise erhalten Sie Bundle.mainZugriff auf Ressourcen, die von der aktuellen Anwendung verwendet werden.

Betrachten Sie die Struktur Bundle.mainanhand der Klasse FileManager:




Auf der Grundlage des Vorstehenden können wir folgern: Wenn die Anwendung geladen ist, wird sie gebildet Bundle.main, und die aktuelle Gerätelokalisierung (Systemsprache), Anwendungslokalisierung und lokalisierte Ressourcen werden analysiert. Anschließend wählt die Anwendung aus allen verfügbaren Lokalisierungen diejenige aus, die der aktuellen Systemsprache entspricht, und ruft die entsprechenden lokalisierten Ressourcen auf. Wenn es keine Übereinstimmung gibt, werden die 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 Benutzeroberfläche bereits der russischen Lokalisierung.




Bevor Sie jedoch das Thema Lokalisierung der Benutzeroberfläche mit Interface Builder schließen , sollten Sie noch einen weiteren bemerkenswerten Punkt beachten. Wenn Sie Lokalisierungsdateien erstellen (indem Sie dem Projekt oder dem Inspektor für lokalisierte Dateien eine neue Sprache hinzufügen), können Sie leicht erkennen, dass Sie mit Xcode den zu erstellenden Dateityp auswählen können:




Anstelle einer String-Datei können Sie einfach eine lokalisierte Datei erstellen Storyboard/Xib, bei der alle Markups der Basisdatei erhalten bleiben. Der große Vorteil dieses Ansatzes ist, dass der Entwickler sofort sehen kann, wie der Inhalt in der einen oder anderen Sprache angezeigt wird, und das Bildschirmlayout sofort korrigiert, insbesondere wenn das Textvolumen variiert oder eine andere Textrichtung verwendet wird (z. B. auf Arabisch, Hebräisch). . Gleichzeitig wird durch das Erstellen zusätzlicher Storyboard- / Xib- Dateien die Größe der Anwendung selbst erheblich erhöht (String-Dateien belegen jedoch weniger Speicherplatz).


Daher sollte bei der Auswahl der einen oder anderen Schnittstellenlokalisierungsmethode berücksichtigt werden, welcher Ansatz in einer bestimmten Situation zweckmäßiger 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 angegeben ist?


Die Entwickler des iOS-Betriebssystems haben sich darum gekümmert.



Für die Arbeit mit lokalisierten Textressourcen bietet das Foundation Framework eine Methodenfamilie NSLocalizedStringsin Swift


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 Parameter keyist ein String-Schlüssel in der Strings-Datei. val(Standardwert) - Standardwert, der verwendet wird, wenn der angegebene Schlüssel in der Datei fehlt. comment- (weniger offensichtlich) eine kurze Beschreibung der lokalisierten Zeichenfolge (enthält in der Tat keine nützliche Funktionalität und soll den Zweck der Verwendung einer bestimmten Zeichenfolge verdeutlichen).


Die Parameter tableName( tbl) und bunblesollten dann genauer betrachtet werden.


tableName( tbl) Ist der Name der String-Datei (um ehrlich zu sein, ich weiß nicht, warum Apple sie als Tabelle bezeichnet), in der sich der erforderliche String beim angegebenen Schlüssel befindet. Bei der Übertragung wird die Erweiterung .stringnicht angegeben. Durch die Möglichkeit, zwischen Tabellen zu navigieren, können Sie Zeichenfolgenressourcen nicht in einer einzelnen Datei speichern, sondern nach eigenem Ermessen verteilen. Auf diese Weise können Sie Dateistaus beseitigen, die Bearbeitung vereinfachen und die Wahrscheinlichkeit von Fehlern minimieren.


Diese bundleOption erweitert die Fähigkeit, in Ressourcen noch mehr zu navigieren. Wie bereits erwähnt, ist ein Bundle ein Mechanismus für den Zugriff auf Anwendungsressourcen. Das heißt, wir können die Ressourcenquelle unabhängig bestimmen.


Ein bisschen mehr. Gehen wir direkt zur Stiftung und betrachten die Methodendeklaration (Makros) für ein klareres Bild, weil Die meisten Tutorials ignorieren 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. Im Fall von Objective-C ist der Fall ein wenig 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 sehen Sie deutlich, dass mit den String-Ressourcendateien bundle(in den ersten beiden Fällen mainBundle) kein anderer funktioniert - genau wie bei der Schnittstellenlokalisierung. Natürlich könnte ich angesichts der class Bundle( NSBundle) im vorherigen Absatz sofort etwas dazu sagen , aber zu diesem Zeitpunkt hatten diese Informationen nicht viel praktischen Wert. Aber im Zusammenhang mit der Arbeit mit Zeilen im Code kann dies nicht gesagt werden. Tatsächlich sind die von der Foundation bereitgestellten globalen Funktionen lediglich Wrapper für Standard-Bundle-Methoden, deren Hauptaufgabe darin besteht, den Code übersichtlicher und sicherer zu gestalten. Niemand verbietet die Initialisierungbundle Manuell und direkt von seinem Namen aus greifen Sie auf Ressourcen zu, aber auf diese Weise erscheint (wenn auch sehr, sehr gering) die Wahrscheinlichkeit, zyklische Referenzen und Speicherlecks zu erzeugen.


Weitere Beispiele beschreiben die Arbeit mit globalen Funktionen und Makros.


Überlegen Sie, wie 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";

( Lokalisierung von String-Dateien ist genau das gleiche wie ein Storyboard / XIB daher diesen Prozess zu beschreiben, ich will nicht. Ersetzen in Dateien russischer Lokalisierung „ die Testvalue “ auf „ Testwert *“.)


Es ist wichtig! In iOS ist eine Datei mit diesem Namen die Standard-String-Ressourcendatei, d. H. Wenn Sie den Tabellennamen tableName( tbl) nicht angeben , klopft die Anwendung automatisch an Localizable.strings.


Fügen Sie unserem Projekt den folgenden Code hinzu


//Swift
print("String for 'testKey': " + NSLocalizedString("testKey", comment: ""))

//Objective-C
NSLog(@"String for 'testKey': %@", NSLocalizedString(@"testKey", @""));

und führe das Projekt aus. Nach der Ausführung des Codes erscheint die Zeile in der Konsole


String for 'testKey': testValue

Alles funktioniert richtig!


Ändern Sie in ähnlicher Weise mit einem Beispiel für die Lokalisierung der Schnittstelle die Lokalisierung und führen Sie die Anwendung aus. Das Ergebnis des Codes ist


String for 'testKey': тестовое значение

Jetzt werden wir versuchen, den Wert mit einem Schlüssel zu ermitteln, der nicht in der Datei enthalten ist Localizable.strings:


//Swift
print("String for 'unknownKey': " + NSLocalizedString("unknownKey", comment: ""))

//Objective-C
NSLog(@"String for 'unknownKey': %@", NSLocalizedString(@"unknownKey", @""));

Das Ergebnis dieses Codes ist


String for 'unknownKey': unknownKey

Da die Datei keinen Schlüssel enthält, gibt die Methode den Schlüssel selbst als Ergebnis zurück. Wenn dieses 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: ""))

//Objective-C
NSLog(@"String for 'testKey': %@", NSLocalizedStringWithDefaultValue(@"unknownKey", nil, NSBundle.mainBundle, @"noValue", @""));

wo ist der Parameter value( Standardwert ). Stellen Sie in diesem Fall jedoch sicher, dass Sie die Quelle der Ressourcen angeben bundle.


Lokalisierte Zeichenfolgen unterstützen den Interpolationsmechanismus, ähnlich wie standardmäßige iOS-Zeichenfolgen. Um dies zu tun, müssen Sie Zeilen hinzufügen von Aufnahme mit Stringliteral ( %@, %li, %fetc.), zum Beispiel:


"stringWithArgs" = "String with %@: %li, %f";

Um eine solche Zeile anzuzeigen, müssen Sie einen Code wie hinzufügen


//Swift
print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "some", 123, 123.098 ))

//Objective-C
NSLog(@"%@", [NSString stringWithFormat: NSLocalizedString(@"stringWithArgs", @""), @"some", 123, 123.098]);

Aber wenn Sie solche Konstruktionen verwenden, müssen Sie sehr vorsichtig sein! Tatsache ist, dass iOS die Anzahl, die Reihenfolge der Argumente und die Entsprechung ihrer Typen zu den angegebenen Literalen genau verfolgt. Wenn Sie beispielsweise die Zeichenfolge anstelle des ganzzahligen Werts als zweites Argument einsetzen


//Swift
print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "some", "123", 123.098 ))

//Objective-C
NSLog(@"%@", [NSString stringWithFormat: NSLocalizedString(@"stringWithArgs", @""), @"some", @"123", 123.098]);

In diesem Fall ersetzt die Anwendung den Integer-Code der Zeichenfolge "123" anstelle der Inkonsistenz


"String with some: 4307341664, 123.089000"

Wenn Sie es überspringen, bekommen Sie


"String with some: 0, 123.089000"

Aber wenn wir das entsprechende Objekt in der Liste der Argumente weglassen %@


//Swift
print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "123", 123.098 ))

//Objective-C
NSLog(@"%@", [NSString stringWithFormat: NSLocalizedString(@"stringWithArgs", @""),  @"123", 123.098]);

dann fällt die Anwendung einfach, wenn der Code ausgeführt wird.


Drück mich Baby! Lokalisierung von Benachrichtigungen


Eine weitere wichtige Aufgabe im Umgang mit lokalisierten Zeichenfolgenressourcen, die ich kurz beschreiben möchte, ist das Lokalisieren von Benachrichtigungen. Das Fazit ist, dass die meisten Tutorials (sowohl rein Push Notificationsals auch raus Localizable Strings) dieses Problem oft vernachlässigen und solche Aufgaben keine Seltenheit sind. Wenn der Entwickler zum ersten Mal mit einem ähnlichen Problem konfrontiert wird, hat er möglicherweise eine vernünftige Frage: Ist dies grundsätzlich möglich? Apple Push Notification ServiceIch werde den Mechanismus der Arbeit hier nicht berücksichtigen, zumal ab iOS 10.0 Push- und lokale Benachrichtigungen über dasselbe Framework implementiert werden UserNotifications.


Bei der Entwicklung mehrsprachiger Client-Server-Anwendungen müssen wir uns mit einer ähnlichen Aufgabe befassen. Als ein solches Problem zum ersten Mal vor mir auftauchte, war das erste, was mir in den Sinn kam, das Problem der Lokalisierung von Nachrichten auf der Serverseite abzuschaffen. Die Idee war sehr einfach: Wenn die Anwendung gestartet wird, sendet sie die aktuelle Lokalisierung an das Backend , und wenn der Server gesendet wird, drücken Sie-und wählt die entsprechende Nachricht aus. Aber sofort gab es ein Problem: Wenn sich die Lokalisierung des Geräts änderte und die Anwendung nicht neu gestartet wurde (die Daten in der Datenbank wurden nicht aktualisiert), sendete der Server den Text, der der letzten "registrierten" Lokalisierung entsprach. Und wenn die Anwendung auf mehreren Geräten mit unterschiedlichen Systemsprachen installiert ist, funktioniert die gesamte Implementierung so, als wüsste der Teufel, was. Da mir eine solche Lösung sofort als die wildeste Krücke erschien, begann ich sofort nach geeigneten Lösungen zu suchen (lustig, aber in vielen Foren rieten die "Entwickler", den Push auf dem Backend zu lokalisieren ).


Die richtige Entscheidung erwies sich als schrecklich einfach, wenn auch nicht ganz offensichtlich. Anstelle des vom Server an APNS gesendeten Standard- JSON


    "aps" : {
            "alert" : {
                      "body" : "some message";
                      };
            };

Es ist erforderlich, JSON eines Typs zu senden


    "aps" : {
            "alert" : {
                      "loc-key" : "message localized key";
                      };
            };

Dabei ist der Schlüssel loc-keyder Schlüssel der lokalisierten Zeichenfolge aus der Datei Localizable.strings. Dementsprechend wird die Push-Nachricht gemäß der aktuellen Lokalisierung des Geräts angezeigt.


Der Interpolationsmechanismus für lokalisierte Zeichenfolgen in Push- Benachrichtigungen funktioniert auf dieselbe Weise :


  "aps" : {
          "alert" : {
                    "loc-key" : "message localized key";
                    "loc-args" : [ "First argument", "Second argument" ];
                    };
          };

Der Schlüssel loc-argsist ein Array von Argumenten, die in den lokalisierten Benachrichtigungstext eingebettet werden müssen.


Fassen wir zusammen ...


Und so, was haben wir am Ende:


  • der Standard zum Speichern von Zeichenfolgendaten in spezialisierten Dateien .stringmit einfacher und zugänglicher Syntax;
  • die Fähigkeit, die Schnittstelle ohne zusätzliche Code-Manipulationen zu lokalisieren;
  • schneller Zugriff auf lokalisierte Ressourcen über Code;
  • automatische Generierung von Lokalisierungsdateien und Strukturierung der Ressourcen des Projekt- (Applikations-) Verzeichnisses mit Xcode;
  • die Fähigkeit, Textbenachrichtigungen zu lokalisieren.

Im Allgemeinen bietet Xcode Entwicklern einen relativ einfachen und flexiblen Mechanismus zum Lokalisieren von Ressourcen für Anwendungszeichenfolgen, der ausreicht, um einfache Lokalisierungsaufgaben in relativ kleinen Projekten zu implementieren.


Ich werde versuchen, Sie über die Fallstricke des beschriebenen Mechanismus und die Methoden ihrer Umgehung im nächsten Artikel zu informieren.