الجمع والتواريخ بالعربي في Flutter مع gen-l10n

يوسف محمد15 دقيقة قراءة

ليه الجمع في العربي بيكسر الكود البسيط؟

الإنجليزي فيه صيغتين بس: 1 message و 2 messages. العربي فيه ست صيغ. الاسم بيتغيّر بعد الواحد، وبعد الاتنين، ومن 3 لـ 10، ومن 11 لـ 99، وتاني عند 100. كود زي count == 1 ? 'رسالة' : 'رسائل' هيطلع غلط قدام أي حد بيقرا عربي، وغالبًا بيبقى في أكتر الشاشات اللي الناس بتشوفها: السلة، والرسايل، والإشعارات.

أنا ببني تطبيقات Flutter بالعربي والإنجليزي لعملاء في مصر والخليج وأوروبا، وصيغ الجمع من الحاجات اللي بشيّك عليها في كل مشروع. ده الإعداد اللي بشتغل بيه: gen-l10n، وملفات ARB برسائل ICU، ومكتبة intl للأرقام والتواريخ. الأكواد اتجرّبت على آخر نسخة مستقرة من Flutter، وهقولك على الأماكن اللي الشروحات القديمة بقت غلط فيها.

الست صيغ للعدد في العربي

  • zero للصفر: لا توجد رسائل. أغلب التطبيقات بتكتب جملة كاملة هنا بدل الرقم.
  • one للواحد: رسالة واحدة. العربي بيشيل الرقم ويقول «رسالة واحدة».
  • two للاتنين: رسالتان. ده المثنى، وبرضه من غير رقم.
  • few من 3 لـ 10: 3 رسائل، 10 رسائل. هنا الاسم بييجي جمع.
  • many من 11 لـ 99: 11 رسالة، 99 رسالة. الاسم بيرجع مفرد.
  • other لـ 100 و101 و102 و1000 وأي رقم تاني: 100 رسالة.

الحالات دي جاية من قواعد CLDR بتاعة Unicode، و intl ماشي عليها. few و many مش معناهم صغير وكبير: القاعدة بتبص على آخر رقمين في العدد (باقي القسمة على 100). فالـ 103 بتاخد الجمع (103 رسائل)، والـ 111 بتاخد المفرد (111 رسالة)، ومن 100 لـ 102 بيقعوا في other. وده نفس منطق النحو العربي، و intl بيطبّقه لوحده.

many و other شكلهم واحد مع «رسالة»، بس مش مع كل الأسماء: بتقول 11 كتابًا بألف تنوين النصب، لكن 100 كتاب من غيرها. سيب الحالتين في الملف حتى لو النص متطابق، علشان المترجم يقدر يعدّل واحدة من غير ما يلمس التانية.

جهّز gen-l10n في مشروع Flutter حديث

ضيف flutter_localizations من الـ SDK ومكتبة intl. اكتب intl: any، لأن flutter_localizations بتثبّت نسخة معيّنة من intl، و pub هيختار المناسبة لوحده. فعّل التوليد في pubspec.yaml، واعمل ملف l10n.yaml في جذر المشروع. الخيار nullable-getter: false بيشيل الـ ! بعد AppLocalizations.of(context)، و untranslated-messages-file بيكتب تقرير بالترجمات الناقصة.

الشروحات القديمة بتعمل import لـ package:flutter_gen/gen_l10n/app_localizations.dart. الـ synthetic package دي اتشالت خلاص. gen-l10n دلوقتي بيكتب ملفات Dart جوه مشروعك، جنب ملفات ARB بشكل افتراضي، فبتعمل import لـ package:my_app/l10n/app_localizations.dart. الملفات بتتولّد تاني مع flutter pub get ومع كل build، و flutter gen-l10n بيشغّل الأداة وقت ما تحب.

# pubspec.yaml
dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter
  intl: any

flutter:
  generate: true

# l10n.yaml, in the project root
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
nullable-getter: false
untranslated-messages-file: untranslated.json

إزاي صيغة ICU للجمع بتشتغل في ملف ARB

ملف ARB هو JSON عادي. كل مفتاح رسالة، والمفتاح اللي بيبدأ بـ @ فيه البيانات الوصفية للرسالة دي. رسالة الجمع ليها تلات أجزاء جوه أقواس معقوفة: اسم المتغيّر، وكلمة plural، وقائمة حالات، كل حالة اسمها وبعده النص بتاعها بين أقواس. وجوه النص {count} بتطبع الرقم.

