localization_gen 2.1.0 copy "localization_gen: ^2.1.0" to clipboard
localization_gen: ^2.1.0 copied to clipboard

Type-safe Flutter localization generator from JSON/JSONC, with nested keys, placeholders, and plural/gender/context variants.

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'assets/app_localizations.gen.dart';

void main() {
  runApp(const LocalizationExampleApp());
}

class LocalizationExampleApp extends StatefulWidget {
  const LocalizationExampleApp({super.key});

  @override
  State<LocalizationExampleApp> createState() => _LocalizationExampleAppState();
}

class _LocalizationExampleAppState extends State<LocalizationExampleApp> {
  Locale _locale = const Locale('en');

  void _changeLanguage(Locale locale) {
    setState(() {
      _locale = locale;
    });
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Localization Example',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.green),
        useMaterial3: true,
      ),
      localizationsDelegates: const [
        AppLocalizationsExtension.delegate,
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
      ],
      supportedLocales: AppLocalizations.supportedLocales,
      locale: _locale,
      home: ExampleHomePage(onLanguageChange: _changeLanguage),
    );
  }
}

class ExampleHomePage extends StatelessWidget {
  final void Function(Locale) onLanguageChange;

  const ExampleHomePage({super.key, required this.onLanguageChange});

  @override
  Widget build(BuildContext context) {
    final currentLocale = Localizations.localeOf(context);

    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(AppLocalizations.of(context).strings.appTitle),
        actions: [
          PopupMenuButton<Locale>(
            icon: const Icon(Icons.language),
            tooltip: 'Language',
            onSelected: onLanguageChange,
            itemBuilder: (BuildContext context) => [
              _buildLanguageMenuItem(
                const Locale('en'),
                'English',
                currentLocale,
              ),
              _buildLanguageMenuItem(
                const Locale('id'),
                'Indonesia',
                currentLocale,
              ),
            ],
          ),
        ],
      ),
      body: ListView(
        padding: const EdgeInsets.all(16),
        children: [
          _Section(
            title: 'Basic strings',
            children: [
              Text(
                'app_title: ${AppLocalizations.of(context).strings.appTitle}',
              ),
              Text(
                'powered_by: ${AppLocalizations.of(context).strings.poweredBy}',
              ),
            ],
          ),
          _Section(
            title: 'Nested keys',
            children: [
              Text(
                'simple.hello: ${AppLocalizations.of(context).simple.hello}',
              ),
              Text(
                'simple.welcome.title: ${AppLocalizations.of(context).simple.welcome.title}',
              ),
              Text(
                'deep (max 6): ${AppLocalizations.of(context).simple.app.settings.security.password.change.title}',
              ),
            ],
          ),
          _Section(
            title: 'Placeholders',
            children: [
              Text(
                AppLocalizations.of(context).placeholders.welcomeUser(name: 'Alice'),
              ),
              Text(
                AppLocalizations.of(context).placeholders.fullName(firstName: 'Alice', lastName: 'Doe'),
              ),
              Text(
                AppLocalizations.of(context).placeholders.itemsInCity(count: '12', city: 'Jakarta'),
              ),
            ],
          ),
          _Section(
            title: 'Formatting',
            children: [
              Text('multiline:'),
              Text(AppLocalizations.of(context).formatting.multiline),
              Text('quotes: ${AppLocalizations.of(context).formatting.quotes}'),
              Text(
                'unicode: ${AppLocalizations.of(context).formatting.unicode}',
              ),
            ],
          ),
          _Section(
            title: 'Symbols and special characters',
            children: [
              Text(
                'masked_pin: ${AppLocalizations.of(context).symbols.maskedPin}',
              ),
              Text(
                'masked_otp: ${AppLocalizations.of(context).symbols.maskedOtp}',
              ),
              Text(
                'copyright: ${AppLocalizations.of(context).symbols.copyrightNotice}',
              ),
              Text(
                'registered: ${AppLocalizations.of(context).symbols.registeredMark}',
              ),
              Text(
                'trademark: ${AppLocalizations.of(context).symbols.trademarkNotice}',
              ),
              Text(
                'currency: ${AppLocalizations.of(context).symbols.currencyAndAmount}',
              ),
              Text(
                'percent: ${AppLocalizations.of(context).symbols.percentLike}',
              ),
              Text('math: ${AppLocalizations.of(context).symbols.mathLike}'),
              Text(
                'degree: ${AppLocalizations.of(context).symbols.degreeLike}',
              ),
              Text('arrow: ${AppLocalizations.of(context).symbols.arrowLike}'),
              Text('pipe: ${AppLocalizations.of(context).symbols.pipeLike}'),
              Text(AppLocalizations.of(context).symbols.bulletListLike),
              Text('url: ${AppLocalizations.of(context).symbols.urlQueryLike}'),
            ],
          ),
          _Section(
            title: 'Literals (not placeholders)',
            children: [
              Text(AppLocalizations.of(context).literals.doubleCurly),
              Text(AppLocalizations.of(context).literals.squareBrackets),
              Text(AppLocalizations.of(context).literals.literalBraces),
            ],
          ),
          _Section(
            title: 'Structured forms (shape validation)',
            children: [
              Text(
                'plural (5): ${AppLocalizations.of(context).structured.items(count: 5)}',
              ),
              Text(
                'gender (male): ${AppLocalizations.of(context).structured.userTitle(gender: 'male', lastName: 'Doe')}',
              ),
              Text(
                'context (formal): ${AppLocalizations.of(context).structured.greeting(context: 'formal', name: 'Alice')}',
              ),
            ],
          ),
          _Section(
            title: 'Runtime key lookup (resolveByKey)',
            children: [
              Text(
                "resolveByKey('strings.app_title'): ${AppLocalizations.of(context).resolveByKey('strings.app_title', fallback: '<missing>')}",
              ),
              Text(
                "resolveByKey('app_title', namespace: 'strings'): ${AppLocalizations.of(context).resolveByKey('app_title', namespace: 'strings', fallback: '<missing>')}",
              ),
              Text(
                "resolveByKey('missing.key', fallback): ${AppLocalizations.of(context).resolveByKey('missing.key', fallback: '<missing>')}",
              ),
            ],
          ),
          _Section(
            title: 'Multi-variant errors (context: register/verification)',
            children: [
              Text(
                "invalid_code_errors(register): ${AppLocalizations.of(context).structured.invalidCodeErrors(context: 'register')}",
              ),
              Text(
                "invalid_code_errors(verification): ${AppLocalizations.of(context).structured.invalidCodeErrors(context: 'verification')}",
              ),
              Text(
                "action_label(primary): ${AppLocalizations.of(context).structured.actionLabel(context: 'primary')}",
              ),
              Text(
                "action_label(secondary): ${AppLocalizations.of(context).structured.actionLabel(context: 'secondary')}",
              ),
            ],
          ),
        ],
      ),
    );
  }

  PopupMenuItem<Locale> _buildLanguageMenuItem(
    Locale locale,
    String label,
    Locale currentLocale,
  ) {
    return PopupMenuItem<Locale>(
      value: locale,
      child: Row(
        children: [
          Text(label),
          if (currentLocale.languageCode == locale.languageCode) ...[
            const Spacer(),
            const Icon(Icons.check, color: Colors.green),
          ],
        ],
      ),
    );
  }
}

class _Section extends StatelessWidget {
  final String title;
  final List<Widget> children;

  const _Section({required this.title, required this.children});

  @override
  Widget build(BuildContext context) {
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text(title, style: Theme.of(context).textTheme.titleMedium),
            const SizedBox(height: 12),
            ...children.map(
              (w) =>
                  Padding(padding: const EdgeInsets.only(bottom: 8), child: w),
            ),
          ],
        ),
      ),
    );
  }
}
2
likes
0
points
484
downloads

Publisher

unverified uploader

Weekly Downloads

Type-safe Flutter localization generator from JSON/JSONC, with nested keys, placeholders, and plural/gender/context variants.

Repository (GitHub)
View/report issues

Documentation

Documentation

License

unknown (license)

Dependencies

args, path, watcher, yaml

More

Packages that depend on localization_gen