التدويل (i18n) في Rust: نظرة عامة على المكتبات والأدوات
\n\nالتدويل (اختصاراً i18n - من 18 حرفاً بين 'i' و 'n') هو عملية تصميم التطبيق بحيث يمكن تكييفه مع لغات ومعايير إقليمية مختلفة دون تغيير الكود المصدري. في نظام Rust البيئي، توجد عدة مكتبات ناضجة لتنفيذ i18n. في هذه المقالة، سنستعرض ثلاثة أساليب رئيسية: الكلاسيكي gettext، والمكتبة الموجهة بالماكرو rust-i18n، والحديث fluent-rs من Mozilla.
1. مكتبة gettext (crate gettext-rs)
\ngettext هو المعيار الفعلي لتوطين أنظمة Unix. توفر الواجهة البرمجية لـ Rust gettext-rs وصولاً كاملاً إلى دوال GNU gettext.
التثبيت
\n[dependencies]\ngettext-rs = "0.7"\n\nمثال على الاستخدام
\nuse gettextrs::*;\nuse std::env;\n\nfn main() {\n // تعيين الإعدادات المحلية والنطاق\n setlocale(LocaleCategory::LcAll, "ru_RU.UTF-8");\n bindtextdomain("myapp", "/usr/share/locale").unwrap();\n textdomain("myapp");\n\n // ترجمة سلسلة نصية\n println!("{}", gettext("Hello, world!"));\n \n // صيغ الجمع (العدد الجمعي)\n let n = 5;\n println!("{}", ngettext("{} apple", "{} apples", n, n));\n}\n\nالمزايا: النضج، دعم صيغ الجمع، الترجمات السياقية (pgettext)، التكامل مع Poedit و Transifex.
\nالعيوب: يتطلب تثبيت gettext على مستوى النظام، دعم غير مثالي لـ Unicode على Windows.
2. مكتبة rust-i18n
\nتنفيذ خالص بلغة Rust بدون تبعيات خارجية. تستخدم ملفات YAML لتخزين الترجمات والماكرو لاستخراج السلاسل النصية.
\n\nالتثبيت
\n[dependencies]\nrust-i18n = "3.0"\n\nهيكل المشروع
\nlocales/\n├── en.yml\n└── ru.yml\n\nمثال locales/ru.yml:
hello: "مرحباً بالعالم!"\napples: \n zero: "لا يوجد تفاح"\n one: "{} تفاحة"\n few: "{} تفاحات"\n many: "{} تفاح"\n\nالاستخدام في الكود
\nuse rust_i18n::t;\n\nrust_i18n::i18n!("locales");\n\nfn main() {\n // ترجمة بسيطة\n println!("{}", t!("hello"));\n\n // صيغ الجمع مع مراعاة قواعد اللغة العربية\n let n = 3;\n println!("{}", t!("apples", count = n, n));\n}\n\nالمزايا: البساطة، التحديد التلقائي للإعدادات المحلية، دعم العناصر النائبة وصيغ الجمع للغات المعقدة (الروسية، العربية).
\nالعيوب: أقل مرونة من gettext، لا يوجد دعم للسياقات.
3. مكتبة fluent-rs
\nطورتها Mozilla لمتصفح Firefox. تستخدم بناء جملة خاص بها FTL (قائمة ترجمة Fluent).
\n\nالتثبيت
\n[dependencies]\nfluent = "0.16"\nfluent-bundle = "0.15"\nfluent-resmgr = "0.4"\n\nمثال على ملف FTL (locales/ar/main.ftl)
\nhello = مرحباً بالعالم!\napples = \n { $count ->\n [0] لا يوجد تفاح\n [one] { $count } تفاحة\n [two] { $count } تفاحتان\n *[many] { $count } تفاحة\n }\n\nالاستخدام في Rust
\nuse fluent_bundle::{FluentBundle, FluentResource};\nuse fluent_resmgr::ResourceManager;\nuse unic_langid::langid;\n\nfn main() {\n let langid = langid!("ar");\n let res_mgr = ResourceManager::new("./locales/".into());\n \n let mut bundle = FluentBundle::new(&[langid]);\n let ftl_string = res_mgr.load("ar/main.ftl").unwrap();\n let resource = FluentResource::try_new(ftl_string).unwrap();\n bundle.add_resource(resource).unwrap();\n\n let mut errors = vec![];\n let msg = bundle.format_pattern(\n bundle.get_message("hello").unwrap().value().unwrap(),\n None,\n &mut errors\n );\n println!("{}", msg);\n\n // صيغ الجمع\n let mut args = fluent_bundle::FluentArgs::new();\n