← Back to list

Flutter Localization

How to create multiple language app with Flutter

Yudi Setiawan in Nusanet Developers · 2019-11-17 13:25 · 63 claps · 9.7 min read
#flutter #flutter-localization #flutter-language #multiple-language-app #dart
Open on Medium ↗
Wiki topics: 📱 · Mobile Development

Flutter Localization

How to create multiple language app with Flutter

Photo by Liam Desic on Unsplash

Photo by Liam Desic on Unsplash

Pengenalan

Fitur multiple language atau pengaturan bahasa pada aplikasi merupakan fitur yang sederhana. Di native sendiri seperti di Android (saya bahasnya Android karena saya basic di Android) untuk membuat fitur multiple language proses pembuatannya cukup gampang. Kita hanya perlu menyediakan aset dalam bentuk file strings.xml untuk semua bahasa yang ingin kita buat. Berikut contoh asetnya di projek native Android.

Aset bahasa English dan Indonesia

Aset bahasa English dan Indonesia

Lalu, kita cuma perlu tambahkan sedikit bumbu-bumbu magic coding logika untuk membuat app kita bisa berubah bahasanya sesuai dengan pengaturan bahasanya.

Bagaimana Dengan Flutter

Di Flutter, pada awal-awal peluncuran versi stabilnya saya coba cari-cari di internet ternyata pembuatan fitur bahasa ini ternyata cukup susah untuk menemukan tulisan tentang hal tersebut. Setelah saya berusaha mencari-cari caranya ternyata tidak ada hasilnya sama sekali. Dengan berberat hati akhirnya saya merelakan rasa keingintahuan saya waktu itu. Lalu, seiring berjalannya waktu dari akhir tahun 2018 dimana, itu waktu pertama kalinya saya mencoba Flutter lalu, sampai pada hari tulisan ini dipublikasikan dan rasa penasaran saya itu masih ada. Dan akhirnya saya berhasil juga menemukan caranya untuk mengubah bahasa pada app di Flutter. Berikut ialah contoh projek yang saya implementasikan pengaturan bahasa di Flutter.

[embed]Contoh projek yang saya implementasikan fitur multiple language

Mulai Pembuatan Contoh Projek

Contoh 1

Di Flutter untuk membuat fitur pengaturan bahasa kita bisa pakai plugin berikut.

[embed]intl_translation | Dart Package This package provides message extraction and code generation from translated messages for the Intl package. It's a…pub.dev

Silakan kita buat projek baru di Flutter. Untuk contoh nama projeknya bebas tapi kalau mau ikuti punya saya juga boleh. Berikut contoh nama projek punya saya.

Buat projek baru

Buat projek baru

Lalu, kita tambahkan plugin diatas tadi kedalam projek kita. Caranya, kita buka file pubspec.yaml. Lalu, buat flutter_localizations didalam dependencies dan tambahkan intl_translation: <latest_version> . Berikut kode lengkapnya.

dependencies:
  flutter:
    sdk: flutter
  flutter_localizations:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^0.1.2

  intl_translation: ^0.17.7

Lalu, kita unduh paketnya dengan perintah flutter packages get .

Buat Class MyLocalization

Class MyLocalization berfungsi sebagai tempat kita mendeklarasikan setiap kata-kata yang mau kita buat bahasanya. Silakan buat class tersebut didalam package lib/locale. Dan nama file-nya my_localization.dart.

import 'package:flutter/material.dart';
import 'package:intl/intl.dart';

class MyLocalization {
  static Future<MyLocalization> load(Locale locale) {
    final String name = locale.countryCode.isEmpty ? locale.languageCode : locale.toString();
    final String localeName = Intl.canonicalizedLocale(name);
    return initializeMessages(localeName).then((_) {
      Intl.defaultLocale = localeName;
      return MyLocalization();
    });
  }

  static MyLocalization of (BuildContext context) {
    return Localizations.of<MyLocalization>(context, MyLocalization);
  }

  String get helloWorld {
    return Intl.message(
      'Hello World',
      name: 'helloWorld',
      desc: 'Kata Hello World', /* Optional */
    );
  }
}

Pada kode diatas, seharusnya kita akan mendapatkan error pada baris kode berikut.

Error initializeMessages

Error initializeMessages

Error tersebut untuk saat ini kita abaikan saja karena nantinya error tersebut akan hilang setelah kita selesai melewati langkah-langkah selanjutnya.

