Om herhaalde berichten in een Mac-app samen te voegen, geef je elke gedeelde betekenis één lokalisatiesleutel en één Swift-definitie, en gebruik je die overal waar dat bericht verschijnt. Houd de argumenten, meervoudsregels en context voor vertalers bij elkaar; alleen overeenkomende Engelse tekst is niet voldoende.

Deze uitleg is bedoeld voor een Mac-ontwikkelaar die een selectiesamenvatting onderhoudt in zowel SwiftUI als een Interface Builder-venster. De concrete taak is om berichten zoals 2 items selected in Batch A. consistent weer te geven, zonder afzonderlijke zinsjablonen in een XIB en Swift-code te onderhouden. Alle aantallen en labels hieronder zijn synthetisch.

Bepaal welke herhaalde berichten bij elkaar horen

Definieer voordat je catalogi bewerkt het berichtcontract: wat de zin betekent, welke waarden deze accepteert en waar deze verschijnt. Voor dit voorbeeld is het contract:

Contractelement Definitie
Betekenis Aantal momenteel geselecteerde items binnen een benoemde verzameling
Sleutel selection.summary
Tabel Localizable
Bundel Hoofdbundel van de app
Argument 1 Een selectietelling van het type Int64
Argument 2 Een letterlijk verzamelingslabel, zoals Batch A
Variatie Meervoudsvorm bepaald door de selectietelling
Context Een volledige statuszin die wordt weergegeven in SwiftUI en een AppKit-label

Gebruik dit contract als toets voor samenvoeging. Twee voorkomens kunnen hetzelfde bericht delen als hun betekenis, argumenten en grammaticale functie overeenkomen. Een telling van geselecteerde items en een telling van alle items moeten afzonderlijk blijven, zelfs als beide momenteel 2 items weergeven. Een knop met de naam Select heeft ook een eigen bericht nodig, omdat deze een actie uitdrukt.

Apple ondersteunt expliciete sleutels met afzonderlijke standaardwaarden, speciaal om tekst eenduidig te maken. Zo kun je een bericht naar zijn doel benoemen en tegelijk de leesbare brontekst behouden. Een opmerking geeft context; de sleutel identificeert de vermelding. De initializer van String met expliciete sleutel.

Beschouw de tabel en bundel ook als onderdeel van het opzoekcontract. Een sleutel in een andere tabel is een afzonderlijk opzoekdoel. Apple beschrijft tabelselectie via de parameter table of tableName en raadt aan lokaliseerbare tekst door te geven via LocalizedStringResource. Houd voor dit voorbeeld de helper en catalogus in het appdoel en gebruik de hoofdbundel. De tekst van je app voorbereiden op vertaling.

Begrijp het onderscheid tussen extractie en opmaak tijdens runtime

Extractie vindt plaats tijdens het bouwen in Xcode: daarbij worden ondersteunde lokaliseerbare expressies gevonden en wordt hun brontekst gesynchroniseerd met catalogi. Lokalisatie tijdens runtime vindt plaats wanneer de app een bericht opzoekt en de werkelijke waarden invult. Dat een vermelding in een catalogus staat, bewijst dat deze bij extractie is gevonden; het bewijst niet dat elk besturingselement deze correct weergeeft.

Interface Builder heeft een eigen resourceworkflow. Apple beschrijft catalogi die zijn gekoppeld aan een storyboard of XIB, terwijl Swift-broncode doorgaans bijdraagt aan de tabel Localizable. De beschreven workflow vermeldt geen alias tussen resources waarmee berichten worden samengevoegd alleen omdat hun zichtbare tekst overeenkomt. Een praktische, ondersteunde aanpak is om het gedeelde gelokaliseerde bericht vanuit Swift toe te wijzen nadat de interface is geladen. Dit is een implementatie die is afgeleid van de door Apple beschreven API’s. Stringcatalogi ontdekken.

SwiftUI maakt ook onderscheid tussen een letterlijke lokalisatiesleutel en een gewone tekenreekswaarde. Text("Summary") vraagt bijvoorbeeld om lokalisatie, terwijl het doorgeven van een String-variabele de waarde ervan weergeeft zonder die opzoeking. Een runtime-tekenreeks in LocalizedStringKey verpakken vraagt om opzoeking, maar bewijst niet dat extractie de mogelijke waarden heeft gevonden. LocalizedStringKey.

Het onderstaande ontwerp houdt de extraheerbare letterlijke tekst daarom in één helper. Deze bevat de telling en het label in een LocalizedStringResource en lost die resource vervolgens op waar een voltooide tekenreeks nodig is. Apple beschrijft dit resourcetype als een manier om het opzoeken van lokalisatie uit te stellen. Het is beschikbaar vanaf macOS 13 en dat is de minimale doelversie voor dit voorbeeld. LocalizedStringResource.

