anas_localization 1.3.0
anas_localization: ^1.3.0 copied to clipboard
Flutter/Dart localization with multiple language support, runtime switching, custom dictionaries, code generation, and RTL for scalable internationalization.
anas_localization #
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.
Platform Support #
| Android | iOS | Web | macOS | Windows | Linux |
|---|---|---|---|---|---|
| ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
Features #
- 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
Quick Start #
Installation #
Add to your pubspec.yaml:
dependencies:
anas_localization: ^0.1.0
Run:
flutter pub get
1. Create Translation Files #
Create 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/
2. Generate Dictionary #
Run the code generator:
dart run anas_localization:anas update --gen
Or use watch mode for live updates:
dart run anas_localization:anas update --gen --watch
This creates lib/generated/dictionary.dart with type-safe accessors.
3. Configure Your App #
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(),
);
}
}
4. Use Translations #
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,
),
],
),
);
}
}
Runtime Lookup (No Generation) #
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.
Language Switching #
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,
)
Advanced Features #
Arabic Gender-Aware Pluralization #
{
"car": {
"one": {"male": "سيارة واحدة", "female": "سيارة واحدة"},
"two": {"male": "سيارتان", "female": "سيارتان"},
"few": {"male": "{count} سيارات", "female": "{count} سيارات"},
"many": {"male": "{count} سيارة", "female": "{count} سيارة"}
}
}
dictionary.car(count: 5, gender: 'male') // "5 سيارات"
CLI Tools #
# 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 --serve
Remote Localization (Optional) #
Pull translations from a remote backend at runtime, in addition to local assets.
// 1. Implement a connector
class MyRemoteConnector implements RemoteLocalizationConnector {
@override
bool get supportsGlobalCheck => true;
@override
bool get supportsLocaleCheck => true;
@override
Future<RemoteCheckResponse> checkForUpdates(cachedVersions) async { /* ... */ }
@override
Future<RemoteCheckResponse> checkForLocaleUpdate(locale, cachedVersion) async { /* ... */ }
@override
Future<RemoteLocalizationPayload> downloadPayload(update) async { /* ... */ }
}
// 2. Configure
await AnasLocalization.initialize(
fallbackLocale: const Locale('en'),
supportedLocales: const [Locale('en'), Locale('ar')],
remote: RemoteLocalizationConfig(
connector: MyRemoteConnector(),
checkOnStartup: true,
),
);
// 3. Check for updates manually
final result = await AnasLocalization.remote.checkForUpdates();
Protected app keys and merge policy: package < app < remote cache. Mark entries in app assets with {"value": "text", "__override__": false} to prevent remote replacement.
Migration Support #
Migrate 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
Documentation #
- 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/
Why 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.
Example #
See the example directory for a complete working app demonstrating all features.
cd example
flutter pub get
flutter run
Contributing #
Contributions are welcome! See CONTRIBUTING.md for guidelines.
Security #
Report security issues privately. See SECURITY.md for details.
License #
Apache License 2.0 - See LICENSE for details.
Arabic translation (unofficial): LICENSE.ar.md
Trademark #
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.