Jadi, pada kode diatas bisa kita lihat bahwa di fungsi getter helloWorld merupakan salah satu contoh String yang akan kita coba buat dalam 2 bahasa yaitu bahasa Inggris dan Indonesia. Dan property desc itu sifatnya opsional jadi boleh kita isi dengan keterangan atau empty string.

Buat Class MyLocalizationDelegate

Class MyLocalizationDelegate merupakan class yang kita turunkan dari class LocalizationDelegate dimana, class ini berfungsi untuk menterjemahkan kumpulan list String yang sudah kita buat tadi di dalam class MyLocalization. Sekarang silakan kita buat class MyLocalizationDelegate didalam package yang sama dengan class MyLocalization. Dan beri nama file-nya my_localization_delegate.dart.

import 'package:flutter/material.dart';
import 'package:flutter_language/lib/locale/my_localization.dart';

class MyLocalizationDelegate extends LocalizationsDelegate<MyLocalization> {
  final Locale locale;

  const MyLocalizationDelegate(this.locale);

  @override
  bool isSupported(Locale locale) {
    return ['en', 'id'].contains(locale.languageCode);
  }

  @override
  Future<MyLocalization> load(Locale locale) {
    return MyLocalization.load(locale);
  }

  @override
  bool shouldReload(LocalizationsDelegate<MyLocalization> old) {
    return false;
  }
}

Pada kode diatas, kita ada mendeklarasikan bahasa apa saja yang akan didukung oleh app kita. Contoh diatas kita buat app kita akan mendukung dalam 2 bahasa yaitu bahasa Inggris dan Indonesia.

Buat File .arb

Sebelum kita membuat file .arb-nya kita perlu membuat satu package baru dengan nama lib/l10n dimana nantinya semua kumpulan String yang sudah diterjemahkan akan diletakkan didalam package tersebut. Untuk membuat file .arb silakan jalankan perintah berikut.

flutter pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/locale/my_localization.dart

Jalankan perintah diatas dengan kondisi kita sudah berada didalam direktori root projek kita.

Perintah untuk membuat file .arb

Perintah untuk membuat file .arb

Adapun format dari perintah diatas adalah seperti berikut.

flutter pub run intl_translation:extract_to_arb --output-dir=<direktori_file_arb_nya> <file_localization_yang_sudah_kita_buat>

Jika berhasil seharusnya di dalam package lib/l10n tadi akan terbentuk sebuah file dengan nama intl_messages.arb.

File intl_messages.arb

File intl_messages.arb

Pada gambar diatas kita lihat file intl_messages.arb sudah terbentuk dan file my_localization.dart masih ada error. Untuk error tersebut kita abaikan saja dulu ya karena nantinya error tersebut akan hilang setelah kita melewati beberapa langkah lagi.

Buat Aset Bahasa Inggris dan Indonesia

Untuk membuat aset bahasa Inggris dan Indonesia kita perlu membuka file intl_messages.arb dan didalamnya bisa kita lihat kira-kira isinya seperti berikut.

{
  "@@last_modified": "2019-11-17T16:07:23.398925",
  "helloWorld": "Hello World",
  "@helloWorld": {
    "description": Word Hello World",
    "type": "text",
    "placeholders": {}
  }
}

Untuk membuat aset bahasa Inggris dan Indonesianya kita cuma perlu menyalin isi dari file intl_messages.arb dan masukkan kedalam file baru dengan nama intl_en.arb (untuk bahasa Inggris) dan intl_id.arb (untuk bahasa Indonesia).

Catatan: File intl_en.arb dan intl_id.arb kita buat sendiri ya.

Jika sudah kita salin isi dari file intl_messages.arb kedalam file intl_en.arb dan intl_id.arb maka, hasilnya akan menjadi seperti berikut.

Salin isi file intl_messages.arb

Salin isi file intl_messages.arb

Langkah selanjutnya adalah kita perlu menterjemahkan String yang berada di dalam file intl_en.arb kedalam bahasa Inggris dan intl_id.arb kedalam bahasa Indonesia. Dikarenakan bahasa default pada app kita sudah kita buat dalam bahasa Inggris jadi yang perlu kita terjemahkan String -nya hanyalah file intl_id.arb saja. Berikut ialah hasilnya.

Hasil terjemahan yang kita buat

Hasil terjemahan yang kita buat

Ubah File arb Menjadi File dart

