Globalization (العولمة، وأيضاً التدويل، i18n) — عملية إعداد التطبيق المحمول للعمل بعدة لغات وتنسيقات إقليمية دون تغيير الكود المصدري. تتضمن استخراج موارد السلاسل النصية من الكود، ودعم تنسيقات مختلفة للتواريخ والأرقام والعملات، ومراعاة اتجاه النص (LTR/RTL)، وتكييف التخطيط للغات المختلفة. في iOS يُستخدم NSLocalizedString و Localizable.strings، وفي Android يُستخدم strings.xml في أدلة values-{lang}. للمزيد — في وثائق Apple حول التدويل.
أهم النقاط
Globalization (اختصاراً i18n — 18 حرفاً بين "i" و "n") — الإعداد المعماري للتطبيق للعمل مع أي لغة ومنطقة. القاعدة الأساسية لـ i18n: لا يجب أن يكون أي نص ثابتاً (hardcoded) في الكود المصدري. بدلاً من ذلك، تُستخرج السلاسل النصية إلى ملفات موارد، ويتعامل معها الكود عبر مفاتيح. عند إضافة لغة جديدة، يكفي إضافة ملف ترجمة — يبقى الكود دون تغيير. هذا ما يميز i18n عن التوطين (l10n)، حيث تُترجم السلاسل نفسها.
الحجة التجارية — العولمة توسع السوق. وفقاً لـ Common Sense Advisory (2023)، أكثر من 70% من المستخدمين يفضلون الشراء في التطبيقات بلغتهم الأم. التوطين إلى 10 لغات يزيد الجمهور المحتمل بنسبة 80%. بدون i18n، كل توسع إلى لغة جديدة يتطلب تعديلات في الكود، مما يبطئ الوصول إلى السوق ويزيد التكاليف من 5 إلى 10 أضعاف. البنية التحتية الصحيحة لـ i18n تتيح دعم أكثر من 40 لغة بأقل التكاليف.
مكونات i18n تشمل: استخراج السلاسل النصية، صيغ الجمع (pluralization لـ 1/2/5+)، تنسيق التواريخ والأرقام (DateFormatter/SimpleDateFormat)، دعم اللغات RTL (من اليمين إلى اليسار)، الفرز وفق قواعد الإعدادات المحلية (Collator)، الرموز الإقليمية (فواصل الآلاف، العلامات العشرية). في IT Sectr، نضع i18n في مرحلة البنية التحتية، وليس لاحقاً — وهذا يوفر حتى 60% من الوقت عند التوطين اللاحق.
NSLocalizedString — الماكرو الرئيسي في Swift للعمل مع الترجمات. الصيغة: NSLocalizedString("key", comment: "وصف للمترجم"). يقوم الماكرو تلقائياً باستبدال السلسلة النصية من Localizable.strings بناءً على الإعدادات المحلية الحالية للجهاز (NSLocale.preferredLanguages). إذا لم يُعثر على ترجمة للمفتاح، يتم إرجاع المفتاح نفسه أو القيمة بلغة التطوير (عادة en). توصي Apple باستخدام مفاتيح ذات معنى بدلاً من استخدام السلاسل الإنجليزية كمفاتيح.
// Localizable.strings (en)
// "welcome_title" = "Welcome!";
// Localizable.strings (ru)
// "welcome_title" = "مرحبًا بك!";
// كود Swift — موحد لجميع اللغات
titleLabel.text = NSLocalizedString(
"welcome_title",
comment: "عنوان شاشة الترحيب"
)
// صيغ الجمع عبر Localizable.stringsdict
//
// <dict>
// <key>items_count</key>
// <dict>
// <key>NSStringLocalizedFormatKey</key>
// <string>%#@items@</string>
// <key>items</key>
// <dict>
// <key>one</key>
// <string>%d منتج</string>
// <key>few</key>
// <string>%d منتجان</string>
// <key>many</key>
// <string>%d منتجات</string>
// </dict>
// </dict>
// </dict>
// استخدام صيغ الجمع
let items = 5
let label = String.localizedStringWithFormat(
NSLocalizedString("items_count", comment: ""), items
)
XLIFF — تنسيق تبادل الترجمات بين المطورين والمترجمين. يصدر Xcode ملف XLIFF (Editor → Export for Localization) يحتوي على جميع السلاسل للترجمة. يعمل المترجم على XLIFF في أدوات CAT (Trados، memoQ، Smartcat). بعد الترجمة، يُستورد XLIFF مرة أخرى إلى Xcode (Editor → Import Localizations). يقوم XLIFF تلقائياً بتحديث جميع أدلة .lproj. هذه هي سير العمل القياسية لتوطين تطبيقات iOS في الإنتاج.
SwiftUI يعمل مع NSLocalizedString عبر المُهيئ Text. النص في SwiftUI مُدول تلقائياً: Text("welcome_title") يبحث عن الترجمة في Localizable.strings تماماً مثل NSLocalizedString. لصيغ الجمع، استخدم Text("%d items", count: items). يدعم SwiftUI تنسيق التواريخ عبر Text(date, style: .date) — ويستخدم تلقائياً Locale.current. توصي Apple باستخدام SwiftUI للمشاريع الجديدة لأن التدويل فيه أكثر شفافية.
Android i18n مبني على نظام الموارد. تُوضع السلاسل النصية في res/values/strings.xml للغة الافتراضية (عادة الإنجليزية). لكل لغة يُنشأ دليل منفصل: res/values-ru/strings.xml (الروسية)، res/values-de/strings.xml (الألمانية)، res/values-fr/strings.xml (الفرنسية). يختار Android السلاسل تلقائياً بناءً على لغة نظام الجهاز (Locale.getDefault()). إذا لم يُعثر على إعدادات محلية دقيقة، تُستخدم القاعدة (values/strings.xml).
// res/values/strings.xml (الإنجليزية، الافتراضية)
<resources>
<string name="welcome_title">Welcome!</string>
<string name="items_count">%d item(s)</string>
</resources>
// res/values-ru/strings.xml (الروسية)
<resources>
<string name="welcome_title">أهلاً بك!</string>
<plurals name="items_count">
<item quantity="one">%d منتج</item>
<item quantity="few">%d منتجات</item>
<item quantity="many">%d منتجًا</item>
</plurals>
</resources>
// كود Kotlin
textView.text = getString(R.string.welcome_title)
// صيغ الجمع
val items = 5
textView.text = resources.getQuantityString(
R.plurals.items_count, items, items
)
// دعم RTL في الكود
textView.textDirection = View.TEXT_DIRECTION_LOCALE
// Manifest: supportsRtl="true"
RTL (Right-to-Left) — دعم اللغات حيث يُقرأ النص من اليمين إلى اليسار (العربية، العبرية، الأردية، الفارسية). يدعم Android RTL عبر الخاصيتين android:layoutDirection و android:textDirection. في البيان (manifest)، حدد android:supportsRtl="true" — وسيعكس Android التخطيط تلقائياً. يجب أن تعمل قائمة التنقل NavDrawer، أيقونات الرجوع/التقدم، ومحاذاة النص في كلا الاتجاهين. في الكود، استخدم View.LAYOUT_DIRECTION_LOCALE و Gravity.START/END بدلاً من LEFT/RIGHT.
مؤهلات موارد Android تتيح توطين ليس فقط السلاسل النصية بل أيضاً الصور (res/drawable-ru/) والتخطيطات (res/layout-ru/) والرسوم المتحركة والألوان. للعربية والعبرية، نحتاج تخطيطات منفصلة مع عناصر معكوسة — استخدم res/layout-ar/ (العربية). يدعم Android أيضاً المتغيرات الإقليمية: values-rUS، values-rGB، values-de-DE. يمكن دمج المؤهلات: values-ldrtl-ru — الروسية لشاشات RTL.
التواريخ والوقت — أحد الجوانب الرئيسية لـ i18n. تستخدم المناطق المختلفة تنسيقات مختلفة: روسيا — DD.MM.YYYY، الولايات المتحدة — MM/DD/YYYY، اليابان — YYYY.MM.DD. استخدام تنسيق ثابت (yyyy-MM-dd) للعرض على المستخدم خطأ. في iOS، استخدم DateFormatter مع Locale(identifier: locale)، في Android — DateFormat.getDateInstance(DateFormat.SHORT, locale). للمساعدات الصوتية والبحث بالذكاء الاصطناعي، يجب أن تكون التواريخ بصيغة ISO 8601 داخلياً.
الأرقام والعملات — المناطق المختلفة لها فواصل مختلفة: 1,234.56 (الولايات المتحدة) مقابل 1.234,56 (روسيا)، 1 234,56 (فرنسا). iOS: NumberFormatter مع .locale = locale. Android: DecimalFormat مع DecimalFormatSymbols(locale). للعملات: تنسيق ¥1,234 (اليابان) مقابل $1,234.56 (الولايات المتحدة) مقابل 1 234,56 ₽ (روسيا). لا تقم أبداً بدمج العملة والرقم يدوياً — استخدم NumberFormatter.currencyCode و .currencySymbol.
| المنطقة | التاريخ | الرقم | العملة |
|---|---|---|---|
| روسيا | 31.12.2024 | 1 234,56 | 1 234,56 ₽ |
| الولايات المتحدة | 12/31/2024 | 1,234.56 | $1,234.56 |
| ألمانيا | 31.12.2024 | 1.234,56 | 1.234,56 € |
| اليابان | 2024/12/31 | 1,234 | ¥1,234 |
| المملكة العربية السعودية | 31/12/2024 | 1,234.56 | 1,234.56 SAR |
الفرز (Collation) — يختلف الترتيب الأبجدي بين اللغات. في الإسبانية، "ch" يأتي بعد "c". في السويدية، "ä" في نهاية الأبجدية. في الألمانية، "ß" يُفرز كـ "ss". iOS: LocalizedComparison (String.localizedCompare). Android: Collator.getInstance(locale). لا تستخدم أبداً compareTo() للسلاسل المعروضة للمستخدم — فهو يستخدم ترتيب نقاط Unicode Code Point، الذي لا يراعي القواعد الإقليمية.
المبادئ المعمارية — ابدأ i18n من أول commit. يجب أن تمر كل سلسلة في الكود عبر دالة غلاف (tr("key")) غير موجودة حتى يتم إعداد i18n — مما يجبر المطور على استخراج السلاسل فوراً. لا تستخدم السلاسل الإنجليزية كمفاتيح — فعند تغيير الصياغة الإنجليزية، يجب تحديث جميع الترجمات. استخدم مفاتيح ذات معنى: "profile.title"، "settings.language.label".
التدوين الزائف (Pseudolocalization) — تقنية اختبار i18n قبل الترجمة الفعلية. استبدل كل حرف لاتيني بأحرف ذات علامات تشكيل (á، é، ñ، ü) للتحقق من الترميز، أضف بادئة [XXX] للتحقق من اقتطاع السلاسل. Xcode: مخططات التشغيل — لغة زائفة "Double-Length Pseudolanguage". Android: خيارات المطور — فرض اتجاه تخطيط RTL، مقياس خط النظام حتى 200%. يكتشف التدوين الزائف 80% من مشاكل i18n دون مشاركة المترجم.
قائمة التحقق i18n من IT Sectr — قبل الإصدار نتحقق من: (1) لا توجد سلاسل ثابتة في الكود (استثناء: السجلات)، (2) صيغ الجمع تعمل بشكل صحيح لجميع اللغات، (3) التواريخ/الأرقام تُنسق عبر Locale API، (4) التخطيط يُعرض بشكل صحيح على لغات RTL، (5) السلاسل لا تُقتطع عند أقصى تحجيم، (6) التدوين الزائف لم يُظهر أخطاء، (7) جميع اللغات المعلنة في المتاجر لديها مجموعة كاملة من الترجمات.
الأسئلة الشائعة
i18n (التدويل) — إعداد الكود: استخراج السلاسل، دعم RTL، التنسيق. يقوم به المطور مرة واحدة. l10n (التوطين) — ترجمة السلاسل إلى لغة محددة. يقوم به المترجم مرات عديدة لكل إعدادات محلية. i18n هو البنية التحتية، l10n هو المحتوى. بدون i18n، التوطين مستحيل من حيث المبدأ.
NSLocalizedString — ماكرو يبحث عن القيمة بالمفتاح في Localizable.strings للإعدادات المحلية الحالية للجهاز. إذا وُجدت الترجمة، يُعيدها. إذا لم تُوجد، يُعيد المفتاح. الصيغة: NSLocalizedString("key", comment: "وصف"). للتنسيق مع المعاملات، استخدم String.localizedStringWithFormat().
strings.xml — ملف بالترجمات في دليل res/values/{lang}/. النسخة الأساسية في values/strings.xml، الترجمات في values-ru/strings.xml. يتعامل الكود عبر getString(R.string.key). يختار Android الملف المناسب تلقائياً بناءً على لغة النظام. لصيغ الجمع، يُستخدم مورد <plurals> مع مؤهلات zero/one/few/many/other.
RTL (Right-to-Left) — اتجاه الكتابة للعربية والعبرية والأردية والفارسية. Android: supportsRtl="true" في البيان، android:layoutDirection، Gravity.START/END. iOS: UISemanticContentAttribute.forceLeftToRight لـ RTL القسري. يجب أن ينعكس التخطيط: القائمة على اليمين، النص — من اليمين إلى اليسار، أيقونات التنقل — مقلوبة.
لـ النشر العالمي، المجموعة الدنيا: الإنجليزية، الإسبانية، الفرنسية، الألمانية، اليابانية، الصينية، الكورية، البرتغالية، الروسية، الإيطالية. يتطلب App Store حداً أدنى التوطين بالإنجليزية. كل إعدادات محلية إضافية توسع الجمهور المحتمل. للسوق المحلي، 1–2 لغات كافية.
الخلاصة
سنقوم بتطوير تطبيق جوال جاهز
تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.
اقرأ أيضًا