Feature Guide
Localization

Localization Module

The Localization module creates a complete internationalization system for your app, supporting multiple languages with state management integration.

Generated Structure

lib/core/localization/
├── generated/
│   └── app_localizations.dart (generated by Flutter)
├── l10n/
│   ├── app_en.arb
│   ├── app_es.arb
│   └── l10n.dart
├── widgets/
│   └── language_selector.dart
└── localization.dart

Plus state management-specific files like:

  • bloc/locale_bloc.dart (for BLoC)
  • providers/localization_provider.dart (for Provider)
  • controllers/localization_controller.dart (for GetX)

Key Components

1. ARB Files (app_en.arb, app_es.arb, etc.)

Define translated strings for each supported language:

// app_en.arb
{
  "@@locale": "en",
  "appTitle": "My App",
  "welcome": "Welcome",
  "hello": "Hello, {name}",
  "@hello": {
    "description": "A welcome message with a name parameter",
    "placeholders": {
      "name": {
        "type": "String",
        "example": "John"
      }
    }
  },
  // Other strings...
}
 
// app_es.arb
{
  "@@locale": "es",
  "appTitle": "Mi Aplicación",
  "welcome": "Bienvenido",
  "hello": "Hola, {name}",
  // Other translations...
}

2. L10n Configuration (l10n.dart)

Defines supported locales:

class L10n {
  L10n._();
  
  /// All supported locales in the app
  static const supportedLocales = [
    Locale('en'),
    Locale('es'),
    // Add more locales as needed
  ];
}

3. Localization Extensions (localization.dart)

Provides easy access to translated strings and utility methods:

/// Extension method to get localized strings easier
extension LocalizationExtension on BuildContext {
  /// Get the translation strings instance
  AppLocalizations get l10n => AppLocalizations.of(this);
}
 
/// Utility methods for localization
class Localization {
  Localization._();
  
  /// Get all available locales
  static List<Locale> get supportedLocales => AppLocalizations.supportedLocales;
  
  /// Get all localization delegates
  static List<LocalizationsDelegate<dynamic>> get localizationDelegates => [
    AppLocalizations.delegate,
    ...GlobalMaterialLocalizations.delegates,
  ];
  
  /// Get a friendly display name for a locale
  static String getLanguageName(String languageCode) {
    switch (languageCode) {
      case 'es':
        return 'Español';
      // Other languages...
      case 'en':
      default:
        return 'English';
    }
  }
  
  /// Get a flag emoji for a language
  static String getLanguageFlag(String languageCode) {
    switch (languageCode) {
      case 'es':
        return '🇪🇸';
      // Other languages...
      case 'en':
      default:
        return '🇺🇸';
    }
  }
}

4. Language Selector Widget (language_selector.dart)

A reusable widget for language selection:

class LanguageSelector extends StatelessWidget {
  /// Callback when language changes
  final Function(Locale) onChanged;
 
  const LanguageSelector({Key? key, required this.onChanged}) : super(key: key);
 
  @override
  Widget build(BuildContext context) {
    final currentLocale = Localizations.localeOf(context);
    
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Padding(
          padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
          child: Text(
            context.l10n.language,
            style: Theme.of(context).textTheme.titleMedium,
          ),
        ),
        const SizedBox(height: 8),
        ...L10n.supportedLocales.map((locale) {
          final isSelected = currentLocale.languageCode == locale.languageCode;
          
          return ListTile(
            leading: Text(
              Localization.getLanguageFlag(locale.languageCode),
              style: const TextStyle(fontSize: 24),
            ),
            title: Text(Localization.getLanguageName(locale.languageCode)),
            trailing: isSelected 
              ? const Icon(Icons.check, color: Colors.green) 
              : null,
            onTap: () {
              if (!isSelected) {
                onChanged(locale);
              }
            },
          );
        }).toList(),
      ],
    );
  }
}

5. State Management Integration

BLoC Example:

// Events
abstract class LocaleEvent extends Equatable {
  const LocaleEvent();
  
  @override
  List<Object> get props => [];
}
 
class ChangeLocaleEvent extends LocaleEvent {
  final String languageCode;
  const ChangeLocaleEvent(this.languageCode);
  
  @override
  List<Object> get props => [languageCode];
}
 
class LoadLocaleEvent extends LocaleEvent {}
 
// State
class LocaleState extends Equatable {
  final Locale locale;
  const LocaleState(this.locale);
  
  @override
  List<Object> get props => [locale];
}
 
// BLoC
class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
  static const String LOCALE_KEY = 'app_locale';
  
  LocaleBloc() : super(const LocaleState(Locale('en'))) {
    on<ChangeLocaleEvent>(_onChangeLocale);
    on<LoadLocaleEvent>(_onLoadLocale);
    
    // Load saved locale when bloc is created
    add(LoadLocaleEvent());
  }
  
  // Event handlers...
}
 
// Extension for easy use with BuildContext
extension LocaleBlocExtension on BuildContext {
  void changeLocale(String languageCode) {
    read<LocaleBloc>().add(ChangeLocaleEvent(languageCode));
  }
  
  Locale get locale => read<LocaleBloc>().state.locale;
}

How to Use the Localization System

Access translated strings:

// Access a simple string
Text(context.l10n.welcome)
 
// With parameters
Text(context.l10n.hello('John'))
 
// Plurals
Text(context.l10n.counter(itemCount))

Change the language:

// With BLoC
context.changeLocale('es');
 
// With Provider
context.read<LocalizationProvider>().setLocaleByLanguageCode('es');
 
// With GetX
Get.find<LocalizationController>().setLocale('es');

Add localization to MaterialApp:

return MaterialApp(
  // Other properties...
  supportedLocales: Localization.supportedLocales,
  localizationsDelegates: Localization.localizationDelegates,
  locale: currentLocale, // From your state management
);

Customizing the Localization System

  1. Add New Languages: Create new ARB files (app_fr.arb, etc.) and add the locale to L10n.supportedLocales
  2. Add New Strings: Update all ARB files with new string entries
  3. Customize Language Selector: Modify the LanguageSelector widget for your UI needs
  4. Country-Specific Locales: Support country variants with full locale codes (Locale('en', 'US'))

Push Notification Module

The Push Notification module creates a complete notification system using Firebase Cloud Messaging and Flutter Local Notifications.

Generated Structure

lib/core/notifications/
├── models/
│   └── push_notification_model.dart
├── services/
│   ├── fcm_service.dart
│   └── local_notification_service.dart
└── notification_handler.dart

Key Components

1. Notification Model (push_notification_model.dart)

Defines the data structure for notifications:

class PushNotificationModel {
  final String title;
  final String body;
  final String? imageUrl;
  final String? payload;
  
  PushNotificationModel({
    required this.title,
    required this.body,
    this.imageUrl,
    this.payload,
  });
  
  factory PushNotificationModel.fromJson(Map<String, dynamic> json) {
    return PushNotificationModel(
      title: json['title'] ?? '',
      body: json['body'] ?? '',
      imageUrl: json['imageUrl'],
      payload: json['payload'],
    );
  }
  
  Map<String, dynamic> toJson() {
    return {
      'title': title,
      'body': body,
      'imageUrl': imageUrl,
      'payload': payload,
    };
  }
}

2. FCM Service (fcm_service.dart)

Handles Firebase Cloud Messaging integration:

class FCMService {
  final FirebaseMessaging _firebaseMessaging = FirebaseMessaging.instance;
  final LocalNotificationService _localNo