Jadi, untuk meng-konversi file intl_messages.arb, intl_en.arb, dan intl_id.arb kedalam file dart kita perlu menjalankan perintah berikut.

flutter pub run intl_translation:generate_from_arb \--output-dir=lib/l10n --no-use-deferred-loading \lib/l10n/intl_messages.arb lib/l10n/intl_en.arb lib/l10n/intl_id.arb lib/locale/my_localization.dart

Perintah generator untuk konversi file arb ke file dart

Perintah generator untuk konversi file arb ke file dart

Adapun format dari perintah diatas adalah sebagai berikut.

flutter pub run intl_translation:generate_from_arb \--output-dir=<lokasi_direktori_file_arb> --no-use-deferred-loading <semua_file_arb_yang_kita_buat> <file_localization_yang_sudah_kita_buat>

Jika berhasil seharusnya didalam package lib/l10n akan terbentuk file messages_all.dart, messages_en.dart, messages_id.dart, dan messages_messages.dart.

Hasil konversi file arb ke file dart

Hasil konversi file arb ke file dart

Perbaikan Error Di File my_localization.dart

Selanjutnya kita buka lagi file my_localization.dart dan perbaiki dengan cara melakukan import.

Perbaiki error di file my_localization.dart

Perbaiki error di file my_localization.dart

Hello World App

Sekarang kita perlu meng-implementasikan fungsi localization yang sudah kita buat tadi kedalam app kita. Caranya silakan kita buka file main.dart dan ubah isinya menjadi seperti berikut.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization.dart';
import 'package:flutter_language/locale/my_localization_delegate.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  MyLocalizationDelegate _myLocalizationDelegate = MyLocalizationDelegate(Locale('en', 'US'));

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        _myLocalizationDelegate,
      ],
      supportedLocales: [
        Locale('en', 'US'),
        Locale('id', 'ID'),
      ],
      home: MyApp(),
    );
  }
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Localization'),
      ),
      body: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 16.0),
        child: Center(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: <Widget>[
              RaisedButton(
                child: Text('English'),
                onPressed: () {
                  setState(() {
                    MyLocalization.load(Locale('en', 'US'));
                  });
                },
              ),
              Text(MyLocalization.of(context).helloWorld),
              RaisedButton(
                child: Text('Indonesia'),
                onPressed: () {
                  setState(() {
                    MyLocalization.load(Locale('id', 'ID'));
                  });
                },
              ),
            ],
          ),
        ),
      ),
    );
  }
}

Dan berikut ialah output-nya.

[embed]Output contoh 1

Contoh 2

Pada contoh 1 kita sudah berhasil membuat fitur multiple language yang sederhana. Sekarang kita buat lagi untuk contoh 2 dimana, pada contoh 2-nya kita akan buat 3 screen dalam bentuk Bottom Navigation Bar. Untuk aset bahasanya kita update ya. Jadi, kita perlu tambahkan aset list String nya didalam file my_localization.dart seperti berikut.

String get helloWorld {
  return Intl.message(
    'Hello World',
    name: 'helloWorld',
    desc: 'Word Hello World', /* Optional */
  );
}

String get homeScreen {
  return Intl.message(
    'Home Screen',
    name: 'homeScreen',
    desc: '',
  );
}

String get accountScreen {
  return Intl.message(
    'Account Screen',
    name: 'accountScreen',
    desc: '',
  );
}

String get settingScreen {
  return Intl.message(
    'Setting Screen',
    name: 'settingScreen',
    desc: '',
  );
}

String get home {
  return Intl.message(
    'Home',
    name: 'home',
    desc: '',
  );
}

String get account {
  return Intl.message(
    'Account',
    name: 'account',
    desc: '',
  );
}

String get setting {
  return Intl.message(
    'Setting',
      name: 'setting',
    desc: '',
  );
}

Selanjutnya kita jalankan perintah

flutter pub run intl_translation:extract_to_arb --output-dir=lib/l10n lib/locale/my_localization.dart

Lalu, buka file intl_messages.arb dan salin isinya kedalam file intl_en.arb dan intl_id.arb. Lalu, kita buka file intl_id.arb dan kita terjemahkan secara manual list String -nya kedalam bahasa Indonesia. Sehingga hasilnya seperti berikut.

Update list String

Update list String

Lalu, jalankan perintah berikut untuk mengubah file arb menjadi dart.

