flutter_pipwave_localization 0.3.1 copy "flutter_pipwave_localization: ^0.3.1" to clipboard
flutter_pipwave_localization: ^0.3.1 copied to clipboard

Powerful and flexible localization package for Pipwave Flutter projects, featuring ICU message formatting, runtime locale switching, asset and dynamic translation file support.

PW Localization Flutter #

License

A powerful and flexible localization package for Flutter applications, designed as a replacement for EasyLocalization with enhanced features including runtime ICU formatting support and dynamic language file downloading.

Features #

  • 🚀 Easy Integration: Drop-in replacement for EasyLocalization with familiar API patterns
  • 🌍 ICU Message Formatting: Full support for ICU message format including plurals and gender rules
  • 📱 Dynamic Downloads: Download and update language files at runtime from remote servers
  • 💾 Asset Fallback: Automatic fallback to asset-based translations when downloads are unavailable or when a locale is not found in downloaded files; empty translation maps fall through the lookup chain
  • 🔄 Hot Reload: Support for runtime locale switching and translation updates
  • 🏗️ Code Generation: Generate type-safe translation keys from JSON files
  • 🎯 Flutter Integration: Seamless integration with Flutter's localization system
  • 🗣️ 17 Built-in Delegates: Material, Cupertino, and Widget localization for Guarani, Hausa, Hawaiian, Igbo, Javanese, Latin, Maori, Nahuatl, Quechua, Shona, Somali, Swahili, Tajik, Turkmen, Xhosa, Yoruba, and Cantonese

Installation #

Add this to your package's pubspec.yaml file:

dependencies:
  flutter_pipwave_localization: ^0.3.1

Example #

A complete working example is available in the example/ directory. The example demonstrates:

  • Custom setup with PWLocalizationService and PWLocalizationDelegate
  • Using context.tr() for simple translations, context.plural() and context.gender() for plurals and gender
  • Runtime language switching with AnimatedBuilder
  • Dynamic download of language files from a remote URL
  • BCP-47 locale support (e.g., en, id, zh-CN)

To run the example:

cd example
flutter pub get
flutter run

Quick Start #

1. Basic Setup #

Wrap your app with PWLocalizationProvider:

import 'package:flutter/material.dart';
import 'package:flutter_pipwave_localization/flutter_pipwave_localization.dart';

void main() {
  runApp(
    PWLocalizationProvider(
      startLocale: const Locale('en'),
      assetPath: 'assets/translations',
      downloadedPath: 'translations',
      supportedLocales: const [
        Locale('en'),
        Locale('es'),
        Locale('fr'),
      ],
      child: const MyApp(),
    ),
  );
}

2. Using Translations #

Access translations through the context extension:

class MyHomePage extends StatelessWidget {
  const MyHomePage({super.key});

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(context.tr('welcome.title')),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(context.tr('welcome.message', args: {'name': 'John'})),
            Text(context.plural('items.countInObject', 5)),
          ],
        ),
      ),
    );
  }
}

3. Using Translation Keys (Optional) #

After running the code generator, use type-safe constants:

// Generated keys (names depend on your JSON structure)
Text(LocaleKeys.welcomeTitle.tr());
Text(LocaleKeys.itemsCount.trPlural(5));

API Reference #

PWLocalizationProvider #

The main widget that provides localization to your app. Wraps your app and initializes [PWLocalizationService].

PWLocalizationProvider({
  required Widget child,
  required Locale startLocale,
  required String assetPath,
  required String downloadedPath,
  List<Locale> supportedLocales = const [Locale('en')],
  Widget? loadingWidget,
  bool isNewInstance = false,
  Key? key,
});

Parameters:

  • child: The widget tree to provide localization for
  • startLocale: The initial locale to use
  • assetPath: Path to asset-based translation files (e.g., 'assets/translations')
  • downloadedPath: Directory name for downloaded translation files
  • supportedLocales: List of supported locales
  • loadingWidget: Optional widget to show while the initial locale is loading
  • isNewInstance: If true, creates a new service instance instead of using the singleton

