In Memory of Anas Al-Sharif - A Palestinian journalist who gave his life reporting truth. This package serves as a Sadaqah Jariyah (ongoing charity) in his honor.
A comprehensive Flutter/Dart localization solution with type-safe translations, advanced pluralization, runtime flexibility, and powerful CLI tools.
| Android | iOS | Web | macOS | Windows | Linux |
|---|---|---|---|---|---|
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
- Type-safe generated Dictionary with compile-time validation
- Runtime key lookup for fast iteration without code generation
- Dual access modes - use both typed and runtime access simultaneously
- Zero-configuration setup with automatic dictionary detection
- Deterministic locale fallback chain with script/region handling
- Advanced pluralization including Arabic gender-aware forms
- Built-in RTL support with automatic text direction
- CLI tools for validation, ARB/CSV/JSON import/export, and statistics
- Catalog UI - Swift String Catalog-style translation editor
- Regional English support -
en_US,en_GB,en_CA,en_AUoverlays - Date/time and number formatting with locale-specific patterns
- Rich text support with markdown-like formatting
- Migration guides from
gen_l10nandeasy_localization
Add to your pubspec.yaml:
dependencies:
anas_localization: ^0.1.0Run:
flutter pub getCreate JSON files in assets/lang/:
assets/lang/en.json
{
"app_name": "My App",
"welcome_user": "Welcome, {name}!",
"items_count": {
"one": "{count} item",
"other": "{count} items"
}
}assets/lang/ar.json
{
"app_name": "تطبيقي",
"welcome_user": "مرحباً، {name}!",
"items_count": {
"one": "{count} عنصر",
"other": "{count} عناصر"
}
}Update pubspec.yaml:
flutter:
assets:
- assets/lang/Run the code generator:
dart run anas_localization:anas update --genOr use watch mode for live updates:
dart run anas_localization:anas update --gen --watchThis creates lib/generated/dictionary.dart with type-safe accessors.
lib/main.dart
import 'package:flutter/material.dart';
import 'package:anas_localization/anas_localization.dart';
import 'generated/dictionary.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const AnasLocalization(
fallbackLocale: Locale('en'),
assetPath: 'assets/lang',
assetLocales: [
Locale('en'),
Locale('ar'),
],
app: MainApp(),
);
}
}
class MainApp extends StatelessWidget {
const MainApp({super.key});
@override
Widget build(BuildContext context) {
final locale = AnasLocalization.of(context).locale;
return MaterialApp(
locale: locale,
builder: (context, child) => AnasDirectionalityWrapper(
locale: locale,
child: child!,
),
localizationsDelegates: [
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
const DictionaryLocalizationsDelegate(),
],
supportedLocales: context.supportedLocales,
home: const HomePage(),
);
}
}Access translations with type-safe getters:
class HomePage extends StatelessWidget {
const HomePage({super.key});
@override
Widget build(BuildContext context) {
final dictionary = getDictionary();
return Scaffold(
appBar: AppBar(
title: Text(dictionary.appName),
),
body: Column(
children: [
// Simple translation
Text(dictionary.appName),
// With parameters
Text(dictionary.welcomeUser(name: 'Ahmed')),
// Pluralization
Text(dictionary.itemsCount(count: 1)), // "1 item"
Text(dictionary.itemsCount(count: 5)), // "5 items"
// Language selector widget
AnasLanguageSelector(
supportedLocales: context.supportedLocales,
),
],
),
);
}
}For fast iteration during development, you can skip code generation:
// Use getString for runtime key lookup
Text(dictionary.getString('app_name'))
Text(dictionary.getStringWithParams('welcome_user', {'name': 'Ahmed'}))See Runtime Lookup Guide for details.
Built-in language switching with smooth animations:
ElevatedButton(
onPressed: () {
AnasLocalization.of(context).setLocale(const Locale('ar'));
},
child: const Text('العربية'),
)
// Or use pre-built widgets
AnasLanguageDialog(
supportedLocales: context.supportedLocales,
showDescription: true,
){
"car": {
"one": {"male": "سيارة واحدة", "female": "سيارة واحدة"},
"two": {"male": "سيارتان", "female": "سيارتان"},
"few": {"male": "{count} سيارات", "female": "{count} سيارات"},
"many": {"male": "{count} سيارة", "female": "{count} سيارة"}
}
}dictionary.car(count: 5, gender: 'male') // "5 سيارات"# Validate translations
anas validate assets/lang --profile=strict
# Import/Export ARB files
anas export assets/lang arb lib/l10n
anas import l10n.yaml assets/lang
# Translation statistics
anas stats assets/lang
# Catalog UI for visual editing
anas catalog --init
anas catalog --serveMigrate from existing solutions:
# From gen_l10n
anas convert --from gen_l10n --source l10n.yaml --out assets/lang
# From easy_localization
anas convert --from easy_localization
# Validate migration
anas validate-migration --from gen_l10n- Getting Started: Installation & Setup
- Full Setup Guide: doc/SETUP_AND_USAGE.md
- Runtime Lookup: doc/RUNTIME_LOOKUP_WITHOUT_GENERATION.md
- Catalog UI: doc/CATALOG_UI.md
- CLI Reference: doc/reference/cli-reference.md
- Migration Guides:
- Cookbook: https://melsaeed276.github.io/anas_localization/
| Feature | Flutter gen_l10n |
easy_localization |
slang |
anas_localization |
|---|---|---|---|---|
| Type-safe accessors | ✅ | ✅ | ✅ | |
| Runtime flexibility | ✅ | ✅ | ✅ | |
| ARB import/export | ✅ | ✅ | ✅ | |
| CLI validation | ❌ | ✅ | ✅ | |
| Module namespaces | ❌ | ❌ | ✅ | ✅ |
| Migration tools | ❌ | ✅ | ||
| Custom UI | ❌ | ❌ | ❌ | ✅ |
anas_localization prioritizes migration tooling, runtime flexibility, and CI-friendly validation workflows. See detailed comparison.
See the example directory for a complete working app demonstrating all features.
cd example
flutter pub get
flutter runContributions are welcome! See CONTRIBUTING.md for guidelines.
Report security issues privately. See SECURITY.md for details.
Apache License 2.0 - See LICENSE for details.
Arabic translation (unofficial): LICENSE.ar.md
The name "anas_localization" honors Anas Al-Sharif's legacy. Modified versions should use different names. See TRADEMARK.md.
Remember: This work is a Sadaqah Jariyah for Anas Al-Sharif, whose courage in journalism continues to inspire.