توطين التطبيقات في iOS. الجزء 1. ماذا لدينا؟

توطين التطبيقات في iOS


الجزء 1. ماذا لدينا؟


دليل موارد السلسلة المترجمة


مقدمة


قبل بضع سنوات ، انغمست في العالم السحري لتطوير iOS ، والذي وعدني بكل جوهره بمستقبل سعيد في مجال تكنولوجيا المعلومات. ومع ذلك ، عند التعمق في ميزات النظام الأساسي وبيئة التطوير ، واجهت العديد من الصعوبات والإزعاج في حل المهام التي تبدو تافهة للغاية: أحيانًا تجعل "المحافظة المبتكرة" من Apple المطورين في غاية التعقيد من أجل إرضاء عميل "WANT" الجامح.


إحدى هذه المشاكل هي مسألة توطين موارد السلسلة للتطبيق. أود أن أكرس العديد من مطبوعاتي الأولى حول مساحات هبر لهذه المشكلة.


في البداية ، كنت آمل أن أضع أفكاري في مقال واحد ، لكن كمية المعلومات التي أود تقديمها كانت كبيرة جدًا. في هذه المقالة ، سأحاول الكشف عن جوهر الآليات القياسية للعمل مع الموارد المحلية مع التركيز على بعض الجوانب التي أهملتها معظم الأدلة والبرامج التعليمية. تهدف المادة في المقام الأول إلى بدء المطورين (أو أولئك الذين لم يواجهوا مثل هذه المهام). بالنسبة للمطورين ذوي الخبرة ، قد لا تكون هذه المعلومات ذات قيمة خاصة. ولكن عن المضايقات والعيوب التي يمكن مواجهتها في الممارسة العملية ، سأقول في المستقبل ...


خارج الصندوق. كيف يتم تنظيم تخزين موارد السلسلة في تطبيقات iOS


بادئ ذي بدء ، نلاحظ أن وجود آليات التوطين في النظام الأساسي هو بالفعل إضافة ضخمة ، لأنه يحفظ المبرمج من التطوير الإضافي ويضبط صيغة واحدة للعمل مع البيانات. وكثيرا ما تكون الآليات الأساسية كافية لتنفيذ المشاريع الصغيرة نسبيا.


وبالتالي ، ما هي الفرص التي توفرها لنا Xcode "خارج الصندوق"؟ أولاً ، دعنا نلقي نظرة على معيار تخزين موارد السلسلة في المشروع.


في المشاريع ذات المحتوى الثابت ، يمكن تخزين بيانات السلسلة مباشرة في الواجهة ( .storyboard و .xib ، والتي بدورها ملفات XML يتم تقديمها باستخدام أدوات منشئ واجهة ) أو في التعليمات البرمجية. يتيح لنا النهج الأول تبسيط وتسريع عملية ترميز الشاشات والشاشات الفردية ، كما يمكن للمطور ملاحظة معظم التغيير دون إنشاء التطبيق. ومع ذلك ، في هذه الحالة ، ليس من الصعب التعامل مع تكرار البيانات (إذا تم استخدام نفس النص من قبل العديد من العناصر ، يعرض). يزيل الأسلوب الثاني فقط مشكلة تكرار البيانات ، ولكنه يؤدي إلى الحاجة إلى ملء الشاشات يدويًا (عن طريق تعيين IBOutlet إضافية وتعيين قيم نصية مقابلة لها) ، مما يؤدي بدوره إلى تكرار التعليمات البرمجية (بالطبع ، باستثناء الحالات التي يجب أن يكون فيها النص يتم تثبيته مباشرة بواسطة رمز التطبيق).


بالإضافة إلى ذلك ، توفر Apple امتداد ملف .strings . .strings . ينظم هذا المعيار تنسيق تخزين بيانات السلسلة في شكل مصفوفة ترابطية ( "-" ):


 "key" = "value"; 

المفتاح حساس لحالة الأحرف ، ويسمح باستخدام المسافات والشرطات السفلية وعلامات الترقيم والأحرف الخاصة.


