لتوحيد الرسائل المتكررة في تطبيق Mac، عيّن لكل معنى مشترك مفتاح توطين وتعريف Swift واحدًا، ثم استخدمه أينما ظهرت تلك الرسالة. أبقِ الوسائط وقواعد الجمع وسياق المترجم معًا؛ فتطابق النص الإنجليزي وحده لا يكفي.
هذا الشرح موجّه إلى مطوّر Mac يتولى صيانة ملخص للتحديد في كل من SwiftUI ونافذة Interface Builder. والمهمة المحددة هي عرض رسائل مثل 2 items selected in Batch A. باتساق، دون صيانة قوالب جمل منفصلة في ملف XIB وشيفرة Swift. جميع الأعداد والتسميات أدناه اصطناعية.
حدّد الرسائل المتكررة التي تنتمي إلى المجموعة نفسها
قبل تعديل الكتالوجات، حدّد عقد الرسالة: ما معنى الجملة، وما القيم التي تقبلها، وأين تظهر. في هذا المثال، العقد هو:
| عنصر العقد | التعريف |
|---|---|
| المعنى | عدد العناصر المحددة حاليًا ضمن مجموعة مسماة |
| المفتاح | selection.summary |
| الجدول | Localizable |
| الحزمة | الحزمة الرئيسية للتطبيق |
| الوسيط 1 | عدد تحديد من النوع Int64 |
| الوسيط 2 | تسمية حرفية للمجموعة، مثل Batch A |
| التنويع | صيغة الجمع التي يحددها عدد العناصر المحددة |
| السياق | جملة حالة كاملة تُعرض في SwiftUI وفي تسمية AppKit |
استخدم هذا العقد معيارًا للتوحيد. يمكن لتكرارين مشاركة الرسالة عندما يتطابق معناهما ووسائطهما ودورهما النحوي. ينبغي أن يبقى عدد العناصر المحددة وعدد العناصر الإجمالي منفصلين، حتى لو كان كلاهما يعرض حاليًا 2 items. كما أن الزر المسمى Select يحتاج إلى رسالة مستقلة لأنه يعبّر عن إجراء.
تدعم Apple المفاتيح الصريحة ذات القيم الافتراضية المنفصلة لتوضيح المقصود من النص. يتيح لك ذلك تسمية الرسالة بحسب الغرض مع الإبقاء على صياغة المصدر سهلة القراءة. يوفّر التعليق السياق؛ أما المفتاح فيحدّد المدخل. المهيّئ ذو المفتاح الصريح في String.
اعتبر الجدول والحزمة جزءًا من عقد البحث أيضًا. فالمفتاح الموجود في جدول آخر هدف بحث منفصل. توثّق Apple اختيار الجدول عبر المعامل table أو tableName، وتوصي بتمرير النص القابل للتوطين عبر LocalizedStringResource. في هذا المثال، أبقِ المساعد والكتالوج في هدف التطبيق واستخدم الحزمة الرئيسية. إعداد نص تطبيقك للترجمة.
افهم الحد الفاصل بين الاستخراج وتنسيق وقت التشغيل
يحدث الاستخراج أثناء بناء Xcode: إذ يكتشف التعبيرات القابلة للتوطين والمدعومة ويزامن نص المصدر مع الكتالوجات. أما التوطين وقت التشغيل فيحدث عندما يحل التطبيق رسالة ويستبدل القيم الفعلية بها. العثور على مدخل في كتالوج يثبت أن الاستخراج عثر عليه؛ لكنه لا يثبت أن كل عنصر تحكم يعرضه على نحو صحيح.
لدى Interface Builder مسار عمل خاص بالموارد. توثّق Apple الكتالوجات المقترنة بلوحة القصة أو ملف XIB، بينما تضيف شيفرة Swift عادةً إلى جدول Localizable. ولا يصف مسار العمل الموثّق اسمًا مستعارًا بين الموارد يدمج الرسائل لمجرد تطابق صياغتها الظاهرة. ومن المسارات العملية المدعومة إسناد الرسالة المترجمة المشتركة من Swift بعد تحميل الواجهة. هذا تطبيق مستمد من واجهات Apple البرمجية الموثّقة. اكتشاف كتالوجات السلاسل.
يميّز SwiftUI أيضًا بين مفتاح توطين حرفي وقيمة سلسلة عادية. على سبيل المثال، يطلب Text("Summary") التوطين، بينما يعرض تمرير متغير من النوع String قيمته دون إجراء البحث. إن تغليف سلسلة وقت التشغيل في LocalizedStringKey يطلب البحث، لكن لا ينبغي الخلط بين ذلك وبين إثبات أن الاستخراج اكتشف قيمها المحتملة. LocalizedStringKey.
لذلك يُبقي التصميم أدناه القيمة الحرفية القابلة للاستخراج داخل مساعد واحد. ويحمل العدد والتسمية في LocalizedStringResource، ثم يحل ذلك المورد في الموضع الذي تحتاج فيه إلى سلسلة مكتملة. تصف Apple هذا النوع من الموارد بأنه وسيلة لتأجيل البحث عن التوطين. وهو متاح في macOS 13 والإصدارات الأحدث، وهو الحد الأدنى المستهدف لهذا المثال. LocalizedStringResource.
عرّف الرسالة المشتركة مرة واحدة في Swift
أنشئ مشروع تطبيق macOS باستخدام SwiftUI، واضبط إصدار النشر المستهدف على macOS 13 أو أحدث، وأضف Localizable.xcstrings إلى هدف التطبيق. في توثيق Xcode الحالي، مسار الإنشاء هو File > New > File from Template؛ ابحث عن string واختر String Catalog. توطين النصوص وتنويعها باستخدام كتالوج سلاسل.
استبدل نقطة دخول التطبيق التي أنشأها المشروع بالبرنامج الكامل أدناه. أزل نقطة دخول التطبيق الأصلية كيلا يتضمن الهدف سوى تصريح واحد لـ @main. تعمل نافذة SwiftUI بصورة مستقلة عن ملف XIB؛ ويُستخدم الصنف الفرعي المضمّن من AppKit عند تكييف تسمية موجودة في Interface Builder في القسم التالي.
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()
}
}
}
يحدّد المفتاح الثابت الرسالة؛ وتوفّر القيمة الافتراضية المضمّنة الجملة المصدر ووسائط وقت التشغيل. ويقبل المهيّئ أيضًا الجدول والحزمة وتعليق المترجم. الحزمة الافتراضية هي الحزمة الرئيسية. المهيّئ ذو المفتاح الصريح في LocalizedStringResource.
التسمية Batch A محتوى نموذجي يُدرج في الجملة، وليست مفتاح رسالة آخر. يحافظ هذا التمييز على فصل تسميات المجموعات عن صياغة الواجهة المحيطة بها. إذا كان تطبيقك الفعلي يستخدم أسماء مجموعات محددة ومترجمة، فوطّن تلك الأسماء عبر تعريفاتها الخاصة قبل تمريرها هنا.
لا تركّب هذه الجملة من أجزاء موطّنة كل على حدة، مثل عدد العناصر وitems selected in والتسمية. إن إبقاء الجملة كاملة ضمن العقد يمنح المترجمين وحدة واحدة يمكن تعديل صياغتها وترتيب وسائطها معًا.
وجّه تسمية Interface Builder عبر التعريف نفسه
في ملف XIB أو لوحة قصة موجودة، استخدم تسمية NSTextField ثابتة للملخص. اضبط صنفها المخصص على SelectionSummaryField ووحدتها على هدف التطبيق. امسح الجملة القديمة من قيمة النص في وقت التصميم، لأن هذه التسمية بالذات ستتلقى نصها الآن من تعريف Swift المشترك.
عند تحميل الواجهة، يستدعي الصنف الفرعي super.awakeFromNib() ويعيّن ملخصًا أوليًا اصطناعيًا. توثّق Apple awakeFromNib() على أنه الخطاف الذي يُستدعى بعد التحميل، وبعد إنشاء اتصالات المنافذ والإجراءات، وتشترط استدعاء تنفيذ الصنف الفائق. awakeFromNib().
في النافذة الفعلية، استدعِ updateSelection(count:collectionLabel:) على التسمية المتصلة كلما تغير التحديد، باستخدام قيم النموذج نفسها المقدمة إلى SwiftUI. استبدل الإسناد الأولي الاصطناعي بمسار التهيئة الفعلي للنافذة. فالإسناد لمرة واحدة أثناء التحميل لا يتتبع تغييرات التحديد اللاحقة.
يعيّن محوّل AppKit الخاصية stringValue، وهي طريقة موثّقة لتعيين نص NSTextField. بذلك يبقى التنسيق في Interface Builder بينما تنتقل ملكية الرسالة إلى Swift. خصص عرضًا كافيًا للجملة كاملة أو فعّل التفاف النص. NSTextField.
أبقِ نصوص الواجهة الثابتة غير المرتبطة بهذا التغيير ضمن مسار عمل مواردها الحالي. تتناول هذه الهجرة رسالة مشتركة واحدة؛ ولا حاجة إلى نقل كل تسمية إلى Swift. وتحقق أيضًا من أن الربط أو إسنادًا آخر من وحدة تحكم لا يستبدل الملخص لاحقًا بالصياغة القديمة.
اضبط صيغ الجمع دون تغيير الوسائط
اختر Product > Build، وافتح Localizable.xcstrings، ثم ابحث عن selection.summary. انقر مع الضغط على مفتاح Control على المدخل، واختر Vary by Plural، وحدد وسيط العدد إذا سألك Xcode أي وسيط تريد تنويعه. توثّق Apple سير العمل هذا للرسائل ذات القيم المضمّنة. توطين النصوص وتنويعها باستخدام كتالوج سلاسل.
بالنسبة إلى التوطين المصدر باللغة الإنجليزية، اجعل صيغة المفرد تنتج 1 item selected in Batch A.، والصيغة الأخرى تنتج جملًا مثل 2 items selected in Batch A.. حافظ على عنصري الوسيط النائب اللذين يوفّرهما Xcode. عدّل الصياغة المحيطة بدلًا من استبدال عنصر نائب بعدد أو تسمية نموذجية.
| الإدخال الاصطناعي | النتيجة الإنجليزية المتوقعة بعد ضبط الجمع |
|---|---|
العدد 0، التسمية Batch A |
0 items selected in Batch A. |
العدد 1، التسمية Batch A |
1 item selected in Batch A. |
العدد 2، التسمية Batch A |
2 items selected in Batch A. |
العدد 2، التسمية Batch B |
2 items selected in Batch B. |
هذه حالات قبول توضيحية وليست نتائج مقاسة. قبل ضبط الجمع، تظل جملة المصدر الافتراضية تتضمن items لكل عدد. يحافظ الاستخراج على الرسالة ذات القيم المضمّنة؛ لكنه لا يصحح قواعدها اللغوية تلقائيًا.
تُفيد التسمية المتغيرة في الصف الأخير للتشخيص: فإذا ظل العرض Batch A، فربما ثُبّتت قيمة نموذجية في إحدى الصيغ أو يمرر أحد المستدعين حالة قديمة. وإذا اختفت التسمية، فتحقق من العناصر النائبة في الصيغة قبل تغيير توقيع المساعد.
تحقّق من كل مسار عرض قبل إزالة المداخل القديمة
اختبر نافذة SwiftUI ونافذة Interface Builder الفعلية كلًا على حدة. استخدم الأعداد والتسميات نفسها فيهما. تحقق من التحميل الأولي ومن تغيير لاحق للتحديد ومن تسمية نموذجية أطول مثل Batch A Extended. تأكد من تطابق الصياغة ومن وضوح قراءة الجملة.
لكل توطين مدعوم، اختر Product > Scheme > Edit Scheme، ثم Run، وافتح Options، واضبط App Language. شغّل التطبيق مجددًا وافحص مساري العرض كليهما. توثّق Apple إعدادات المخطط هذه لاختبار التوطينات دون تغيير لغة النظام بأكمله. اختبار التوطينات عند تشغيل تطبيقك.
استخدم التسلسل التالي عندما تكون النتيجة غير صحيحة:
- المدخل غير موجود: تأكد من أن الكتالوج تابع لهدف التطبيق وابنِ المخطط المعني. تحقق من تفعيل
Use Compiler to Extract Swift Strings. - ظهور نص المصدر على نحو غير متوقع: تحقق من المفتاح والجدول والحزمة والترجمة قبل اعتبار النص الاحتياطي المقروء نجاحًا.
- اختلاف تسمية Interface Builder وحدها: تحقق من الصنف المخصص والوحدة ومسار التحميل والإسنادات اللاحقة.
- اختلاف القيم اللاحقة وحدها: تحقق من تلقي الواجهتين قيم النموذج المحدّثة.
- خطأ في صياغة الجمع: تحقق من وسيط العدد المحدد للتنويع ومن كل صيغة منطبقة.
توثّق Apple إعداد استخراج المترجم وتوضح أن المداخل المترجمة التي لم تعد موجودة في المصدر قد تبقى معلّمة بالحالة Stale. وهذه الحالة إشارة إلى ضرورة التنظيف، وليست دليلًا على أن المورد غير مستخدم. راجع إسناد الواجهة القديمة ومستدعي Swift قبل حذف مدخل وترجماته. اكتشاف كتالوجات السلاسل.
يكتمل التوحيد عندما تحصل الواجهتان على الرسالة السياقية نفسها من تعريف واحد، وتظل وسائطها سليمة، ولا يبقى أي مستدعٍ لقوالب الجمل القديمة. أبقِ العقد وحالات القبول إلى جانب المساعد، كي تحافظ تغييرات الصياغة المستقبلية على المعنى المشترك بين النافذتين.
المصادر
إعداد نص تطبيقك للترجمة — Apple
اكتشاف كتالوجات السلاسل — Apple
LocalizedStringKey — Apple
LocalizedStringResource — Apple
init(localized:defaultValue:table:bundle:locale:comment:) — Apple
NSTextField — Apple
awakeFromNib() — Apple