لإنشاء تسمية macOS قابلة لإعادة الاستخدام، اقبل الرسائل القابلة للتوطين بصيغة LocalizedStringResource، واحتفظ بمسار منفصل باستخدام verbatim: للنص الحرفي، وأبقِ الاستيفاء كما هو حتى مرحلة التوطين. يطبّق هذا الدليل هذا العقد على عدّاد عناصر لسطح المكتب، ويفحص استخراج النصوص بمعزل عن عرضها.

ما الذي ينبغي أن تضمنه واجهة النص القابلة لإعادة الاستخدام؟

لنفترض أن تطبيق Mac يحتاج إلى ملخص موجز يعرض عدد العناصر واسم مجموعة اصطناعيًا مثل Sample Set. يجب أن يميّز المكوّن القابل لإعادة الاستخدام بين ثلاثة مدخلات: رسالة من تأليف التطبيق تحتاج إلى ترجمة، ومفتاح توطين موجود في SwiftUI، ونص يجب أن يظهر تمامًا كما قُدّم.

توصي Apple باستخدام LocalizedStringResource لتمثيل السلاسل القابلة للتوطين وتمريرها عبر العروض المخصّصة وغيرها من شيفرات Swift. وتعرض إرشاداتها الحالية خصائص في عروض مخصّصة من هذا النوع تُعرض باستخدام Text. استخدمه بوصفه عقد الرسائل الأساسي عند تصميم مكوّن جديد. إعداد نص تطبيقك للترجمة.

يوضّح جدول القرار التالي تصميمًا للواجهة مستندًا إلى هذه السلوكيات الموثّقة. تجعل تسميات الوسائط الصريحة مقصد المستدعي قابلًا للمراجعة، من دون الاعتماد على تحميلين زائدين متنافسين لسلاسل نصية بلا تسميات.

مقصد المستدعي نقطة الدخول المقترحة مسار العرض
تمرير رسالة قابلة للترجمة مع سياق اختياري SummaryLabel(localized:) Text(resource)
تمرير مفتاح SwiftUI، بما في ذلك الاستيفاء في SwiftUI SummaryLabel(key:) Text(key, tableName:bundle:)
عرض تسمية حرفية SummaryLabel(verbatim:) Text(verbatim:)
توفير نص صاغه المستدعي مسبقًا SummaryLabel(text:) تخزين كائن Text المقدّم

أبقِ LocalizedStringKey متاحًا عندما يحتاج المكوّن تحديدًا إلى سلوك SwiftUI القائم على المفاتيح. توثّق Apple أن سلسلة نصية حرفية تُمرّر مباشرة إلى Text تنشئ مفتاح توطين، بينما تسلك قيمة String عادةً مسارًا يتجاوز التوطين. لذلك، فإن غلافًا لا يقبل سوى String يغيّر معنى استدعاءات تبدو متشابهة. LocalizedStringKey.

أنشئ مكوّنًا كاملًا بنقاط دخول صريحة

استخدم مشروع تطبيق SwiftUI لنظام macOS في Xcode 26 أو إصدار أحدث، واضبط هدف النشر على macOS 26 في هذا المثال. استبدل تعريفات التطبيق وعرض المحتوى التي أُنشئت تلقائيًا بالبرنامج الكامل أدناه، وأبقِ تعريفًا واحدًا فقط لـ @main في الهدف. جميع التسميات والأعداد اصطناعية. روجعت الشيفرة بالاستناد إلى واجهات API الموثّقة، لكن لم تُترجم هنا لعدم توفر مترجم Swift في هذه البيئة.

import Foundation
import SwiftUI

struct SummaryLabel: View {
    private let text: Text

    init(localized resource: LocalizedStringResource) {
        text = Text(resource)
    }

    init(
        key: LocalizedStringKey,
        tableName: String? = nil,
        bundle: Bundle? = nil,
        comment: StaticString? = nil
    ) {
        text = Text(
            key,
            tableName: tableName,
            bundle: bundle,
            comment: comment
        )
    }

    init(verbatim value: String) {
        text = Text(verbatim: value)
    }

    init(text: Text) {
        self.text = text
    }

    var body: some View {
        text
            .font(.callout)
            .padding(8)
    }
}

struct ContentView: View {
    @State private var itemCount = 2
    private let collectionLabel = "Sample Set"

    var body: some View {
        VStack(alignment: .leading, spacing: 12) {
            Stepper(value: $itemCount, in: 0...12) {
                Text("Item count")
            }

            SummaryLabel(
                localized: LocalizedStringResource(
                    "summary.item-count",
                    defaultValue: "\(itemCount) items",
                    comment: "Summary below the item-count control. The integer is the number of items."
                )
            )

            SummaryLabel(
                key: "Collection: \(collectionLabel)"
            )

            SummaryLabel(verbatim: collectionLabel)

            SummaryLabel(
                text: Text(
                    "Preview",
                    comment: "Heading for a preview of the current item selection."
                ).bold()
            )
        }
        .padding(20)
        .frame(minWidth: 320)
    }
}

