Nguồn : Internationalizing Phần này hướng dẫn app bạn có thể hỗ trợ nhiều ngôn ngữ. Tham khảo source code gen_l10n_example
I. Cấu Hình
1.1. Cài đặt Package
-
Mở terminal, thực hiện các lệnh sau :
flutter pub add flutter_localizations --sdk=flutter flutter pub add intl:any -
Sau khi cài đặt xong, mở file
pubspec.ymlkiểm tra, có các khai báo như bên dưới thì ok.dependencies: flutter: sdk: flutter flutter_localizations: sdk: flutter intl: any
1.2. Cấu hình localizationsDelegates và supportedLocales
-
Thực hiện bổ sung đoạn code dưới đây :
import 'package:flutter_localizations/flutter_localizations.dart'; //----------------------------------------------------------------- return const MaterialApp( title: 'Localizations Sample App', localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: [ Locale('en'), // English Locale('es'), // Spanish ], home: MyHomePage(), ); -
Trong đó :
- GlobalMaterialLocalizations : Cung cấp các chuỗi
localizedcho Material Components - GlobalCupertinoLocalizations : Cung cấp các chuỗi
localizedcho Cupertino Components - GlobalWidgetsLocalizations : Hướng text (left-to-right, right-to-left…)
- GlobalMaterialLocalizations : Cung cấp các chuỗi
1.3. Tạo các localized messages cho App của bạn
-
Bước 1 :: Thêm package
intlflutter pub add intl:any -
Bước 2 : Mở file
pubspec.yamlSet flaggenerate= true.flutter: generate: true -
Bước 3 : Tạo file
l10n.yamltại vị trí root project của bạn, mở file và thêm các đoạn cấu hình như dưới đây :```dart arb-dir: lib/l10n template-arb-file: app_en.arb output-localization-file: app_localizations.dartTrong đó :
arb-dir: là folder chứa file .arb,${FLUTTER_PROJECT}/lib/l10ntemplate-arb-file: định dạng tên file .arboutput-localization-file: dựa vào file .arb, flutter sẽ thực hiện generate code dart
-
Bước 5 : Thêm các giá trị message cần thiết cho app của bạn vào các file .arb
- Ví dụ: Trong file
app_en.arb
"helloWorld": "Hello World!",- Trong file
app_vi_arb
"helloWorld": "Xin chào các bạn!", - Ví dụ: Trong file
-
Bước 6 : Thực hiện tạo file bằng lệnh
flutter gen-l10n. Bạn sẽ tìm thấy các file đã được generate ở${FLUTTER_PROJECT}/.dart_tool/flutter_gen/gen_l10n -
Bước 7: Thay đổi các giá trị
localizationsDelegatesvàsupportedLocales. Ở đầu bài viết, chúng ta chỉ định dựa vào các constants của thư viện.localizationsDelegates: [ GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: [ Locale('en'), // English Locale('es'), // Spanish ],Hãy thay đổi các giá trị này bằng các giá trị đã được generate.
const MaterialApp( title: 'Localizations Sample App', localizationsDelegates: AppLocalizations.localizationsDelegates, supportedLocales: AppLocalizations.supportedLocales, ); -
Bước 8 : Các bước setup đã ok, giờ thì sử dụng thôi. Mỗi keywork bạn khai báo trong các file
.arbkhi generate ra code dart sẽ là một getter. Ví dụ ở đây, chúng ta có thể truy cập keyhelloWorldnhư là một getter.Text(AppLocalizations.of(context)!.helloWorld
II. Placeholders, plurals, and selects
2.1 Placeholders
-
Trong app bạn cần một số chuỗi cụ thể, chúng giống nhau hoàn toàn chỉ khác một giá trị. Bình thường, chúng ta sẽ tạo ra các key như thế này :
"hellotam" : "Hello Tâm" "hellohuy" : "Hello Huy" "hellohung" : "Hello Hùng" -
Chúng ta có thể thấy, chuỗi
Hellolà giống nhau. Có cách nào tái sử dụng nó không ?. Placeholder sẽ giúp chúng ta làm việc này.
Khai báo placeholder trong file .arb :"hello": "Hello {userName}", "@hello": { "description": "A message with a single parameter", "placeholders": { "userName": { "type": "String", "example": "Bob" } } } -
Các giá trị trên có ý nghĩa như thế nào khi generate ra code dart :
@hello: sẽ tạo ra methodhellodescription: Mô tả cho methodhellouserName: Tên tham số của methodhello-
type: Kiểu dữ liệu của tham sốText(AppLocalizations.of(context)!.hello('Tâm')), // Kết quả sẽ là : "Hello Tâm";
2.2 Plurals
-
Trở lại với vị dụ của
Placeholders. Mình sẽ thêm 2 giá trịhellohevàhelloshe, và đặt tinh huống là hai giá trị này dùng rất nhiều trong app."hellotam" : "Hello Tâm" "hellohuy" : "Hello Huy" "hellohung" : "Hello Hùng" "hellohe" : "Hello Anh" "helloshe" : "Hello Chị" -
Nếu áp dụng
placeholdernhư 2.1 thì ở mỗi nơi gọi mình lại cần truyềnAnhhoặcChịthì không hay.Pluralsgiúp chúng ta cải thiện điều này"hello": "Hello {userName, plural, =0{Anh} =1{Chi} other}", "@hello": { "description": "A message with a single parameter", "placeholders": { "userName": { "type": "String", "example": "Bob" } } -
Các giá trị trên sẽ giống với
placeholderkhi generate ra code dart. Nhưng chúng ta có lưu ý nơi định nghĩa chuỗihello"hello": "Hello {userName, plural, =0{Anh} =1{Chi} other}", ```Hello Anh -
Trong đó :
userName: chính là tham số của methodhelloplural: chỉ định keyword này để thông báo rằng chúng ta đang dùngplural=0{Anh}hoặc=1{Chi}: Lúc này methodhellosẽ nhận tham số là kiểuintother{userName}: Lúc này methodhellosẽ nhận tham số là chuỗi
Text(AppLocalizations.of(context)!.hello(0)), // Kết quả sẽ là : Hello Anh
2.3. Selects
-
Chúng ta thấy
Pluralshỗ trợ các giá trị cố định. Nhưng khi sử dụng ta lại truyền index0,1để lấy giá trị ra, nó không tường mình cho lắm, khi đọc code chúng ta lại phải kiểm tra xem nó trả về giá trị gì . Biết vậy package cung cấp cho chúng ta khái niệmSelect -
Về phân khai báo cũng giống như
placeholdernên chúng ta quan tâm đến phần đĩnh nghĩa chuỗi : Cách định nghĩa của mộtPlurals"hello": "Hello {userName, plural, =0{Anh} =1{Chi} other}" -
Khi dùng
Selecthãy đổi nó thành như thế này :"hello": "Hello {userName, select, he{Anh}, she{Chị} other}" -
Và khi sử dụng
Text(AppLocalizations.of(context)!.hello("he")), // Kết quả là : Hello Anh
III. Escaping syntax
-
Chúng ta thấy nhưng giá trị đặ trong dấu ngoặc
{...}được xem như tham số. Trường hợp chúng ta vẫn muốn nó hiển thị như mổt text bình thường được không ? Câu trả lời trả được chứ =)). Mở filel10n.yamlvà thêm đoạn này :use-escaping: true -
Lúc này để trong file .arb, để đánh dấu giá trị
{}là chuỗi, chúng ta chỉ cần thêm kí tự nháy đơn phía trước'{ "helloWorld": "Hello! '{Isn''t}' this a wonderful day?" }
IV. Một số format với số
-
Bảng dưới đây, liệt kê một số format khi dùng số :
Message “format” value Output for 1200000 compact“1.2M” compactCurrency*“$1.2M” compactSimpleCurrency*“$1.2M” compactLong“1.2 million” currency*“USD1,200,000.00” decimalPattern“1,200,000” decimalPercentPattern*“120,000,000%” percentPattern“120,000,000%” scientificPattern“1E6” simpleCurrency*“$1,200,000” -
Ví dụ :
"numberOfDataPoints": "Number of data points: {value}", "@numberOfDataPoints": { "description": "A message with a formatted int parameter", "placeholders": { "value": { "type": "int", "format": "compactCurrency", "optionalParameters": { "decimalDigits": 2 } } } }
VI. Formart DateTime
-
Ví dụ sử dụng date format
"helloWorldOn": "Hello World on {date}", "@helloWorldOn": { "description": "A message with a date parameter", "placeholders": { "date": { "type": "DateTime", "format": "yMd" } } } -
Khi sử dụng
AppLocalizations.of(context).helloWorldOn(DateTime.utc(1959, 7, 9))
VII. Localizing for iOS: Updating the iOS app bundle
-
Trong iOS app, chúng ta cần khai báo các locale mà app hỗ trợ. Tại mở file info.plist theo đường dẫn :
${FLUTTER_PROJECT}/ios/Runner/Info.plist. Thực hiện khai báo các locale mà app hỗ trợ<key>CFBundleLocalizations</key> <array> <string>en</string> <string>vi</string> </array>
VIII. Advanced topics for further customization
8.1. Advanced locale definition
-
Một số ngôn ngữ hỗ trợ nhiều
language code, chúng ta cần chỉ định chính xác nó. Ví dụ, tiếng Trung Quốc rất đang dạng nên chung ta cần chỉ định cụ thểlanguage code,script code,country codethông qua contructorfromSubtagssupportedLocales: [ Locale.fromSubtags(languageCode: 'zh'), // generic Chinese 'zh' Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hans'), // generic simplified Chinese 'zh_Hans' Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hant'), // generic traditional Chinese 'zh_Hant' Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hans', countryCode: 'CN'), // 'zh_Hans_CN' Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hant', countryCode: 'TW'), // 'zh_Hant_TW' Locale.fromSubtags( languageCode: 'zh', scriptCode: 'Hant', countryCode: 'HK'), // 'zh_Hant_HK' ],
8.2. Tracking the locale: The Locale class and the Localizations widget
-
Localelà class đại diện cho một ngôn ngữ.Localizationslà widget dùng để chỉ định locale cho các widget con. Để bạn biết UI hiện tại đang dùngLocalegì, bạn có thể sử dụng hàmlocaleOfLocale myLocale = Localizations.localeOf(context);
8.3. Specifying the app’s supportedLocales parameter
- Tham số
supportedLocalescủaMaterialApphạn chế thay đổi. Khi User thay đổi cài đặt trên thiết bị ,Localizationswidget sẽ cập nhật locale dựa trên độ ưu tiên sau :- LocaleNew có trong danh sách mà app đã khai báo
- Dùng locale đầu tiền mà có
languageCodematch với LocaleNew - Dùng locale đầu tiên trong danh sách
supportedLocaleslocaleResolutionCallback : TBD
8.4. Configuring the l10n.yaml
`l10n.yaml` file cho bạn cấu hình để tool `gen-l10n` làm việc :
- Nơi tất các file input được đặt.
- Nơi tất các output nên được tạo
- Tên class Dart mà thể hiện localizations delegate Tham khảo : Configuring the l10n.yaml file
IX. Cách Internationalization Làm Việc
9.1. Loading and retrieving localized values
-
Localizationswidget dùng để load và tìm kiếm các giá trịlocalized. Nếu device của bạn thay đổi locale, widget này sẽ load tự động các giá trị từ locale mới và rebuild lại widget.Localizationslàm việc giống nhưInheritedWidget. Nghĩa là widget con củaLocalizationschỉ bị rebuild khi có truy cậpText(AppLocalizations.of(context) -
LocalizationsDelegatecó hàmloaddùng để load các giá trị từ file .arb vào memory mỗi khi có sự thay đổi locale.
To be Contiune…