Flutter Mobile Development · Pelajaran

Pluralisasi, Gender, dan Pemformatan Pesan ICU

Tangani bentuk jamak, kasus pilihan, dan string berparameter menggunakan sintaks pesan ICU.

Pelajaran 2 dari 413 langkah

Pluralisasi, Gender, dan Pemformatan Pesan ICU adalah pelajaran Flutter Mobile Development gratis di CoddyKit. Ini adalah pelajaran 2 dari 4. Kamu bisa membaca pelajaran lengkapnya di bawah secara gratis — lalu praktikkan langsung di browser dengan editor kode bawaan dan tutor AI 24/7. Ini adalah bagian dari jalur belajar Flutter Mobile Development, dan progresmu tersinkronisasi di web dan aplikasi CoddyKit. Kursus Flutter Mobile Development mencakup 4 pelajaran total.

Bagian dari pelajaran ini belum diterjemahkan dan ditampilkan dalam bahasa Inggris.

Why ICU Messages Matter

Translating an app is more than swapping words. Different languages pluralize, gender, and order words differently. A naive string like "$count items" reads wrong as "1 items", and many languages have several plural forms.

Flutter solves this with ICU message syntax (International Components for Unicode), the same standard used across the industry. You write one message with rules for plurals, select/gender, and placeholders, and the right form is chosen at runtime per locale.

  • plural — pick a form based on a number
  • select — pick a branch based on a string (e.g. gender)
  • placeholders — inject typed values like names, dates, numbers

The ARB File: Where Messages Live

Flutter's flutter_localizations + intl toolchain reads ARB files (Application Resource Bundle). Each locale has its own file: app_en.arb, app_tr.arb, etc.

An ARB entry has a key, a value (the ICU message), and an optional @key metadata object describing placeholders.

  • Keys become generated Dart getters/methods.
  • The @key block declares each placeholder's type and optional format.
{
  "appTitle": "My Shop",
  "@appTitle": {
    "description": "The title shown in the app bar"
  },
  "welcome": "Welcome, {name}!",
  "@welcome": {
    "placeholders": {
      "name": { "type": "String" }
    }
  }
}

Simple Placeholders

A placeholder is written in curly braces inside the message: {name}. The generated Dart code becomes a method whose parameter matches the placeholder name.

After enabling generate: true in pubspec.yaml and running flutter gen-l10n, you call it through AppLocalizations.

// app_en.arb
//   "welcome": "Welcome, {name}!"

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

Widget build(BuildContext context) {
  final l10n = AppLocalizations.of(context)!;
  return Text(l10n.welcome('Aylin')); // -> "Welcome, Aylin!"
}

Pluralization with ICU

The plural form picks a branch based on a number argument. Syntax: {count, plural, ...categories...}.

ICU plural categories are =0, =1, zero, one, two, few, many, other. The other branch is mandatory — it is the fallback when no other category matches. Use # to print the number itself.

  • =0, =1 match the exact value.
  • one, few, many are language-defined categories (English only uses one and other).
{
  "itemsInCart": "{count, plural, =0{Your cart is empty} =1{1 item in cart} other{# items in cart}}",
  "@itemsInCart": {
    "placeholders": {
      "count": { "type": "int" }
    }
  }
}

Calling a Plural Message

The generated method takes the count argument. The framework selects the correct branch for the active locale automatically.

Notice that English only ever needs one/other, but a locale like Polish or Arabic will use few/many in its own ARB file — your Dart call site does not change.

final l10n = AppLocalizations.of(context)!;

Text(l10n.itemsInCart(0));  // "Your cart is empty"
Text(l10n.itemsInCart(1));  // "1 item in cart"
Text(l10n.itemsInCart(7));  // "7 items in cart"

Why '=1' and 'one' Are Different

A common confusion: =1 is an exact value match, while one is a language plural category. They are not the same.

  • =1 matches only the literal number 1.
  • one matches whatever the locale's CLDR rules call the "one" category. In English that is just 1, but in some locales the one category also covers values like 21, 31, etc.

Best practice: provide other always; add one for natural singular/plural; use =0/=1 only when you need special wording ("empty", "no messages") that differs from the grammatical plural.

Gender and the 'select' Form

The select form branches on a string value rather than a number. The classic use is grammatical gender, which changes pronouns and verb agreement in many languages.

Syntax: {gender, select, male{...} female{...} other{...}}. Like plural, other is required as the fallback (and handles unknown/non-binary values gracefully).

{
  "sharedPhoto": "{gender, select, male{He shared a photo} female{She shared a photo} other{They shared a photo}}",
  "@sharedPhoto": {
    "placeholders": {
      "gender": { "type": "String" }
    }
  }
}

Demonstrating select() in Pure Dart

You don't need Flutter to understand the intl primitives. The Intl.select function mirrors what the generated code does: it maps a key to a branch with an other fallback.

This standalone program shows the selection logic, including the fallback when an unexpected value arrives.

import 'package:intl/intl.dart';

String sharedPhoto(String gender) {
  return Intl.select(gender, {
    'male': 'He shared a photo',
    'female': 'She shared a photo',
    'other': 'They shared a photo',
  }, name: 'sharedPhoto', args: [gender]);
}

void main() {
  print(sharedPhoto('male'));    // He shared a photo
  print(sharedPhoto('female'));  // She shared a photo
  print(sharedPhoto('unknown')); // They shared a photo (fallback)
}

Combining Gender and Plurals (Nesting)

ICU lets you nest a plural inside a select (or vice versa) to handle messages that vary by both gender and count. Place one block inside a branch of the other.

