localization_by_muz 2.1.0
localization_by_muz: ^2.1.0 copied to clipboard
A simple Flutter package for easy JSON-based localization with parameter interpolation and instant language switching
Localization by Muz #
A simple Flutter package for easy JSON-based localization. No extra commands, no code generation - just add the package and start localizing!
Features #
- JSON-based Localization: Use a simple JSON file for organized translations
- Parameter Interpolation: Support for dynamic text with placeholders like
{name}via args map - Number/Date Formatting: Built-in helpers for formatting numbers, currencies, percentages, dates, and times with locale support
- Namespaces/Dotted Keys: Support for nested JSON structures and dotted key notation (e.g.,
user.profile.name) - Instant Language Switching: Change languages instantly without app restart
- No Code Generation: No need for build runner or code generation commands
- Simple Setup: Just add the package and start using
Getting Started #
Add the package to your pubspec.yaml:
dependencies:
localization_by_muz: ^2.1.0
Usage #
JSON-based Localization #
- Create a
localization.jsonfile in yourlib/directory (required path for this package):
{
"helloWorld": {
"en": "Hello World",
"fr": "Bonjour Le Monde",
"es": "Hola Mundo"
},
"welcome": {
"en": "Welcome",
"fr": "Bienvenue",
"es": "Bienvenido"
},
"goodbye": {
"en": "Goodbye",
"fr": "Au revoir",
"es": "Adiós"
}
}
- Add it to your app's
pubspec.yamlassets so Flutter bundles it:
flutter:
assets:
- lib/localization.json
Note: The package reads from
lib/localization.jsonviarootBundle. Keep this exact path and add it to assets as shown above.
- Use in your Flutter app:
import 'package:flutter/material.dart';
import 'package:localization_by_muz/localization_by_muz.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LocalizationProvider(
defaultLocale: 'en',
child: LocalizedBuilder(
builder: (context, locale) {
return MaterialApp(
title: "appTitle".localize(),
home: MyHomePage(),
);
},
),
);
}
}
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("helloWorld".localize()),
),
body: Column(
children: [
Text("welcome".localize()),
Text("goodbye".localize()),
ElevatedButton(
onPressed: () => LocalizationProvider.setLocale(context, 'fr'),
child: Text("Switch to French"),
),
ElevatedButton(
onPressed: () => LocalizationProvider.setLocale(context, 'es'),
child: Text("Switch to Spanish"),
),
],
),
);
}
}
That's it! Just wrap your MaterialApp with LocalizedBuilder once, and you're done. The package automatically:
- Initializes the localization system in the background
- Handles persistent locale storage
- Rebuilds all localized text when language changes
- Provides instant language switching without app restart
- No need to wrap individual screens with
LocalizedBuilder
Language Switching #
To change the language instantly:
LocalizationProvider.setLocale(context, 'fr'); // Switch to French
LocalizationProvider.setLocale(context, 'en'); // Switch to English
LocalizationProvider.setLocale(context, 'es'); // Switch to Spanish
The UI will update instantly without requiring app restart or refresh!
Parameter Interpolation #
Support for dynamic text with placeholders using JSON-based translations:
// In localization.json:
// {
// "userWelcome": {
// "en": "Welcome back, {username}!",
// "fr": "Bon retour, {username}!",
// "es": "¡Bienvenido de vuelta, {username}!"
// },
// "greeting": {
// "en": "Hello {name}, welcome to {app}!",
// "fr": "Bonjour {name}, bienvenue dans {app}!",
// "es": "¡Hola {name}, bienvenido a {app}!"
// }
// }
// Use localizeArgs for translations with parameters
Text("userWelcome".localizeArgs(
args: {"username": "Alice"}
))
Text("greeting".localizeArgs(
args: {
"name": "John",
"app": "My App"
}
))
Number and Date Formatting #
The package includes built-in formatting helpers for numbers, currencies, percentages, dates, and times with locale-aware formatting:
import 'package:localization_by_muz/localization_by_muz.dart';
// Number formatting
String formattedNumber = FormattingHelpers.formatNumber(1234.56, 'en'); // "1,234.56"
String germanNumber = FormattingHelpers.formatNumber(1234.56, 'de'); // "1.234,56"
String frenchNumber = FormattingHelpers.formatNumber(1234.56, 'fr'); // "1 234,56"
// Currency formatting
String usdAmount = FormattingHelpers.formatCurrency(1234.56, 'en', 'USD'); // "$1,234.56"
String euroAmount = FormattingHelpers.formatCurrency(1234.56, 'de', 'EUR'); // "1.234,56 €"
// Percentage formatting
String percentage = FormattingHelpers.formatPercentage(0.1234, 'en'); // "12.3%"
String germanPercent = FormattingHelpers.formatPercentage(0.1234, 'de'); // "12,3 %"
// Date formatting
String usDate = FormattingHelpers.formatDate(DateTime.now(), 'en'); // "12/25/2023"
String germanDate = FormattingHelpers.formatDate(DateTime.now(), 'de'); // "25.12.2023"
String customDate = FormattingHelpers.formatDate(DateTime.now(), 'en', pattern: 'yyyy-MM-dd'); // "2023-12-25"
// Time formatting
String usTime = FormattingHelpers.formatTime(DateTime.now(), 'en'); // "3:30 PM"
String germanTime = FormattingHelpers.formatTime(DateTime.now(), 'de'); // "15:30"
Optional Intl Integration: The formatting helpers are designed with a feature flag (kUseIntlFormatting) that can be enabled to use the intl package for more advanced formatting when needed.
Namespaces and Dotted Keys #
Support for nested JSON structures and dotted key notation for better organization:
{
"user": {
"profile": {
"name": {
"en": "Name",
"fr": "Nom",
"es": "Nombre"
},
"email": {
"en": "Email Address",
"fr": "Adresse e-mail",
"es": "Dirección de correo"
}
},
"settings": {
"theme": {
"en": "Theme",
"fr": "Thème",
"es": "Tema"
}
}
},
"app": {
"title": {
"en": "My Application",
"fr": "Mon Application",
"es": "Mi Aplicación"
}
}
}
Use dotted notation to access nested translations:
// Access nested translations using dotted keys
Text("user.profile.name".localize()), // "Name" (in English)
Text("user.profile.email".localize()), // "Email Address"
Text("user.settings.theme".localize()), // "Theme"
Text("app.title".localize()), // "My Application"
// Also works with parameter interpolation
Text("user.welcome.message".localizeArgs(
args: {"username": "John"}
)), // If the nested key contains "Welcome back, {username}!"
Backward Compatibility: The package still supports flat key structures, so existing implementations continue to work without changes.
Migration from Older Versions #
If you're upgrading from an older version where you had to wrap each screen with LocalizedBuilder:
Old approach (no longer needed on each screen):
class MyScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LocalizedBuilder( // ❌ Remove from individual screens
builder: (context, locale) {
return Scaffold(
appBar: AppBar(title: Text("title".localize())),
body: Text("content".localize()),
);
},
);
}
}
New approach - wrap MaterialApp once:
// In your main app file
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LocalizationProvider(
defaultLocale: 'en',
child: LocalizedBuilder( // ✅ Wrap MaterialApp once
builder: (context, locale) {
return MaterialApp(
title: 'appTitle'.localize(),
home: MyScreen(),
);
},
),
);
}
}
// Individual screens - no wrapper needed
class MyScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold( // ✅ Direct usage - automatic rebuilding
appBar: AppBar(title: Text("title".localize())),
body: Text("content".localize()),
);
}
}
Key changes:
- Remove
LocalizedBuilderfrom individual screens - Wrap your
MaterialAppwithLocalizedBuilderonce in your main app widget - All screens will automatically rebuild when language changes!
Complete Working Example #
Here's a complete example showing language selection and switching:
import 'package:flutter/material.dart';
import 'package:localization_by_muz/localization_by_muz.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return LocalizationProvider(
defaultLocale: 'en',
child: LocalizedBuilder(
builder: (context, locale) {
return MaterialApp(
title: 'appTitle'.localize(),
home: LanguageSelectionScreen(),
);
},
),
);
}
}
class LanguageSelectionScreen extends StatelessWidget {
final List<Map<String, String>> languages = [
{'code': 'en', 'name': 'English'},
{'code': 'fr', 'name': 'French'},
{'code': 'es', 'name': 'Spanish'},
];
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('selectLanguage'.localize()),
),
body: ListView.builder(
itemCount: languages.length,
itemBuilder: (context, index) {
final language = languages[index];
return ListTile(
title: Text(language['name']!),
onTap: () {
LocalizationProvider.setLocale(context, language['code']!);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'languageChangedTo'.localizeArgs(
args: {'language': language['name']!}
)
),
),
);
},
);
},
),
);
}
}
With corresponding localization.json:
{
"appTitle": {
"en": "Localization Demo",
"fr": "Démo de Localisation",
"es": "Demo de Localización"
},
"helloWorld": {
"en": "Hello World",
"fr": "Bonjour Le Monde",
"es": "Hola Mundo"
},
"welcome": {
"en": "Welcome to our app!",
"fr": "Bienvenue dans notre application!",
"es": "¡Bienvenido a nuestra aplicación!"
},
"goodbye": {
"en": "Goodbye! See you later",
"fr": "Au revoir! À bientôt",
"es": "¡Adiós! Hasta luego"
},
"selectLanguage": {
"en": "Select Language",
"fr": "Sélectionner la langue",
"es": "Seleccionar idioma"
},
"languageChangedTo": {
"en": "Language changed to {language}",
"fr": "Langue changée en {language}",
"es": "Idioma cambiado a {language}"
}
}
Features Breakdown #
- JSON-based localization: Simple JSON file approach for organized translations
- Parameter interpolation: Dynamic text with
{placeholder}support via.localizeArgs(args: {...}) - Number/date formatting: Built-in locale-aware formatting for numbers, currencies, percentages, dates, and times
- Namespaces/dotted keys: Support for nested JSON structures and dotted key notation for better organization
- Missing key diagnostics: Track missing translation keys for debugging
- Instant updates: Language changes reflect immediately in the UI without app restart or manual rebuilding
- Zero configuration: No build runner or code generation required
- Simple API: Just use
.localize()for simple text and.localizeArgs()for parameterized text - Automatic rebuilding: Wrap MaterialApp once with
LocalizedBuilder- all screens update automatically - Fallback support: If translation not found, returns the key as fallback text
- Provider pattern: Efficient state management using Flutter's provider pattern
- Easy initialization: Automatic initialization - just wrap your app with
LocalizationProvider
Additional Information #
This package is designed to make Flutter localization as simple as possible using JSON-based translations. Perfect for projects of any size that need organized, maintainable localization.
For issues and feature requests, please visit our GitHub repository.
Author #
Muzamil Ghafoor
- GitHub: @muzzammil763
Made By Muzamil Ghafoor With ❤️ For The Flutter Developers To Make Localization Easy