الملف الإنجليزي هو القالب، وفيه تعريف كل متغيّر ونوعه، فالملف العربي بيبقى فيه النصوص بس. اكتب description لكل رسالة، لأنه غالبًا السياق الوحيد اللي المترجم هيشوفه. وأي رسالة جمع لازم يبقى فيها other، وإلا gen-l10n هيوقف بخطأ syntax.

{
  "@@locale": "en",
  "unreadMessages": "{count, plural, =0{No messages} =1{1 message} other{{count} messages}}",
  "@unreadMessages": {
    "description": "Inbox badge. count is the number of unread messages.",
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

=0 و =1 و =2 ولا zero و one و two؟

في معيار ICU، الحالة =0 معناها صفر بالظبط، أما zero فهي اسم فئة من فئات CLDR. لكن في gen-l10n بتاع Flutter الاتنين بيروحوا لنفس المكان: =0 و zero بيبقوا الـ zero في Intl.pluralLogic، ونفس الكلام لـ =1 و one، ولـ =2 و two.

وبعدين intl بيشيّك على 0 و1 و2 كقيم بالظبط قبل ما يطبّق قاعدة اللغة. علشان كده =0 بتشتغل في الإنجليزي رغم إنه مفيهوش فئة zero. وفي العربي zero و one و two أصلًا هم 0 و1 و2 بالظبط، فالكتابتين بيشتغلوا زي بعض.

النتيجة: المطابقة بالرقم بتقف عند 2، فلو كتبت =5 أو =100 هيرفض gen-l10n يولّد الملف. ولو الرسالة فيها =1 و one مع بعض، هيفضل الأخير بس وهتطلع warning إن فيه حالة اتلغت. أنا بكتب =0 و =1 في الإنجليزي، وأسامي الفئات في العربي.

الملف العربي صيغة صيغة

الملف العربي بيكرر المفتاح بالست حالات، ومش محتاج بيانات @. لاحظ إن one و two مفيهمش {count}: «رسالة واحدة» و«رسالتان» بيقولوا العدد لوحدهم، و«2 رسالتان» شكلها غلطة. ومن أول 11 الاسم بيرجع «رسالة».

اكتب النصوص دي مع المترجم، مش من وراه. المثنى بيتغيّر حسب مكانه في الجملة: «لديك رسالتان» لما يبقى مبتدأ، و«أرسلت رسالتين» لما يبقى مفعول به، فالمترجم محتاج الجملة كاملة لكل حالة. وأنا بكتب نصوص الواجهة بفصحى بسيطة، لأنها بتتقري بشكل طبيعي في مصر والخليج.

{
  "@@locale": "ar",
  "unreadMessages": "{count, plural, zero{لا توجد رسائل} one{رسالة واحدة} two{رسالتان} few{{count} رسائل} many{{count} رسالة} other{{count} رسالة}}"
}

استخدم الدالة المتولّدة في الـ widgets

gen-l10n بيحوّل كل رسالة لدالة في AppLocalizations، فالرسالة دي بتبقى unreadMessages(int count)، ولو نسيت تبعت الرقم الكومبايلر هيقولك بدل ما يطلع نص فاضي. سجّل الـ delegates مرة واحدة في MaterialApp. و AppLocalizations.localizationsDelegates فيها أصلًا الـ delegates بتاعة Material و Cupertino و Widgets، فمش محتاج تكتبهم بإيدك.

import 'package:flutter/material.dart';
import 'package:my_app/l10n/app_localizations.dart';

extension L10nX on BuildContext {
  AppLocalizations get l10n => AppLocalizations.of(this);
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: AppLocalizations.localizationsDelegates,
      supportedLocales: AppLocalizations.supportedLocales,
      home: const InboxScreen(),
    );
  }
}

class InboxBadge extends StatelessWidget {
  const InboxBadge({super.key, required this.count});

  final int count;

  @override
  Widget build(BuildContext context) {
    return Text(context.l10n.unreadMessages(count));
  }
}

المذكر والمؤنث بـ select

العربي بيفرّق بين المذكر والمؤنث في الأفعال والصفات وحتى في «أنت»: «هل أنت متأكد؟» للراجل و«هل أنتِ متأكدة؟» للست. ICU بيحل ده بـ select، اللي بيختار الحالة بقيمة نصية بدل رقم.