flutter pub run intl_translation:generate_from_arb \--output-dir=lib/l10n --no-use-deferred-loading \lib/l10n/intl_messages.arb lib/l10n/intl_en.arb lib/l10n/intl_id.arb lib/locale/my_localization.dart

Buat Home Screen

Sekarang kita buat file home_screen.dart dan isikan dengan kode berikut.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization.dart';

class HomeScreen extends StatefulWidget {
  @override
  _HomeScreenState createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text(MyLocalization.of(context).homeScreen),
      ),
    );
  }
}

Buat Account Screen

Buat file account_screen.dart dan isikan dengan kode berikut.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization.dart';

class AccountScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Text(MyLocalization.of(context).accountScreen),
      ),
    );
  }
}

Buat Setting Screen

Selanjutnya kita juga perlu membuat file setting_screen.dart dan isi dengan kode berikut.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization.dart';

class SettingScreen extends StatefulWidget {
  @override
  _SettingScreenState createState() => _SettingScreenState();
}

class _SettingScreenState extends State<SettingScreen> {
  @override
  Widget build(BuildContext context) {
    return Container(
      child: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            RaisedButton(
              child: Text('English'),
              onPressed: () {
                setState(() {
                  MyLocalization.load(Locale('en', 'US'));
                });
              },
            ),
            Text(MyLocalization.of(context).settingScreen),
            RaisedButton(
              child: Text('Indonesia'),
              onPressed: () {
                setState(() {
                  MyLocalization.load(Locale('id', 'ID'));
                });
              },
            ),
          ],
        ),
      ),
    );
  }
}

Ubah File main.dart

Selanjutya, kita buka file main.dart dan ubah kodenya menjadi seperti berikut.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization_delegate.dart';
import 'package:flutter_language/ui/account/account_screen.dart';
import 'package:flutter_language/ui/home/home_screen.dart';
import 'package:flutter_language/ui/setting/setting_screen.dart';
import 'package:flutter_localizations/flutter_localizations.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  Widget build(BuildContext context) {
    return MaterialApp(
      localizationsDelegates: [
        GlobalMaterialLocalizations.delegate,
        GlobalWidgetsLocalizations.delegate,
        MyLocalizationDelegate(Locale('en', 'US')),
      ],
      supportedLocales: [
        Locale('en', 'US'),
        Locale('id', 'ID'),
      ],
      home: MyApp(),
    );
  }
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int indexSelected = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Localization'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        onTap: (indexSelected) {
          setState(() {
            this.indexSelected = indexSelected;
          });
        },
        items: [
          BottomNavigationBarItem(
            title: Text('Home'),
            icon: Icon(Icons.home),
          ),
          BottomNavigationBarItem(
            title: Text('Account'),
            icon: Icon(Icons.account_balance),
          ),
          BottomNavigationBarItem(
            title: Text('Setting'),
            icon: Icon(Icons.settings),
          ),
        ],
      ),
      body: _buildWidgetBody(),
    );
  }

  Widget _buildWidgetBody() {
    switch (indexSelected) {
      case 0:
        return HomeScreen();
      case 1:
        return AccountScreen();
      case 2:
        return SettingScreen();
      default:
        return Container();
    }
  }
}

Dan sekarang coba kita test apakah fitur multiple language-nya berhasil.

[embed]Output contoh 2 tidak berhasil

Ada yang aneh ya 🤔 . Mengapa label pada Bottom Navigation Bar-nya berubah ketika kita berpindah menu. Seharusnya label di Bottom Navigation Bar-nya akan ikut berubah ketika kita ubah bahasanya. Untuk kasus seperti ini kita punya 2 solusinya yaitu sebagai berikut.

  1. Kita bisa melakukan restart app-nya dengan cara memanggil ulang atau navigator ke file main.dart ketika perubahan bahasa dilakukan. Untuk beberapa sebagian app dipasaran saya lihat masih ada yang menggunakan teknik seperti ini.
  2. Kita bisa melakukan perubahan bahasanya tanpa perlu melakukan restart app. Tekniknya kita bisa pakai Provider atau BLoC.

Solusi

Untuk solusinya kita pakai Provider saja ya. Silakan buat file baru dengan nama provider_localization.dart dan isikan dengan kode berikut.

import 'package:flutter/material.dart';

class ProviderLocalization extends ChangeNotifier {
  Locale _locale = Locale('en', 'US');
  Locale get language => _locale;

