Um einen Lokalisierungsschlüssel eines Frameworks aufzulösen, übergib sowohl sein Ressourcen-Bundle als auch seine Zeichenfolgentabelle. Diese Anleitung zeigt, wie ein Label aus einem Framework in einer Mac-App korrekt angezeigt wird und wie du anschließend überprüfst, ob der Text aus der Tabelle statt aus einem Fallback stammt.

Die Aufgabe ist bewusst klein gehalten: Zeige das synthetische Label Open panel aus dem Katalog Panel.xcstrings eines Frameworks an. Du benötigst ein Mac-App-Projekt in Xcode und ein Framework-Ziel, das du kontrollierst. Das Hauptbeispiel verwendet Xcode 26 oder neuer und zielt auf macOS 12 oder neuer ab; laut Apple ist der Initializer für lokalisierte Zeichenfolgen ab macOS 12 verfügbar. Dokumentation zum Swift-Initializer.

Bundle, Tabelle und Schlüssel vor der Codeänderung bestimmen

Betrachte eine lokalisierte Meldung als eine Suche mit drei klar definierten Koordinaten. Das Bundle gibt an, wem die Ressource gehört, die Tabelle bezeichnet eine Gruppe von Zeichenfolgen innerhalb dieses Bundles und der Schlüssel bezeichnet einen Eintrag in dieser Tabelle. Apples Lokalisierungs-APIs führen Bundle und Tabelle getrennt auf, da sowohl Framework- als auch App-Ziele Zeichenfolgenressourcen enthalten können. App-Texte für die Übersetzung vorbereiten.

Notiere für dieses Beispiel den folgenden Vertrag, bevor du den Katalog öffnest. Das sind veranschaulichende Namen, keine von Apple vorgeschriebenen Bezeichnungen.

Bestandteil Beispielwert Zweck
Ressourcenbesitzer Dein Framework-Ziel Enthält den Katalog
Katalogdatei Panel.xcstrings Speichert den Ausgangstext und die Übersetzungen der Tabelle
Tabellenargument Panel Wählt den Katalog ohne Dateierweiterung aus
Schlüssel PANEL_OPEN_ACTION Bezeichnet die Meldung
Englischer Ausgangswert Open panel Liefert lesbaren Schnittstellentext
Kommentar Label for the action that opens the panel. Erklärt den Verwendungszweck der Meldung

Mit table: "Panel" wählst du die durch Panel.xcstrings dargestellte Tabelle aus. Wenn du keine Tabelle angibst, wird Localizable ausgewählt. Wenn du kein Bundle angibst, sucht der Initializer für Zeichenfolgen entsprechend im Haupt-Bundle der App. Ein passender Schlüssel in einem Framework-Katalog benötigt daher sowohl das Bundle des Frameworks als auch die richtige Tabelle. Parameter für lokalisierte Swift-Zeichenfolgen.

Das ergibt eine nützliche Reihenfolge für die Diagnose: Prüfe zuerst den Besitzer, dann die Tabelle und zuletzt den Eintrag. Nach alternativen Schreibweisen des Schlüssels zu suchen, hilft nicht, wenn die Suche auf die Ressourcen der App statt auf das Framework verweist, dem die Meldung gehört.

Zeichenfolgenkatalog zum Framework-Ziel hinzufügen

Wähle in Xcode File > New > File from Template, wähle die Plattform aus, filtere nach string und wähle String Catalog. Nenne die Datei Panel. Achte darauf, dass der Katalog zum Framework-Ziel gehört und neben dem Framework-Quellcode liegt, der darauf zugreifen wird. Apples Katalog-Workflow erlaubt eigene Katalognamen; in der Framework-Demonstration von Apple wird der Katalog innerhalb des Framework-Ziels erstellt. Text mit einem Zeichenfolgenkatalog lokalisieren und variieren, Apples Framework-Lokalisierungsdemonstration.

Das Beispiel verwendet einen semantischen Schlüssel, statt den angezeigten Wortlaut als Schlüssel zu verwenden. Mit PANEL_OPEN_ACTION als Bezeichner und Open panel als Standardwert nennt der Code beide Bestandteile ausdrücklich. Apple unterstützt diese Anordnung durch den Initializer, der einen statischen Schlüssel und einen separaten Standard-Lokalisierungswert entgegennimmt. Swift-Initializer mit statischem Schlüssel.