الإنجليزي مش محتاجها هنا، فالقالب بيفضل جملة عادية وبيعرّف متغيّر gender وخلاص. أي قيمة ملهاش حالة بتروح لـ other، و other لازم تكون موجودة. وبما إن المذكر هو الأصل في النحو العربي، بخلّي other بصيغة المذكر، أو بكتب جملة محايدة لو فيه واحدة طبيعية.

في Dart ابعت String: l10n.confirmDelete(user.gender.name). ولو الـ enum فيه male و female و unknown، فالـ unknown ملهاش حالة وهتقع في other. ومتسألش المستخدم عن النوع (ذكر أو أنثى) إلا لو المنتج محتاجه فعلًا.

// app_en.arb
"confirmDelete": "Are you sure you want to delete this?",
"@confirmDelete": {
  "description": "Delete dialog title. gender is the signed-in user's gender.",
  "placeholders": {
    "gender": { "type": "String" }
  }
}

// app_ar.arb
"confirmDelete": "{gender, select, male{هل أنت متأكد من الحذف؟} female{هل أنتِ متأكدة من الحذف؟} other{هل أنت متأكد من الحذف؟}}"

select و plural في رسالة واحدة

في «أضافت سارة 3 صور»، الفعل بيتبع الشخص (أضاف أو أضافت)، والاسم بيتبع العدد. حط select برّه، وجوه كل حالة plural كاملة، وكرّر الجملة كلها في كل فرع. شكلها طويل، بس دي الطريقة الوحيدة اللي تطلّع كل التوافيق صح.

المثنى هنا «صورتين» مش «صورتان»، لأن الصور مفعول به. والمفتاح الإنجليزي محتاج plural بس. والدالة المتولّدة بتاخد المتغيّرات بنفس ترتيبها في القالب: photosAdded(name, gender, count).

// app_en.arb
"photosAdded": "{count, plural, =1{{name} added a photo} other{{name} added {count} photos}}",
"@photosAdded": {
  "placeholders": {
    "name": { "type": "String" },
    "gender": { "type": "String" },
    "count": { "type": "int" }
  }
}

// app_ar.arb
"photosAdded": "{gender, select, female{{count, plural, one{أضافت {name} صورة واحدة} two{أضافت {name} صورتين} few{أضافت {name} {count} صور} many{أضافت {name} {count} صورة} other{أضافت {name} {count} صورة}}} other{{count, plural, one{أضاف {name} صورة واحدة} two{أضاف {name} صورتين} few{أضاف {name} {count} صور} many{أضاف {name} {count} صورة} other{أضاف {name} {count} صورة}}}}"

تنسيق الأرقام جوه الرسالة

المتغيّر اللي ملوش format بيتطبع بـ toString، فالـ 1250 بتظهر 1250. لو ضفت format في القالب، gen-l10n بيعمل NumberFormat من intl للغة الحالية: decimalPattern بيطبع 1,250. والـ formats اللي ليها خيارات، زي decimalPatternDigits أو currency، بتاخدها من optionalParameters. وحالة الجمع لسه بتتحسب من الرقم الأصلي، اللي بيتغيّر هو شكل الرقم بس.

علشان كده compact و plural مش بيتجمعوا كويس في العربي. compact بيطبع «1.25 ألف»، والعربي بعد «ألف» بيستخدم المفرد، لكن رقم زي 1,205 القاعدة بتقول عليه few وهتختار الجمع. فللعدادات الكبيرة بعمل رسالة منفصلة من غير plural، وبختار بينهم في Dart: count < 1000 ? l10n.views(count) : l10n.viewsCompact(count).

// app_en.arb
"views": "{count, plural, =0{No views yet} =1{1 view} other{{count} views}}",
"@views": {
  "placeholders": {
    "count": { "type": "int", "format": "decimalPattern" }
  }
},
"viewsCompact": "{count} views",
"@viewsCompact": {
  "placeholders": {
    "count": { "type": "int", "format": "compact" }
  }
},
"rating": "Rated {rating} out of 5",
"@rating": {
  "placeholders": {
    "rating": {
      "type": "double",
      "format": "decimalPatternDigits",
      "optionalParameters": { "decimalDigits": 1 }
    }
  }
}