  void setLanguage(Locale locale) {
    _locale = locale;
    notifyListeners();
  }
}

Selanjutnya, kita buka file main.dart dan kita cuma perlu membungkus widget MaterialApp dengan ChangeNotifierProvider dan Consumer . Berikut ialah perubahannya pada file main.dart.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization.dart';
import 'package:flutter_language/locale/my_localization_delegate.dart';
import 'package:flutter_language/provider_localization.dart';
import 'package:flutter_language/ui/account/account_screen.dart';
import 'package:flutter_language/ui/home/home_screen.dart';
import 'package:flutter_language/ui/setting/setting_screen.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'package:provider/provider.dart';

void main() => runApp(App());

class App extends StatelessWidget {
  Widget build(BuildContext context) {
    return ChangeNotifierProvider(
      builder: (context) => ProviderLocalization(),
      child: Consumer<ProviderLocalization>(
        builder: (context, localization, child) {
          return MaterialApp(
            localizationsDelegates: [
              GlobalMaterialLocalizations.delegate,
              GlobalWidgetsLocalizations.delegate,
              MyLocalizationDelegate(localization.language),
            ],
            supportedLocales: [
              Locale('en', 'US'),
              Locale('id', 'ID'),
            ],
            home: MyApp(),
          );
        },
      ),
    );
  }
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  int indexSelected = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Flutter Localization'),
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: indexSelected,
        onTap: (indexSelected) {
          setState(() {
            this.indexSelected = indexSelected;
          });
        },
        items: [
          BottomNavigationBarItem(
            title: Text(MyLocalization.of(context).home),
            icon: Icon(Icons.home),
          ),
          BottomNavigationBarItem(
            title: Text(MyLocalization.of(context).account),
            icon: Icon(Icons.account_circle),
          ),
          BottomNavigationBarItem(
            title: Text(MyLocalization.of(context).setting),
            icon: Icon(Icons.settings),
          ),
        ],
      ),
      body: _buildWidgetBody(),
    );
  }

  Widget _buildWidgetBody() {
    switch (indexSelected) {
      case 0:
        return HomeScreen();
      case 1:
        return AccountScreen();
      case 2:
        return SettingScreen();
      default:
        return Container();
    }
  }
}

Lalu, kita juga perlu mengubah file setting_screen.dart menjadi seperti berikut.

import 'package:flutter/material.dart';
import 'package:flutter_language/locale/my_localization.dart';
import 'package:flutter_language/provider_localization.dart';
import 'package:provider/provider.dart';

class SettingScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final providerLocalization = Provider.of<ProviderLocalization>(context);
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 16.0),
      child: Center(
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: <Widget>[
            RaisedButton(
              child: Text('English'),
              onPressed: () {
                MyLocalization.load(Locale('en', 'US'));
                providerLocalization.setLanguage(Locale('en', 'US'));
              },
            ),
            Text(MyLocalization.of(context).settingScreen),
            RaisedButton(
              child: Text('Indonesia'),
              onPressed: () {
                MyLocalization.load(Locale('id', 'ID'));
                providerLocalization.setLanguage(Locale('id', 'ID'));
              },
            ),
          ],
        ),
      ),
    );
  }
}

Sekarang coba kita test lagi.

[embed]Output contoh 2 berhasil

Dan solusinya berhasil. Sebenarnya solusi yang kita lakukan pada contoh kedua tadi adalah kita cuma me-listen perubahan bahasa yang dilakukan oleh widget SettingScreen dan si consumer-nya itu kita letakkan didalam widget MaterialApp sehingga ketika ada perubahan data bahasa maka, MaterialApp akan langsung mendeteksi perubahan bahasa tersebut.

Kesimpulan

Jadi, dari tulisan ini saya ambil kesimpulan bahwa Flutter sudah memiliki plugin localization yang bisa kita pakai untuk mengubah bahasa sesuai dengan localization yang kita inginkan. Untuk projeknya bisa dilihat di Github ya.

[embed]CoderJava/Flutter-Localization Flutter app with multiple language This project is a starting point for a Flutter application. A few resources to get…github.com


메타데이터
post_id
bb22547ca653
slug
flutter-localization-bb22547ca653
url
https://medium.com/nusanet/flutter-localization-bb22547ca653
canonical_url
https://medium.com/nusanet/flutter-localization-bb22547ca653
author_url
https://medium.com/@coderjava
status
ok
fetched_at
2026-08-06 09:14:48