من المهم ملاحظة أنه على الرغم من البنية المباشرة ، فإن ملفات Strings هي مصادر منتظمة للأخطاء أثناء تجميع التطبيق أو تجميعه أو تشغيله. هناك عدة أسباب لذلك.


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


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


ونتيجة لذلك ، يتطلب التصميم البسيط أن يكون المبرمج دقيقًا ومنتبهًا للغاية عند ملء الملفات بالبيانات.


حسن الاطلاع يمكن للمطورين أن يهتفوا على الفور: "ولكن ماذا عن JSON و PLIST؟ ما الذي لم يعجبهم؟" حسنًا ، أولاً ، JSON و PLIST (في الواقع ، XML عادي) هي معايير عالمية تسمح بتخزين السلاسل PLIST المنطقية ( BOOL ) والبيانات الثنائية والوقت والتاريخ بالإضافة إلى المجموعات - المفهرسة ( Array ) Array ( Dictionary ) المصفوفات. وبناءً على ذلك ، فإن بنية هذه المعايير أكثر تشبعًا ، وبالتالي يسهل فهمها. ثانيًا ، سرعة معالجة هذه الملفات أقل قليلاً من ملفات Strings ، ويرجع ذلك مرة أخرى إلى بناء الجملة الأكثر تعقيدًا. ناهيك عن حقيقة أنه للعمل معهم تحتاج إلى تنفيذ عدد من التلاعبات في التعليمات البرمجية.


مترجمة ، محلية ، ولكن غير مترجمة. تعريب واجهة المستخدم


وهكذا ، بعد تحديد المعايير ، دعونا الآن نكتشف كيفية استخدام كل شيء.


دعنا نذهب بالترتيب. أولاً ، قم بإنشاء تطبيق عرض فردي بسيط وأضف بعض مكونات النص إلى Main.storyboard على ViewController .




يتم تخزين المحتوى في هذه الحالة مباشرة في الواجهة. لتوطينه ، يجب عليك القيام بما يلي:


1) انتقل إلى إعدادات المشروع




2) ثم - من الهدف إلى المشروع




3) افتح علامة التبويب معلومات




في قسم الترجمة ، نرى على الفور أن لدينا بالفعل إدخال "اللغة الإنجليزية - لغة التطوير" . هذا يعني أنه يتم تعيين اللغة الإنجليزية كلغة التطوير (أو الافتراضية).


دعنا نضيف لغة أخرى الآن. للقيام بذلك ، انقر فوق " + " وحدد اللغة المطلوبة (على سبيل المثال ، اخترت الروسية). تقدم لنا Caring Xcode على الفور اختيار الملفات التي تريد ترجمتها للغة المضافة.




انقر فوق " إنهاء" ، لترى ما حدث. في متصفح المشروع ، ظهرت أزرار لعرض التداخل بالقرب من الملفات المحددة. بالضغط عليها نرى أن الملفات المحددة مسبقًا تحتوي على ملفات التوطين التي تم إنشاؤها.




على سبيل المثال ، Main.storyboard (Base) هو ملف ترميز الواجهة الافتراضية في لغة التطوير الأساسية ، وعند تشكيل الأقلمة إليها ، تم إنشاء Main.strings (Russian) المرتبطة في أزواج - ملف سلسلة للترجمة الروسية. فتحه ، يمكنك رؤية ما يلي:


 /* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */ "tQe-tG-eeo.text" = "Label"; /* Class = "UITextField"; placeholder = "TextField"; ObjectID = "cpp-y2-Z0N"; */ "cpp-y2-Z0N.placeholder" = "TextField"; /* Class = "UIButton"; normalTitle = "Button"; ObjectID = "EKl-Rz-Dc2"; */ "EKl-Rz-Dc2.normalTitle" = "Button"; 

هنا ، بشكل عام ، كل شيء بسيط ، ولكن من أجل الوضوح ، سننظر بمزيد من التفصيل ، مع الانتباه إلى التعليقات التي تم إنشاؤها بواسطة Xcode المهتم:


 /* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */ "tQe-tG-eeo.text" = "Label"; 