@main
struct TextContractDemoApp: App {
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

يفصل مُهيّئ المورد عمدًا بين المفتاح الثابت summary.item-count والرسالة الافتراضية \(itemCount) items. توثّق Apple لهذا المُهيّئ مفتاحًا ثابتًا وقيمة افتراضية قابلة للتوطين وجدولًا وإعدادات لغة وحزمة وتعليقًا للمترجم. وتُستخدم القيمة الافتراضية عند غياب المفتاح عن الجدول المحدد. مُهيّئ LocalizedStringResource.

يقدّم المُهيّئ verbatim: ضمانًا واضحًا بالقدر نفسه: عرض السلسلة المقدّمة دون توطين. وهو يعمل مع وسيط حرفي ومع متغير أيضًا. استخدم هذا المسار لتسمية المجموعة الاصطناعية عندما يكون المطلوب عرض تهجئتها كما هي. Text.init(verbatim:).

تتيح نقطة الدخول text: للمستدعي إنشاء نص موطّن أو منسّق قبل تمريره. يضيف هذا المكوّن تنسيقًا طباعيًا وتباعدًا مشتركين، بينما يظل المستدعي مسؤولًا عن اختيار دلالات الرسالة. وتمرير Text منفذ للهروب، لذا يمكن للمكوّن الذي يحتاج إلى فرض عقد أضيق حذف هذا المُهيّئ.

ما الفرق بين الاستخراج والتنسيق وقت التشغيل؟

تعامل مع التوطين على أنه فحصان منفصلان. أثناء البناء، يعثر Xcode على تعبيرات المصدر القابلة للتوطين ويحدّث كتالوج السلاسل. وأثناء التنفيذ، يحلّ التطبيق الرسالة ويستبدل وسائطها. تصف جلسة كتالوج السلاسل من Apple صراحةً التعرّف على القيم الحرفية المستخدمة لإنشاء LocalizedStringResource عند موضع استدعاء عرض مخصّص. وتشير أيضًا إلى إعداد البناء Use Compiler to Extract Swift Strings. اكتشاف كتالوجات السلاسل.

يجب أن يصل الاستيفاء إلى نوع واعٍ بالتوطين قبل أن يتحول إلى سلسلة مكتملة عادية. توضح Apple أن أداة إنشاء الاستيفاء في SwiftUI تُبقي مفتاح التنسيق وقيم الوسائط منفصلين، ما يسمح بالتوطين قبل الاستبدال. ولا يمكن لتحويل String سبق استيفاؤه إلى مفتاح أن يستعيد الوسائط الأصلية ذات الأنواع المحددة. ما الجديد في Swift.

يوضح هذا المقتطف التشخيصي الفرق؛ وهو ليس تطبيقًا ثانيًا. جميع القيم المستخدمة فيه معرّفة محليًا.

import SwiftUI

let count = 2

// Ordinary String interpolation has already produced "2 items".
let completed: String = "\(count) items"
let exactDisplay = Text(completed)

// Looks up the completed value as a key.
// This does not restore a count placeholder.
let completedValueLookup = Text(LocalizedStringKey(completed))

// Preserves localization-aware interpolation from the beginning.
let messageKey: LocalizedStringKey = "\(count) items"
let interpolatedDisplay = Text(messageKey)

يُعد إنشاء LocalizedStringKey من متغير طريقة موثّقة لطلب البحث وقت التشغيل. وهي مفيدة عندما يحتوي المتغير عمدًا على مفتاح معروف. لكنها لا تضمن أن Xcode استخرج كل القيم الممكنة لهذا المتغير إلى كتالوج. احتفظ بمفاتيح ديناميكية مقصودة يدويًا، أو استخدم تعريفات موارد حرفية للرسائل المحدودة التي يملكها تطبيقك. سلوك البحث والقيمة الاحتياطية موثّقان في Text.init(_:tableName:bundle:comment:).

أبقِ الرسالة كاملة، بما في ذلك علامات الترقيم ومواضع العناصر النائبة، ضمن تعبير واحد قابل للتوطين. في هذا المثال، أبقِ Collection: \(collectionLabel) معًا. إن تكوين رسالة مكتملة من أجزاء حُلّت منفردة سيترك للمستدعي مسؤولية ترتيبها وتباعدها.

أضف الكتالوج واضبط سلوك الجمع

أولًا، أضف كتالوج سلاسل من خلال File > New > File from Template، واختر String Catalog، وسمّه Localizable. ثم اختر Product > Build. توثّق Apple أن البناء يملأ الكتالوج من واجهات API القابلة للتوطين ويحدّثه عند تغيّر رسائل المصدر. توطين النصوص وتنويعها باستخدام كتالوج سلاسل.

في العينة، افحص الإدخال summary.item-count والعدد الصحيح المستوفى فيه. انقر على الإدخال مع الضغط على Control واختر Vary by Plural. في التوطين الإنجليزي للمصدر، اضبط One على %lld item وOther على %lld items، مع الإبقاء على العنصر النائب للعدد الصحيح الذي يوفّره Xcode. أضف الصيغ المطلوبة عند إضافة توطينات أخرى؛ إذ تختلف فئات الجمع حسب اللغة. توطين النصوص وتنويعها باستخدام كتالوج سلاسل.

يوفّر الاستيفاء العدد، لكنه لا ينشئ بمفرده صياغة المفرد. يوضّح الدرس العملي من Apple كيفية إضافة صيغ الجمع في الكتالوج وكيف يختار النظام الصيغة المطابقة وقت التشغيل. لذلك، لا يمثّل نجاح البناء واستخراج الرسالة سوى جزء من التحقق. درس عملي: استكشاف التوطين باستخدام Xcode.

استخدم مصفوفة القبول الصغيرة هذه بعد ضبط صيغ الجمع للمصدر. هذه نتائج متوقعة للبرنامج التوضيحي، وليست نتائج تنفيذ مُبلّغًا عنها.

الفحص النتيجة المتوقعة
ابنِ المشروع وافحص summary.item-count إدخال رسالة واحد مع استبدال عدد صحيح
اضبط العدد على 0 0 items
اضبط العدد على 1 1 item
اضبط العدد على 2 2 items
افحص صف التسمية الحرفية تبقى Sample Set حرفية
افحص رسالة المجموعة تكون التسمية وسيطًا ضمن الرسالة الكاملة

شخّص الإدخالات المفقودة بمعزل عن العرض غير الصحيح

إذا غابت رسالة عن الكتالوج، فافحص نوع المصدر أولًا. قد تكون وسيطة String قد أزالت التعبير القابل للتوطين قبل وصوله إلى المكوّن. افحص هدف الكتالوج، وابنِ المخطط الذي يتضمن موضع الاستدعاء، وتحقق من إعداد Use Compiler to Extract Swift Strings. تصف Apple الاستخراج بأنه يعمل على المخطط والمنصة الحاليين، لذا افحص الإعدادات التي تترجم الرسالة فعليًا. اكتشاف كتالوجات السلاسل.

إذا كان الإدخال موجودًا لكن التطبيق يعرض مفتاحًا أو نصًا احتياطيًا، فافحص إعدادات البحث. يبحث مُهيّئ Text القائم على المفتاح في الجدول والحزمة المحددين؛ وعند حذف القيم، يُختار الجدول الافتراضي والحزمة الرئيسية. ويؤدي غياب المفتاح أو الجدول إلى عرض التمثيل النصي للمفتاح. لذلك قد تخفي قيمة احتياطية مقروءة نقصًا في إعدادات البحث. Text.init(_:tableName:bundle:comment:).

عند نقل المكوّن إلى إطار عمل أو حزمة، حدّد مكان الرسائل. تحتاج الرسائل التي يملكها المكوّن إلى حزمة موارده؛ أما الموارد التي يملكها المستدعي فينبغي أن تحتفظ بمعلومات البحث المقدّمة معها. تدعم إرشادات Apple الحالية تمرير #bundle إلى واجهات التوطين لتحديد حزمة الهدف الحاوي. وتحتاج الجداول المسماة كذلك إلى كتالوجات مطابقة. إعداد نص تطبيقك للترجمة.

أخيرًا، لا تفترض أن كل استيفاء يقبله SwiftUI يصلح أيضًا ضمن مورد Foundation. فـ LocalizedStringKey لديه أساليب استيفاء خاصة به، بما فيها صيغ التنسيق والمتغيرات التي تستخدم أدوات التنسيق. اختر نوع الرسالة قبل تكوين التعبير، وراجع عمليات الاستيفاء المدعومة إذا تعذّر ترجمة وسيط. LocalizedStringKey.StringInterpolation.

يكون مكوّن النص القابل لإعادة الاستخدام جاهزًا عندما يستطيع المستدعون التعبير عن مقصدهم بوضوح والتحقق منه في المرحلتين: ينتج البناء رسالة الكتالوج المطلوبة، ويعرض تطبيق Mac أثناء التشغيل الاستبدال أو صيغة الجمع أو التسمية الحرفية الصحيحة. أبقِ هذه الفحوص إلى جانب عقد الواجهة كلما تغيّر المكوّن.

المصادر