Found me on Upwork? If you found me through Upwork and want to work together, please contact me through Upwork. Messages from Upwork clients sent outside Upwork will not be answered.
Localization notes🌏 Localization

Localizing a Flutter App into Vietnamese: ARB, Plurals, and VND

Wire Flutter's gen-l10n pipeline for Vietnamese in two hours: ARB file setup, CLDR plural rules, VND formatting with no decimals, and dd/MM/yyyy dates.

Dao Huy (Lucas)7 min read8 sections
Localizing a Flutter App into Vietnamese: ARB, Plurals, and VND

💡 Flutter adds Vietnamese in under two hours: add flutter_localizations and intl: any, create lib/l10n/app_vi.arb, declare Locale('vi'), and run flutter gen-l10n. Vietnamese nouns never inflect for number, so a single other{...} category usually covers all counts. Format VND with decimalDigits: 0 and use dd/MM/yyyy for dates.

Key takeaways

  • Add flutter_localizations (Flutter SDK) and intl: any to pubspec.yaml; set generate: true and create l10n.yaml at project root.
  • Create lib/l10n/app_vi.arb with the same ICU message keys as your English template - only the string values change.
  • Vietnamese has two CLDR plural categories (one for n=0 or n=1, other for n≥2), but nouns never inflect: =0{...} plus other{...} is usually enough.
  • VND currency: use NumberFormat.currency(locale: 'vi_VN', symbol: '₫', decimalDigits: 0) - no decimal places, period as thousands separator.
  • Date format is day-first: DateFormat('dd/MM/yyyy', 'vi_VN'). Test on a device set to Vietnamese before submitting to the app stores.

How do you add Vietnamese to Flutter's gen-l10n pipeline?

Flutter's official i18n solution uses ARB (Application Resource Bundle) files processed by the gen-l10n tool. Setup involves three files: updated dependencies, a config file, and a locale declaration in MaterialApp.

In pubspec.yaml, add flutter_localizations from the Flutter SDK, intl: any, and set generate: true under the flutter: key. Then create l10n.yaml at the project root:

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

In your MaterialApp, pass AppLocalizations.delegate and ...GlobalMaterialLocalizations.delegates to localizationsDelegates. Add Locale('vi') to supportedLocales. Run flutter gen-l10n to produce the typed Dart class. The class is regenerated on every flutter pub get as long as generate: true is set.

What does app_vi.arb look like?

The ARB file is JSON where every key maps to an ICU message string. Vietnamese keys mirror the English template exactly - only the content changes. Here is a minimal example covering a plain string, a placeholder, and a plural:

{
  "appTitle": "Ứng dụng của tôi",
  "greeting": "Xin chào, {name}!",
  "@greeting": {
    "placeholders": {
      "name": { "type": "String" }
    }
  },
  "itemCount": "{count, plural, =0{Không có mục nào} other{{count} mục}}"
}

Descriptive @key metadata from the English template is optional in translation ARBs. Include @key objects only when you need to define new placeholders or add locale-specific notes.

Store ARB files in UTF-8 without BOM. Vietnamese diacritics must be real Unicode code points, not escape sequences. Most editors handle this automatically, but verify if your CI pipeline runs on Windows and touches these files.

How do plural rules work for Vietnamese?

The Unicode CLDR plural rules define two cardinal categories for Vietnamese: one (when n = 0 or n = 1) and other (n ≥ 2). Unlike English, Vietnamese nouns carry no singular or plural inflection. "1 cuốn sách" and "5 cuốn sách" use the same word "sách" (book). The noun form never changes based on count.

This simplifies ARB strings considerably. For most UI copy, a single other{...} branch suffices with an explicit =0{...} match for the empty state:

"cartItems": "{count, plural, =0{Giỏ hàng trống} other{{count} sản phẩm}}"

You do not need a one{...} branch to handle "1 item" vs "2 items" as in English. This reduces Vietnamese ARB maintenance by roughly one third compared to inflected languages like French or German.

Classifier words (cái, con, chiếc, cuốn, tờ) pair with specific noun categories in Vietnamese. A machine-translation tool will sometimes pick the wrong classifier - "con" is for animals, "cái" for objects. This is one place where automated checks miss errors that a native reviewer catches immediately.

Number, currency, and date formatting for Vietnamese

Vietnam's currency (₫, ISO code VND) has no sub-units. All prices are whole numbers. Showing "1.250.000,00 ₫" is incorrect and will confuse Vietnamese buyers at checkout.

Vietnamese number formatting follows the convention inherited from French: a period (.) groups thousands and a comma (,) marks the decimal point - the reverse of US English. Use Dart's intl package and pass decimalDigits: 0 explicitly:

import 'package:intl/intl.dart';

