تبدو ترجمة تطبيق Flutter أصعب مما هي عليه. يأتي Flutter بكل ما تحتاجه. تحفظ نصوصك في ملفات ARB، ملف لكل لغة، ويحوّلها Flutter إلى صنف Dart تستدعيه من عناصر الواجهة. يأخذك هذا الدليل من تطبيق بالإنجليزية فقط إلى تطبيق يغيّر لغته حسب إعدادات الهاتف. ويغطي أيضًا ما يخطئ فيه كثيرون: العناصر النائبة وصيغ الجمع واللغات التي تُكتب من اليمين إلى اليسار.
1. أضف الحزم
في pubspec.yaml، أضف حزمة الترجمة الخاصة بـ Flutter وintl، وفعّل توليد الشيفرة:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: any
flutter:
generate: trueيسمح intl: any لـ Flutter باختيار إصدار intl المناسب لإصدار Flutter لديك، فتتجنّب تعارض الإصدارات.
2. أخبر Flutter بمكان نصوصك
أنشئ l10n.yaml في المجلد الرئيسي للمشروع:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
nullable-getter: falseملف القالب هو لغتك المصدر. وتتبع كل اللغات الأخرى مفاتيحه. أما السطر الأخير، nullable-getter: false، فيُغنيك عن إضافة ! في كل مرة تستخدم فيها نصًا.
3. اكتب أول ملف ARB
أنشئ lib/l10n/app_en.arb:
{
"@@locale": "en",
"homeTitle": "Welcome back",
"@homeTitle": {
"description": "Title on the home screen"
},
"cartItems": "{count, plural, =0{Your cart is empty} =1{1 item in your cart} other{{count} items in your cart}}",
"@cartItems": {
"placeholders": {
"count": { "type": "num" }
}
},
"greeting": "Hello, {name}!",
"@greeting": {
"placeholders": {
"name": { "type": "String" }
}
}
}بعض العادات تؤتي ثمارها لاحقًا:
- أضف وصفًا لكل مفتاح. يرى المترجمون، وأدوات الترجمة بالذكاء الاصطناعي، النص فقط. وعبارة "Title on the home screen" تخبرهم أنه عنوان قصير وليس جملة.
- لا تبنِ الجمل بربط السلاسل النصية. لا يمكن ترجمة
"Hello, " + name، لأن لغات كثيرة تضع الاسم في مكان آخر. استخدم عنصرًا نائبًا. - استخدم صيغ الجمع بدل جمل if. في الإنجليزية صيغتان، وفي العربية ست صيغ، وفي البولندية أربع. وصيغة الجمع أعلاه (وهي معيار يُسمّى ICU) تتعامل معها كلها. وعند ترجمة صيغة جمع، استخدم الصيغ التي تحتاجها اللغة الأخرى (
zeroوoneوtwoوfewوmanyوother)، لا=0و=1من الإنجليزية فقط.
أضف الآن لغة ثانية. أنشئ lib/l10n/app_es.arb بالمفاتيح نفسها:
{
"@@locale": "es",
"homeTitle": "¡Hola de nuevo!",
"cartItems": "{count, plural, =0{Tu carrito está vacío} =1{1 artículo en tu carrito} other{{count} artículos en tu carrito}}",
"greeting": "¡Hola, {name}!"
}لا تلزم الأوصاف (إدخالات @) إلا في ملف القالب.
4. ولّد الشيفرة واربطها بتطبيقك
شغّل flutter pub get أو شغّل التطبيق، وسيولّد Flutter الشيفرة نيابةً عنك. ويمكنك أيضًا تشغيل flutter gen-l10n بنفسك. تكتب إصدارات Flutter الحديثة الملف app_localizations.dart بجوار ملفات ARB. أما الإصدارات الأقدم فكانت تضعه في حزمة مخفية، لذا حدّث Flutter إذا لم يعمل الاستيراد أدناه.
ثم اربطه في MaterialApp:
import 'package:flutter/material.dart';
import 'l10n/app_localizations.dart';
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
home: const HomeScreen(),
);
}
}يتضمّن localizationsDelegates أيضًا ترجمات Flutter الخاصة بعناصر الواجهة المدمجة، مثل منتقي التاريخ وتسميات زر "رجوع".
5. استخدم النصوص في عناصر الواجهة
// Inside a widget's build method:
final l10n = AppLocalizations.of(context);
Text(l10n.homeTitle);
Text(l10n.greeting('Sara'));
Text(l10n.cartItems(3)); // "3 items in your cart"يصبح كل مفتاح خاصية أو دالة في Dart، لذا فإن أي خطأ في اسم المفتاح يوقف البناء بدل أن يعرض تسمية فارغة لمستخدميك.
يتبع التطبيق الآن لغة الهاتف. لتجربته، غيّر اللغة في المحاكي (Simulator أو Emulator)، أو افرض لغة مؤقتًا بـ locale: const Locale('es') في MaterialApp.
6. لا تنسَ iOS
على iOS، لا يعرض متجر App Store إلا اللغات التي يعلنها مشروع Xcode لديك. افتح ios/Runner.xcodeproj في Xcode، واختر المشروع Runner (تحت Projects لا Targets)، وافتح تبويب Info، وأضف كل لغة تحت Localizations. سيُنشئ Xcode بعدها بضعة ملفات صغيرة يستخدمها App Store لعرض اللغات التي يدعمها تطبيقك.
7. اللغات من اليمين إلى اليسار تعمل دون جهد تقريبًا
عندما تكون اللغة العربية أو العبرية أو الفارسية، يقلب MaterialApp اتجاه التخطيط تلقائيًا. أما ما لا يستطيع إصلاحه فهو الشيفرة التي تفترض اليسار واليمين:
- استخدم
EdgeInsetsDirectional.only(start: 16)بدلEdgeInsets.only(left: 16). - استخدم
AlignmentDirectional.centerStartبدلAlignment.centerLeft. - اعكس أيقونات الأسهم التي تشير "إلى الأمام". أسهم الرجوع والتقدّم الشائعة مثل
Icons.arrow_backتنقلب من تلقاء نفسها، فتحقّق من أي سهم آخر تستخدمه. أما أيقونات مثل الهاتف أو الكاميرا فلا تحتاج إلى عكس.
اختبر مبكرًا بلغة حقيقية تُكتب من اليمين إلى اليسار. كما أن النص الألماني غالبًا ما يكون أطول بكثير من الإنجليزي، والعربية تحتاج إلى ارتفاع سطر أكبر، فتأكد من أن الأزرار لا تفيض.
8. أبقِ الترجمات متزامنة مع نمو التطبيق
الخطوات السابقة هي الجزء السهل. أما الصعب فيبدأ مع الإصدار التالي، حين تضيف اثني عشر مفتاحًا وتغيّر ثلاثة، وتحتاجها بكل اللغات قبل النشر. هذه طرق شائعة للتعامل مع ذلك:
- تعديل ملفات ARB يدويًا. يصلح ذلك للغة أو لغتين ولتطبيق صغير. لكنه يتعثّر حين يترجم شخص آخر، أو حين تنسى أي المفاتيح تغيّرت.
- إرسال الملفات إلى مترجم. تصدّر
app_en.arb، وتستلم الترجمات، ثم تلصقها. تنجح هذه الطريقة لكنها بطيئة، وعليك أن تتابع بنفسك ما تغيّر منذ المرة السابقة. - استخدام أداة لإدارة الترجمة. ترفع ملفك الإنجليزي، وتترجم المفاتيح الجديدة (يدويًا أو بالذكاء الاصطناعي أو بكليهما)، ثم تنزّل اللغات الأخرى.
litei18n إحدى هذه الأدوات، وهي مصمَّمة للفرق الصغيرة. يمكنك استيراد ملفات ARB وتصديرها (في الخطط المدفوعة، بدءًا من 9 دولارات شهريًا؛ والخطة المجانية تعمل مع JSON)، وترجمة المفاتيح الناقصة بالذكاء الاصطناعي، ومراجعة التغييرات قبل نشرها. يقرأ litei18n وصف كل مفتاح جديد من ملف ARB لديك، ويعيد كتابة الأوصاف عند التنزيل، فيراها المترجمون والذكاء الاصطناعي. وتحمل الملفات المنزّلة الأسماء التي يتوقعها Flutter، مثل app_es.arb. ولتغيير وصف لاحقًا، عدّله في litei18n، لأن رفع الملف مرة أخرى لا يحدّثه. لكنه لا يحفظ إعدادات العناصر النائبة بعد، لذا احتفظ بملف app_en.arb الخاص بك كمصدر ونزّل اللغات الأخرى فقط. وإذا كنت تعمل مع مساعد برمجة بالذكاء الاصطناعي مثل Claude أو Cursor، فيمكنه أيضًا إضافة المفاتيح وترجمتها نيابةً عنك عبر اتصال MCP الخاص بـ litei18n، الذي يتيح لأدوات الذكاء الاصطناعي العمل مباشرةً داخل litei18n.
9. تحديث النصوص دون إصدار جديد للتطبيق
يحوّل Flutter ملفات ARB إلى شيفرة تُبنى داخل تطبيقك. وهذا يعني أن تصحيح خطأ إملائي في الألمانية، أو إضافة لغة، يحتاج عادةً إلى بناء جديد ومراجعة من App Store وGoogle Play.
إذا كانت هذه مشكلة بالنسبة لك، فيمكنك بدلًا من ذلك تحميل الترجمات أثناء التشغيل. احتفظ بنسخة مضمّنة في التطبيق للاستخدام دون اتصال وعند التشغيل الأول، ثم اجلب أحدث نسخة من خادم عند بدء التطبيق. يعرض دليلنا للتحديثات عبر الهواء في Flutter الشيفرة كاملة. إنها نحو 30 سطرًا، وتستخدم صنفًا صغيرًا خاصًا بها بدل AppLocalizations. هذه الطريقة الأبسط تتعامل مع النص العادي فقط: فالعناصر النائبة وصيغ الجمع تحتاج إلى شيفرة إضافية، لذا تناسب التطبيقات التي نصوصها بسيطة في الغالب. وفي litei18n، التحديثات عبر الهواء متاحة في الخطط المدفوعة.
قائمة تحقق سريعة
- أضفت
flutter_localizationsوintl، معgenerate: true - يشير
l10n.yamlإلى مجلد ARB والقالب - لكل مفتاح وصف
- عناصر نائبة وصيغ جمع بدل ربط السلاسل النصية
- أضفت كل لغة تحت Localizations في Xcode
- هوامش ومحاذاة اتجاهية للغات التي تُكتب من اليمين إلى اليسار
- خطة لإبقاء المفاتيح الجديدة مترجمة
هذا كل ما يلزم ليتحدث تطبيق Flutter بأكثر من لغة. ابدأ بلغة إضافية واحدة. وحين يعمل الإعداد، تصبح إضافة اللغة التالية مجرد ملف ARB آخر.
هل تريد إدارة ملفات ARB في مكان واحد وترجمة المفاتيح الجديدة بالذكاء الاصطناعي؟ ابدأ مجانًا مع litei18n.