Episode ini membuka aplikasi ke dunia yang lebih luas: internationalization dengan flutter_localizations, dukungan RTL dan locale-aware formatting, accessibility best practices lewat semantics dan focus order, serta inclusive UX dan accessibility testing.

Aplikasi yang hebat tidak membatasi penggunanya pada satu bahasa atau satu cara berinteraksi. Episode 17 membangun fondasi untuk pengguna global dan pengguna dengan kebutuhan berbeda: internationalization, dukungan teks kanan-ke-kiri, formatting yang sadar locale, dan accessibility untuk screen reader dan keyboard.
Tambahkan dukungan localization dari SDK:
dependencies:
flutter:
sdk: flutter
flutter_localizations:
sdk: flutter
intl: ^0.19.0Tambahkan flutter_localizations dan intl ke blok dependencies. Lalu daftarkan delegates dan locale di MaterialApp:
MaterialApp(
localizationsDelegates: GlobalMaterialLocalizations.delegates,
supportedLocales: const [
Locale('id'),
Locale('en'),
],
locale: const Locale('id'),
)supportedLocales mendeklarasikan bahasa yang didukung. GlobalMaterialLocalizations.delegates menyediakan terjemahan bawaan untuk widget Material — seperti label tanggal dan tombol default.
Pesan aplikasi dikelola di file .arb:
{
"@@locale": "id",
"appTitle": "Aplikasi Saya",
"greeting": "Selamat datang, {name}!"
}File .arb berformat {"@@locale": "id", ...} dan menyimpan semua string dalam satu kunci. Flutter tool kemudian membangkitkan class bertipe-safe dari file ini, sehingga kesalahan terjemahan terdeteksi saat compile, bukan runtime.
Flutter menangani layout kanan-ke-kiri secara otomatis untuk locale Arab, Ibrani, dan sejenisnya. Widget Row dan Column membalik arah sesuai Directionality yang disuntikkan oleh locale aktif. Untuk menguji, ubah locale ke bahasa RTL:
MaterialApp(
locale: const Locale('ar'),
supportedLocales: const [Locale('ar')],
)MaterialApp(locale: Locale('ar')) memaksa aplikasi memakai arah RTL. Uji setiap layar dengan locale RTL — margin, ikon panah, dan posisi elemen sering kali perlu penyesuaian manual meski layout inti sudah otomatis.
Angka, tanggal, dan mata uang tidak boleh di-format manual. Pakai intl:
import 'package:intl/intl.dart';
final formatter = DateFormat.yMMMMd(Localizations.localeOf(context).toString());
print(formatter.format(DateTime.now()));DateFormat.yMMMMd(locale) memformat tanggal sesuai bahasa dan kebiasaan lokal. Aturan: simpan data mentah (timestamp, angka) dan format di lapisan presentasi — jangan pernah menyimpan string hasil format ke storage.
Widget visual sering tidak terbaca oleh screen reader tanpa bantuan. Gunakan Semantics untuk memberi label:
Semantics(
label: 'Tombol untuk menambah jumlah',
button: true,
child: FloatingActionButton(
onPressed: _tambah,
child: const Icon(Icons.add),
),
)Semantics(label: '...') memberi teks yang dibacakan screen reader. Tombol ikon tanpa teks membutuhkan label — jika tidak, pengguna screen reader hanya mendengar "tombol" tanpa makna.
Untuk pengguna keyboard dan TV, urutan fokus penting:
FocusTraversalGroup(
policy: OrderedTraversalPolicy(),
child: Column(
children: [
TextField(decoration: const InputDecoration(labelText: 'Email')),
TextField(decoration: const InputDecoration(labelText: 'Password')),
ElevatedButton(onPressed: login, child: const Text('Masuk')),
],
),
)OrderedTraversalPolicy memaksa urutan fokus mengikuti urutan visual child. Pastikan semua elemen interaktif bisa dijangkau keyboard dan order-nya masuk akal — dari email, password, ke tombol masuk.
Kontras warna yang rendah menyulitkan pembacaan. Gunakan warna dari ColorScheme yang sudah dirancang kontrasnya, dan uji dengan MediaQuery.textScalerOf(context) untuk memastikan layout tidak pecah saat ukuran teks diperbesar.
Flutter menyediakan test untuk semantics:
testWidgets('label tombol tersedia untuk screen reader', (tester) async {
await tester.pumpWidget(const MaterialApp(home: MyButton()));
expect(
find.bySemanticsLabel('Tombol untuk menambah jumlah'),
findsOneWidget,
);
});find.bySemanticsLabel mencari widget berdasarkan label semantics. Test seperti ini memastikan aksesibilitas tidak rusak oleh perubahan tak sengaja.
Jadikan aksesibilitas bagian dari definisi selesai, bukan fitur tambahan di akhir.
Inti yang harus dibawa pulang:
flutter_localizations dan intl untuk dukungan bahasa..arb agar terjemahan bertipe-safe.intl, simpan data mentah.Semantics memberi label untuk screen reader; atur focus order untuk keyboard.find.bySemanticsLabel dan tools bawaan.Di episode 18 selanjutnya kita membahas advanced rendering dan architecture — custom render objects dan widgets, adaptasi spesifik platform dan aplikasi responsif, micro frontends dan plugin-driven architectures, serta hybrid app patterns dengan web dan desktop. Kalian masuk ke area lanjutan Flutter.