هنا مثال لفئة UILabel مع القيمة "Label" لمعلمة text . ObjectID - معرف الكائن في ملف الترميز - هذا خط فريد مخصص لأي مكون في الوقت الذي يتم فيه وضعه على Storyboard/Xib . يتم إنشاء المفتاح من ObjectID واسم المعلمة للكائن (في هذه الحالة ، text ) ، ويمكن تفسير السجل نفسه رسميًا على النحو التالي:


قم بتعيين معلمة النص لكائن tQe-tG-eeo إلى Label.


في هذا السجل ، فقط " القيمة " هي عرضة للتغيير. استبدل " Label " بـ " Label ". سنفعل نفس الشيء مع أشياء أخرى.


 /* Class = "UILabel"; text = "Label"; ObjectID = "tQe-tG-eeo"; */ "tQe-tG-eeo.text" = ""; /* Class = "UITextField"; placeholder = "TextField"; ObjectID = "cpp-y2-Z0N"; */ "cpp-y2-Z0N.placeholder" = " "; /* Class = "UIButton"; normalTitle = "Button"; ObjectID = "EKl-Rz-Dc2"; */ "EKl-Rz-Dc2.normalTitle" = ""; 

أطلقنا تطبيقنا.




لكن ماذا نرى؟ يستخدم التطبيق التعريب الأساسي. كيف تتحقق مما إذا قمنا بالتحويل بشكل صحيح؟


هنا يجدر إجراء حفز صغير والحفر قليلاً في اتجاه ميزات نظام iOS الأساسي وهيكل التطبيق.


للبدء ، ضع في اعتبارك تغيير هيكل المشروع في عملية إضافة التوطين. هكذا يبدو دليل المشروع قبل إضافة الأقلمة الروسية:




وهكذا بعد:




كما نرى ، أنشأ Xcode دليلًا جديدًا ru.lproj ، حيث وضع السلاسل المترجمة التي تم إنشاؤها.




وأين هيكلة مشروع Xcode لتطبيق iOS النهائي؟ وعلى الرغم من حقيقة أن هذا يساعد على فهم ميزات النظام الأساسي بشكل أفضل ، بالإضافة إلى مبادئ التوزيع وتخزين الموارد مباشرة في التطبيق النهائي. خلاصة القول هي أنه عند تجميع مشروع Xcode ، بالإضافة إلى إنشاء ملف قابل للتنفيذ ، تنقل البيئة الموارد (ملفات تخطيط واجهة Storyboard / Xib والصور وملفات الخطوط وما إلى ذلك) إلى التطبيق النهائي ، مع الحفاظ على التسلسل الهرمي المحدد في مرحلة التطوير.


للعمل مع هذا التسلسل الهرمي ، توفر Apple فئة Bundle(NSBundle) ( ترجمة مجانية ):


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

خذ بعين الاعتبار بنية Bundle.main باستخدام فئة FileManager :




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




ولكن قبل إغلاق موضوع توطين واجهة المستخدم من خلال Interface Builder ، تجدر الإشارة إلى طريقة أخرى جديرة بالملاحظة. عند إنشاء ملفات الترجمة (عن طريق إضافة لغة جديدة إلى المشروع أو في عارض الملفات المترجمة) ، من السهل ملاحظة أن Xcode يوفر القدرة على اختيار نوع الملف المراد إنشاؤه:




بدلاً من ملف سطر ، يمكنك بسهولة إنشاء Storyboard/Xib مترجمة Storyboard/Xib كل ترميز الملف الأساسي. تتمثل إحدى المزايا الإضافية لهذا النهج في أن المطور يمكنه أن يرى على الفور كيف سيتم عرض المحتوى بلغة معينة وتصحيح تخطيط الشاشة على الفور ، خاصة إذا اختلف مقدار النص ، أو تم استخدام اتجاه آخر للنص (على سبيل المثال ، بالعربية والعبرية) وما إلى ذلك . ولكن في نفس الوقت ، يؤدي إنشاء ملفات Storyboard / Xib إضافية إلى زيادة كبيرة في حجم التطبيق نفسه (ومع ذلك ، تشغل ملفات السلسلة مساحة أقل بكثير).