Keep nesting shallow — deeply nested messages are painful for translators. If it gets complex, consider splitting into separate keys.

{
  "likes": "{gender, select, female{She got {count, plural, =0{no likes} =1{1 like} other{# likes}}} male{He got {count, plural, =0{no likes} =1{1 like} other{# likes}}} other{They got {count, plural, =0{no likes} =1{1 like} other{# likes}}}}",
  "@likes": {
    "placeholders": {
      "gender": { "type": "String" },
      "count": { "type": "int" }
    }
  }
}

Formatted Placeholders: Numbers and Dates

Placeholders can be formatted per locale using the format field in metadata. Numbers use formats like decimalPattern or currency; dates use DateFormat skeletons such as yMMMd.

This means 1234.5 renders as 1,234.5 in en-US but 1.234,5 in many European locales — automatically.

{
  "price": "Total: {amount}",
  "@price": {
    "placeholders": {
      "amount": {
        "type": "double",
        "format": "currency",
        "optionalParameters": { "symbol": "\u20ac", "decimalDigits": 2 }
      }
    }
  },
  "lastSeen": "Last seen {when}",
  "@lastSeen": {
    "placeholders": {
      "when": { "type": "DateTime", "format": "yMMMd" }
    }
  }
}

Formatting Numbers and Dates in Plain Dart

The same intl formatters power those ARB format fields. Here is a runnable program using NumberFormat and DateFormat directly, the way the generated localization code does under the hood.

import 'package:intl/intl.dart';

void main() {
  final amount = 1234.5;
  final usd = NumberFormat.currency(locale: 'en_US', symbol: '\$');
  final eur = NumberFormat.currency(locale: 'de_DE', symbol: '\u20ac');

  print(usd.format(amount)); // \$1,234.50
  print(eur.format(amount)); // 1.234,50 \u20ac

  final date = DateTime(2026, 6, 10);
  print(DateFormat.yMMMd('en_US').format(date)); // Jun 10, 2026
  print(DateFormat.yMMMd('tr_TR').format(date)); // 10 Haz 2026
}

Quick Check: Choosing the Right Form

You need a message that says "no messages", "1 message", or "N messages" depending on a count, and you want it to also work correctly in locales with few/many categories. Which approach is correct?

Recap

You now know how to localize dynamic text in Flutter with ICU message syntax:

  • ARB files hold messages per locale; @key metadata declares placeholder types and formats.
  • Placeholders {name} inject typed values into messages.
  • plural {count, plural, =0{} =1{} other{}} picks a form by number; other is mandatory and # prints the value.
  • =1 vs one: exact-value match versus language plural category — use exact matches only for special wording.
  • select {gender, select, male{} female{} other{}} branches on a string; great for gender.
  • Nesting combines gender and count when needed.
  • format metadata + NumberFormat/DateFormat render numbers and dates per locale.

Write messages so translators control wording per language while your Dart call sites stay unchanged.

Gratis untuk memulai

Belajar Dart dengan tutor AI — gratis

Tulis dan jalankan kode asli di browser kamu, dapatkan bantuan instan dari tutor AI 24/7, dan lanjutkan di mana kamu tinggalkan di web atau aplikasi.

Kursus
22
Pelajaran
88

Pertanyaan yang Sering Diajukan

Apakah pelajaran “Pluralisasi, Gender, dan Pemformatan Pesan ICU” gratis?

Ya — teks lengkap “Pluralisasi, Gender, dan Pemformatan Pesan ICU” gratis dibaca di sini di web. Untuk praktiknya secara interaktif (editor kode bawaan dan tutor AI 24/7) dan buka sisa kursus Flutter Mobile Development, upgrade ke CoddyKit PRO. Kursus Flutter Mobile Development mencakup 4 pelajaran total.

Apa yang akan aku pelajari di “Pluralisasi, Gender, dan Pemformatan Pesan ICU”?

Tangani bentuk jamak, kasus pilihan, dan string berparameter menggunakan sintaks pesan ICU. Kamu berlatih Flutter Mobile Development dengan kode praktik yang langsung kamu jalankan di browser, dan tutor AI 24/7 menjawab pertanyaanmu saat kamu mengerjakan pelajaran ini.

Apakah aku perlu pengalaman untuk memulai Flutter Mobile Development?

Tidak diperlukan pengalaman sebelumnya. Flutter Mobile Development di CoddyKit dirancang untuk pemula hingga pelajar tingkat lanjut, jadi kamu bisa memulai di sini atau dari awal dan belajar sesuai kecepatan kamu sendiri. Ini adalah pelajaran 2 dari 4.

Berapa lama pelajaran “Pluralisasi, Gender, dan Pemformatan Pesan ICU” memakan waktu?

Sebagian besar pelajaran CoddyKit memakan waktu sekitar 5–10 menit. Setiap pelajaran ringkas dan interaktif, jadi kamu membuat kemajuan stabil dan melanjutkan dari tempat kamu tinggalkan di web dan aplikasi.

Bisakah aku menulis dan menjalankan kode dalam pelajaran Flutter Mobile Development ini?

Ya. Setiap pelajaran Flutter Mobile Development menyertakan editor kode bawaan, jadi kamu menulis dan menjalankan kode nyata langsung di browser dan mendapatkan umpan balik AI instan — tidak diperlukan penyiapan lokal.

Semua pelajaran dalam kursus ini

  1. File ARB dan Alur Kerja Lokalisasi gen_l10n
  2. Pluralisasi, Gender, dan Pemformatan Pesan ICU
  3. Layout RTL dan Penanganan Directionality
  4. Semantik, Pembaca Layar, dan Widget Aksesibel
← Kembali ke Flutter Mobile Development