DEV Community

Saina
Saina

Posted on

Flutter Localization with gen-l10n + BLoC

"l10n" is short for localization — you take the first and last letter of the word and replace the middle characters with the number of characters skipped:

l o c a l i z a t i o n → l10n

You don't need to install this from pub.dev — it's part of Flutter SDK.
flutter_localizations,flutter_bloc,intl

📁 Step 1: Add ARB Files

First, create a folder:

lib/l10n

Then, create two files inside:

  • app_en.arb – English
  • app_ne.arb – Nepali

Here’s an example:

lib/l10n/app_en.arb

{
  "title1": "Hello World!",
  "description1": "Greetings from the digital realm...",
  "title2": "Localization",
  "description2": "Making apps speak multiple languages.",
  "title3": "Dynamic Switching",
  "description3": "Change languages on the fly!",
  "details": "Details",
  "home": "Home"
}

Enter fullscreen mode Exit fullscreen mode

lib/l10n/app_ne.arb

{
  "title1": "नमस्ते संसार!",
  "description1": "डिजिटल संसारबाट शुभकामना...",
  "title2": "स्थानीयकरण",
  "description2": "एपलाई बहुभाषी बनाउने प्रक्रिया।",
  "title3": "डायनामिक स्विच",
  "description3": "भाषा तुरुन्त परिवर्तन गर्नुहोस्!",
  "details": "विवरण",
  "home": "गृहपृष्ठ"
}
Enter fullscreen mode Exit fullscreen mode

⚙️ Step 2: Add l10n.yaml
Create a l10n.yaml file in your project root:

arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
output-class: AppLocalizations

📦 Step 3: Update pubspec.yaml
Add the following under the flutter section:

flutter:
  generate: true
  uses-material-design: true
Enter fullscreen mode Exit fullscreen mode

Then run:

flutter gen-l10n
Enter fullscreen mode Exit fullscreen mode

This will generate the AppLocalizations class under lib/l10n.

Image description

🧠 Step 4: Add Locale Support via BLoC

Bloc Event

final class ChangeLocale extends SettingsEvent {
  final Locale locale;
  ChangeLocale(this.locale);
}
Enter fullscreen mode Exit fullscreen mode

State

final class SettingsState {
  final Locale locale;
  const SettingsState({this.locale = const Locale('en')});

  SettingsState copyWith({Locale? locale}) =>
      SettingsState(locale: locale ?? this.locale);
}
Enter fullscreen mode Exit fullscreen mode

BLoC Handler

Future<void> _onChangeLocale(
  ChangeLocale event,
  Emitter<SettingsState> emit,
) async {
  emit(state.copyWith(locale: event.locale));
}
Enter fullscreen mode Exit fullscreen mode

🏗️ Step 5: Configure MaterialApp
In your main widget, set up the localization config:

return MaterialApp(
  restorationScopeId: 'app',
  localizationsDelegates: AppLocalizations.localizationsDelegates,
  supportedLocales: AppLocalizations.supportedLocales,
  locale: settingsState.locale,
  home: const LocalizedTextScreen(),
);
Enter fullscreen mode Exit fullscreen mode

🖥️ Step 6: Use Localized Strings in Your Screen

import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:xuno/features/settings/bloc/settings_bloc.dart';
import 'package:xuno/l10n/app_localizations.dart';

class LocalizedTextScreen extends StatelessWidget {
  const LocalizedTextScreen({super.key});

  @override
  Widget build(BuildContext context) {
    return BlocBuilder<SettingsBloc, SettingsState>(
      builder: (context, state) {
        final localizations = AppLocalizations.of(context)!;

        return Scaffold(
          backgroundColor: Colors.black,
          appBar: AppBar(
            title: Text(localizations.title1),
            backgroundColor: Colors.grey[900],
            actions: [
              Padding(
                padding: const EdgeInsets.only(right: 12.0),
                child: DropdownButtonHideUnderline(
                  child: DropdownButton<Locale>(
                    dropdownColor: Colors.grey[850],
                    value: state.locale,
                    iconEnabledColor: Colors.white,
                    items: const [
                      DropdownMenuItem(
                        value: Locale('en'),
                        child: Text('🇬🇧 EN', style: TextStyle(color: Colors.white)),
                      ),
                      DropdownMenuItem(
                        value: Locale('ne'),
                        child: Text('🇳🇵 NE', style: TextStyle(color: Colors.white)),
                      ),
                    ],
                    onChanged: (locale) {
                      if (locale != null) {
                        context.read<SettingsBloc>().add(ChangeLocale(locale));
                      }
                    },
                  ),
                ),
              ),
            ],
          ),
          body: Padding(
            padding: const EdgeInsets.all(16.0),
            child: ListView(
              children: [
                _buildSection(localizations.title1, localizations.description1),
                _buildSection(localizations.title2, localizations.description2),
                _buildSection(localizations.title3, localizations.description3),
                _buildSection(localizations.details, ''),
                _buildSection(localizations.home, ''),
              ],
            ),
          ),
        );
      },
    );
  }

  Widget _buildSection(String title, String description) {
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 12.0),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(title,
              style: const TextStyle(
                  fontSize: 18, fontWeight: FontWeight.bold, color: Colors.white)),
          const SizedBox(height: 4),
          if (description.isNotEmpty)
            Text(description,
                style: const TextStyle(fontSize: 16, color: Colors.white70)),
        ],
      ),
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

🧠 How It Works
Here’s a breakdown of the core logic:

AppLocalizations is generated from ARB files using gen-l10n.

BLoC listens to locale change events and updates the locale in SettingsState.

MaterialApp reads the locale from SettingsState and rebuilds with new localized strings.

The UI layer accesses translations via AppLocalizations.of(context).

Final Output
Your app is now fully localized and supports live language switching between English 🇬🇧 and Nepali 🇳🇵!

🔧 What is gen-l10n in Flutter?
gen-l10n is Flutter's built-in localization code generator.

It automatically generates a Dart class (like AppLocalizations) from your .arb files, which contain key-value pairs for different languages. This makes it easy to internationalize your app (i18n) and localize it (l10n) for specific languages.

Image description
Image description

Top comments (0)