لذلك ، عند اختيار طريقة أو أخرى لتعريب الواجهة ، يجدر النظر في أي نهج سيكون أكثر ملاءمة وعمليًا في حالة معينة.


افعلها بنفسك. العمل مع موارد السلسلة المترجمة في التعليمات البرمجية


نأمل أن يكون كل شيء أكثر أو أقل وضوحًا مع المحتوى الثابت. ولكن ماذا عن النص الذي يتم تعيينه مباشرة في التعليمات البرمجية؟


اهتم مطورو نظام التشغيل iOS بذلك.


للعمل مع موارد النص المترجمة ، يوفر إطار عمل المؤسسة مجموعة NSLocalizedStrings من الأساليب في Swift


 NSLocalizedString(_ key: String, comment: String) NSLocalizedString(_ key: String, tableName: String?, bundle: Bundle, value: String, comment: String) 

ووحدات الماكرو في الهدف جيم


 NSLocalizedString(key, comment) NSLocalizedStringFromTable(key, tbl, comment) NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) 

لنبدأ بما هو واضح. المعلمة key هي مفتاح السلسلة في ملف Strings ؛ val (القيمة الافتراضية) - القيمة الافتراضية المستخدمة إذا لم يكن المفتاح المحدد في الملف ؛ comment - (أقل وضوحًا) وصف موجز للسلسلة المترجمة (في الواقع ، لا يحمل وظيفة مفيدة ويهدف إلى شرح الغرض من استخدام سلسلة معينة).


أما بالنسبة إلى المعلمات tableName ( tbl ) و bunble ، فيجب النظر فيها بمزيد من التفصيل.


tableName ( tbl ) هو اسم ملف String (لنكون صادقين ، لا أعرف لماذا تطلق عليه Apple جدولاً) ، والذي يحتوي على الصف الذي نحتاجه بالمفتاح المحدد ؛ عند نقله ، لم يتم تحديد امتداد .string . تتيح لك إمكانية التنقل بين الجداول عدم تخزين موارد السلسلة في ملف واحد ، ولكن توزيعها وفقًا لتقديرك الخاص. هذا يسمح لك بالتخلص من ازدحام الملفات ، يبسط التحرير ، ويقلل من فرصة الأخطاء.


تعمل معلمة bundle توسيع التنقل في الموارد بشكل أكبر. كما ذكرنا سابقًا ، تعد الحزمة آلية للوصول إلى موارد التطبيق ، أي يمكننا تحديد مصدر الموارد بشكل مستقل.


أكثر قليلاً. سنذهب مباشرة إلى المؤسسة وننظر في إعلان الأساليب (وحدات الماكرو) للحصول على صورة أوضح ، لأن تتجاهل الغالبية العظمى من البرامج التعليمية هذه النقطة ببساطة. إطار Swift ليس غنيًا بالمعلومات:


 /// Returns a localized string, using the main bundle if one is not specified. public func NSLocalizedString(_ key: String, tableName: String? = default, bundle: Bundle = default, value: String = default, comment: String) -> String 

"الحزمة الرئيسية تُرجع سلسلة مترجمة" - كل ما لدينا. الهدف C مختلف قليلاً.


 #define NSLocalizedString(key, comment) \ [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:nil] #define NSLocalizedStringFromTable(key, tbl, comment) \ [NSBundle.mainBundle localizedStringForKey:(key) value:@"" table:(tbl)] #define NSLocalizedStringFromTableInBundle(key, tbl, bundle, comment) \ [bundle localizedStringForKey:(key) value:@"" table:(tbl)] #define NSLocalizedStringWithDefaultValue(key, tbl, bundle, val, comment) \ [bundle localizedStringForKey:(key) value:(val) table:(tbl)] 

