Smart Localization

A backend-agnostic smart localization system for Flutter. It provides version-controlled translations with intelligent caching, automatic fallback chains, parameterized translations, and device language detection.

Smart Localization Demo

Features

  • Backend-Agnostic: Plug in Firestore, REST API, Supabase, or any other data source.
  • Version-Controlled Translations: Download translations only when they change.
  • Intelligent Caching: SharedPreferences-based caching with version tracking.
  • Fallback Chain: Gracefully degrades from Current Language to Default Language to Provided Text.
  • Parameterized Translations: Support for dynamic values (e.g., Hello {name}).
  • Device Language Detection: Automatically detects device language, including Chinese variants.
  • Flexible Lookups: Supports both ID-based and key-based translation identification.
  • Sync & Async APIs: Provides context.localization() and context.localizationAsync().
  • Built-In Backend: Includes MapTranslationBackend for simple setups and testing.

Installation

Add the following to your pubspec.yaml:

dependencies:
  smart_localization: ^<latest_version>

Quick Start

1. Initialization

Initialize the service before running your app.

import 'package:smart_localization/smart_localization.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  await SmartLocalization.initialize(
    backend: MapTranslationBackend(
      translations: {
        'en': {'home.title': 'My App', 'home.greeting': 'Hello {name}!'},
        'tr': {'home.title': 'Uygulamam', 'home.greeting': 'Merhaba {name}!'},
      },
    ),
  );

  runApp(MyApp());
}

2. Usage in Widgets

Use the provided BuildContext extensions to access translations seamlessly.

// Simple translation
Text(context.localization('My App', id: 'home.title'))

// With parameters
Text(context.localization(
  'Hello {name}!',
  id: 'home.greeting',
  params: {'name': userName},
))

// Async translation (waits for full fallback chain if necessary)
Text(await context.localizationAsync('My App', id: 'home.title'))

3. Switching Language

await SmartLocalization.instance.setLanguage('tr');
setState(() {}); // Rebuild your widgets to reflect the new language

Custom Backend Integration

Implement the TranslationBackend interface to connect your preferred data source.

Example: Firestore Backend

class FirestoreBackend implements TranslationBackend {
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  @override
  Future<TranslationData?> fetchTranslations(String languageCode) async {
    final doc = await _firestore.collection('translations').doc(languageCode).get();
    if (!doc.exists) return null;

    final data = doc.data()!;
    return TranslationData(
      translations: Map<String, String>.from(data['translations']),
      version: data['version'],
      isActive: data['isActive'] ?? true,
    );
  }

  @override
  Future<int> getRemoteVersion() async {
    final doc = await _firestore.collection('translation_metadata').doc('version').get();
    return doc.data()?['currentVersion'] ?? 0;
  }

  @override
  Future<List<String>> getSupportedLanguages() async {
    final doc = await _firestore.collection('translation_metadata').doc('version').get();
    return List<String>.from(doc.data()?['supportedLanguages'] ?? ['en']);
  }
}

Example: REST API Backend

class RestApiBackend implements TranslationBackend {
  final String baseUrl;
  
  RestApiBackend({required this.baseUrl});

  @override
  Future<TranslationData?> fetchTranslations(String languageCode) async {
    final response = await http.get(Uri.parse('$baseUrl/translations/$languageCode'));
    if (response.statusCode != 200) return null;

    final data = jsonDecode(response.body);
    return TranslationData(
      translations: Map<String, String>.from(data['translations']),
      version: data['version'],
    );
  }
}

Configuration Options

You can configure the behavior of SmartLocalization during initialization.

await SmartLocalization.initialize(
  backend: myBackend,
  config: SmartLocalizationConfig(
    defaultLanguage: 'en',
    versionCheckInterval: const Duration(minutes: 5),
    enableLogging: true,
    autoDetectLanguage: true,
  ),
);
Property Type Default Description
defaultLanguage String 'en' The ultimate fallback language.
versionCheckInterval Duration 5 min Minimum interval between version updates.
enableLogging bool false Enables debug console logs.
autoDetectLanguage bool true Automatically detects the device language on startup.

API Reference

SmartLocalization

Method / Property Description
initialize(backend, config) Initializes the service (expected to be called once in main()).
instance Accesses the singleton instance.
translate(text, {id, params}) Synchronous translation lookup.
translateAsync(text, {id, params}) Asynchronous translation with the full fallback chain.
setLanguage(code) Changes the active language and fetches updates if needed.
getSupportedLanguages() Returns a list of supported language codes.
getLanguageName(code) Returns the display name for a specific language code.
checkForUpdates() Manually checks for version updates (respects throttling).
refreshTranslations() Forces a refresh from the remote backend.
clearCache() Clears all cached translation data.
currentLanguage Returns the currently active language code.

BuildContext Extensions

Method Description
context.localization(text, {id, params}) Synchronous translation access.
context.localizationAsync(text, {id, params}) Asynchronous translation access.

Translation Fallback Chain

When a translation is requested, the system attempts to resolve it in the following order:

  1. Current language translation (by ID)
  2. Default language translation (by ID)
  3. Provided fallback text

Requirements

  • Flutter 3.10 or higher
  • Dart 3.0 or higher

License

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

Libraries

smart_localization