PWLocalizedMaterialApp #

A convenience widget combining [MaterialApp] with localization. Use when you need both Material Design and localization in a single widget.

PWLocalizedMaterialApp(
  home: const MyHomePage(),
  startLocale: const Locale('en'),
  assetPath: 'assets/translations',
  downloadedPath: 'translations',
  supportedLocales: const [Locale('en'), Locale('es')],
  theme: ThemeData.light(),
);

PWLocalizationService #

The core service that handles translations and ICU formatting. Accessed via PWLocalizationService.instance.

Key Methods

// Initialize the service
await PWLocalizationService.instance.initialize(
  assetPath: 'assets/translations',
  downloadedPath: 'translations',
  defaultLanguage: 'en',
  locale: const Locale('en'),
);

// Translate a key (supports map, list, or named args)
String translated = PWLocalizationService.instance.tr(
  'welcome.message',
  args: {'name': 'John'},
);
// For plurals, use plural()
String plural = PWLocalizationService.instance.plural(
  'newMessages',
  5,
);

// Check if locale is supported
bool isSupported = PWLocalizationService.instance.isLocaleSupported('en');

// Download language files (headers and query params optional)
await PWLocalizationService.instance.downloadLanguageFiles(
  'https://api.example.com/translations',
  ['en', 'es', 'fr'],
  headers: {'Authorization': 'Bearer token'},
  queryParameters: {'version': '1.0'},
);

// Alternative: download by locale tags or Locale objects
await PWLocalizationService.instance.downloadLanguageFilesForTags(
  baseUrl, ['en', 'zh-CN'],
);
await PWLocalizationService.instance.downloadLanguageFilesForLocales(
  baseUrl, [const Locale('en'), const Locale('zh', 'CN')],
);

// Clear downloaded translations
await PWLocalizationService.instance.clearDownloadedTranslations();

Locale Helpers

// Convert between Locale and BCP-47 tags
String tag = PWLocalizationService.localeToTag(const Locale('zh', 'CN')); // 'zh-CN'
Locale locale = PWLocalizationService.localeFromTag('zh-CN');

PWLocalizationDelegate #

Integrates with Flutter's localizationsDelegates. Requires either an already-initialized service or configuration for initialization.

PWLocalizationDelegate(
  instance: PWLocalizationService.instance,
  locale: locale,
  supportedLocales: supportedLocales,
  assetPath: 'assets/translations',
  downloadedPath: 'translations',
  defaultLocaleTag: 'en',
);

Helper to get configured delegates:

PWLocalizationDelegate.getConfiguredDelegates(
  instance: PWLocalizationService.instance,
  locale: locale,
  supportedLocales: supportedLocales,
  assetPath: 'assets/translations',
  downloadedPath: 'translations',
  defaultLocaleTag: 'en',
);

Context Extensions #

Convenient extensions for accessing localization in widgets:

// Simple translation with arguments
String text = context.tr('welcome.message', args: {'name': 'John'});

// Plural forms (object-based: zero, one, many, other)
String plural = context.plural('items.countInObject', 5);

// Gender forms (object-based: male, female, other)
String welcome = context.gender('profileWelcome', 'male', namedArgs: {'name': 'John'});

// Get current locale
Locale? locale = context.currentLocale;

String Extensions #

Extensions for direct string translation:

// Simple translation
String text = 'welcome.message'.tr();

// Translation with arguments
String text = 'welcome.message'.tr(args: {'name': 'John'});
String text = 'welcome.message'.trArgs({'name': 'John'});

// Plural and gender (for object-based translation keys)
String text = 'items.countInObject'.trPlural(5);
String text = 'profileWelcome'.trGender('male', namedArgs: {'name': 'John'});

ICU Message Format Support #