final vndFormat = NumberFormat.currency(
  locale: 'vi_VN',
  symbol: '₫',
  decimalDigits: 0,
);
print(vndFormat.format(1250000)); // "1.250.000 ₫"

Without decimalDigits: 0, the formatter defaults to two decimal places for currency types, producing the incorrect "1.250.000,00 ₫".

Vietnamese date order is little-endian: day, then month, then year. October 11, 2026 is "11/10/2026". A user who sees "10/11" reads November 10, not October 11. Use DateFormat('dd/MM/yyyy', 'vi_VN'). For full written dates, the CLDR pattern produces "Chủ Nhật, 11 tháng 10, 2026". Vietnamese business contexts use 24-hour time: use DateFormat('HH:mm', 'vi_VN') rather than jm to avoid 12-hour output on some devices.

Why do Vietnamese strings run longer than English on screen?

Vietnamese uses stacked diacritics. A single character like "ộ" (o + circumflex + dot below) renders visibly wider than a plain ASCII letter in most system fonts. Vietnamese strings typically need 20-30% more horizontal space than their English equivalents. "Add to cart" (11 characters) becomes "Thêm vào giỏ hàng" (18 characters with diacritics).

Build layouts with flexible constraints. Use Expanded, FittedBox, or percentage-based widths for buttons, chips, and tab labels rather than hard-coded pixel values. The flutter_localizations package provides Vietnamese translations for built-in Material widget strings such as "OK", "Hủy" (Cancel), and date picker headers.

Test your app with the device locale set to Vietnamese before submitting to Google Play or the App Store. DataReportal's 2025 Vietnam report counts 127 million mobile connections across 101 million people. Meeting users' expectations on first launch determines whether they stay or uninstall.

What you can do in-house vs when a native Vietnamese reviewer pays off

The technical pipeline - ARB files, gen-l10n, number and date formatting - is entirely within a developer's reach and takes a few hours to wire up. The resulting strings will be syntactically valid and structurally correct.

Where non-native Vietnamese translation typically falls short:

  • Register mismatch: B2B software uses Sino-Vietnamese (Hán Việt) vocabulary; consumer apps use everyday Vietnamese. A fintech dashboard that mixes the two feels inconsistent to native speakers.
  • Classifier errors: Vietnamese uses noun classifiers (cái, con, chiếc, cuốn) that vary by object category. Machine translation picks the wrong classifier often enough to be noticed immediately by Vietnamese users.
  • UI edge-case phrasing: Error messages, empty states, and confirmation dialogs need natural Vietnamese. Awkward phrasing damages user trust at the worst point in the flow.

A single review pass by a native Vietnamese localization specialist after a machine-translation first pass catches most of these issues at a fraction of full translation cost. For fintech, medical, or legal apps, build a terminology glossary before the first translation pass to keep register consistent across all screens.

FAQ

Does Flutter ship Vietnamese translations for Material widgets out of the box?

Yes. Adding GlobalMaterialLocalizations.delegate and GlobalCupertinoLocalizations.delegate to localizationsDelegates gives you Vietnamese strings for the date picker, back button, alert dialog buttons, and similar standard widgets. You still supply translations for your own app strings via ARB files.

Can I omit a key from app_vi.arb if the Vietnamese string is identical to English?

Yes. If a string such as a brand name or technical term is unchanged in Vietnamese, omit it from app_vi.arb and Flutter falls back to the template locale value. Add a note in the English @key description to flag intentional non-translations for future reviewers.

What font works best for Vietnamese diacritics in Flutter?

Noto Sans is the most reliable choice. Its Vietnamese coverage includes all 134 precomposed diacritic combinations. Add it via the google_fonts package and use GoogleFonts.notoSans(). If you bundle a custom font, test every tone-mark combination: ắ ặ ể ị ộ ụ ướ ự - these are most likely to render as boxes with incomplete font subsets.

How do I test Vietnamese locale in the simulator without changing system language?

Wrap MaterialApp in a Localizations.override during development: Localizations.override(context: context, locale: const Locale('vi'), child: MaterialApp(...)). This forces Vietnamese for the wrapped subtree without changing the device language. Remove the wrapper before releasing to production.

When should I use a human Vietnamese translator instead of machine translation for ARB files?

Use human translation when the app handles money, medical data, legal terms, or sensitive user data - incorrect phrasing in these areas carries trust and legal risk. For general consumer apps, a machine-translation first pass with a native Vietnamese review pass is cost-effective. Budget 15-20 minutes per screen of UI strings for a human reviewer.

Official Sources

Dao Huy (Lucas)
Dao Huy (Lucas)
Graduate, University of Foreign Language Studies, University of Da Nang. Signs a certificate of accuracy on every certified translation (USCIS, IRCC).

Written by Dao Huy (Lucas), Vietnamese translator and localization specialist (English, Chinese and French into Vietnamese). See translation services →

Get QuoteWhatsApp