# Đa Ngôn Ngữ Cho Ứng Dụng Flutter Với LanguageHelper

# PHẦN 1: CÁC BƯỚC THIẾT LẬP VÀ SỬ DỤNG CƠ BẢN

## GIỚI THIỆU

Có nhiều cách để có thể sử dụng được nhiều ngôn ngữ (hay còn gọi là localization) cho ứng dụng Flutter. Ở bài viết này, mình sẽ giới thiệu thư viện [language\_helper](https://pub.dev/packages/language_helper) và cách sử dụng của nó để có thể tạo ứng dụng đa ngôn ngữ một cách đơn giản và hiệu quả nhất.

## TÍNH NĂNG

* Dễ dàng kiểm soát và thay đổi ngôn ngữ trong ứng dụng. Tự động áp dụng ngôn ngữ hiện tại của máy cho ứng dụng.
    
* Có thể kiểm soát bản dịch với `LanguageConditions` (như dịch số nhiều trong tiếng Anh).
    
* Sử dụng generator để tách chuỗi cần thiết để tiện cho việc dịch (không cần sử dụng build\_runner nên chạy rất nhanh).
    
* Có thể sử dụng `Language Helper Translator` trên Chat GPT-4 để hỗ trợ dễ hơn cho việc dịch.
    

## CÀI ĐẶT

Chỉ có bước này là bắt buộc trong quá trình phát triển ứng dụng, những bước còn lại có thể thực hiện sau khi ứng dụng đã sẵn sàng cho việc phát hành.

* Thêm `language_helper` vào project:
    
    ```bash
    flutter pub add language_helper
    ```
    
* Thêm khởi tạo ngôn ngữ vào project:
    
    ```dart
    main() async {
      WidgetsFlutterBinding.ensureInitialized();
      await LanguageHelper.instance.initial(data: []);
      runApp(const MyApp());
    }
    ```
    
* Thêm `.tr`, `.trP` hay `.trF` vào những chuỗi cần dịch:
    
    * Cơ bản:
        
        ```dart
        Text('Chữ cần dịch'.tr)
        ```
        
    * Dịch có điều kiện:
        
        ```dart
        Text('Xin chào @{name}'.trP({'name': name}))
        ```
        
    * Số nhiều:
        
        ```dart
        final data = {
            'We have @{number} dollar': LanguageConditions(
                param: 'number',
                conditions: {
                    '0': 'We have zero dollar',
                    '1': 'We have one dollar',
                    '_': 'We have @{number} dollars'
                },
            ),
        }
        
        Text('We have @{number} dollar'.trP({'number': number}))
        ```
        

## GENERATOR

Generate:

```bash
dart run language_helper:generate
```

Đường dẫn sau khi chạy:

```bash
.lib
|--- resources
|    |--- language_helper
|    |    |--- language_data.dart
|    |    |--- languages
|    |    |    |--- _generated.dart   ; This file will be overwritten when re-generating
```

## DỊCH VÀ HIỆU CHỈNH

Tạo thêm tệp với ngôn ngữ tương ứng như `en.dart`, `vi.dart`,... ở trong thư mục `languages`.

Mở [Language Helper Translator](https://chat.openai.com/g/g-qoPMopEAb-language-helper-translator) trên Chat-GPT 4, sao chép nội dung trong tệp `_generated.dart`, dán vào với theo mẫu sau và tiến hành dịch:

````dart
Đây là bản dịch của ứng dụng [Tên ứng dụng và mục đích cơ bản của ứng dụng]. Dịch sang [Ngôn ngữ đích]:

```dart
const analysisLanguageData = <String, dynamic>{
  'Xin chào @{name}': 'Xin chào @{name}',
  'Chúng ta có @{number} đô-la': 'Chúng ta có @{number} đô-la',
};
```
````

Sao chép kết quả và dán vào tệp ngôn ngữ tương ứng. Chẳng hạn như tệp `en.dart`:

```dart
const en = <String, dynamic>{
  'Xin chào @{name}': 'Xin chào @{name}',
  'Chúng ta có @{number} đô-la': 'We have @{number} dollar',
};
```

Hiệu chỉnh lại kết quả cần thiết như số nhiều, bạn có thể hiệu chỉnh trực tiếp ở biến `en` hoặc tạo biến mới như `enOverride` như sau:

```dart
final enOverride = <String, dynamic>{
  'Chúng ta có @{number} đô-la': LanguageCondition(
    param: 'number',
    conditions: {
      '0': 'We have zero dollar',
      '1': 'We have one dollar',
      '_': 'We have @{number} dollars',
    }
  ),
};
```

Thêm ngôn ngữ vừa dịch vào tệp `language_data.dart`:

```dart
LanguageData data = {
  LanguageCodes.vi: analysisLanguageData,
  LanguageCodes.en: en,
};

LanguageData dataOverrides = {
  LanguageCodes.en: enOverride,
};
```

Cập nhật lại trong project:

```dart
main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await LanguageHelper.instance.initial(
      data: [LanguageDataProvider.data(data)]
      dataOverrides: [LanguageDataProvider.data(dataOverrides)],   
  );
  runApp(const MyApp());
}
```

## CẬP NHẬT WIDGET KHI NGÔN NGỮ THAY ĐỔI

Sử dụng `LanguageBuilder` hoặc `Tr` cho những Widget cần thay đổi khi ứng dụng thay đổi ngôn ngữ. Chỉ có `LanguageBuilder` cần thiết được cập nhật nên bạn có không cần quan tâm nếu sử dụng `LanguageBuilder` ở nhiều nơi dẫn đến dư thừa.

Ở `MaterialApp`:

```dart
class App extends StatelessWidget {
  const App({super.key});

  @override
  Widget build(BuildContext context) {
    return LanguageBuilder(
      builder: (context) {
        return MaterialApp(
          localizationsDelegates: languageHelper.delegates,
          supportedLocales: languageHelper.locales,
          locale: languageHelper.locale,
          home: const HomePage(),
        );
      }
    );
  }
}
```

Ở `Widget`:

```dart
LanguageBuilder(
    builder: (context) {
        return Scaffold(
          body: Column(
            children: [
              Text('Xin chào @{name}'.tr),
              Text('Chúng ta có @{number} đô-la'.tr),
            ],
          ),
        );
    },
),
```

Sử dụng `Tr` (Phiên bản thu gọn của `LanguageBuilder`):

```dart
Tr((_) => Text('Xin chào @{name}'.tr)),
```

## KIỂM SOÁT NGÔN NGỮ

Thay đổi ngôn ngữ:

```dart
languageHelper.change(LanguageCodes.vi);
```

Thêm bản dịch mới:

```dart
languageHelper.addData(LanguageDataProvider.data(newLanguageData));
languageHelper.addDataOverrides(LanguageDataProvider.data(newLanguageDataOverrides));
```

## KẾT LUẬN

Ở phần mở đầu, chúng ta đã hoàn thành việc cài đặt và cách sử dụng căn bản cho [language\_helper](https://pub.dev/packages/language_helper). Ở phần tiếp theo, chúng ta sẽ tìm hiểu cách thiết lập để có thể sử dụng được cho ứng dụng phức tạp hơn với JSON.
