Flutter Locale Master

A comprehensive, production-ready Flutter localization package with automatic text direction switching, custom widgets, and developer-friendly APIs. Built for modern Flutter apps with performance and ease of use in mind.

✨ Features

  • πŸš€ One-line initialization with asset-based translations
  • πŸ“± Built-in pluralization with ICU MessageFormat syntax
  • πŸ”§ Parameter interpolation with named placeholders
  • 🎨 Context extensions for convenient access
  • 🧡 String extensions for BuildContext-free usage
  • πŸ—οΈ Custom widgets for automatic translation
  • πŸ“¦ Type-safe API with full null-safety
  • 🎯 Performance optimized with caching and preloading
  • πŸ“š Rich documentation and examples

πŸ“¦ Installation

Add this to your pubspec.yaml:

dependencies:
  flutter_locale_master: ^1.0.4

πŸš€ Quick Start

1. Setup Translation Files

Create translation files in your assets/ directory:

assets/
  lang/
    en/
      en.json          # General translations (default namespace)
      fields.json      # Form field labels
      validation.json  # Validation messages
    ar/
      ar.json          # General translations (default namespace)
      fields.json      # Form field labels
      validation.json  # Validation messages
    fr/
      fr.json          # General translations (default namespace)
      fields.json      # Form field labels
      validation.json  # Validation messages

Example en.json (general translations):

{
  "hello": "Hello",
  "welcome": "Welcome :name!",
  "item_count": "no items | :count item | :count items",
  "current_time": "Current time: :time",
  "user_greeting": "Hello :name, welcome back!"
}

Example fields.json (form field labels):

{
  "email": "Email Address",
  "password": "Password",
  "first_name": "First Name",
  "last_name": "Last Name"
}

Example validation.json (validation messages):

{
  "required": "This field is required",
  "email_invalid": "Please enter a valid email address",
  "password_too_short": "Password must be at least 8 characters",
  "passwords_not_match": "Passwords do not match",
  "phone_invalid": "Please enter a valid phone number",
  "min_length": "Minimum length is :min characters",
  "max_length": "Maximum length is :max characters"
}

### 2. Initialize the Package