// app_ar.arb
"views": "{count, plural, zero{لا توجد مشاهدات بعد} one{مشاهدة واحدة} two{مشاهدتان} few{{count} مشاهدات} many{{count} مشاهدة} other{{count} مشاهدة}}",
"viewsCompact": "{count} مشاهدة",
"rating": "التقييم {rating} من 5"

التواريخ بالعربي مع DateFormat

الـ widgets بتاعة Material زي اختيار التاريخ بتعرض أسامي الشهور بالعربي لوحدها. وللنص بتاعك، ادّي متغيّر DateTime في ARB format زي yMMMd، أو استخدم DateFormat مع l10n.localeName بدل ما تكتب 'ar' ثابتة. استخدم الأشكال الجاهزة زي yMMMMd و jm، لأنها بترتّب اليوم والشهر والسنة صح لكل لغة وبتستخدم أسامي شهور زي «أكتوبر». ولو محتاج pattern خاص بيك في متغيّر ARB، حط عليه isCustomDateFormat بقيمة true.

الـ delegates بتاعة Material بتحمّل بيانات التاريخ العربي للـ widgets. لكن الكود اللي برّه شجرة الـ widgets، زي unit test عادي أو main() قبل runApp، لازم ينادي initializeDateFormatting('ar') من package:intl/date_symbol_data_local.dart الأول، وإلا هيرمي LocaleDataException. التعليقات في الكود تحت بأرقام إنجليزي، والقسم الجاي بيشرح ليه تطبيقك ممكن يطبع ٢٠ بدلها.

import 'package:intl/intl.dart';

// app_en.arb
// "lastOrder": "Last order on {date}",
// "@lastOrder": { "placeholders": { "date": { "type": "DateTime", "format": "yMMMd" } } }
// app_ar.arb
// "lastOrder": "آخر طلب في {date}"
Text(l10n.lastOrder(order.createdAt)); // آخر طلب في 20 أكتوبر 2026

// Your own text, in the current language.
final date = DateTime(2026, 10, 20, 15, 30);
DateFormat.yMMMMd(l10n.localeName).format(date); // 20 أكتوبر 2026
DateFormat.yMMMMEEEEd(l10n.localeName).format(date); // الثلاثاء، 20 أكتوبر 2026
DateFormat.jm(l10n.localeName).format(date); // 3:30 م

أرقام إنجليزي (0123) ولا أرقام عربي (٠١٢٣)؟

العربي ممكن يتكتب بأرقام غربية (0123456789)، اللي الناس بتسميها أرقام إنجليزي، أو بأرقام عربية هندية (٠١٢٣٤٥٦٧٨٩). الاتنين صح، وهتلاقي الاتنين في تطبيقات شغّالة في مصر والخليج. ده قرار منتج، فأنا بسأل العميل موقعه ومطبوعاته بيستخدموا إيه، وبطبّق نفس الاختيار على الأرقام والتواريخ.

الإعدادات الافتراضية مش متّسقة. NumberFormat مع ar أو ar_SA أو ar_AE بيطبع أرقام غربية، و ar_EG بيطبع أرقام عربية هندية، والمتغيّر اللي ملوش format دايمًا بيطلع بأرقام غربية. لكن بيانات التاريخ العربي اللي flutter_localizations بتحمّلها بأرقام عربية هندية، فممكن شاشة واحدة يبقى فيها «٢٠ أكتوبر» جنب «1,250 مشاهدة».

لو عايز أرقام غربية في كل حتة، اقفل الأرقام المحلية لتواريخ العربي في main()، زي الكود تحت. ولو عايز أرقام عربية هندية، ادّي متغيّرات الأرقام format، وضيف ملف app_ar_EG.arb مفيهوش غير سطر @@locale بقيمة ar_EG: gen-l10n هياخد النصوص العربي زي ما هي وينسّق بـ ar_EG. وخلّي الـ locale في MaterialApp يبقى Locale('ar', 'EG') لما المستخدم يختار العربي. ومفاتيح الملف ده هتظهر في تقرير الترجمات الناقصة، لأنه بيورثها.

ولو كمان بتنادي initializeDateFormatting('ar') في أول التطبيق، أرقام التواريخ ممكن تعتمد على أنهي بيانات اتستخدمت الأول، فحدّد الشكل بنفسك ومتسيبهوش للصدفة.

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

