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

مقدمة
هذا هو دليل قصير لتدويل بيثون (i18n) التطبيقات. هذا الدليل سيكون مثيرا لجميع المبرمجين ذوي الخبرة في تطوير بيثون. قراءة مقال سيستغرق 10-15 دقيقة.
سوف نستخدم أداة gettext المختبرة جيدًا والمضمنة في لغة الثعبان.
بادئ ذي بدء ، سوف نفهم ما هو التدويل:
التدويل (I18N) هو عملية تكييف التطبيق مع لغات البلدان والمناطق المختلفة بخلاف تلك التي تم تطويرها فيه.
ولكن هناك أيضًا مفهوم أوسع:
التعريب (L10N) هي عملية تكييف تطبيق دولي إلى منطقة أو لغة معينة عن طريق إضافة مكونات خاصة إلى لغة معينة وترجمة النص.
الترجمة تعني الترجمة:
- تنسيق التاريخ والوقت ؛
- تنسيق الأرقام ؛
- المنطقة الزمنية
- تقويم
- تمثيل العملة
- الضرائب / ضريبة القيمة المضافة ؛
- درجة الحرارة وغيرها من التدابير ؛
- الرموز البريدية والهواتف
- تنسيق العنوان ؛
- رمز التسوية.

تتعدى الترجمة ترجمة المحتوى إلى لغة أخرى. هناك معايير الثقافية والوظيفية التي تتطلب الاهتمام أيضا. على سبيل المثال ، تنسيق التاريخ في أمريكا الشمالية هو MM / DD / YYYY ، ولكن في معظم البلدان الآسيوية يتم كتابته كـ DD / MM / YYYY.
مثال معروف عن خطأ في ترجمة التطبيقمثال آخر يتعلق بعرض الأسماء في التطبيقات. في الولايات المتحدة الأمريكية ، يعتبر الاتصال بشخص ما بالاسم مقبولًا وحتى أفضل ، يتم عرض اسم العميل في الرأس بمجرد تسجيل دخول العميل. ومع ذلك ، فإن العكس هو الصحيح في اليابان: استدعاء شخص بالاسم غير مهذب أو حتى مسيء. يجب أن يأخذ التعريب هذا في الاعتبار ويتجنب استخدام الأسماء للجمهور الياباني.
سننظر في هذه المقالة في التدويل فقط ، لكن آليات التعريب مبنية بطريقة مماثلة. تدعم المكتبات المذكورة في هذه المقالة تعريب التطبيق.
الأنواع الرئيسية
ينقسم التدويل إلى:
- ترجمة البيانات مباشرة في البرامج النصية بيثون.
- ترجمة البيانات في محركات القوالب.
- ترجمة البيانات المخزنة في قاعدة البيانات.
1. ترجمة البيانات النصي بيثون
من أجل تدويل أعمالنا ، نحتاج إلى التعامل مع مكتبة بابل ومجموعة أدوات distutils لإدارة تجميع المشروع للبيع وما بعده.
إعداد الترجمة
بادئ ذي بدء ، نحن بحاجة إلى إنشاء قائمة من الترجمات. بادئ ذي بدء ، نقوم بتثبيت مكتبة
Babel - هذه مكتبة بيثون معترف بها عمومًا لتوطين وتحويل التواريخ والعملات ، مع إضافات ملائمة لبناء المشروع (الموضحة أدناه).
يوفر Python مجموعة أدوات لتعدد اللغات - gettext. gettext GNU هو في الواقع حل تعريب عالمي يوفر الدعم للغات البرمجة الأخرى في الرسائل متعددة اللغات. يستخدم Gettext ليس فقط في العديد من لغات البرمجة ، ولكن أيضًا في ترجمة أنظمة التشغيل ؛ إنه برنامج مُختبر جيدًا وموزعًا مجانًا ومتوفر على
github .
لكي تعمل الترجمات ، تحتاج إلى استيراد الوحدة النمطية gettext وتمرير البرامج النصية مع الترجمات إلى الإدخال. أولاً ، نحتفل بجميع السلاسل المترجمة مع الوظيفة الخاصة _ ('some_text'). ستبدو الدعوة إلى هذه الوظيفة في المشروع كما يلي:
import gettext import os localedir = os.path.join(os.path.abspath('/path/to/locales'), 'locales') translate = gettext.translation('domain_name', localedir, ['ru']) _ = translate.gettext print(_('some_text')) print(_('some_text_2'))
في جزء صغير من التعليمات البرمجية ، قم بإنشاء كائن تدويل يستخدم دليل "الإعدادات المحلية" كمصدر للعبارات المترجمة. لم يتم إنشاء دليل "لغات" حتى الآن ، ولكن من خلاله سيبحث التطبيق عن الترجمات في وقت التشغيل.
للإيجاز ، سيتم الإشارة إلى وظيفة translate.gettext أدناه على أنها _. الشرطة السفلية هي الاسم الشائع لهذه الوظيفة ، والتي يتم التعرف عليها من قبل مجتمع بيثون.
تحدد الدالة _ () الأسطر المراد ترجمتها. الوحدة النمطية gettext مصحوبة بأداة xgettext التي تقوم بتوزيع علامات السلسلة _ () بواسطة الكود وتشكيل قالب كائن محمول (ملف القرعة). لإنشاء ملف التدوين ، دعنا نعود إلى مكتبة Babel المثبتة ، والتي تحتوي على العديد من الميزات لدعم التدويل. بابل يمتد سكربت بناء setup.py ، والذي يمكن كتابته إما باستخدام مكتبة distutils القياسية بيثون أو حزمة setuptools لجهة خارجية من اختيارك. يتجاوز تجميع وحدات Python نطاق مقالتنا ؛ لمزيد من التفاصيل ، راجع
الوثائق . كل ما هو مطلوب هو إنشاء ملف setup.py بالمحتويات التالية:
from babel.messages import frontend as babel from distutils.core import setup setup(name='foo', version='1.0', cmdclass = {'extract_messages': babel.extract_messages, 'init_catalog': babel.init_catalog, 'update_catalog': babel.update_catalog, 'compile_catalog': babel.compile_catalog,} )
وهكذا ، أنشأنا تعليمات لبناء المشروع وأضفنا أربعة فرق تدويل من مكتبة بابل. النظر في هذه الأوامر بمزيد من التفصيل في ترتيب الاستخدام.
extract_messagesهذا الأمر عبارة عن التفاف على أداة GNU xgettext ، التي تقوم بتوزيع _ () العلامات القابلة للترجمة إلى ملف pot. لتشغيل ، تحتاج إلى عدة إعدادات للتجميع. للقيام بذلك ، في الدليل الجذر ، قم بإنشاء ملف setup.cfg بالمحتويات:
[extract_messages] input_dirs = foobar output_file = foobar/locales/messages.pot
- input_dirs - اسم الدليل الذي سيتم من خلاله اختيار جميع التصنيفات في رمز _ () للترجمات.
- output_file - مسار ملف .pot الناتج
لتشغيل الأمر ، قم بالتنفيذ في وحدة التحكم:
$ python setup.py extract_messages
running extract_messages extracting messages from foobar/__init__.py extracting messages from foobar/core.py ... writing PO template file to foobar/locales/messages.pot
في ملف الرهان ، يتم جمع الخطوط المميزة في قائمة يستطيع المترجمون من خلالها إنشاء ترجمات لكل لغة من اللغات المرغوبة.
بعد ذلك ، تحتاج إلى إنشاء ترجمات لعدة لغات. للقيام بذلك ، استخدم أوامر بابل التالية.
init_catalogهذا الأمر عبارة عن التفاف على أداة GNU msginit ، التي تنشئ دليل ترجمة جديدًا يستند إلى ملف pot.
$ python setup.py init_catalog -l en -i foobar/locales/messages.pot \ -o foobar/locales/en/LC_MESSAGES/base.po
running init_catalog creating catalog 'foobar/locales/en/LC_MESSAGES/messages.po' based on 'foobar/locales/messages.pot'
! المهم يتم تخزين ملفات التعريب بطريقة محددة ، وفقًا للاتفاقية:
لغات // LC_MESSAGES / .po
- دليل مع ترجمات إلى لغة معينة ، في حالتنا هو الإنجليزية (en). قد يكون هناك أيضًا دليل يحتوي على ترجمات ليس فقط إلى لغة معينة ، ولكن مع مراعاة الميزات الإضافية أيضًا. على سبيل المثال ، الترجمة الإنجليزية للولايات المتحدة هي en_US؛
- المجال مع الترجمات. إذا نما تطبيقنا ، فسيتم تقسيم الترجمات إلى مجالات حتى لا تفرط في ملف واحد.
update_catalogهذا الأمر عبارة عن أداة التفاف على أداة GNU msgmerge ، والتي تقوم بتحديث أدلة الترجمة الموجودة لملفات * .po.
عند إضافة ترجمات جديدة ، فإننا ببساطة نقوم بتشغيل الأمر:
$ python setup.py update_catalog -l en -i foobar/locales/messages.pot \ -o foobar/locales/en/LC_MESSAGES/base.po
running update_catalog updating catalog 'foobar/locales/en/LC_MESSAGES/base.po' based on 'foobar/locales/messages.pot'
يمكننا أيضًا تحديد الترجمة باللغة الروسية عن طريق تحديد ru بدلاً من en.
compile_catalogالأمر النهائي عبارة عن غلاف على أداة GNU msgfmt. يستغرق الأمر رسائل قابلة للترجمة من ملفات * .po ويجمعها في ملفات ثنائية * .mo لتحسين الأداء.
$ python setup.py compile_catalog --directory foobar/locales --domain base
running compile_catalog compiling catalog to foobar/locales/en/LC_MESSAGES/base.mo
- دليل - المسار إلى الدليل مع الترجمة ،
--domain - علامة لتحديد نطاق الترجمة ، فنحن نحددها وفقًا لنطاقات التطبيق الحالية.
البرامج النصية Python تعمل فقط مع ترجمات * .mo المحسّنة. لذلك ، مع أي تغيير ، بحيث يظهر في التطبيق ، من الضروري إعادة ترجمة الملفات مع الترجمة. للعمل مع ملفات الترجمة ، يمكنك استخدام تطبيق poedit - وهو متاح لجميع أنظمة التشغيل وهو برنامج موزع مجانًا.
poedit - تطبيق الترجمةيتم عرض كل ترجمة كسطر منفصل ، وهذا مناسب. عند الانتهاء من العمل مع الترجمات ، عند حفظ التغييرات ، يتم تلقائيًا تجميع ملف ثنائي * .mo مع كل التغييرات.
نتيجة لذلك ، ستبدو بنية كتالوجات الترجمة كما يلي:
locales ├── en │ └── LC_MESSAGES │ ├── base.mo │ └── base.po ├── ru │ └── LC_MESSAGES │ ├── base.mo │ └── base.po └── messages.pot
اتفاقية أسماء علامات الترجمةتحتوي ملفات po على ترجمات نصية ويتم دمجها منطقياً في ملف باسم شائع. وتسمى هذه المجموعات المجالات. في المثال أعلاه ، هناك مجال واحد فقط يسمى قاعدة. سيكون للتطبيقات الكبيرة مجالات أكثر ، ويجب كتابة قوائم الترجمة مع مراعاة هيكل التطبيق.
من الضروري الحفاظ على توحيد أسماء رموز الترجمة من أجل القضاء على مزيد من الالتباس في الترجمات. على سبيل المثال ، لدينا نموذج مع حفظ بيانات المستخدم في صفحة ملف تعريف المستخدم:
profile.user_form.component.title: بيانات المستخدم
profile.user_form.component.save: حفظ
profile.user_form.field.username: اسم المستخدم
profile.user_form.field.password: كلمة المرور
نشر التطبيقلنشر التطبيق ونشره في عامل ميناء ، تحتاج إلى ترجمة ملفات الترجمة إلى * .mo ملفات ثنائية باستخدام الأمر التالي:
$ python setup.py compile_catalog --domain <>
نوصي باستثناء ملفات * .mo و * .pot في .gitignore:
# ترجمات
*
*2. ترجمة البيانات في محركات القالب
مع التعريب في templating ، كل شيء أسهل قليلاً. النظر في محرك قالب بيثون الأكثر شعبية - jinja. بالنسبة لمحرك القوالب هذا ، تم بالفعل دعم دعم ترجمة gettext من خلال الوظائف الإضافية. لتنشيط الوظيفة الإضافية ، يجب عليك تحديد المسار إلى وحدة الوظيفة الإضافية في مُنشئ البيئة. بالنسبة إلى الأنظمة الأساسية متعددة اللغات ، يلزم تنزيل الترجمات مرة واحدة وإضافة كائنات الترجمة إلى كائن البيئة أثناء تهيئة التطبيق:
translations = get_gettext_translations() env = Environment(extensions=['jinja2.ext.i18n']) env.install_gettext_translations(translations)
ثم في القوالب نستخدم فقط البنيات:
{{ gettext('some_text') }} {{ gettext('Hello %(name)s!')|format(name='World') }}
3. ترجمة البيانات المخزنة في قاعدة البيانات
دعنا نفكر في خيارات العمل مع الترجمات في قواعد البيانات العلائقية الأكثر شيوعًا. تجدر الإشارة إلى أن تنفيذ الترجمات والتوطين لقواعد بيانات noSQL و newSQL مماثل.
ملاحظة: لن نأخذ في الاعتبار الحالة عند تخزين ترجمة كل لغة في عمود منفصل. مثل هذا التنفيذ يستلزم قيود التحجيم والمخاطر الأخرى مع مزيد من دعم التطبيق.
1) خطوط منفصلة لكل لغة
باستخدام هذا الأسلوب ، تعتمد الترجمة إلى لغة معينة في الصفوف ، على كل لغة ، على قيمة العمود ، على سبيل المثال language_code. إذا كانت القيمة en في هذا العمود ، فينبغي أن تشير جميع القيم المترجمة إلى البلد والمنطقة المعطاة.