```dart
import 'package:flutter/material.dart';
import 'package:flutter_locale_master/flutter_locale_master.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  // Initialize with asset translations
  final localeMaster = await FlutterLocaleMaster.initialize(
    basePath: 'lang/',
    initialLocale: const Locale('en'),
    fallbackLocale: const Locale('en'),
  );

  runApp(MyApp(localeMaster: localeMaster));
}

3. Wrap Your App

class MyApp extends StatelessWidget {
  final FlutterLocaleMaster localeMaster;

  const MyApp({super.key, required this.localeMaster});

  @override
  Widget build(BuildContext context) {
    return localeMaster.wrapApp(
      (locale) => MaterialApp(
        title: 'My App',
        localizationsDelegates: [
          localeMaster.delegate,
          GlobalMaterialLocalizations.delegate,
          GlobalWidgetsLocalizations.delegate,
          GlobalCupertinoLocalizations.delegate,
        ],
        supportedLocales: localeMaster.supportedLocales,
        locale: locale,
        home: const HomePage(),
      ),
    );
  }
}

That's it! Your app now supports multiple languages with automatic RTL/LTR switching.

🎯 Usage Examples

Basic Translation

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TranslatedText('app_title'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            TranslatedText(
              'welcome',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
            const SizedBox(height: 20),
            TranslatedText(
              'current_time',
              parameters: {'time': DateTime.now().toString()},
            ),
          ],
        ),
      ),
    );
  }
}

Using Context Extensions

class ProfilePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text(context.tr('profile_title')),
        Text(context.tr('welcome', parameters: {'name': user.name})),
        Text(context.plural('item_count', itemCount)),
        Text(context.field('email')),
      ],
    );
  }
}

Using String Extensions

class Utils {
  static String getGreeting(String userName) {
    return 'welcome'.tr(parameters: {'name': userName});
  }

  static String formatItemCount(int count) {
    return 'item_count'.plural(count);
  }

  static bool hasTranslation(String key) {
    return key.exists();
  }
}

class FormLabels {
  static String get email => 'email'.field();
  static String get password => 'password'.field();
}

Advanced Features

Locale Management

class LanguageSelector extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return DropdownButton<Locale>(
      value: context.currentLocaleObj,
      items: context.supportedLocales.map((localeString) {
        final locale = Locale(localeString);
        return DropdownMenuItem(
          value: locale,
          child: Text(locale.languageCode.toUpperCase()),
        );
      }).toList(),
      onChanged: (newLocale) {
        if (newLocale != null) {
          context.setLocaleObj(newLocale);
        }
      },
    );
  }
}

Rich Text Translation

TranslatedRichText.rich(
  'terms_agreement',
  parameters: {'app': 'MyApp'},
  spanBuilder: (translatedText) {
    final parts = translatedText.split(':app');
    return TextSpan(
      children: [
        TextSpan(text: parts[0]),
        TextSpan(
          text: 'MyApp',
          style: TextStyle(fontWeight: FontWeight.bold),
        ),
        if (parts.length > 1) TextSpan(text: parts[1]),
      ],
    );
  },
)

Locale Consumer for Complex UI

class AdaptiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LocaleConsumer(
      builder: (context, localization, child) {
        final isRTL = localization.notifier.isRTL;
        return Directionality(
          textDirection: isRTL ? TextDirection.rtl : TextDirection.ltr,
          child: Row(
            children: [
              if (!isRTL) child!,
              Expanded(
                child: Text(localization.provider.t('content')),
              ),
              if (isRTL) child!,
            ],
          ),
        );
      },
      child: IconButton(
        icon: Icon(Icons.menu),
        onPressed: () => Scaffold.of(context).openDrawer(),
      ),
    );
  }
}

πŸ”§ API Reference

FlutterLocaleMaster (Singleton)

Method Description
initialize() Initialize the localization system
wrapApp() Wrap MaterialApp with localization support
tr() Translate a key with optional parameters
plural() Translate with pluralization
field() Translate a field key
setLocale() Change the current locale
reset() Reset to initial locale
resetToSystemLocale() Reset to system locale
isCurrentLocale() Check if locale is current
toggleLocale() Toggle between two locales
supportedLocales Get supported locales
isLocaleSupported() Check if locale is supported
currentLocale Get current locale
textDirection Get current text direction

BuildContext Extensions

Method Description
tr() Translate with parameters and namespace
plural() Pluralize with count
field() Translate field keys
hasTranslation() Check if key exists
setLocale() Set locale by string
setLocaleObj() Set locale by Locale object
currentLocale Get current locale string
currentLocaleObj Get current locale object
supportedLocales Get supported locales
fallbackLocale Get fallback locale
textDirection Get text direction
isRTL Check if current locale is RTL

String Extensions

Method Description
tr() Translate string key
plural() Pluralize string key
field() Translate as field key
exists() Check if translation exists

Widgets

Widget Description
TranslatedText Simple translated text widget
TranslatedRichText Rich translated text widget
LocaleConsumer Consumer that rebuilds on locale change

πŸ—οΈ Architecture

Flutter Locale Master follows a clean, layered architecture:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   Extensions    β”‚  String & Context APIs
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚    Widgets      β”‚  TranslatedText, LocaleConsumer
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Controllers   β”‚  Locale state management
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Providers     β”‚  Translation data access
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚   Services      β”‚  Core functionality
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key Components

  • Services Layer: Asset loading, caching, validation, pluralization
  • Providers Layer: Translation data management and access
  • Controllers Layer: Locale state and change notifications
  • Widgets Layer: Reactive UI components
  • Extensions Layer: Developer-friendly APIs

πŸ”„ Automatic Text Direction

The package automatically handles RTL/LTR switching:

  • LTR Languages: English, French, German, Spanish, etc.
  • RTL Languages: Arabic, Hebrew, Persian, Urdu, etc.
// Automatic RTL support - no extra code needed!
class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: TranslatedText('app_title'), // Automatically RTL in Arabic
      ),
      body: TranslatedText('content'), // Text direction adapts automatically
    );
  }
}

πŸ“ Translation File Organization

Basic Structure

assets/
  lang/
    en/
      en.json          # General messages
      fields.json      # Form field labels
      validation.json  # Validation messages
    ar/
      ar.json
      fields.json
      validation.json

Namespace Usage

// Access general translations (default namespace from en.json)
context.tr('welcome')

// Access fields namespace (from fields.json)
context.field('email')  // Same as: context.tr('email', namespace: 'fields')

// Access validation namespace (from validation.json)
context.tr('required', namespace: 'validation')

Pluralization Syntax

{
  "apples": "no apples | You have :count apple | You have :count apples",
  "items": "no items | :count item | :count items"
}

πŸ§ͺ Testing

The package includes comprehensive tests. Run tests with:

flutter test

Example test:

void main() {
  test('Translation loading', () async {
    final localeMaster = await FlutterLocaleMaster.initialize(
      basePath: 'lang/',
    );

    expect(localeMaster.tr('hello'), 'Hello');
    expect(localeMaster.plural('item', 2), '2 items');
  });
}

οΏ½ Performance

  • Preloading: All translations loaded at startup

  • Caching: In-memory caching prevents disk I/O

  • Lazy initialization: Singleton pattern prevents waste

  • Concurrent loading: Multiple files loaded simultaneously

  • Minimal rebuilds: Only affected widgets update on locale change

  • Preloading: All translations loaded at startup

  • Caching: In-memory caching prevents disk I/O

  • Lazy initialization: Singleton pattern prevents waste

  • Concurrent loading: Multiple files loaded simultaneously

  • Minimal rebuilds: Only affected widgets update on locale change

🀝 Contributing

Contributions are welcome! Please:

  1. Fork the repository
  2. Create a feature branch
  3. Add tests for new features
  4. Ensure all tests pass
  5. Update documentation
  6. Submit a pull request

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ“ž Support


Made with ❀️ for the Flutter community

Libraries

flutter_locale_master
Flutter Locale Master - A comprehensive Flutter localization package with automatic text direction switching, custom widgets, and easy-to-use APIs.