Definieer het gedeelde bericht één keer in Swift

Maak een macOS-appproject met SwiftUI, stel de implementatiedoelversie in op macOS 13 of hoger en voeg Localizable.xcstrings toe aan het appdoel. In de huidige Xcode-documentatie is het aanmaakpad File > New > File from Template; zoek naar string en selecteer String Catalog. Tekst lokaliseren en variëren met een stringcatalogus.

Vervang het gegenereerde app-entrypoint door het volledige onderstaande programma. Verwijder het oorspronkelijke app-entrypoint zodat het doel slechts één @main-declaratie bevat. Het SwiftUI-venster werkt onafhankelijk van een XIB; de opgenomen AppKit-subklasse wordt gebruikt wanneer je in de volgende sectie een bestaande Interface Builder-label aanpast.

import AppKit
import Foundation
import SwiftUI

enum SelectionMessages {
    static func summary(
        count: Int64,
        collectionLabel: String
    ) -> LocalizedStringResource {
        LocalizedStringResource(
            "selection.summary",
            defaultValue: "\(count) items selected in \(collectionLabel).",
            table: "Localizable",
            comment: "Complete selection-status sentence used in SwiftUI and an AppKit label. Argument 1 is the selected-item count; argument 2 is a literal collection label. Pluralize by argument 1."
        )
    }
}

struct SelectionDemoView: View {
    private let counts: [Int64] = [0, 1, 2]
    private let collectionLabel = "Batch A"

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            ForEach(counts, id: \.self) { count in
                Text(String(localized: SelectionMessages.summary(
                    count: count,
                    collectionLabel: collectionLabel
                )))
            }
        }
        .padding(24)
        .frame(minWidth: 360, minHeight: 160)
    }
}

final class SelectionSummaryField: NSTextField {
    override func awakeFromNib() {
        super.awakeFromNib()
        // Synthetic initial state for the Interface Builder example.
        updateSelection(count: 2, collectionLabel: "Batch A")
    }

    func updateSelection(count: Int64, collectionLabel: String) {
        stringValue = String(localized: SelectionMessages.summary(
            count: count,
            collectionLabel: collectionLabel
        ))
    }
}

@main
struct SelectionDemoApp: App {
    var body: some Scene {
        WindowGroup {
            SelectionDemoView()
        }
    }
}

De statische sleutel identificeert het bericht; de geïnterpoleerde standaardwaarde levert de bronzin en runtimeargumenten. De initializer accepteert ook de tabel, bundel en opmerking voor vertalers. De standaardbundel is de hoofdbundel. De initializer van LocalizedStringResource met expliciete sleutel.

Het label Batch A is voorbeeldinhoud die in de zin wordt ingevoegd. Het is geen andere berichtsleutel. Dit onderscheid houdt verzamelingslabels gescheiden van de omringende interfacetekst. Als je echte app vooraf gedefinieerde, vertaalde verzamelnamen gebruikt, lokaliseer die namen dan via hun eigen definities voordat je ze hier opgeeft.

Stel deze zin niet samen uit afzonderlijk gelokaliseerde onderdelen, zoals een telling, items selected in en een label. Door de volledige zin in het contract te houden, krijgen vertalers één geheel waarvan de formulering en argumentvolgorde samen kunnen worden aangepast.

Laat het Interface Builder-label dezelfde definitie gebruiken

Gebruik voor een bestaande XIB of storyboard een statisch NSTextField-label voor de samenvatting. Stel de aangepaste klasse in op SelectionSummaryField en de module op het appdoel. Wis de oude zin uit de ontwerptekstwaarde, omdat dit specifieke label zijn tekst nu uit de gedeelde Swift-definitie krijgt.

Wanneer de interface wordt geladen, roept de subklasse super.awakeFromNib() aan en wijst deze de synthetische beginsamenvatting toe. Apple beschrijft awakeFromNib() als de hook na het laden, wanneer outlet- en actionverbindingen tot stand zijn gebracht, en vereist dat de implementatie van de superklasse wordt aangeroepen. awakeFromNib().

Roep in het echte venster updateSelection(count:collectionLabel:) aan op het gekoppelde label telkens wanneer de selectie verandert, met dezelfde modelwaarden als voor SwiftUI. Vervang de synthetische begintoewijzing door het daadwerkelijke initialisatiepad van het venster. Een eenmalige toewijzing tijdens het laden kan latere selectiewijzigingen niet volgen.

