Pub Version Dart SDK Version License: MIT GitHub Stars
Comprehensive offline MENA country data with localized names, ISO codes, currencies, and dial codes.
Perfect for building country selectors, phone number inputs, currency converters, and international applications targeting the Middle East and North Africa region.
- ✨ Features
- 🚀 Quick Start
- 🏴 Flag System
- 📚 API Reference
- 💡 Usage Examples
- 🌍 Supported Countries
- 📱 Platform Support
- 🤝 Contributing
- 📄 License
- 🔗 Links
- ⭐ Support
- 🌍 Complete MENA Coverage: 19 countries across Middle East and North Africa
- 🔍 Multiple Search Methods: Find by ISO code, name, dial code, or currency
- 🌐 Full Localization: Arabic and English names (common + official) with automatic locale switching
- 🏴 Advanced Flag System: SVG, PNG (emoji-style), and JPEG/PNG images
- 📐 Flexible Sizing: 24 emoji sizes + 15 image sizes (width/height based)
- 🎨 Format Options: PNG (lossless) and JPEG (compressed) support
- 📱 Zero Dependencies: Pure Dart implementation, no external packages
- 🚀 Offline First: No network calls - all data bundled with package
- 📊 JSON Ready: Built-in serialization for APIs and storage
- 🎯 Null Safe: Complete null safety for robust applications
- 📦 Lightweight: Minimal footprint, optimized performance
Add to your pubspec.yaml:
dependencies: mena: ^1.0.1
Import and use:
import 'package:mena/mena.dart'; void main() { // Find country by ISO code final palestine = MENA.getBy(query: 'ps', key: MenaKeys.code); print(palestine?.country.englishName); // "Palestine" print(palestine?.country.arabicName); // "فلسطين" // Search by name final egypt = MENA.getBy(query: 'مصر', key: MenaKeys.arabicName); // Arabic search print(egypt?.currency.code); // "EGP" // Or search explicitly in English final egyptEn = MENA.getBy(query: 'Egypt', key: MenaKeys.englishName); // Find by phone code final palestineByPhone = MENA.getBy(query: '970', key: MenaKeys.dialCode); print(palestineByPhone?.dialCodeWithPlus); // "+970" // Get Palestine flag URLs print(palestine?.getSvgUrl); // SVG flag print(palestine?.getEmojiUrl(EmojiSize.size48x36)); // 48x36 PNG print(palestine?.getImageUrl(ImageSize.w160, ImageType.png)); // 160px PNG }
MENA provides the most comprehensive flag system available for Dart packages, offering multiple formats and sizes to suit any use case:
| Format | Method | Description | Best For |
|---|---|---|---|
| SVG | getSvgUrl |
Scalable vector graphics | High-quality displays, print |
| PNG (Emoji) | getEmojiUrl(EmojiSize) |
Emoji-style flags, exact dimensions | UI icons, emoji displays |
| JPEG/PNG (Image) | getImageUrl(ImageSize, ImageType) |
Flexible sizing, format choice | Web optimization, responsive design |
24 predefined sizes maintaining 4:3 aspect ratio:
- Tiny: 16x12, 20x15, 24x18, 28x21, 32x24
- Small: 40x30, 48x36, 56x42, 64x48, 72x54
- Medium: 80x60, 96x72, 112x84, 128x96, 144x108
- Large: 160x120, 192x144, 224x168, 256x192
- Extra Large: 320x240, 384x288, 512x384, 640x480, 768x576
15 flexible sizes with automatic aspect ratio:
- Width-based: w20, w40, w80, w160, w320, w640, w1280, w2560
- Height-based: h20, h24, h40, h60, h80, h120, h240
- PNG: Lossless compression, transparency support, sharp edges
- JPEG: Lossy compression, smaller file sizes, web optimization
final palestine = MENA.getBy(query: 'ps', key: MenaKeys.code); // SVG flag (scalable) final svgFlag = palestine?.getSvgUrl; // "https://flagcdn.com/ps.svg" // Emoji-style PNG flags final smallEmoji = palestine?.getEmojiUrl(EmojiSize.size24x18); // "https://flagcdn.com/24x18/ps.png" final mediumEmoji = palestine?.getEmojiUrl(EmojiSize.size48x36); // "https://flagcdn.com/48x36/ps.png" // Flexible image flags final jpegFlag = palestine?.getImageUrl(ImageSize.w160); // "https://flagcdn.com/w160/ps.jpg" (default JPEG) final pngFlag = palestine?.getImageUrl(ImageSize.w160, ImageType.png); // "https://flagcdn.com/w160/ps.png" final heightFlag = palestine?.getImageUrl(ImageSize.h120, ImageType.png); // "https://flagcdn.com/h120/ps.png"
Use a unified API with MENA.getBy(query: ..., key: MenaKeys.*) or build an allCountriesMap(MenaKeys) for fast lookup.
| Key (MenaKeys) | Description | Example |
|---|---|---|
code |
ISO 3166-1 alpha-2 code | MENA.getBy(query: 'ps', key: MenaKeys.code) |
englishName |
Common English name | MENA.getBy(query: 'Palestine', key: MenaKeys.englishName) |
arabicName |
Common Arabic name | MENA.getBy(query: 'فلسطين', key: MenaKeys.arabicName) |
dialCode |
International dial code (no '+') | MENA.getBy(query: '970', key: MenaKeys.dialCode) |
currencyCode |
ISO 4217 currency code | MENA.getBy(query: 'EGP', key: MenaKeys.currencyCode) |
officalEn / officalAr |
Official names | MENA.getBy(query: 'United Arab Emirates', key: MenaKeys.officalEn) |
capitalEn / capitalAr |
Capital city names | MENA.getBy(query: 'Abu Dhabi', key: MenaKeys.capitalEn) |
| Method | Description | Example |
|---|---|---|
MENA.defaultLocale |
Get current locale ('ar' or 'en') | print(MENA.defaultLocale) |
MENA.setDefaultLocale(String) |
Set locale for subsequent operations | MENA.setDefaultLocale('en') |
| Collection | Countries | Description |
|---|---|---|
MENA.allCountries |
19 | All MENA countries combined |
MENA.middleEast |
12 | Middle Eastern countries |
MENA.northernAfrica |
7 | North African countries |
class MenaItemModel { final Country country; // Localized names & metadata (code, dialCode) final Currency currency; // Currency data with locale-aware helpers String get dialCodeWithPlus; // Formatted dial code, e.g., "+971" String get getSvgUrl; // SVG flag URL String getEmojiUrl(EmojiSize); // Emoji flag with specific dimensions String getImageUrl(ImageSize, [ImageType]); // Flexible image with size and format // Locale-aware convenience proxies String get getCountryName; // Country common name (locale-aware) String get getOfficialName; // Country official name (locale-aware) String get getCapitalName; // Country capital (locale-aware) String get getCurrencyName; // Currency full name (locale-aware) String get getCurrencySymbol; // Currency symbol (locale-aware) Map<String, dynamic> toJson(); }
class Country { final String englishName; // Common English name final String arabicName; // Common Arabic name final String officalEN; // Official English name final String officalAR; // Official Arabic name final String englishCapital; // Capital in English final String arabicCapital; // Capital in Arabic final String code; // ISO 3166-1 alpha-2 (e.g., "ae") final String dialCode; // Dial code without '+' (e.g., "971") // Note: Locale-aware getters are available in MenaItemModel Map<String, dynamic> toJson(); }
enum EmojiSize { size16x12, size20x15, size24x18, size28x21, size32x24, size40x30, size48x36, size56x42, size64x48, size72x54, size80x60, size96x72, size112x84, size128x96, size144x108, size160x120, size192x144, size224x168, size256x192, size320x240, size384x288, size512x384, size640x480, size768x576; String get dimensions; // e.g., "48x36" int get width; // Calculated width int get height; // Calculated height double get aspectRatio; // Width/height ratio }
enum ImageSize { // Width-based w20, w40, w80, w160, w320, w640, w1280, w2560, // Height-based h20, h24, h40, h60, h80, h120, h240; String get sizeParam; // e.g., "w160" or "h120" bool get isWidthBased; // True for width-based sizes bool get isHeightBased; // True for height-based sizes int get width; // Calculated width int get height; // Calculated height }
class Currency { final String code; // ISO 4217 code (e.g., "ILS", "AED") final String _enAdjective; // Country adjective (e.g., "Egyptian", "Saudi") final String _arAdjective; // Country adjective Arabic (e.g., "مصري", "سعودي") final CurrencyType type; // Currency type classification String get fullEnglishName; // Full English name (e.g., "Egyptian Pound") String get fullArabicName; // Full Arabic name (e.g., "جنيه مصري") String get englishSymbol; // English symbol (ISO code) String get arabicSymbol; // Arabic symbol (e.g., "₪", "د.إ") Map<String, dynamic> toJson(); // JSON serialization }
enum CurrencyType { dinar, riyal, dirham, pound, shekel, ouguiya; String get englishName; // "Dinar", "Riyal", etc. String get arabicName; // "دينار", "ريال", etc. (Arabic) List<String> get menaCurrencies; // Currency codes using this type }
enum ImageType { png, jpeg; String get extension; // File extension bool get supportsTransparency; // PNG supports transparency bool get isLossless; // PNG is lossless String get description; // Human-readable format }
import 'package:mena/mena.dart'; class CountrySelector extends StatelessWidget { @override Widget build(BuildContext context) { return DropdownButton<MenaItemModel>( items: MENA.allCountries.map((country) { return DropdownMenuItem( value: country, child: Row( children: [ Image.network( country.getEmojiUrl(EmojiSize.size20x15), width: 20, height: 15, ), SizedBox(width: 8), Text(country.country.englishName), ], ), ); }).toList(), onChanged: (country) { print('Selected: ${country?.country.englishName}'); }, ); } }
import 'package:mena/mena.dart'; class PhoneInput extends StatefulWidget { @override _PhoneInputState createState() => _PhoneInputState(); } class _PhoneInputState extends State<PhoneInput> { MenaItemModel? selectedCountry = MENA.getBy(query: 'ps', key: MenaKeys.code); // Default to Palestine @override Widget build(BuildContext context) { return Row( children: [ // Country code picker DropdownButton<MenaItemModel>( value: selectedCountry, items: MENA.allCountries.map((country) { return DropdownMenuItem( value: country, child: Text(country.dialCodeWithPlus), ); }).toList(), onChanged: (country) { setState(() => selectedCountry = country); }, ), SizedBox(width: 8), // Phone number input Expanded( child: TextField( decoration: InputDecoration( hintText: 'Phone number', prefixText: '${selectedCountry?.dialCodeWithPlus} ', ), keyboardType: TextInputType.phone, ), ), ], ); } }
import 'package:mena/mena.dart'; class FlagGallery extends StatelessWidget { @override Widget build(BuildContext context) { final palestine = MENA.getBy(query: 'ps', key: MenaKeys.code); return Column( children: [ // High-quality SVG flag for Palestine Image.network( palestine!.getSvgUrl, width: 200, height: 150, ), SizedBox(height: 20), // Different sizes for different use cases Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ // Small Palestine flag icon Image.network( palestine.getEmojiUrl(EmojiSize.size24x18), width: 24, height: 18, ), // Medium Palestine flag icon Image.network( palestine.getEmojiUrl(EmojiSize.size48x36), width: 48, height: 36, ), // Large PNG for high quality Image.network( palestine.getImageUrl(ImageSize.w160, ImageType.png), width: 160, ), // Compressed JPEG for performance Image.network( palestine.getImageUrl(ImageSize.w160, ImageType.jpeg), width: 160, ), ], ), ], ); } }
import 'package:mena/mena.dart'; void localeExamples() { // Default locale is Arabic print(MENA.defaultLocale); // 'ar' final country = MENA.getBy(query: 'ae', key: MenaKeys.code); print(country?.getCountryName); // "الإمارات" (Arabic) print(country?.getOfficialName); // "الإمارات العربية المتحدة" (Arabic) print(country?.getCapitalName); // "أبو ظبي" (Arabic) // Switch to English MENA.setDefaultLocale('en'); print(country?.getCountryName); // "United Arab Emirates" (English) print(country?.getOfficialName); // "United Arab Emirates" (English) print(country?.getCapitalName); // "Abu Dhabi" (English) // Search examples with keys final search1 = MENA.getBy(query: 'Egypt', key: MenaKeys.englishName); MENA.setDefaultLocale('ar'); final search2 = MENA.getBy(query: 'مصر', key: MenaKeys.arabicName); }
import 'package:mena/mena.dart'; void displayPrices() { final currencies = ['EGP', 'AED', 'SAR', 'ILS']; // Egypt first for (final currencyCode in currencies) { final country = MENA.getBy(query: currencyCode, key: MenaKeys.currencyCode); if (country != null) { print('Currency: ${country.currency.code}'); print('English: ${country.currency.fullEnglishName}'); print('Arabic: ${country.currency.fullArabicName}'); print('Localized: ${country.getCurrencyName}'); // Adapts to locale print('Symbol: ${country.getCurrencySymbol}'); // Adapts to locale print('Country: ${country.getCountryName}'); // Adapts to locale print('---'); } } } // Advanced currency features void advancedCurrencyFeatures() { final palestine = MENA.getBy(query: 'ps', key: MenaKeys.code); if (palestine != null) { final currency = palestine.currency; // Display price with currency print('Price: 100 ${currency.code}'); // "Price: 100 ILS" print('In Arabic: ١٠٠ ${currency.fullArabicName}'); // Use symbol if available final symbol = currency.arabicSymbol; print('With symbol: $symbol 100'); // "With symbol: ₪ 100" // Currency components and constructed names print('Country adjective (EN): ${currency._enAdjective}'); // Note: private field print('Country adjective (AR): ${currency._arAdjective}'); // Note: private field print('Currency type (EN): ${currency.type.englishName}'); print('Currency type (AR): ${currency.type.arabicName}'); // New convenient getters print('Full English name: ${currency.fullEnglishName}'); print('Full Arabic name: ${currency.fullArabicName}'); // Currency type analysis print('Type: ${currency.type.englishName}'); print('Type Arabic: ${currency.type.arabicName}'); } } // Group currencies by type void analyzeCurrencyTypes() { final dinars = MENA.allCountries .where((c) => c.currency.type == CurrencyType.dinar) .toList(); final riyals = MENA.allCountries .where((c) => c.currency.type == CurrencyType.riyal) .toList(); print('Dinar countries (${dinars.length}): ${dinars.map((c) => c.country.code).join(", ")}'); print('Riyal countries (${riyals.length}): ${riyals.map((c) => c.country.code).join(", ")}'); }
import 'package:mena/mena.dart'; import 'dart:convert'; Future<void> sendCountryData() async { final country = MENA.getBy(query: 'sa', key: MenaKeys.code); if (country != null) { // Serialize for API final payload = { 'user_country': country.toJson(), 'currency_preference': country.currency.toJson(), 'locale': 'ar_${country.country.code.toUpperCase()}', }; // Send to API final jsonString = json.encode(payload); print('API Payload: $jsonString'); } }
🇸🇦 Saudi Arabia • 🇦🇪 United Arab Emirates • 🇰🇼 Kuwait • 🇶🇦 Qatar • 🇧🇭 Bahrain • 🇴🇲 Oman • 🇯🇴 Jordan • 🇱🇧 Lebanon • 🇵🇸 Palestine • 🇮🇶 Iraq • 🇸🇾 Syria • 🇾🇪 Yemen
🇪🇬 Egypt • 🇸🇩 Sudan • 🇱🇾 Libya • 🇹🇳 Tunisia • 🇩🇿 Algeria • 🇲🇦 Morocco • 🇲🇷 Mauritania
- ✅ Flutter: Android, iOS, Web, Desktop
- ✅ Dart: Server-side applications
- ✅ Web: Browser applications
- ✅ Desktop: Windows, macOS, Linux
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
If this package helped you, please consider:
- ⭐ Starring the repository on GitHub
- 👍 Liking the package on pub.dev
- 🐛 Reporting issues or suggesting improvements
- 💰 Sponsoring the project
Made with ❤️ for the MENA developer community