هنا يمكنك أن ترى بوضوح أن لا شيء سوى bundle (في الحالتين mainBundle ) تعمل مع ملفات موارد السلسلة - كما هو الحال في حالة تعريب الواجهة. بالطبع ، يمكنني أن أقول هذا على الفور ، بالنظر إلى فئة Bundle ( NSBundle ) في الفقرة السابقة ، ولكن في ذلك الوقت لم تكن هذه المعلومات ذات قيمة عملية معينة. ولكن في سياق العمل مع الأسطر في التعليمات البرمجية ، لا يمكن قول ذلك. في الواقع ، الوظائف العالمية التي تقدمها المؤسسة هي مجرد أغلفة على طرق الحزمة القياسية ، وتتمثل مهمتها الرئيسية في جعل الشفرة أكثر إيجازًا وأمانًا. لا أحد يمنع تهيئة bundle يدويًا والوصول المباشر إلى الموارد نيابة عنها ، ولكن بهذه الطريقة يبدو أن هناك احتمالية (وإن كانت صغيرة جدًا جدًا) لتكوين روابط دائرية وتسريبات للذاكرة.


ستوضح الأمثلة أدناه كيفية العمل مع الوظائف العالمية ووحدات الماكرو.


دعونا نرى كيف يعمل كل شيء.
أولاً ، قم بإنشاء ملف سلسلة يحتوي على موارد السلسلة لدينا. سمها Localizable.strings * وأضفه إليها.


 "testKey" = "testValue"; 

( يتم تنفيذ توطين ملفات السلسلة بنفس الطريقة تمامًا مثل Storyboard / Xib ، وبالتالي لن أصف هذه العملية. سنستبدل " testValue " في ملف التوطين الروسي بـ " قيمة اختبار *".)


هام! في iOS ، يكون الملف بهذا الاسم هو ملف موارد السلسلة الافتراضي ، أي إذا لم تحدد اسم الجدول tableName ( tbl ) ، tableName التطبيق تلقائيًا على Localizable.strings .


أضف الكود التالي إلى مشروعنا


 //Swift print("String for 'testKey': " + NSLocalizedString("testKey", comment: "")) 

 //Objective-C NSLog(@"String for 'testKey': %@", NSLocalizedString(@"testKey", @"")); 

وتشغيل المشروع. بعد تنفيذ الرمز ، سيظهر سطر في وحدة التحكم


 String for 'testKey': testValue 

كل شيء يعمل بشكل صحيح!


وبالمثل مع مثال الأقلمة للواجهة ، قم بتغيير الأقلمة وتشغيل التطبيق. ستكون نتيجة تنفيذ التعليمات البرمجية


 String for 'testKey':   

الآن دعنا نحاول الحصول على القيمة من خلال المفتاح ، وهو ليس في ملف Localizable.strings :


 //Swift print("String for 'unknownKey': " + NSLocalizedString("unknownKey", comment: "")) 

 //Objective-C NSLog(@"String for 'unknownKey': %@", NSLocalizedString(@"unknownKey", @"")); 

ستكون نتيجة تنفيذ هذا الرمز


 String for 'unknownKey': unknownKey 

نظرًا لعدم وجود مفتاح في الملف ، فإن الطريقة تُرجع المفتاح نفسه نتيجة لذلك. إذا كانت هذه النتيجة غير مقبولة ، فمن الأفضل استخدام الطريقة


 //Swift print("String for 'testKey': " + NSLocalizedString("unknownKey", tableName: nil, bundle: Bundle.main, value: "noValue", comment: "")) 

 //Objective-C NSLog(@"String for 'testKey': %@", NSLocalizedStringWithDefaultValue(@"unknownKey", nil, NSBundle.mainBundle, @"noValue", @"")); 

حيث توجد معلمة value ( القيمة الافتراضية ). ولكن في هذه الحالة ، يجب عليك تحديد مصدر الموارد - bundle .


تدعم السلاسل المترجمة آلية الاستيفاء ، على غرار سلاسل iOS القياسية. للقيام بذلك ، قم بإضافة سجل إلى ملف السلسلة باستخدام حرفية السلسلة ( %@ ، %li ، %f ، إلخ) ، على سبيل المثال:


 "stringWithArgs" = "String with %@: %li, %f"; 

