1. Localization (l10n) là gì?
Khi một ứng dụng được sử dụng ở nhiều quốc gia, sự khác biệt không chỉ nằm ở ngôn ngữ mà còn ở cách người dùng đọc ngày tháng, số, tiền tệ, đơn vị đo lường và các thông tin trên giao diện.
Ví dụ, một ứng dụng bán hàng tại Việt Nam thường hiển thị giá theo đồng Việt Nam, sử dụng tiếng Việt và trình bày ngày theo thứ tự ngày/tháng/năm.
Trong khi đó, người dùng tại Hoa Kỳ có thể quen với tiếng Anh, đồng đô la Mỹ và định dạng tháng/ngày/năm.
Nếu ứng dụng chỉ dịch nội dung từ tiếng Việt sang tiếng Anh nhưng vẫn giữ nguyên tất cả những quy ước hiển thị của Việt Nam, trải nghiệm có thể chưa thực sự phù hợp với người dùng ở khu vực khác.
Để giải quyết vấn đề này, lập trình viên cần thực hiện Localization.
Localization, viết tắt là l10n, là quá trình điều chỉnh nội dung, cách hiển thị và một số hành vi của ứng dụng để phù hợp với ngôn ngữ, khu vực và quy ước của nhóm người dùng mục tiêu.
Thuật ngữ l10n được viết tắt từ chữ “l” đầu tiên, chữ “n” cuối cùng và 10 ký tự ở giữa của từ Localization.
Localization thường được triển khai trên nền tảng Internationalization đã được chuẩn bị trước.
Ví dụ, một ứng dụng Flutter đã có hệ thống i18n. Khi bổ sung tiếng Việt, nhóm phát triển tạo bản dịch tiếng Việt, kiểm tra định dạng ngày tháng, tiền tệ và những nội dung phù hợp với người dùng Việt Nam.
Đó là một phần của quá trình Localization.
2. Phân biệt Internationalization và Localization
Internationalization và Localization có liên hệ chặt chẽ nhưng không giống nhau.
Internationalization là chuẩn bị khả năng hỗ trợ nhiều ngôn ngữ và khu vực.
Localization là triển khai những nội dung và quy ước cụ thể cho từng ngôn ngữ hoặc khu vực.
Ví dụ, một ứng dụng có hệ thống cho phép thay đổi chuỗi văn bản theo locale. Đây là khả năng được xây dựng thông qua i18n.
Khi nhóm phát triển bổ sung các bản dịch như “Đăng nhập”, “Giỏ hàng”, “Thanh toán” cho tiếng Việt và “Login”, “Cart”, “Checkout” cho tiếng Anh, đó là công việc localization.
Có thể hình dung:
Internationalization chuẩn bị cấu trúc → Localization bổ sung nội dung và quy ước cụ thể → Ứng dụng hiển thị phù hợp với locale được chọn.
Trong Flutter, hai khái niệm này thường được học cùng nhau vì nhiều công cụ phục vụ cả hai công việc.
3. Localization bao gồm những nội dung nào?
3.1. Bản dịch giao diện
Đây là thành phần phổ biến nhất.
Ví dụ:
| Nội dung | Tiếng Việt | Tiếng Anh |
|---|---|---|
| Trang chủ | Trang chủ | Home |
| Giỏ hàng | Giỏ hàng | Cart |
| Thanh toán | Thanh toán | Checkout |
| Đơn hàng | Đơn hàng | Orders |
| Đặt hàng thành công | Đặt hàng thành công | Order placed successfully |
Tuy nhiên, bản dịch cần đúng ngữ cảnh.
Ví dụ, từ “Order” có thể mang nghĩa “đơn hàng”, nhưng “Place order” mới phù hợp với hành động đặt hàng.
Vì vậy, Localization không nên chỉ dịch từng từ một cách máy móc.
3.2. Định dạng ngày tháng
Ví dụ, cùng một ngày có thể được hiển thị:
- Việt Nam:
25/12/2026. - Hoa Kỳ:
12/25/2026.
Đây là khác biệt về quy ước hiển thị, không phải sự khác biệt về thời điểm.
3.3. Định dạng số
Ví dụ, số một triệu hai trăm ba mươi bốn nghìn phẩy năm có thể được hiển thị bằng những quy ước khác nhau:
- Một số locale:
1.234.567,5. - Một số locale khác:
1,234,567.5.
Việc sử dụng sai dấu phân cách có thể khiến người dùng hiểu nhầm giá trị.
3.4. Tiền tệ
Các quốc gia sử dụng những loại tiền và quy ước hiển thị khác nhau.
Ví dụ:
150.000 ₫
$150.00
150,00 €
Cần phân biệt định dạng tiền tệ với việc quy đổi tiền tệ.
Localization có thể quyết định cách hiển thị một giá trị, nhưng không tự động chuyển đổi giá trị đó sang loại tiền khác.
3.5. Quy tắc số nhiều
Ví dụ:
1 item
5 items
Các ngôn ngữ có thể có quy tắc số nhiều khác nhau.
Vì vậy, ứng dụng cần sử dụng cơ chế pluralization phù hợp.
3.6. Nội dung văn hóa và khu vực
Một số nội dung có thể cần thay đổi theo thị trường.
Ví dụ, thông tin liên hệ, hướng dẫn giao hàng, phương thức thanh toán và đơn vị đo lường có thể khác nhau.
Tuy nhiên, những thay đổi này cần dựa trên yêu cầu nghiệp vụ thực tế, không nên tự động suy ra chỉ từ ngôn ngữ giao diện.
4. Locale trong Flutter
Flutter sử dụng lớp Locale để biểu diễn ngôn ngữ và những thông tin khu vực liên quan.
Ví dụ:
const Locale('vi', 'VN');
const Locale('en', 'US');
const Locale('en', 'GB');
Ba locale trên lần lượt biểu diễn tiếng Việt tại Việt Nam, tiếng Anh tại Hoa Kỳ và tiếng Anh tại Vương quốc Anh.
Hai locale cùng sử dụng tiếng Anh nhưng có thể khác nhau về quy ước ngày tháng, chính tả hoặc một số nội dung.
Ví dụ, en_US và en_GB đều là tiếng Anh nhưng không nên mặc định mọi quy ước định dạng đều giống nhau.
Trong Flutter, cần phân biệt Locale với múi giờ.
Locale('vi', 'VN') không có nghĩa ứng dụng tự động sử dụng múi giờ Asia/Ho_Chi_Minh.
Locale và timezone là hai khái niệm khác nhau.
5. Localization hoạt động như thế nào trong Flutter?
Một luồng hoạt động cơ bản gồm những bước sau.
Đầu tiên, ứng dụng khai báo những locale được hỗ trợ.
Tiếp theo, ứng dụng chuẩn bị tài nguyên bản dịch.
Khi khởi chạy, Flutter xác định locale phù hợp dựa trên cấu hình ứng dụng và những locale được thiết bị ưu tiên, hoặc sử dụng locale do ứng dụng chỉ định.
Sau đó, hệ thống localization cung cấp những chuỗi văn bản tương ứng.
Khi Widget cần hiển thị nội dung, nó truy cập chuỗi thông qua AppLocalizations.
Ví dụ:
final l10n = AppLocalizations.of(context)!;
Sau đó:
Text(l10n.checkout)
Nếu locale đang sử dụng là tiếng Việt, nội dung hiển thị là “Thanh toán”.
Nếu locale là tiếng Anh, nội dung hiển thị là “Checkout”.
Nhờ đó, cùng một Widget có thể được sử dụng cho nhiều ngôn ngữ.
6. Vai trò của flutter_localizations
Package flutter_localizations cung cấp các tài nguyên và delegate bản địa hóa cho những thành phần giao diện của Flutter.
Ví dụ, một ứng dụng Material có thể sử dụng Date Picker, các nhãn mặc định và những thành phần giao diện khác.
Nếu không cấu hình localization phù hợp, một số thành phần do Flutter cung cấp có thể không hiển thị theo ngôn ngữ mong muốn.
Thông thường, ứng dụng cấu hình:
localizationsDelegates:
AppLocalizations.localizationsDelegates,
Đồng thời khai báo:
supportedLocales:
AppLocalizations.supportedLocales,
Các thuộc tính được tạo bởi Flutter giúp tích hợp bản dịch của ứng dụng cùng những delegate cần thiết.
7. Cấu trúc thư mục Localization
Một cấu trúc tham khảo:
lib/
main.dart
l10n/
app_vi.arb
app_en.arb
app_localizations.dart
screens/
home_page.dart
login_page.dart
cart_page.dart
Trong đó, app_vi.arb chứa tài nguyên tiếng Việt và app_en.arb chứa tài nguyên tiếng Anh.
app_localizations.dart là mã được tạo tự động khi cấu hình output tương ứng.
Trong thực tế, vị trí của mã được tạo phụ thuộc vào l10n.yaml và cấu hình dự án.
Không nên tự chỉnh sửa trực tiếp những file được Flutter tạo tự động, vì nội dung có thể bị ghi đè khi chạy lại quá trình tạo mã.
8. Ví dụ tạo bản dịch bằng ARB
File app_vi.arb:
{
"@@locale": "vi",
"home": "Trang chủ",
"product": "Sản phẩm",
"cart": "Giỏ hàng",
"checkout": "Thanh toán",
"login": "Đăng nhập",
"logout": "Đăng xuất",
"orderHistory": "Lịch sử đơn hàng"
}
File app_en.arb:
{
"@@locale": "en",
"home": "Home",
"product": "Products",
"cart": "Cart",
"checkout": "Checkout",
"login": "Login",
"logout": "Logout",
"orderHistory": "Order history"
}
Các key phải được quản lý nhất quán.
Nếu một key tồn tại ở ngôn ngữ này nhưng thiếu ở ngôn ngữ khác, quá trình tạo mã hoặc kiểm tra bản dịch có thể phát hiện vấn đề tùy cấu hình.
Nhóm phát triển nên có quy trình rà soát bản dịch thiếu và bản dịch chưa phù hợp.
9. Localization và nội dung động
Một ứng dụng không chỉ có các chuỗi cố định.
Ví dụ:
“Chào mừng Nguyễn Văn A”.
“Bạn có 5 đơn hàng”.
“Đơn hàng #1234 đã được giao”.
Những câu này chứa dữ liệu động.
Để dịch chính xác, nên sử dụng placeholder thay vì ghép chuỗi thủ công.
Ví dụ:
{
"welcome": "Xin chào, {name}!",
"@welcome": {
"placeholders": {
"name": {
"type": "String"
}
}
}
}
Bản tiếng Anh:
{
"welcome": "Hello, {name}!",
"@welcome": {
"placeholders": {
"name": {
"type": "String"
}
}
}
}
Sử dụng:
Text(
l10n.welcome('Nguyễn Văn A'),
)
Ưu điểm là mỗi ngôn ngữ có thể sắp xếp vị trí placeholder theo cấu trúc câu phù hợp.
10. Localization và thông báo lỗi API
Trong dự án Flutter có Backend, thông báo lỗi có thể được trả về từ máy chủ.
Ví dụ:
{
"code": "INVALID_PASSWORD",
"message": "Mật khẩu không chính xác"
}
Nếu Flutter hiển thị trực tiếp trường message, người dùng đang sử dụng tiếng Anh vẫn có thể thấy thông báo tiếng Việt.
Một cách thiết kế phù hợp là Backend trả về mã lỗi ổn định.
Ví dụ:
{
"code": "INVALID_PASSWORD"
}
Flutter ánh xạ mã lỗi sang bản dịch:
- Tiếng Việt: “Mật khẩu không chính xác”.
- Tiếng Anh: “Incorrect password”.
Cách này giúp giao diện kiểm soát ngôn ngữ hiển thị.
Tuy nhiên, với những lỗi nghiệp vụ phức tạp, Backend có thể cần cung cấp thêm tham số hoặc cơ chế bản địa hóa riêng.
Điều quan trọng là không nên sử dụng trực tiếp nội dung lỗi kỹ thuật hoặc thông tin nhạy cảm làm thông báo cho người dùng.
11. Localization và dữ liệu sản phẩm từ Backend
Trong ứng dụng bán hàng, dữ liệu sản phẩm thường đến từ API.
Ví dụ:
{
"id": 12,
"name": "Sữa dinh dưỡng",
"description": "Sản phẩm bổ sung dinh dưỡng"
}
Nếu người dùng chuyển sang tiếng Anh, các chuỗi giao diện có thể thay đổi nhưng tên và mô tả sản phẩm vẫn là tiếng Việt.
Nguyên nhân là những nội dung này không nằm trong ARB của Flutter.
Để hỗ trợ đa ngôn ngữ cho dữ liệu sản phẩm, có thể sử dụng một trong những phương pháp sau.
Phương pháp 1: Backend lưu nhiều bản dịch.
Ví dụ, bảng dữ liệu có những bản dịch tương ứng với mã ngôn ngữ.
Phương pháp 2: API trả về nội dung theo locale.
Ví dụ:
GET /api/products?locale=en
Phương pháp 3: Backend trả về nhiều ngôn ngữ trong một response.
Ví dụ:
{
"id": 12,
"name": {
"vi": "Sữa dinh dưỡng",
"en": "Nutrition milk"
}
}
Mỗi phương pháp có ưu điểm và hạn chế.
Nếu số lượng sản phẩm lớn, việc quản lý bản dịch ở Backend thường cần được thiết kế như một phần của hệ thống nội dung.
12. Fallback Locale là gì?
Fallback Locale là cơ chế sử dụng một ngôn ngữ thay thế khi ngôn ngữ mong muốn không được hỗ trợ hoặc không có tài nguyên phù hợp.
Ví dụ, ứng dụng hỗ trợ tiếng Việt và tiếng Anh.
Thiết bị của người dùng đang ưu tiên tiếng Pháp.
Ứng dụng cần xác định sẽ sử dụng ngôn ngữ nào trong những ngôn ngữ được hỗ trợ.
Trong Flutter, quá trình lựa chọn locale có thể được điều chỉnh bằng những callback như localeResolutionCallback hoặc localeListResolutionCallback khi cần.
Ví dụ:
MaterialApp(
supportedLocales: const [
Locale('vi'),
Locale('en'),
],
localeResolutionCallback: (
locale,
supportedLocales,
) {
if (locale != null) {
for (final supported in supportedLocales) {
if (supported.languageCode ==
locale.languageCode) {
return supported;
}
}
}
return const Locale('vi');
},
)
Đây là ví dụ đơn giản ưu tiên khớp mã ngôn ngữ rồi dùng tiếng Việt.
Trong dự án thực tế, cần xem xét cả mã quốc gia, script và quy tắc lựa chọn locale để tránh làm mất những khác biệt quan trọng.
Ngoài ra, cơ chế chọn locale không tự động giải quyết mọi trường hợp thiếu key bản dịch. Việc quản lý bản dịch đầy đủ vẫn là trách nhiệm của nhóm phát triển.
13. Localization và khả năng truy cập
Localization cũng liên quan đến Accessibility, tức khả năng giúp nhiều nhóm người dùng tiếp cận ứng dụng.
Ví dụ, người dùng sử dụng trình đọc màn hình cần nghe những nhãn và mô tả phù hợp với ngôn ngữ đang sử dụng.
Nếu nút bấm chỉ có biểu tượng mà không có nhãn ngữ nghĩa rõ ràng, người dùng sử dụng công nghệ hỗ trợ có thể khó hiểu chức năng của nút.
Vì vậy, khi xây dựng ứng dụng đa ngôn ngữ, cần quan tâm đến những nhãn accessibility và nội dung ngữ nghĩa.
Ngoài ra, nên kiểm tra khả năng hiển thị khi người dùng tăng cỡ chữ trong cài đặt thiết bị.
14. Kiểm thử Localization
Một hệ thống localization cần được kiểm tra ở nhiều cấp độ.
Kiểm tra bản dịch
Xác nhận các key quan trọng đều có nội dung phù hợp.
Kiểm tra giao diện
Xác nhận văn bản không bị tràn, cắt hoặc che khuất.
Kiểm tra ngôn ngữ mặc định
Xác nhận ứng dụng chọn đúng locale theo yêu cầu.
Kiểm tra nội dung động
Xác nhận placeholder và pluralization hoạt động đúng.
Kiểm tra dữ liệu API
Xác nhận thông báo lỗi và nội dung từ Backend có cách xử lý ngôn ngữ phù hợp.
Kiểm tra khi đổi ngôn ngữ
Xác nhận giao diện cập nhật mà không làm mất dữ liệu hoặc trạng thái quan trọng ngoài ý muốn.
15. Những sai lầm thường gặp
Một sai lầm phổ biến là cho rằng Localization chỉ là tạo file dịch.
Sai lầm thứ hai là không phân biệt ngôn ngữ giao diện với quốc gia và múi giờ.
Sai lầm thứ ba là dịch từng từ mà không xem xét ngữ cảnh.
Sai lầm thứ tư là hiển thị trực tiếp thông báo lỗi Backend bằng một ngôn ngữ cố định.
Sai lầm thứ năm là không kiểm tra giao diện với nội dung dài.
Sai lầm thứ sáu là cho rằng đổi locale sẽ tự động đổi loại tiền và quy đổi giá trị tiền.
Sai lầm cuối cùng là bỏ qua dữ liệu động, khiến ứng dụng có giao diện đa ngôn ngữ nhưng nội dung sản phẩm vẫn chỉ hỗ trợ một ngôn ngữ.
16. Kết luận
Localization là quá trình điều chỉnh ứng dụng cho phù hợp với ngôn ngữ và quy ước của từng khu vực.
Trong Flutter, Localization thường được thực hiện thông qua flutter_localizations, intl, ARB và AppLocalizations.
Localization không chỉ liên quan đến dịch chữ mà còn bao gồm cách diễn đạt, định dạng dữ liệu, bố cục giao diện, thông báo lỗi và nội dung động.
Đối với dự án Flutter thực tế, việc xây dựng Localization có tổ chức giúp ứng dụng dễ mở rộng, nhất quán và phù hợp hơn với người dùng ở những khu vực khác nhau.
17. Tài liệu tham khảo
- Flutter Internationalization: https://docs.flutter.dev/ui/accessibility-and-internationalization/internationalization
- Flutter Localization API: https://api.flutter.dev/flutter/flutter_localizations/
- Dart intl: https://pub.dev/packages/intl
- Unicode CLDR: https://cldr.unicode.org/








Khoá học lập trình game con rắn cho trẻ em




