esmaulhusna_muslimbg
A Flutter package providing the 99 Names of Allah (Esmaul Husna / Asma ul Husna) with Arabic text and meanings — fully offline, no internet required.
Designed for Islamic apps, Quran readers, dua apps, zikr apps, prayer-time apps, and Flutter apps targeting Balkan Muslim communities.
Features
- Fully offline — JSON assets bundled inside the package, no network calls
- Arabic text for all 99 names
- 6 locale datasets:
ar,bg,en,tr,bs_BA,sq_AL - Audio pronunciations — 99 MP3 files bundled;
getNames()returns anaudioasset path per entry - Flexible locale input — accepts short codes, regional variants, and full language names
- In-memory caching — repeated calls to
getNames()load assets only once - Built-in
EsmaulHusnaListViewandRandomEsmaulHusnaWidgetwidgets - Null-safe, pure Flutter, no native dependencies
Installation
Add to your pubspec.yaml:
dependencies:
esmaulhusna_muslimbg: ^1.0.8
Then run:
flutter pub get
Quick start
import 'package:esmaulhusna_muslimbg/esmaulhusna_muslimbg.dart';
// List all 99 names in English
final names = await EsmaulHusna.getNames('en');
print(names[0]['arabic']); // الرَّحْمَنُ
print(names[0]['name']); // The Most Gracious
print(names[0]['translation']); // The One who has plenty of mercy for all creation
// Get a random name
final random = await EsmaulHusna.getRandomName('tr');
print('${random['arabic']} — ${random['name']}');
// List all supported locale codes
print(EsmaulHusna.getSupportedLanguages());
// [ar, bg, bs_BA, en, sq_AL, tr]
Supported locales
| Locale code | Language | Notes |
|---|---|---|
ar |
Arabic | 99 entries |
bg |
Bulgarian | 100 entries, fully tested end-to-end |
bs_BA |
Bosnian | 100 entries |
en |
English | 100 entries, used as fallback |
sq_AL |
Albanian | 100 entries |
tr |
Turkish | 100 entries |
Accepted locale aliases
The package resolves these inputs to their canonical locale automatically:
| Input | Resolves to |
|---|---|
ar, arabic, ar_SA |
ar |
bg, bulgarian, bg_BG |
bg |
bs, bs_BA, bosnian |
bs_BA |
en, english, en_US, en_GB |
en |
mk, mk_MK, macedonian |
en (fallback, translation pending) |
sq, sq_AL, sq_XK, albanian |
sq_AL |
tr, turkish, tr_TR |
tr |
Hyphens are normalised to underscores — bs-BA and bs_BA both work. Unknown locales fall back to en.
API reference
EsmaulHusna.getNames(String language)
Returns Future<List<Map<String, String>>> with all 99 names for the specified locale.
Results are cached in memory — calling getNames() multiple times for the same locale loads assets only once.
final names = await EsmaulHusna.getNames('bg');
for (final name in names) {
print(name['arabic']); // Arabic text
print(name['name']); // Localized name
print(name['translation']); // Localized meaning
print(name['audio']); // Asset path for pronunciation MP3
}
EsmaulHusna.getRandomName(String language)
Returns Future<Map<String, String>> with a randomly selected name.
Throws StateError if no data is available for the given locale.
final name = await EsmaulHusna.getRandomName('en');
print('${name['arabic']} — ${name['name']}');
EsmaulHusna.getSupportedLanguages()
Returns an unmodifiable List<String> of all canonical locale codes.
final locales = EsmaulHusna.getSupportedLanguages();
// ['ar', 'bg', 'en', 'tr', 'bs_BA', 'mk_MK', 'sq_AL', 'sq_XK']
Response shape
Each map returned by getNames() and getRandomName() contains:
| Key | Type | Example value |
|---|---|---|
arabic |
String |
Arabic text, e.g. الرَّحْمَنُ |
name |
String |
The Most Gracious |
translation |
String |
The One who has plenty of mercy... |
audio |
String |
Asset path to bundled MP3, or "" for the Allah entry |
The audio field is an empty string for the Allah entry (index 0); all 99 names have a bundled MP3 path.
To play the audio in your app, declare the package assets and use any audio player:
# pubspec.yaml of your app
flutter:
assets:
- packages/esmaulhusna_muslimbg/lib/assets/audio/
// Example with audioplayers ^6.x
import 'dart:io';
import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/services.dart' show rootBundle;
import 'package:path_provider/path_provider.dart';
Future<void> playName(Map<String, String> nameEntry) async {
final assetPath = nameEntry['audio'] ?? '';
if (assetPath.isEmpty) return;
final data = await rootBundle.load(assetPath);
final dir = await getTemporaryDirectory();
final file = File('${dir.path}/audio_${assetPath.hashCode}.mp3');
if (!file.existsSync()) await file.writeAsBytes(data.buffer.asUint8List());
final player = AudioPlayer();
await player.play(DeviceFileSource(file.path));
}
Built-in widgets
The package ships two ready-to-use widgets.
EsmaulHusnaListView
Scrollable list of all 99 names:
import 'package:esmaulhusna_muslimbg/esmaulhusna_muslimbg.dart';
EsmaulHusnaListView(language: 'en')
RandomEsmaulHusnaWidget
Card showing a single randomly picked name:
RandomEsmaulHusnaWidget(language: 'tr')
Custom widget example
Build your own UI around the API:
import 'package:esmaulhusna_muslimbg/esmaulhusna_muslimbg.dart';
import 'package:flutter/material.dart';
class EsmaulHusnaScreen extends StatelessWidget {
const EsmaulHusnaScreen({super.key, this.language = 'en'});
final String language;
@override
Widget build(BuildContext context) {
return FutureBuilder<List<Map<String, String>>>(
future: EsmaulHusna.getNames(language),
builder: (context, snapshot) {
if (snapshot.hasError) {
return Center(child: Text('Error: ${snapshot.error}'));
}
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator());
}
final names = snapshot.data!;
return ListView.builder(
itemCount: names.length,
itemBuilder: (context, index) {
final entry = names[index];
return ListTile(
leading: CircleAvatar(child: Text('${index + 1}')),
title: Text(entry['name'] ?? ''),
subtitle: Text(entry['translation'] ?? ''),
trailing: Text(
entry['arabic'] ?? '',
style: const TextStyle(fontSize: 20),
textDirection: TextDirection.rtl,
),
);
},
);
},
);
}
}
Integrating with the device locale
The package normalises hyphens and casing, so you can pass the device locale tag directly:
import 'dart:ui';
import 'package:esmaulhusna_muslimbg/esmaulhusna_muslimbg.dart';
final deviceLocale = PlatformDispatcher.instance.locale;
final names = await EsmaulHusna.getNames(deviceLocale.toLanguageTag());
// 'bs-BA', 'mk-MK', 'sq-AL' all resolve correctly
Used in production
This package powers the MuslimBG app:
Migration guide
1.0.3 → 1.0.4
The description key in name maps has been renamed to translation:
// Before (≤ 1.0.3)
print(name['description']);
// After (1.0.4+)
print(name['translation']);
v1.1.0 roadmap
- Typed
EsmaulHusnaNamemodel instead of raw maps getByIndex(int index, String language)helper- Search and filtering helpers
- Grid and detail layout widgets
- Expand and verify dedicated translations for all locales
License
MIT — see LICENSE