بالنسبة للنظام الموصوف ، يجب أن تبدو البيانات في الجدول كما يلي:
المزايا:- تنفيذ بسيط وفعال.
- استعلامات بسيطة عند استخدام رمز لغة معين.
العيب:يمكن تخزين الترجمات إلى لغات مختلفة في جداول مختلفة. وبالتالي ، فأنت لا تعرف عدد اللغات التي يتم بها ترجمة طلبك بالكامل.
هذا الحل مناسب للتطبيقات التي لا تتطلب في البداية تدويل كامل لجميع البيانات. ولكن من الممكن إضافة ترجمات لمناطق جديدة مع توسع الأعمال.
سيكون طلب البيانات كما يلي:
SELECT p.product_name, p.price, p.description FROM product p WHERE p.language_code = @language_code;
2) جداول منفصلة مع الترجمات
في هذا النهج ، لكل جدول يتطلب الترجمة ، نقوم بإنشاء جداول بترجمات.
الايجابيات:- ليست هناك حاجة لربط الجداول للبيانات غير المترجمة.
- تصبح الاستعلامات سهلة نظرًا لوجود جداول منفصلة للترجمة.
- لا توجد اختلافات في البيانات.
- بالإضافة إلى الترجمات ، من الممكن توطين بقية البيانات في جدول اللغة بشكل فعال.
العيب:- في التطبيقات الكبيرة ، يكون جدول الترجمة منتفخًا ويبطئ. عند تحسين التطبيق ، سيكون من الضروري تنفيذ ترحيل البيانات في جداول منفصلة.
سيكون طلب البيانات كما يلي:
SELECT tp.text, p.price, tc.text, c.contact_name FROM order_line o, product p, customer c, translation tp, translation tc, language l WHERE o.product_id = p.id AND o.customer_id = c.id AND p.name_translation_id = tp.id AND c.name_translation_id = tc.id AND tp.language_id = l.id AND tc.language_id = l.id AND l.name = @language_code AND o.id = ***;
3) إنشاء كيانات للحقول المترجمة وغير المترجمة
في هذا الحل ، تقوم جداول الكيانات التي تحتوي على حقل مترجم واحد أو أكثر بتوسيع البيانات مع تلك غير المترجمة.
الايجابيات:- ليست هناك حاجة لدمج جداول الترجمة مع الجداول التي تحتوي على بيانات لا تتطلب الترجمة. لذلك ، سيكون لأخذ هذه البيانات أداء أفضل ،
- من السهل كتابة استعلامات ORM ،
- استعلام SQL بسيط للحصول على نص مترجم ،
- من السهل دعم ترجمة بعض البيانات إلى جميع اللغات المتاحة.
العيب:فيما يلي مثال على استعلام يسترجع النص المترجم:
SELECT pt.product_name, pt.description, p.price FROM order_line o, product p, product_translation pt, language l WHERE o.product_id = p.id AND AND p.id = pt.product_non_trans_id AND pt.language_id = l.id AND l.name = @language_code;
النتائج
عند تعريب تطبيقات السوق الدولية وتدويلها ، يمكن استخدام طرق مختلفة ، لكل منها ميزات وقيود معينة.
في هذه المقالة ، درسنا الأنواع التالية من التدويل:
- في الكود: نستخدم الترجمات عند إنشاء خدمة أو تطبيق باستخدام واجهة المستخدم الرسومية ؛
- في القوالب: نستخدمها عند تطوير تطبيق ويب دون واجهة ديناميكية ؛
- في قاعدة البيانات: استخدامها عند تخزين إما المستخدم أو البيانات التي تم إنشاؤها بشكل حيوي.
نأمل أن تساعدك مقالتنا في اختيار الطريقة الأنسب لمشروعك.