Baue nach dem Hinzufügen des folgenden Quellcodes das Framework-Ziel. Xcode erkennt lokalisierbare API-Aufrufe während des Builds und aktualisiert die entsprechenden Kataloge. Öffne Panel.xcstrings und überprüfe, ob der Katalog PANEL_OPEN_ACTION, den englischen Ausgangswert Open panel und den erklärenden Kommentar enthält. Fehlt der Eintrag, prüfe die Zielmitgliedschaft der Quelle und ob das Ziel, das diese Quelle enthält, gebaut wurde. Mit Editor > Assistant kannst du außerdem den einem Katalogeintrag zugeordneten Code untersuchen. Zeichenfolgenkatalog befüllen und prüfen.

Meldung im Framework auflösen

Lege diese vollständige Quelldatei im Framework-Ziel ab. Sie definiert die lokalisierte Zeichenfolge und ein kleines SwiftUI-Label, das die enthaltende Mac-App anzeigen kann. Außerdem enthält sie eine Diagnosemethode, die im nächsten Abschnitt verwendet wird. Der Code wurde anhand der dokumentierten Signaturen von Apple überprüft, hier aber nicht ausgeführt, da kein Swift-Compiler verfügbar war.

import Foundation
import SwiftUI

public enum PanelMessages {
    public static var openPanel: String {
        String(
            localized: "PANEL_OPEN_ACTION",
            defaultValue: "Open panel",
            table: "Panel",
            bundle: #bundle,
            comment: "Label for the action that opens the panel."
        )
    }

    public static func lookupReport() -> String {
        let missingMarker = "__PANEL_LOOKUP_MISSING__"
        let result = #bundle.localizedString(
            forKey: "PANEL_OPEN_ACTION",
            value: missingMarker,
            table: "Panel"
        )

        if result == missingMarker {
            return "No entry resolved from the selected bundle and table."
        }

        return "Resolved table value: \(result)"
    }
}

public struct PanelActionLabel: View {
    public init() {}

    public var body: some View {
        Text(verbatim: PanelMessages.openPanel)
    }
}

Der Ausdruck #bundle wird an der Stelle ausgewertet, an der du ihn schreibst. In diesem Framework-Quellcode liefert er das Bundle, das dem Framework-Ziel zugeordnet ist. Verschiebst du denselben Ausdruck in den Quellcode des App-Ziels, liefert er stattdessen das Bundle der App. Für ein Swift-Paket-Ziel dokumentiert Apple, dass das Makro das Ressourcen-Bundle des Ziels liefert. Platziere die Suche direkt bei den Ressourcen, denen sie gehören. Foundation-Bundle-Makro.

Die Deklaration gibt einen gewöhnlichen String zurück, dessen Lokalisierung bereits aufgelöst wurde. Die Ansicht verwendet Text(verbatim:), um dieses Ergebnis ausdrücklich anzuzeigen. Die öffentliche Ansicht ist nur ein Label. Füge sie zu einer bestehenden App-Ansicht hinzu, an der der Text erscheinen soll.

Framework-Klasse verwenden, wenn das Bundle-Makro nicht verfügbar ist

Apple unterstützt auch die Suche nach einem Framework-Bundle über eine in diesem Framework definierte Klasse. Für ein herkömmliches Framework mit eigenen Ressourcen ist der folgende Code ein vollständiger alternativer Meldungsanbieter. Verwende ihn anstelle der vorherigen Deklaration von PanelMessages und beachte weiterhin den oben beschriebenen Katalog und die Mindestversionen.

import Foundation

private final class PanelBundleAnchor: NSObject {}

public enum PanelMessages {
    public static var openPanel: String {
        String(
            localized: "PANEL_OPEN_ACTION",
            defaultValue: "Open panel",
            table: "Panel",
            bundle: Bundle(for: PanelBundleAnchor.self),
            comment: "Label for the action that opens the panel."
        )
    }
}

Die Ankerklasse muss in das Framework kompiliert werden, dessen Ressourcen du verwenden möchtest. Laut Apple gibt Bundle(for:) das Bundle zurück, das der übergebenen Klasse zugeordnet ist, gegebenenfalls einschließlich des Framework-Bundles. Eine in die App kompilierte Ankerklasse würde stattdessen die App ermitteln. Wähle bei Paketressourcen oder Ressourcen in einem separaten Bundle das tatsächliche Ressourcen-Bundle aus; der Speicherort einer Klasse allein belegt nicht, wem diese Ressourcen gehören. Klassenbasierter Bundle-Initializer, Auswahl des Ressourcen-Bundles mit dem Makro.

Nachweisen, dass lesbarer Text aus einer erfolgreichen Suche stammt