void main() {
  // Western digits (0-9) in Arabic dates, to match the numbers.
  DateFormat.useNativeDigitsByDefaultFor('ar', false);
  runApp(const MyApp());
}

// Or for one formatter only:
final formatter = DateFormat.yMMMMd('ar')..useNativeDigits = false;

أخطاء شايفها كتير في الجمع العربي

دي أكتر الأخطاء اللي بلاقيها لما براجع تطبيق Flutter موجود:

  • بناء الجملة في Dart بالشكل ده: '$count ' + l10n.messages. خلّي الجملة كلها في رسالة واحدة.
  • كتابة s بإيدك: count == 1 ? 'message' : 'messages'، وبعدين نسخ نفس المنطق للعربي.
  • نسيان المثنى: «2 رسائل» بدل «رسالتان».
  • استخدام الجمع فوق 10: «11 رسائل» بدل «11 رسالة».
  • كتابة الرقم في حالتي one و two، زي «1 رسالة واحدة».
  • تجربة =3 أو =11. اللي بيشتغل =0 و =1 و =2 بس، والباقي بـ few و many.
  • تقسيم جملة واحدة على مفتاحين. المترجم مش هيقدر يرتّب كلام عمره ما شافه مع بعض.
  • تجاهل الترجمات الناقصة. المفتاح الناقص في app_ar.arb بيظهر بالإنجليزي جوه التطبيق العربي، من غير أي خطأ.
  • وضع رقم compact جوه plural.

امسك الترجمات الناقصة قبل الإطلاق

المفتاح العربي الناقص بيطلّع سطر واحد بس من gen-l10n، والتطبيق بيتبني عادي. لكن مع untranslated-messages-file، الأداة بتكتب المفاتيح الناقصة في ملف JSON متقسّم حسب اللغة، أو {} لو مفيش حاجة ناقصة. خلّي الـ build في CI يفشل لو الملف مش {}.

خلّي الملف في جذر المشروع، لأن gen-l10n مش بيعمل فولدر ناقص علشانه، وضيفه في .gitignore. وكمان required-resource-attributes: true يستاهل تفعّله: بيوقف التوليد لو مفتاح في القالب ملوش @، وده المكان اللي فيه الوصف بتاع المترجم.

flutter gen-l10n
if [ "$(cat untranslated.json)" != "{}" ]; then
  echo "Missing translations:"
  cat untranslated.json
  exit 1
fi

اختبر صيغ الجمع في unit test

نصوص الجمع بتبوظ في هدوء مع أي تعديل بعدين. lookupAppLocalizations بترجّع الـ class المتولّدة للغة من غير ما تبني widget، فـ test عادي يقدر يشيّك عليها في لحظة. بختبر رقم من كل فئة: 0 و1 و2 و3 و11 و100، وكمان 103 علشان أتأكد إن القاعدة بتبص على آخر رقمين. و Intl.plural تقدر تختبر بيها القاعدة نفسها من غير ملفات ARB.

التواريخ اختبرها لوحدها في widget test بيعمل pump لـ MaterialApp بالـ delegates الحقيقية. الـ test العادي بيحمّل بيانات intl العربي، ودي مش نفس البيانات اللي Flutter بيستخدمها جوه التطبيق، فالأرقام ممكن تختلف.

import 'package:flutter/widgets.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:my_app/l10n/app_localizations.dart';

void main() {
  final ar = lookupAppLocalizations(const Locale('ar'));
  final en = lookupAppLocalizations(const Locale('en'));

  group('unreadMessages in Arabic', () {
    const expected = {
      0: 'لا توجد رسائل',
      1: 'رسالة واحدة',
      2: 'رسالتان',
      3: '3 رسائل',
      11: '11 رسالة',
      100: '100 رسالة',
      103: '103 رسائل',
    };

    for (final MapEntry(key: count, value: text) in expected.entries) {
      test('count = $count', () {
        expect(ar.unreadMessages(count), text);
      });
    }
  });

  test('unreadMessages in English', () {
    expect(en.unreadMessages(0), 'No messages');
    expect(en.unreadMessages(1), '1 message');
    expect(en.unreadMessages(2), '2 messages');
    expect(en.unreadMessages(11), '11 messages');
  });

  test('gender changes the Arabic sentence', () {
    expect(ar.confirmDelete('female'), 'هل أنتِ متأكدة من الحذف؟');
    expect(ar.confirmDelete('male'), 'هل أنت متأكد من الحذف؟');
  });
}

