若要解析框架的本地化索引鍵,請同時傳入其資源套件和字串表。本指南將說明如何讓框架擁有的標籤在 Mac App 中正確顯示,接著確認結果確實來自字串表,而非備用文字。

這項任務刻意保持簡單:從框架的 Panel.xcstrings 目錄顯示合成標籤 Open panel。你需要一個 Xcode 中的 Mac App 專案,以及一個由你掌控的框架目標。主要範例使用 Xcode 26 或以上版本,目標平台為 macOS 12 或以上版本;Apple 文件指出,本地化字串初始化器自 macOS 12 起即可使用。Swift 初始化器文件。

變更程式碼前先確認套件、字串表和索引鍵

將本地化訊息視為具有三個明確座標的查找。套件用來識別資源擁有者,字串表用來識別該套件中的字串群組,而索引鍵用來識別該字串表中的項目。Apple 的本地化 API 將套件和字串表分開提供,因為框架和 App 目標都可以包含字串資源。準備 App 文字以供翻譯。

在這個範例中,開啟目錄前先記下以下約定。這些名稱僅供說明,並非 Apple 規定的名稱。

項目 範例值 用途
資源擁有者 你的框架目標 包含目錄
目錄檔案 Panel.xcstrings 儲存字串表的原始文字和翻譯
字串表引數 Panel 不含副檔名,選取該目錄
索引鍵 PANEL_OPEN_ACTION 識別訊息
英文原始值 Open panel 提供易讀的介面文字
註解 Label for the action that opens the panel. 說明訊息的用途

傳入 table: \"Panel\" 會選取由 Panel.xcstrings 表示的字串表。若未設定字串表,則會選取 Localizable。同樣地,若未設定套件,字串初始化器就會搜尋主 App 套件。因此,若框架目錄中有相符的索引鍵,查找時就必須同時指定框架套件和正確的字串表。Swift 本地化字串參數。

這提供了一個實用的診斷順序:先確認擁有者,再確認字串表,最後確認項目。如果訊息屬於框架,卻將查找指向 App 的資源,那麼搜尋索引鍵的其他拼法也無法解決問題。

將字串目錄加入框架目標

在 Xcode 中,選擇 File > New > File from Template,選取平台,篩選 string,然後選擇 String Catalog。將檔案命名為 Panel。確認目錄屬於框架目標,並與將參照它的框架原始碼放在一起。Apple 的目錄工作流程允許使用自訂目錄名稱,而其框架示範會在框架目標中建立目錄。使用字串目錄進行本地化和文字變化、Apple 的框架本地化示範。

此範例使用語意索引鍵,而不以顯示文字作為索引鍵。使用 PANEL_OPEN_ACTION 作為識別碼,並以 Open panel 作為預設值,程式碼就能明確表達這兩項內容。Apple 透過接受靜態索引鍵和獨立預設本地化值的初始化器支援這種做法。Swift 靜態索引鍵初始化器。

加入下方原始碼後,請建置框架目標。Xcode 會在建置期間尋找可本地化的 API 呼叫,並更新相關目錄。開啟 Panel.xcstrings,確認其中包含 PANEL_OPEN_ACTION、英文原始值 Open panel,以及說明性註解。如果缺少該項目,請檢查原始碼的目標成員資格,以及是否已建置包含該原始碼的目標。Apple 也提供 Editor > Assistant,可檢視與目錄項目相關的程式碼。填入並檢視字串目錄。

在框架內解析訊息

將這個完整的原始碼檔案放入框架目標。它會定義本地化字串,以及一個供所屬 Mac App 顯示的小型 SwiftUI 標籤。它也包含下一節會用到的診斷方法。程式碼已對照 Apple 文件所記載的簽章檢查;由於此處無法使用 Swift 編譯器,因此未實際執行。

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)
    }
}

#bundle 運算式會在撰寫它的位置進行評估。在這份框架原始碼中,它會提供與框架目標相關聯的套件。如果將相同運算式移到 App 目標的原始碼中,它提供的就會是 App 的套件。對於 Swift 套件目標,Apple 文件指出,此巨集會提供目標的資源套件。請將查找程式碼放在資源所屬的位置。Foundation 的套件巨集。