لإخراج مثل هذا الخط ، يجب عليك إضافة رمز للنموذج


 //Swift print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "some", 123, 123.098 )) 

 //Objective-C NSLog(@"%@", [NSString stringWithFormat: NSLocalizedString(@"stringWithArgs", @""), @"some", 123, 123.098]); 

ولكن عند استخدام مثل هذه التصاميم ، يجب أن تكون حذراً للغاية! والحقيقة هي أن نظام iOS يراقب بدقة عدد وترتيب الحجج ومراسلات أنواعها بالحروف المحددة. لذا ، على سبيل المثال ، إذا قمت باستبدال السلسلة كوسيطة ثانية بدلاً من القيمة الصحيحة


 //Swift print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "some", "123", 123.098 )) 

 //Objective-C NSLog(@"%@", [NSString stringWithFormat: NSLocalizedString(@"stringWithArgs", @""), @"some", @"123", 123.098]); 

ثم سيحل التطبيق محل الرمز الصحيح للسلسلة "123" في مكان عدم التطابق


 "String with some: 4307341664, 123.089000" 

إذا تخطيتها ، نحصل عليها


 "String with some: 0, 123.089000" 

ولكن إذا تخطيت الكائن المقابل لـ %@ في قائمة الوسائط


 //Swift print(String(format: NSLocalizedString("stringWithArgs", comment: ""), "123", 123.098 )) 

 //Objective-C NSLog(@"%@", [NSString stringWithFormat: NSLocalizedString(@"stringWithArgs", @""), @"123", 123.098]); 

ثم سيتعطل التطبيق ببساطة في وقت تنفيذ التعليمات البرمجية.


ادفعني ، حبيبي! توطين الإخطارات


مهمة أخرى مهمة في العمل مع موارد السلسلة المترجمة ، والتي أود التحدث عنها بإيجاز ، هي مهمة توطين الإخطارات. خلاصة القول هي أن معظم البرامج التعليمية (في كل من Push Notifications Localizable Strings ) غالبًا ما تهمل هذه المشكلة ، وهذه المهام ليست نادرة جدًا. لذلك ، عندما تواجه هذا للمرة الأولى ، قد يكون لدى المطور سؤال معقول: هل هذا ممكن من حيث المبدأ؟ لن أفكر هنا في آلية تشغيل Apple Push Notification Service ، خاصة منذ البدء بنظام iOS 10.0 ، ويتم تنفيذ الإشعارات المحلية والإشعارات من خلال نفس الإطار - UserNotifications .


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


كان القرار الصحيح بسيطًا بشكل مروع ، على الرغم من أنه لم يكن واضحًا تمامًا. بدلاً من JSON القياسي الذي يرسله الخادم على APNS


  "aps" : { "alert" : { "body" : "some message"; }; }; 

بحاجة لإرسال JSON من النموذج


  "aps" : { "alert" : { "loc-key" : "message localized key"; }; }; 

حيث يتم استخدام loc-key لتمرير مفتاح السلسلة المترجمة من ملف Localizable.strings . وفقًا لذلك ، يتم عرض رسالة الدفع وفقًا للترجمة الحالية للجهاز.


تعمل آلية استيفاء السلاسل المترجمة في إشعارات الدفع بطريقة مماثلة:


  "aps" : { "alert" : { "loc-key" : "message localized key"; "loc-args" : [ "First argument", "Second argument" ]; }; }; 

يمرر المفتاح loc-args مجموعة من الوسيطات التي يجب تضمينها في نص الإعلام المترجم.


لتلخيص ...


وهكذا ، ماذا لدينا في النهاية:


  • معيار لتخزين بيانات السلسلة في ملفات سلسلة متخصصة ذات بنية بسيطة ويسهل الوصول إليها ؛
  • القدرة على توطين الواجهة دون معالجة إضافية في التعليمات البرمجية ؛
  • الوصول السريع إلى الموارد المحلية من التعليمات البرمجية ؛
  • التوليد التلقائي لملفات التوطين وهيكلة موارد دليل المشروع (التطبيق) باستخدام أدوات Xcode ؛
  • القدرة على توطين نص الإخطار.

, Xcode , .


.

Source: https://habr.com/ru/post/ar419077/


All Articles