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

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


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

الحل المعماري
تخيل أن طلبنا مكتوب وفقًا لمنهج أحادي النشاط . ثم يمكن تنفيذ آلية تبديل اللغة على النحو التالي.

SettingsInteractor
هو مصدر قيمة اللغة الحالية. يتيح لك الاشتراك في هذه القيمة ، وتلقيها بشكل متزامن والاشتراك في التحديثات فقط. إذا لزم الأمر ، يمكنك تقديم تجريد إضافي على SettingsInteractor
وفقًا لمبدأ فصل الواجهة . في المخطط ، يتم حذف التفاصيل غير ذات الصلة.
يستبدل التطبيق AppActivity
عند إنشاء السياق سياق جديد بحيث يستخدم التطبيق موارد للغة المحددة.
override fun attachBaseContext(base: Context) { super.attachBaseContext(applySelectedAppLanguage(base)) } private fun applySelectedAppLanguage(context: Context): Context { val locale = settingsInteractor.getUserSelectedLanguageBlocking() val newConfig = Configuration(context.resources.configuration) Locale.setDefault(locale) newConfig.setLocale(locale) return context.createConfigurationContext(newConfig) }
AppPresenter
بدوره ، يشترك في تحديثات اللغة ويبلغ عرض التغييرات.
override fun onFirstViewAttach() { super.onFirstViewAttach() subscribeToLanguageUpdates() } private fun subscribeToLanguageUpdates() { settingsInteractor .getUserSelectedLanguageUpdates() .subscribe( { newLang -> viewState.applyNewAppLanguage(newLang) }, { error -> errorHandler.handle(error) } ) .disposeOnDestroy() }
AppActivity
إعادة إنشاء AppActivity
عند تلقي إشعار بتغيير اللغة.
override fun applyNewAppLanguage(lang: Locale) = recreate()

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

يستخدم UiLocalizer
مثيلات NumberFormat
المناسبة لتحويل رقم إلى سلسلة.
private var numberFormat = NumberFormat.getNumberInstance(lang) private var percentFormat = NumberFormat.getPercentInstance(lang) private fun getNumberFormatForCurrency(currency: Currency) = NumberFormat .getCurrencyInstance(lang) .also { it.currency = currency }
يرجى ملاحظة أنه يجب تعيين العملة بشكل منفصل.
إذا قمت بحفظ دورات CPU ووحدات الذاكرة ، وكان تبديل العملة واللغة هي الوظيفة الرئيسية والمستخدمة في كثير من الأحيان للتطبيق الخاص بك ، فأنت تحتاج بالطبع إلى ذاكرة تخزين مؤقت.
تمثيل اللغات والعملات
يتم إنشاء مثيلات فئة Locale
بواسطة علامة لغة ، والتي تتكون من رمز لغة مؤلف من حرفين ورمز منطقة مؤلف من حرفين. وتستند مثيلات فئة Currency
إلى رمز ISO مكون من ثلاثة أحرف . في هذا النموذج ، يجب إجراء تسلسل للغة والعملة لحفظها على القرص أو النقل عبر الشبكة ، ومن ثم ستكون جيدة. وهنا بعض الأمثلة.
قد تختلف نتيجة أرقام التنسيق وفقًا للمعايير الإقليمية عما كان متوقعًا. سيتم عرض رمز العملة أو الكود المكون من ثلاثة أحرف بلغات مختلفة بطرق مختلفة. ستظهر علامات ناقص للقيم النقدية السلبية في أماكن غير متوقعة ، وسيتم عرض الأقواس بدلاً من ذلك في بعض الأماكن. قد لا تكون علامة النسبة المئوية بالضبط العلامة التي اعتدنا عليها.
والحقيقة هي أن السطر الأخير ، من وجهة نظر الأنماط الإقليمية ، يتكون من بادئة ولاحقة للأرقام الموجبة والسالبة ، وألف فاصل وفاصل فاصل عشري ، وهي مختلفة بالنسبة إلى أماكن مختلفة.
الأرقام
عملة
فائدة
علاوة على ذلك ، قد تكون نتائج التنسيق لـ Android SDK و JDK مختلفة. علاوة على ذلك ، كل الخيارات صحيحة ، يتم استخدام كل منها في سياقات معينة.

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

يمكنك أيضًا كتابة اختبار للاستمتاع بالتنوع. ليس لجميع اللغات يتم عرض العملة نفسها مع رمز.

في النهاية
المخطط العام للحل كما يلي.

دورة حياة AppActivity
هي دورة حياة التطبيق بأكمله. لذلك ، يكفي إعادة إنشائه لإعادة تشغيل التطبيق بالكامل وتطبيق اللغة المحددة. ونظرًا لوجود نشاط واحد فقط ، يكفي الاحتفاظ بالاشتراك لتغيير اللغة في مكان واحد - في AppPresenter
.
كما رأينا ، التنسيقات الإقليمية لإخراج الأرقام ليست تافهة. يجب عدم تعيين قالب واحد بشكل صارم لجميع المناسبات. من الأفضل تكليف تنسيق SDK والموافقة على أن الأرقام سيتم عرضها وفقًا للمعيار ، وليس كما هو مرسوم في التخطيطات.
ما هو أسهل للاختبار؟ (مكافأة)
لتوفير الوقت ، يمكنك استخدام العلم التالي.
android { ... buildTypes { debug { pseudoLocalesEnabled true } } ... }
حدد اللغة الزائفة المطلوبة في إعدادات الهاتف.

وراقب كيف يذهب التصميم بسبب النص الطويل ، وبعض عناصر واجهة المستخدم لا ترغب في عرضها من اليمين إلى اليسار.

يمكن الاطلاع على مزيد من المعلومات في الوثائق .
تجدر الإشارة إلى أن اللغات الزائفة لن تعمل إذا غيرت السياق ، كما في الحل أعلاه. أنت تغير السياق. لذلك ، يجب عليك إضافة en-XA
و ar-XB
إلى قائمة اختيار اللغة داخل التطبيق.
هذا كل شيء. هل لديك توطين جيد ومزاج جيد!