This package fully supports ICU message formatting for advanced pluralization and gender rules. Use dedicated methods:

  • Object-based plurals (zero, one, many, other): context.plural(key, count) or service.plural(key, count)
  • Object-based gender (male, female, other): context.gender(key, gender) or service.gender(key, gender)
  • ICU inline format (e.g. {count, plural, ...} in string): context.tr(key, args: {...})

Plural Rules #

Object-Based Plural Format

Object-based plural definitions use plural():

{
  "items_count": {
    "zero": "No items",
    "one": "One item",
    "many": "{count} items",
    "other": "{count} items"
  }
}

Usage:

Text(context.plural('items_count', 5));

ICU Message Format Plural

For ICU plural syntax embedded directly in string values:

{
  "items_count": "{count, plural, =0{No items} =1{One item} =2{Two items} few{Few items} many{Many items} other{{count} items}}"
}

Usage:

Text(context.tr('items_count', args: {'count': 5}));

The ICU format supports:

  • Exact matches: =0, =1, =2, etc.
  • Plural categories: zero, one, two, few, many, other
  • Variable interpolation: {count} within messages

Gender Rules #

{
  "welcome": {
    "male": "Welcome Mr. {name}",
    "female": "Welcome Ms. {name}",
    "other": "Welcome {name}"
  }
}

Usage:

Text(context.gender('welcome', 'male', namedArgs: {'name': 'John'}));

Complex ICU Formatting #

{
  "message": "You have {count, plural, zero{no messages} one{one message} many{# messages}} from {sender}."
}

Usage:

Text(context.tr('message', args: {
  'count': 5,
  'sender': 'Alice'
}));

Code Generation #

Generate type-safe translation keys from your JSON files:

dart run flutter_pipwave_localization:generate assets/translations/en.json lib/src/generated/locale_keys.g.dart

The arguments are optional and default to:

  • Translation file: assets/translations/en.json
  • Output path: lib/src/generated/locale_keys.g.dart

You can also run without arguments to use the defaults:

dart run flutter_pipwave_localization:generate

This generates a LocaleKeys class with static constants for all translation keys.

Built-in Localization Delegates #

The package includes Material, Cupertino, and Widget localization delegates for 17 languages. These provide localized labels for Flutter's built-in widgets (date pickers, time pickers, buttons, dialogs, reorder semantics, etc.).

Supported Languages #

Code Language Code Language
gn Guarani sn Shona
ha Hausa so Somali
haw Hawaiian sw Swahili
ig Igbo tg Tajik
jv Javanese tk Turkmen
la Latin xh Xhosa
mi Maori yo Yoruba
nah Nahuatl yue Cantonese
qu Quechua

Plus Flutter's built-in locales (en, es, fr, zh, etc.) for Material, Cupertino, and Widgets.

Implementation #

These delegates are automatically included when you use PWLocalizationProvider or PWLocalizationDelegate.getConfiguredDelegates(). You only need to add your desired locales to supportedLocales:

PWLocalizationProvider(
  startLocale: const Locale('ha'),
  supportedLocales: const [
    Locale('en'),
    Locale('ha'),   // Hausa - Material/Cupertino/Widget labels
    Locale('yo'),   // Yoruba
    Locale('sw'),   // Swahili
  ],
  assetPath: 'assets/translations',
  downloadedPath: 'translations',
  child: const MyApp(),
);

When the app locale matches one of the built-in delegates (e.g. ha for Hausa), date pickers, buttons, and other Flutter widgets will display labels in that language.

Adding New Delegates #

To add a new language delegate, use the delegate generator tool:

dart tool/create_delegate.dart tool/sample_delegate.json

Provide a JSON file following the structure in tool/sample_delegate.json. The script generates all delegate files and automatically updates lib/src/delegates/delegates.dart. See tool/README.md for the JSON format and available keys.

Advanced Usage #

Custom Localization Setup #

