← Back to Blog

Flutter Pluralization: A Complete Guide for Developers

flutterlocalizationpluralizationicui18n

Flutter Pluralization: A Complete Guide for Developers

Handling plurals correctly is one of the most overlooked aspects of Flutter localization. Different languages have wildly different pluralization rules—English has two forms (one/other), but Arabic has six, and Polish has complex rules based on the last digit.

Why Pluralization Matters

Consider this simple English string: "You have 1 item" vs "You have 5 items". Now multiply that complexity across 20+ languages, each with their own rules. Getting it wrong makes your app feel unprofessional and can even change the meaning of sentences.

Flutter's ICU Message Format

Flutter uses the ICU (International Components for Unicode) message format for plurals. Here's the basic syntax:

{
  "itemCount": "{count, plural, =0{No items} =1{One item} other{{count} items}}",
  "@itemCount": {
    "description": "Number of items",
    "placeholders": {
      "count": {
        "type": "int"
      }
    }
  }
}

Plural Categories

Different languages support different plural categories:

  • zero: Used in Arabic for zero items
  • one: Singular form
  • two: Used in Arabic for exactly two items
  • few: Used in languages like Polish, Russian for numbers ending in 2-4
  • many: Used in Arabic for numbers 11-99
  • other: Default fallback for all other cases

Real-World Example: Shopping Cart

Here's how to handle a shopping cart message across multiple languages:

English (app_en.arb)

{
  "cartItems": "{count, plural, =0{Your cart is empty} =1{You have one item} other{You have {count} items}}",
  "@cartItems": {
    "description": "Shopping cart item count",
    "placeholders": {
      "count": {"type": "int"}
    }
  }
}

Arabic (app_ar.arb)

{
  "cartItems": "{count, plural, =0{سلتك فارغة} =1{لديك منتج واحد} =2{لديك منتجان} few{لديك {count} منتجات} many{لديك {count} منتجاً} other{لديك {count} منتج}}",
  "@cartItems": {
    "description": "Shopping cart item count",
    "placeholders": {
      "count": {"type": "int"}
    }
  }
}

Polish (app_pl.arb)

{
  "cartItems": "{count, plural, =0{Twój koszyk jest pusty} =1{Masz jeden przedmiot} few{Masz {count} przedmioty} many{Masz {count} przedmiotów} other{Masz {count} przedmiotu}}",
  "@cartItems": {
    "description": "Shopping cart item count",
    "placeholders": {
      "count": {"type": "int"}
    }
  }
}

Using Plurals in Your Code

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

class CartPage extends StatelessWidget {
  final int itemCount;

  const CartPage({required this.itemCount});

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context)!;

    return Scaffold(
      appBar: AppBar(
        title: Text(l10n.cartItems(itemCount)),
      ),
      body: // ... your cart content
    );
  }
}

Common Mistakes to Avoid

❌ Don't concatenate strings

// Wrong!
String message = '$count ' + (count == 1 ? 'item' : 'items');

✅ Use proper pluralization

// Correct!
String message = AppLocalizations.of(context)!.itemCount(count);

❌ Don't assume English plural rules

// Wrong! Doesn't work for Arabic, Polish, etc.
if (count == 1) {
  return 'item';
} else {
  return 'items';
}

Testing Plural Forms

Test your plurals with edge cases:

void main() {
  testWidgets('Plural forms test', (tester) async {
    await tester.pumpWidget(MyApp());

    // Test zero
    expect(find.text(l10n.cartItems(0)), findsOneWidget);

    // Test one
    expect(find.text(l10n.cartItems(1)), findsOneWidget);

    // Test few (for Polish)
    expect(find.text(l10n.cartItems(3)), findsOneWidget);

    // Test many (for Arabic)
    expect(find.text(l10n.cartItems(15)), findsOneWidget);

    // Test large numbers
    expect(find.text(l10n.cartItems(100)), findsOneWidget);
  });
}

Complex Plurals with Gender

Some languages combine plurals with gender. Here's a French example:

{
  "friendsCount": "{count, plural, =0{Aucun ami} =1{Un ami} other{{count} amis}}",
  "friendsCountFemale": "{count, plural, =0{Aucune amie} =1{Une amie} other{{count} amies}}"
}

FlutterLocalisation Makes This Easy

Managing plural forms across dozens of languages manually is error-prone. FlutterLocalisation provides:

  • ✅ Automatic plural form validation for each language
  • ✅ Visual editor showing all plural categories
  • ✅ AI translation that understands plural rules
  • ✅ Warning when plural forms are incomplete
  • ✅ Testing tools for all plural categories

Best Practices

  1. Always provide all necessary plural forms for each language
  2. Test with real data from native speakers
  3. Use descriptive placeholder names like {itemCount} not just {n}
  4. Document your plurals with clear @ metadata
  5. Use FlutterLocalisation to catch missing plural forms automatically

Conclusion

Pluralization is complex, but Flutter's ICU message format makes it manageable. The key is understanding that different languages have different rules, and planning for that from the start.

Don't let poor pluralization make your app feel unprofessional. With proper implementation and tools like FlutterLocalisation, you can handle even the most complex plural rules with confidence.


Ready to simplify your Flutter pluralization? Try FlutterLocalisation and get automatic plural validation, visual editing, and AI translation that understands language-specific plural rules.