此宣告會傳回已完成本地化解析的一般 String。此檢視使用 Text(verbatim:) 明確顯示該結果。公開檢視只是一個標籤;請將它加入現有的 App 檢視,讓文字顯示在需要的位置。

巨集無法使用時,改用框架類別

Apple 也支援透過框架中定義的類別來定位框架套件。對於包含自有資源的傳統框架,以下是另一個完整的訊息提供者。請用它取代前面的 PanelMessages 宣告,並遵守上述目錄和部署需求。

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."
        )
    }
}

錨點類別必須編譯進你要使用其資源的框架。Apple 文件指出,Bundle(for:) 會傳回與提供的類別相關聯的套件;若適用,也包括其框架套件。若錨點是在 App 中編譯,就會識別出 App。如果使用套件資源或放在獨立套件中的資源,請選擇其實際資源套件;類別所在的位置本身並不能決定資源的擁有者。以類別為基礎的套件初始化器、使用巨集選取資源套件。

確認易讀文字來自成功的查找

在畫面上看到 Open panel,不足以證明目錄查找成功。查找失敗時,初始化器會傳回 defaultValue,因此相同的可見文字可能代表查找成功,也可能是使用了備用文字。這種行為有助於提供易讀的介面文字,但在開發期間可能掩蓋錯誤的套件或字串表。Swift 預設值行為。

第一個原始碼檔案中的 lookupReport() 方法可消除此歧義。它會使用一個特殊的備用標記進行查找,而這個標記不得作為真正的目錄值。請從執行中的 App 或現有的除錯環境檢查其傳回值。如果結果顯示沒有解析到項目,請先檢查選取的資源,再修改翻譯。

這項診斷直接依據 Bundle.localizedString(forKey:value:table:) 的文件行為:若找不到索引鍵,而且提供的備用文字不為空,方法就會傳回該備用文字。若找不到索引鍵,且備用文字為 nil 或空字串,方法則會傳回索引鍵本身。使用標記有助於更容易區分查找失敗和合法的原始文字。套件本地化字串的傳回值).

觀察結果 下一步檢查
診斷結果傳回找不到項目的訊息 確認目錄已建置到所選套件中,接著檢查 Panel 和 PANEL_OPEN_ACTION
診斷結果解析出非預期值 檢查所選字串表中的該項目,以及目前執行所使用的語言
診斷結果正確,但介面顯示不同 追查介面實際顯示的是哪個值
翻譯執行期間顯示英文原始值 檢查該項目的翻譯和執行設定;查找成功本身並不能證明所需翻譯已存在

這份表格是根據查找約定整理出的疑難排解步驟。標記測試成功,代表查找傳回了一個項目,但不能證明所有支援的語言都已完成翻譯。請將資源解析和翻譯完整性分開檢查。

使用 Mac App 所選語言測試標籤

若 App 支援其他語言,請在目錄側邊欄選取相關語言,並在該項目的文字欄位輸入翻譯。接著透過所屬的 Mac App 進行測試。Apple 文件指出,可以直接在目錄編輯器中輸入翻譯,並會隨著工作進行更新各項目的翻譯狀態。將翻譯加入字串目錄。

若要控制除錯執行語言,請選擇 Product > Scheme > Edit Scheme,選取 Run,然後開啟 Options。將 App Language 設為專案支援的語言,關閉編輯器,再次執行 Mac App。如果希望執行時遵循系統的語言設定,請選擇 System Language。執行 App 時測試本地化。

請勿以字串初始化器的 locale: 引數代替此語言測試。Apple 文件指出,此引數會控制插值內容的本地化,例如數字,但不會改變查找本地化字串所使用的地區設定。範例中沒有使用它,因為標籤不含插值內容。Swift 本地化字串的地區設定參數。

最後的約定應保持簡單明確:框架擁有 Panel.xcstrings,查找選取 Panel,而 PANEL_OPEN_ACTION 用來識別標籤。先透過診斷確認項目,再確認它在 App 所選的執行語言中顯示正確的翻譯。這個順序能讓你先修正資源查找,再花時間調整 App 可能根本沒有讀取的文字。

來源