For more control (e.g., manual locale switching without PWLocalizationProvider), use the service and delegate directly:

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    final localizationService = PWLocalizationService.instance;

    return AnimatedBuilder(
      animation: localizationService,
      builder: (context, _) {
        final locale = localizationService.currentLocale ?? const Locale('en');
        const supported = [Locale('en'), Locale('es'), Locale('zh', 'CN')];

        return MaterialApp(
          home: const HomePage(),
          localizationsDelegates: PWLocalizationDelegate.getConfiguredDelegates(
            instance: localizationService,
            locale: locale,
            supportedLocales: supported,
            assetPath: 'assets/translations',
            downloadedPath: 'translations',
            defaultLocaleTag: 'en',
          ),
          supportedLocales: supported,
          locale: locale,
        );
      },
    );
  }
}

Dynamic Locale Switching #

// Access the localization service (works with both PWLocalizationProvider and custom setup)
final localization = PWLocalizationProvider.of(context);

// Optionally download new language files first
await PWLocalizationService.instance.downloadLanguageFiles(
  'https://api.example.com/translations',
  ['es'],
);

// Switch locale (re-initializes with new locale)
await localization.initialize(
  assetPath: 'assets/translations',
  downloadedPath: 'translations',
  defaultLanguage: 'en', // BCP-47 tag, lowercased internally
  locale: const Locale('es'),
);

When using AnimatedBuilder with the service, locale changes will trigger a rebuild and the delegate will load the new locale.

BCP-47 Locale Tags (e.g. zh-CN) #

This package stores and looks up translations by lowercased BCP-47 locale tags such as en, id, zh-CN (not by languageCode only).

  • Assets/downloads are resolved as {localeTag}.json (e.g. assets/translations/zh-CN.json)
  • Backward compatibility: if {localeTag}.json is missing, it may fall back to {languageCode}.json (e.g. zh.json) for legacy projects.

Example download:

await PWLocalizationService.instance.downloadLanguageFiles(
  'https://api.example.com/translations',
  ['en', 'es', 'fr', 'zh-CN'],
);

Error Handling #

try {
  await PWLocalizationService.instance.initialize(
    assetPath: 'assets/translations',
    downloadedPath: 'translations',
    defaultLanguage: 'en',
    locale: const Locale('en'),
  );
} catch (e) {
  // Handle initialization errors
  print('Localization initialization failed: $e');
}

Translation File Structure #

Your translation files should be JSON files with the following structure:

{
  "welcome": {
    "title": "Welcome",
    "message": "Hello {name}!",
    "items": {
      "count": {
        "zero": "No items",
        "one": "One item",
        "many": "{count} items",
        "other": "{count} items"
      }
    }
  },
  "items_count_icu": "{count, plural, =0{No items} =1{One item} =2{Two items} few{Few items} many{Many items} other{{count} items}}",
  "common": {
    "ok": "OK",
    "cancel": "Cancel",
    "loading": "Loading..."
  }
}

You can use either:

  • Object-based plurals: Nested objects with zero, one, many, other, etc.
  • ICU message format: Direct string values with ICU plural syntax

Best Practices #

  1. Key Naming: Use descriptive, hierarchical keys (e.g., welcome.title instead of welcomeTitle)
  2. Fallback Strategy: Always provide fallback translations in your default language
  3. ICU Formatting: Use ICU message format for complex pluralization and gender rules
  4. Asset Organization: Keep translation files organized in assets/translations/ directory
  5. Error Handling: Implement proper error handling for network failures when downloading translations

License #

This project is licensed under the MIT License - see the LICENSE file for details.

0
likes
70
points
401
downloads

Documentation

API reference

Publisher

verified publisherpipwave.com

Weekly Downloads

Powerful and flexible localization package for Pipwave Flutter projects, featuring ICU message formatting, runtime locale switching, asset and dynamic translation file support.

Homepage

License

ISC (license)

Dependencies

dio, flutter, flutter_localizations, intl, path_provider

More

Packages that depend on flutter_pipwave_localization