Open panel auf dem Bildschirm zu sehen, reicht nicht als Beleg dafür aus, dass die Suche im Katalog erfolgreich war. Der Initializer gibt bei einer fehlgeschlagenen Suche defaultValue zurück. Derselbe sichtbare Text kann daher sowohl eine erfolgreiche Suche als auch einen Fallback darstellen. Dieses Verhalten ist für lesbaren Schnittstellentext nützlich, kann aber während der Entwicklung ein falsches Bundle oder eine falsche Tabelle verbergen. Verhalten des Swift-Standardwerts.

Die Methode lookupReport() aus der ersten Quelldatei beseitigt diese Mehrdeutigkeit. Sie führt eine Suche mit einer unverwechselbaren Fallback-Markierung aus, die nicht als tatsächlicher Katalogwert verwendet werden darf. Prüfe ihren Rückgabewert in der laufenden App oder in einem bestehenden Debug-Kontext. Meldet sie keinen aufgelösten Eintrag, untersuche die ausgewählten Ressourcen, bevor du Übersetzungen bearbeitest.

Diese Diagnose ergibt sich direkt aus dem dokumentierten Verhalten von Bundle.localizedString(forKey:value:table:): Fehlt ein Schlüssel und ist der angegebene Fallback nicht leer, gibt die Methode diesen Fallback zurück. Bei einem fehlenden Schlüssel und einem nil- oder leeren Fallback gibt sie stattdessen den Schlüssel zurück. Mit der Markierung lässt sich ein Fehler leichter von einem gültigen Ausgangstext unterscheiden. Rückgabewerte lokalisierter Bundle-Zeichenfolgen).

Beobachtung Nächste Prüfung
Die Diagnose gibt die Meldung zum fehlenden Eintrag zurück Prüfe, ob der Katalog in das ausgewählte Bundle eingebaut wird, und überprüfe dann Panel und PANEL_OPEN_ACTION
Die Diagnose löst einen unerwarteten Wert auf Untersuche genau diesen Eintrag in der ausgewählten Tabelle und die Sprache des aktuellen Laufs
Die Diagnose löst den richtigen Wert auf, aber die Oberfläche zeigt etwas anderes Verfolge, welchen Wert die Oberfläche tatsächlich anzeigt
Während eines übersetzten Laufs wird der englische Ausgangswert angezeigt Untersuche die Übersetzung des Eintrags und die Laufkonfiguration; eine erfolgreiche Suche beweist allein nicht, dass die angeforderte Übersetzung vorhanden ist

Die Tabelle zeigt eine aus dem Suchvertrag abgeleitete Reihenfolge zur Fehlersuche. Ein erfolgreicher Test mit der Markierung belegt, dass die Suche einen Eintrag zurückgegeben hat, aber nicht, dass für jede unterstützte Sprache eine vollständige Übersetzung vorliegt. Prüfe die Ressourcenauflösung und die Vollständigkeit der Übersetzungen getrennt voneinander.

Label in der ausgewählten Sprache der Mac-App testen

Wenn deine App weitere Sprachen unterstützt, wähle in der Seitenleiste des Katalogs die betreffende Sprache aus und gib die Übersetzung in das Textfeld dieses Eintrags ein. Teste anschließend in der enthaltenden Mac-App. Apple dokumentiert die direkte Eingabe von Übersetzungen im Katalogeditor. Außerdem wird der Übersetzungsstatus jedes Eintrags während der Arbeit aktualisiert. Übersetzungen zu einem Zeichenfolgenkatalog hinzufügen.

Um den Debug-Lauf zu steuern, wähle Product > Scheme > Edit Scheme, dann Run und öffne Options. Stelle App Language auf eine vom Projekt unterstützte Sprache ein, schließe den Editor und starte die Mac-App erneut. Wähle System Language, wenn der Lauf der Spracheinstellung des Systems folgen soll. Lokalisierungen beim Ausführen der App testen.

Verwende das Argument locale: des Initializers für Zeichenfolgen nicht als Ersatz für diesen Sprachtest. Apple dokumentiert, dass dieses Argument die Lokalisierung interpolierter Werte wie Zahlen steuert, aber nicht die für die Suche nach der lokalisierten Zeichenfolge verwendete Locale ändert. Im Beispiel wird es weggelassen, da das Label keine interpolierten Werte enthält. Locale-Parameter lokalisierter Swift-Zeichenfolgen.

Halte den abschließenden Vertrag knapp und eindeutig: Panel.xcstrings gehört dem Framework, bei der Suche wird Panel ausgewählt und PANEL_OPEN_ACTION bezeichnet das Label. Überprüfe den Eintrag mithilfe der Diagnose und anschließend die angezeigte Übersetzung in der für den Lauf ausgewählten Sprache der App. So kannst du die Ressourcensuche korrigieren, bevor du Zeit in einen Wortlaut investierst, den die App möglicherweise gar nicht liest.

Quellen