قائمة مراجعة وإيه الخطوة الجاية

  • flutter_localizations و intl: any في pubspec.yaml، ومعاهم generate: true
  • ملف l10n.yaml فيه nullable-getter: false و untranslated-messages-file
  • كل رسالة عدد بالعربي فيها zero و one و two و few و many و other
  • مفيش رقم في حالتي one و two
  • الجملة كلها في رسالة واحدة، ومفيش لزق في Dart
  • select للمذكر والمؤنث في أي نص بيكلّم شخص أو بيتكلم عنه
  • decimalPattern على متغيّرات الأرقام، و compact برّه plural بس
  • شكل أرقام واحد، متطبّق على الأرقام والتواريخ
  • التواريخ متنسّقة بـ l10n.localeName والأشكال الجاهزة
  • unit test لـ 0 و1 و2 و3 و11 و100 و103
  • ملف untranslated.json قيمته {} قبل كل إطلاق
  • حد لغته الأم عربي شاف كل جملة جمع على شاشة حقيقية

لو تطبيقك فيه عربي بالفعل، ابدأ بالنصوص اللي الناس بتشوفها أكتر: إجمالي السلة، وعدد الإشعارات، وسجل الطلبات. حوّلهم لرسائل plural، وضيف الـ test، وبعدين كمّل شاشة شاشة.

ولو بتبدأ برمجة تطبيق Flutter جديد بالعربي والإنجليزي، جهّز ده من أول يوم، لأنه سهل في الأول وصعب تضيفه بعدين. ولو حابب أراجع العربي في تطبيقك أو نبنيه سوا، تقدر تكلّمني من صفحة التواصل في الموقع.

أسئلة شائعة

العربي فيه كام صيغة جمع؟
ست صيغ: zero و one و two و few و many و other. يعني 0، و1، و2، ومن 3 لـ 10، ومن 11 لـ 99، وأي رقم تاني زي 100. القاعدة بتبص على آخر رقمين، فالـ 103 بتبقى few والـ 111 بتبقى many.
إيه الفرق بين =0 و zero في ملف ARB؟
في ICU، الحالة =0 معناها قيمة بالظبط، و zero معناها فئة لغوية. لكن في gen-l10n بتاع Flutter الاتنين بيروحوا لنفس الحالة، و intl بيشيّك على 0 و1 و2 كقيم بالظبط الأول. ومفيش مطابقة لأرقام بعد =2.
ليه تطبيق Flutter بيظهر كلام إنجليزي وهو على العربي؟
لأن المفتاح ناقص في app_ar.arb، فالـ class العربي بيرجع لنص القالب الإنجليزي. حط untranslated-messages-file في l10n.yaml علشان تاخد قائمة كاملة بالمفاتيح الناقصة.
ليه import لـ package:flutter_gen مش شغّال؟
الـ synthetic package اللي اسمها flutter_gen اتشالت من Flutter الحالي. gen-l10n بقى يكتب الملفات جوه مشروعك، جنب ملفات ARB بشكل افتراضي. اعمل import من الباكدج بتاعتك، زي package:my_app/l10n/app_localizations.dart.
إزاي أعرض الأرقام بالعربي (٠١٢٣) في تطبيق Flutter؟
ادّي متغيّرات الأرقام format زي decimalPattern، ونسّقها بـ ar_EG، مثلًا عن طريق ملف app_ar_EG.arb. والتواريخ اللي جاية من flutter_localizations بتستخدم أرقام عربية هندية مع ar أصلًا، إلا لو قفلت الأرقام المحلية.
هل لازم أنادي initializeDateFormatting في Flutter؟
مش جوه الـ widgets، لأن الـ delegates بتاعة flutter_localizations بتحمّل بيانات التاريخ العربي. لكن هتحتاجها في الـ unit tests العادية، وفي أي كود بينسّق تاريخ قبل ما الترجمة تتحمّل، زي main().
ينفع رسالة عربي واحدة يبقى فيها مذكر ومؤنث وجمع؟
أيوه. حط select على النوع برّه، و plural كاملة جوه كل حالة. كل فرع بيكرر الجملة كلها، فالفعل والاسم الاتنين بيطلعوا صح.

شارك

متاح لمشاريع جديدة

حساباتي