Better I18NBetter I18N
Flutter

Setup

Install better_i18n and configure BetterI18nProvider in your Flutter app.

This guide walks you through installing better_i18n and setting up BetterI18nProvider in your Flutter app.

Prerequisite: Create a project at dash.better-i18n.com. Your project identifier will be in the format org/project (e.g., my-company/mobile-app).

Install

Add better_i18n to your pubspec.yaml:

pubspec.yaml
dependencies:
  better_i18n: ^0.1.0

Then run:

flutter pub get

For offline caching (recommended), also add shared_preferences:

pubspec.yaml
dependencies:
  better_i18n: ^0.1.0
  shared_preferences: ^2.3.0  # for SharedPrefsStorage

shared_preferences is optional. Without it, translations are cached in memory only — suitable for development. For production, pass a SharedPrefsStorage() to enable offline support.

Wrap with BetterI18nProvider

Wrap your root widget (typically MaterialApp or CupertinoApp) with BetterI18nProvider:

lib/main.dart
import 'package:better_i18n/better_i18n.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    BetterI18nProvider(
      project: 'your-org/your-project', 
      defaultLocale: 'en',
      child: const MyApp(),
    ),
  );
}

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

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomeScreen(),
    );
  }
}

BetterI18nProvider fetches translations from CDN when the app starts and rebuilds its subtree when the locale changes.

Translate

Use context.t('namespace.key') anywhere in the widget tree below BetterI18nProvider:

lib/home_screen.dart
import 'package:better_i18n/better_i18n.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(context.t('common.appTitle')), 
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(context.t('common.welcome')), 
            // With interpolation arguments
            Text(
              context.t('common.greeting', args: {'name': 'Osman'}), 
            ),
          ],
        ),
      ),
    );
  }
}

Key format is "namespace.key" — matching your CDN translation structure. If the key is not found, the key itself is returned as fallback.

Switch Locale

Use context.setI18nLocale(code) to switch the active language at runtime:

lib/settings_screen.dart
import 'package:better_i18n/better_i18n.dart';
import 'package:flutter/material.dart';

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

  @override
  Widget build(BuildContext context) {
    final languages = context.i18nLanguages; 
    final currentLocale = context.i18nLocale; 

    return ListView.builder(
      itemCount: languages.length,
      itemBuilder: (context, index) {
        final lang = languages[index];
        return ListTile(
          title: Text(lang.nativeName ?? lang.name ?? lang.code),
          trailing: lang.code == currentLocale
              ? const Icon(Icons.check)
              : null,
          onTap: () => context.setI18nLocale(lang.code), 
        );
      },
    );
  }
}

context.i18nLanguages returns the language list from the CDN manifest — same languages you configure in the dashboard. No hardcoded lists needed.

With Offline Support

For production apps, enable offline caching and locale persistence:

lib/main.dart
import 'package:better_i18n/better_i18n.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(
    BetterI18nProvider(
      project: 'your-org/your-project',
      defaultLocale: 'en',
      storage: SharedPrefsStorage(), 
      loadingBuilder: (_) => const MaterialApp( 
        home: Scaffold(body: Center(child: CircularProgressIndicator())),
      ),
      child: const MyApp(),
    ),
  );
}

See Offline & Caching for the full caching guide.

Next Steps

On this page