Localization in Flutter with ChatGPT

Odinachi DavidOdinachi David
5 min read

What is an App if everybody can’t get to use it or even more because of language barriers?

Here’s how you can bridge that gap in your Flutter app.

Before we start we need to ensure all our strings are in a single class and accessed using getters.

1. Install Packages
we need to first install flutter_translate and flutter_localization packages

flutter_translate: ^4.0.4 
flutter_localization: ^0.2.1

2. Initializing Localization
This is where we set the languages we want to support and we do this by initializing our delegate and providing LocalizedApp on the topmost widget.

Future<void> main() async {
  var delegate = await LocalizationDelegate.create(
      fallbackLocale: 'en', supportedLocales: ['en', 'es', 'fr', 'de']);

  runApp(LocalizedApp(delegate, const MyApp()));
}

What we did here was initialize our app with the delegate and the delegate supports Spanish, French and German, also note that the locale code has to be correct so you can check here and pick the first characters before the underscore(two or three).

3. Add Delegate to MaterialApp
We need to set the supported locale for the app.

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

  @override
  Widget build(BuildContext context) {
    var localizationDelegate = LocalizedApp.of(context).delegate;
    return MaterialApp(
      title: AppString.flutterDemo,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        localizationDelegate
      ],
      supportedLocales: localizationDelegate.supportedLocales,
      locale: localizationDelegate.currentLocale,
      home: const MyHomePage(),
    );
  }
}

4. Set up iOS
We need to provide iOS with our supported locale.

    <key>CFBundleLocalizations</key>
        <array>
            <string>en</string>
            <string>es</string>
            <string>fr</string>
            <string>de</string>
        </array>

5. Setup Assets

Firstly we need to create an i18n folder in the assets folder, so this folder will contain all our json translations that were set in our supported locale and add it to our pubspec.

assets:
  - assets/i18n/

Then we need to ask chatGPT to generate the json translations for each of the words in our AppString class, here’s a sample prompt

generate the translation for this class using this example

class AppString { static String get keyName => translate(key) }

and the json should be

{ key: translated_text }

generate for english, spanish, french and german

this is the class

class AppString { static String get selectLanguage => 'Select Language';

static String get flutterDemo => 'Flutter Demo';

static String get interestingStories => 'Interesting Stories';

static String get story1 => "Once upon a time, in a faraway land, a young prince was cursed to live as a beast until he learned to love.";

static String get story2 => "A group of explorers discovered an ancient city hidden beneath the ice of Antarctica.";

static String get story3 => "A boy found a mysterious key that opened a door to another dimension.";

static String get story4 => "A scientist accidentally created a potion that made him invisible, but the effects were irreversible.";

static String get story5 => "During a space mission, an astronaut encountered a strange, glowing object that gave him superpowers.";

static String get story6 => "A small village in Japan has a forest where it is said people can communicate with spirits.";

static String get story7 => "In a world where time stops for everyone except for one person, that person becomes the guardian of time.";

static String get story8 => "A magical library exists where the books write themselves, containing stories of people’s dreams.";

static String get story9 => "A pirate ship sailing through the Caribbean found a map leading to the legendary lost city of gold.";

static String get story10 => "A woman wakes up every day with no memory of her past, but she leaves herself clues hidden around the house.";
}

now copy and past the respective json in into the file on asset

  1. Change your locale
    Changing your locale will automatically change the language automatically
  Widget _languageOption(String language) {
    return RadioListTile<String>(
      title: Text(language),
      value: language,
      groupValue: langNotifier.value,
      onChanged: (String? value) {
        langNotifier.value = value!;
        changeLocale(context, getLangString(value)); // Chnage the locale
        Navigator.of(context).pop(); // Close the modal after selection
      },
    );
  }

here’s the complete code

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:flutter_translate/flutter_translate.dart';
import 'package:language_app/app/app_string.dart';

Future<void> main() async {
  var delegate = await LocalizationDelegate.create(
      fallbackLocale: 'en', supportedLocales: ['en', 'es', 'fr', 'de']);

  runApp(LocalizedApp(delegate, const MyApp()));
}

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

  @override
  Widget build(BuildContext context) {
    var localizationDelegate = LocalizedApp.of(context).delegate;
    return MaterialApp(
      title: AppString.flutterDemo,
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
        useMaterial3: true,
      ),
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        GlobalCupertinoLocalizations.delegate,
        localizationDelegate
      ],
      supportedLocales: localizationDelegate.supportedLocales,
      locale: localizationDelegate.currentLocale,
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  ValueNotifier<String> langNotifier = ValueNotifier('en');

  @override
  void initState() {
    super.initState();
  }

  void _showLanguageModal() {
    showDialog(
      context: context,
      builder: (BuildContext context) {
        return AlertDialog(
          title: Text(AppString.selectLanguage),
          content: Column(
            mainAxisSize: MainAxisSize.min,
            children: <Widget>[
              _languageOption('English'),
              _languageOption('Español'),
              _languageOption('Français'),
              _languageOption('Deutsch'),
            ],
          ),
        );
      },
    );
  }

  Widget _languageOption(String language) {
    return RadioListTile<String>(
      title: Text(language),
      value: language,
      groupValue: langNotifier.value,
      onChanged: (String? value) {
        langNotifier.value = value!;
        changeLocale(context, getLangString(value));
        Navigator.of(context).pop(); // Close the modal after selection
      },
    );
  }

  String getLangString(String value) {
    switch (value) {
      case "English":
        return 'en';
      case 'Español':
        return 'es';

      case 'Français':
        return 'fr';

      case 'Deutsch':
        return 'de';
      default:
        return 'en';
    }
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder(
      valueListenable: langNotifier,
      builder: (_, value, child) {
        List<String> allStories = [
          AppString.story1,
          AppString.story2,
          AppString.story3,
          AppString.story4,
          AppString.story5,
          AppString.story6,
          AppString.story7,
          AppString.story8,
          AppString.story9,
          AppString.story10,
        ];
        return Scaffold(
          appBar: AppBar(
            backgroundColor: Theme.of(context).colorScheme.inversePrimary,
            title: Text(AppString.interestingStories),
            actions: [
              IconButton(
                icon: const Icon(Icons.language),
                onPressed: _showLanguageModal,
              ),
            ],
          ),
          body: Column(
            children: [
              Padding(
                padding: const EdgeInsets.all(8.0),
                child: Text(
                  '${AppString.selectLanguage}: ${langNotifier.value}',
                  style: Theme.of(context).textTheme.headlineSmall,
                ),
              ),
              Expanded(
                child: ListView.builder(
                  itemCount: allStories.length,
                  itemBuilder: (context, index) {
                    String story = allStories[index];
                    return ListTile(
                      title: Text(story),
                    );
                  },
                ),
              ),
            ],
          ),
          floatingActionButton: FloatingActionButton(
            onPressed: _showLanguageModal,
            tooltip: AppString.selectLanguage,
            child: const Icon(Icons.language),
          ),
        );
      },
    );
  }
}

Here’s the repo: https://github.com/Odinachi/flutter-localization

Here’s the video explaining it better: https://www.youtube.com/watch?v=xerUWn_s-xs

Happy coding!!

0
Subscribe to my newsletter

Read articles from Odinachi David directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Odinachi David
Odinachi David

I am vastly knowledgeable in designing mobile applications and testing and maintenance with proficiency in Flutter, Dart and every relevant technology with years of professional experience.