De AppKit-adapter stelt stringValue in, een gedocumenteerde manier om de tekst van een NSTextField toe te wijzen. Zo blijft de opmaak in Interface Builder terwijl Swift het bericht beheert. Zorg voor voldoende breedte of tekstterugloop om de volledige zin weer te geven. NSTextField.

Laat niet-gerelateerde statische interfacetekst in de bestaande resourceworkflow staan. Deze migratie betreft één gedeeld bericht; het is niet nodig elk label naar Swift te verplaatsen. Controleer ook of een binding of een andere controller-toewijzing de samenvatting later niet alsnog vervangt door de oude tekst.

Configureer meervoudsvormen zonder de argumenten te wijzigen

Kies Product > Build, open Localizable.xcstrings en zoek selection.summary. Klik met Control ingedrukt op de vermelding, kies Vary by Plural en selecteer het numerieke telargument als Xcode vraagt welk argument moet variëren. Apple beschrijft deze workflow voor geïnterpoleerde berichten. Tekst lokaliseren en variëren met een stringcatalogus.

Laat voor de Engelse brontaal de enkelvoudsvorm 1 item selected in Batch A. opleveren en de andere vorm zinnen zoals 2 items selected in Batch A.. Behoud beide argumentplaceholders die Xcode aanlevert. Bewerk de omringende formulering in plaats van een placeholder te vervangen door een voorbeeldtelling of -label.

Synthetische invoer Verwacht Engels resultaat na configuratie van de meervoudsvorm
Telling 0, label Batch A 0 items selected in Batch A.
Telling 1, label Batch A 1 item selected in Batch A.
Telling 2, label Batch A 2 items selected in Batch A.
Telling 2, label Batch B 2 items selected in Batch B.

Dit zijn illustratieve acceptatiegevallen, geen gemeten resultaten. Vóór configuratie van de meervoudsvorm bevat de standaardbronzin voor elke telling nog items. Extractie behoudt het geïnterpoleerde bericht; de grammatica wordt niet zelfstandig gecorrigeerd.

Het veranderende label in de laatste rij is diagnostisch nuttig: als de weergave Batch A blijft tonen, kan een voorbeeldwaarde hardgecodeerd zijn in een variant of kan een aanroeper verouderde status doorgeven. Als het label verdwijnt, controleer dan de placeholders van de variant voordat je de signatuur van de helper wijzigt.

Controleer elk weergavepad voordat je oude vermeldingen verwijdert

Test het SwiftUI-venster en het daadwerkelijke Interface Builder-venster afzonderlijk. Gebruik in beide dezelfde aantallen en labels. Controleer het laden, een latere selectiewijziging en een langer synthetisch label zoals Batch A Extended. Bevestig dat de formulering overeenkomt en de zin leesbaar blijft.

Selecteer voor elke ondersteunde lokalisatie Product > Scheme > Edit Scheme, kies Run, open Options en stel App Language in. Start de app opnieuw en bekijk beide weergavepaden. Apple beschrijft deze schemainstellingen voor het testen van lokalisaties zonder de taal van het hele systeem te wijzigen. Lokalisaties testen wanneer je app wordt uitgevoerd.

Volg deze stappen als een resultaat niet klopt:

  1. Vermelding ontbreekt: Controleer of de catalogus bij het appdoel hoort en bouw het relevante schema. Controleer of Use Compiler to Extract Swift Strings is ingeschakeld.
  2. Brontekst verschijnt onverwacht: Controleer de sleutel, tabel, bundel en vertaling voordat je leesbare terugvaltekst als succes beschouwt.
  3. Alleen het Interface Builder-label wijkt af: Controleer de aangepaste klasse, module, laadroute en latere toewijzingen.
  4. Alleen latere waarden wijken af: Controleer of beide interfaces bijgewerkte modelwaarden ontvangen.
  5. Meervoudsvorm is onjuist: Controleer welk numeriek argument voor variatie is geselecteerd en controleer elke toepasselijke variant.

Apple documenteert de compilerinstelling voor extractie en legt uit dat vertaalde vermeldingen die niet meer in de broncode worden gevonden de status Stale kunnen behouden. Die status is een opruimsignaal, geen bewijs dat een resource ongebruikt is. Controleer de oude interfacetoewijzing en Swift-aanroepen voordat je een vermelding en de bijbehorende vertalingen verwijdert. Stringcatalogi ontdekken.

De samenvoeging is voltooid wanneer beide interfaces hetzelfde contextuele bericht uit één definitie halen, de argumenten intact blijven en de oude zinsjablonen nergens meer worden aangeroepen. Bewaar het contract en de acceptatiegevallen bij de helper, zodat toekomstige wijzigingen in de formulering de gedeelde betekenis voor beide vensters behouden.

Bronnen