# How AppFlowy Implements Localization and Internationalization with JSON Translation Files

> Learn how AppFlowy implements localization and internationalization using JSON translation files. Discover runtime translation, type-safe constants, and dynamic locale switching.

- Repository: [AppFlowy-IO/AppFlowy](https://github.com/AppFlowy-IO/AppFlowy)
- Tags: internals
- Published: 2026-03-03

---

**AppFlowy uses the EasyLocalization package to provide runtime translation of UI strings through JSON assets, generating type-safe Dart constants that enable compile-time key validation while supporting dynamic locale switching.**

The AppFlowy-IO/AppFlowy repository implements a robust internationalization system for its Flutter frontend that decouples translation content from presentation logic. By storing localized strings as JSON assets and leveraging code generation, the codebase ensures type-safe access to translations while maintaining a clean separation between UI components and language-specific text.

## JSON Translation Assets Structure

Translation files follow a flat JSON structure stored in `frontend/appflowy_flutter/resources/translations/`. Each supported locale maintains its own file, such as [`en-US.json`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/en-US.json) for United States English or [`zh-CN.json`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/zh-CN.json) for Simplified Chinese.

Key/value pairs map semantic identifiers to localized strings:

```json
// frontend/appflowy_flutter/resources/translations/en-US.json
{
  "welcome_message": "Welcome to AppFlowy"
}

```

```json
// frontend/appflowy_flutter/resources/translations/zh-CN.json
{
  "welcome_message": "欢迎使用 AppFlowy"
}

```

## EasyLocalization Initialization

The application bootstrap configures **EasyLocalization** in `frontend/appflowy_flutter/lib/startup/tasks/app_widget.dart`. The `InitAppWidgetTask` class wraps the root widget with `EasyLocalization`, specifying the asset directory, supported locales list, and fallback locale.

Configuration parameters include:

- **Asset path**: Points to `assets/translations` directory
- **Supported locales**: Explicit list of all application locales
- **Fallback locale**: Defaults to `en-US` when translations are missing

## Generated Type-Safe Translation Keys

A build-time code generation step produces `frontend/appflowy_flutter/lib/generated/locale_keys.g.dart` using the `easy_localization:generate` command. This generated file contains a `LocaleKeys` class where each JSON key becomes a static constant.

Generate the keys by running:

```bash
flutter pub run easy_localization:generate -f json -o lib/generated/locale_keys.g.dart

```

The resulting class eliminates magic strings from the codebase, providing IDE autocomplete and compile-time validation for translation keys.

## Runtime Translation Usage

UI components import the generated keys and invoke the `.tr()` extension method provided by EasyLocalization. This pattern appears throughout the codebase, including in `frontend/appflowy_flutter/lib/workspace/presentation/widgets/view_title_bar.dart` at line 117.

Usage example:

```dart
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';

class WelcomeBanner extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(LocaleKeys.welcome_message.tr());
  }
}

```

The `.tr()` method queries EasyLocalization’s `EasyLocalizationController` to resolve the current locale's translation at runtime.

## Fallback Translation Handling

For scenarios requiring manual fallback resolution, `frontend/appflowy_flutter/lib/shared/easy_localiation_service.dart` provides the `EasyLocalizationService` class. This service exposes helper methods to retrieve either the current locale's translation or the fallback translation when keys are missing.

Example service usage:

```dart
final service = getIt<EasyLocalizationService>();
String fallback = service.getFallbackTranslation(LocaleKeys.welcome_message);

```

## Summary

- **Asset Organization**: JSON translation files reside in `resources/translations/` with locale-specific naming (e.g., [`en-US.json`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/en-US.json), [`zh-CN.json`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/zh-CN.json)).
- **Type Safety**: The `locale_keys.g.dart` file provides compile-time constants generated from JSON keys via the `easy_localization:generate` command.
- **Runtime Resolution**: UI code calls `.tr()` on `LocaleKeys` constants to trigger EasyLocalization's lookup mechanism.
- **Bootstrap Configuration**: `InitAppWidgetTask` initializes the localization system with supported locales and fallback settings in `app_widget.dart`.
- **Fallback Support**: `EasyLocalizationService` offers programmatic access to fallback translations for edge cases.

## Frequently Asked Questions

### How do I add a new translation key to AppFlowy?

Add the key-value pair to all JSON files in `frontend/appflowy_flutter/resources/translations/`, then run the generator command to update `locale_keys.g.dart`. Import the generated file and use the new constant with `.tr()` in your widget code.

### Where does AppFlowy store its translation files?

Translation assets are stored in `frontend/appflowy_flutter/resources/translations/` as JSON files named with locale codes (e.g., [`en-US.json`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/en-US.json), [`zh-CN.json`](https://github.com/AppFlowy-IO/AppFlowy/blob/main/zh-CN.json)). The build system treats this directory as a Flutter asset folder referenced during EasyLocalization initialization.

### What happens if a translation key is missing in the current locale?

EasyLocalization automatically falls back to the configured fallback locale (`en-US`) when a key is absent. Additionally, the `EasyLocalizationService` class in `easy_localiation_service.dart` provides explicit methods to retrieve fallback translations programmatically when needed.

### How does AppFlowy ensure type safety for translation keys?

The project uses the `easy_localization:generate` package to parse JSON translation files and generate the `LocaleKeys` class in `lib/generated/locale_keys.g.dart`. This converts string keys into static constants, enabling IDE autocomplete and compile-time validation rather than relying on error-prone string literals.