esmaulhusna_muslimbg

pub package pub points likes license

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.

pub.devGitHubIssues


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 an audio asset 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 EsmaulHusnaListView and RandomEsmaulHusnaWidget widgets
  • 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 EsmaulHusnaName model 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