Zubora Code

Develop and release a simple app using Flutter that plays a sound when an icon is tapped. 2/n Internationalization

This is the second article in a series summarizing the process of developing and releasing a simple app using Flutter that plays a sound when an icon is tapped.

Published: 2 August, 2023
Revised: 2 August, 2023

Summary

I am creating a simple app for my 1-year and 1-month-old son, where he can tap on animal and vehicle icons to hear sounds. My goal is to release this app on both iOS and Android platforms.

Progress so far

I have linked the previous articles to this tag:

https://zubora-code.net/ja/tags/first_flutter_tutorial

Goal for this article

In the previous step, I completed the implementation of the core functionality. In this article, I will briefly explain how to support both Japanese and English languages. The completed version can be found here.


Implementation

Library Installation

There are several libraries available for multi-language support, but I decided to go with the official one, flutter_localizations.

https://docs.flutter.dev/accessibility-and-localization/internationalization

$ flutter pub add flutter_localizations --sdk=flutter
$ flutter pub add intl:any

Setting up the MaterialApp delegate and supported locales

 import 'package:flutter/material.dart';
+import 'package:flutter_localizations/flutter_localizations.dart';
 import 'Sound.dart';
 
 void main() {
@@ -12,6 +13,15 @@ class MyApp extends StatelessWidget {
   Widget build(BuildContext context) {
     return MaterialApp(
       title: 'ぴよぴよサウンドパーク',
+      localizationsDelegates: const [
+        GlobalMaterialLocalizations.delegate,
+        GlobalWidgetsLocalizations.delegate,
+        GlobalCupertinoLocalizations.delegate,
+      ],
+      supportedLocales: const [
+        Locale('en'),
+        Locale('ja'),
+      ],
       theme: ThemeData(
         colorScheme: ColorScheme.fromSeed(seedColor: Colors.orange),
         useMaterial3: true,

Adding generate flag: true in pubspec.yaml

We will add a setting to automatically generate language support files when installing the library.

 flutter:
-
+  generate: true

Adding l10n.yaml

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

Adding lib/l10n/app_en.arb and lib/l10n/app_ja.arb

{
  "appTitle": "PiyoPiyo Sound Park",
  "@appTitle": {
    "description": "The app title"
  },
  "animal": "Animal",
  "@animal": {
    "description": "Animal"
  },
  "vehicle": "Vehicle",
  "@vehicle": {
    "description": "Vehicle"
  }
}

{
    "appTitle": "ぴよぴよサウンドパーク",
    "animal": "どうぶつ",
    "vehicle": "のりもの"
}


app_en.arb is specified as the template file, and app_ja.arb is the translation file.

Run flutter run command to automatically generate .dart_tool/gen_l10n

$ flutter run

Extracting values based on the context in main.dart

 git diff lib/main.dart 
diff --git a/lib/main.dart b/lib/main.dart
index 3b9397a..f3414a3 100644
--- a/lib/main.dart
+++ b/lib/main.dart
@@ -1,5 +1,6 @@
 import 'package:flutter/material.dart';
 import 'package:flutter_localizations/flutter_localizations.dart';
+import 'package:flutter_gen/gen_l10n/app_localizations.dart';
 import 'Sound.dart';
 
 void main() {
@@ -12,29 +13,25 @@ class MyApp extends StatelessWidget {
   @override
   Widget build(BuildContext context) {
     return MaterialApp(
       title: "ぴよぴよサウンドパーク",
       localizationsDelegates: const [
+        AppLocalizations.delegate,
         GlobalMaterialLocalizations.delegate,
         GlobalWidgetsLocalizations.delegate,
         GlobalCupertinoLocalizations.delegate,
       ],
-      supportedLocales: const [
-        Locale('en'),
-        Locale('ja'),
-      ],
+      supportedLocales: AppLocalizations.supportedLocales,
       theme: ThemeData(
         colorScheme: ColorScheme.fromSeed(seedColor: Colors.orange),
         useMaterial3: true,
       ),
-      home: const MyHomePage(title: 'ぴよぴよサウンドパーク'),
+      home: MyHomePage(),
     );
   }
 }
 
 class MyHomePage extends StatefulWidget {
-  const MyHomePage({super.key, required this.title});
-
-  final String title;
+  const MyHomePage({super.key});
 
   @override
   State<MyHomePage> createState() => _MyHomePageState();
@@ -141,23 +138,24 @@ class _MyHomePageState extends State<MyHomePage> {
 
   @override
   Widget build(BuildContext context) {
+    final l10n = AppLocalizations.of(context)!;
     return Scaffold(
       appBar: AppBar(
         backgroundColor: Theme.of(context).colorScheme.inversePrimary,
-        title: Text(widget.title),
+        title: Text(l10n.appTitle),
       ),
       body: Center(
         child: _widgetOptions.elementAt(_selectedIndex),
       ),
       bottomNavigationBar: BottomNavigationBar(
-        items: const <BottomNavigationBarItem>[
+        items: <BottomNavigationBarItem>[
           BottomNavigationBarItem(
-            icon: Icon(Icons.pets),
-            label: 'どうぶつ',
+            icon: const Icon(Icons.pets),
+            label: l10n.animal,
           ),
           BottomNavigationBarItem(
-            icon: Icon(Icons.directions_car),
-            label: 'のりもの',
+            icon: const Icon(Icons.directions_car),
+            label: l10n.vehicle,
           ),
         ],
         currentIndex: _selectedIndex,

In conclusion

Though it felt a bit cumbersome, it was easier compared to Web FrontEnd since there are no routing issues. Since it's a shame to limit the app to only Japanese when we can reach the world, I will actively pursue multi-language support in future development.

The changes made in this article can be found in the following Pull Request: https://github.com/tkugimot/touch_and_hear/pull/2?w=1

Remaining tasks include:

  • Introducing Crashlytics for monitoring
  • Integrating AdMob for advertising
  • Creating and setting up icons/feature graphics
  • Creating a support site and privacy policy site
  • Adding a Drawer (for app usage, contact, privacy policy links)
  • Releasing the app on Android
  • Releasing the app on iOS

I will write about Crashlytics in the next article.

Toshimitsu Kugimoto

Software Engineer

Specializing in backend and web frontend development for payment and media at work, the go-to languages for these tasks include Java and TypeScript. Additionally, currently exploring Flutter app development as a side project.