🌐 LinguaFlow

AI-powered localization for Flutter apps.

Runtime language switching Β· JSON translations Β· Automatic AI translation of missing keys

pub.dev License: MIT


Features

Feature Status
Runtime language switching βœ…
JSON-based translations βœ…
.tr(context) extension βœ…
Persist selected language βœ…
AI translation of missing keys βœ…
Translation caching βœ…
CLI batch translation generator βœ…
Interactive provider setup wizard βœ…
OpenAI provider βœ…
Google Gemini provider βœ…
Anthropic Claude provider βœ…
NVIDIA NIM provider βœ…
DeepL provider βœ…
LibreTranslate provider (free) βœ…

Installation

dependencies:
  linguaflow: ^0.1.0

Quick Setup

1. Add your JSON translation files

assets/
  lang/
    en.json
    hi.json
    fr.json

en.json

{
  "welcome": "Welcome Back",
  "hello": "Hello",
  "settings": "Settings"
}

2. Declare assets in pubspec.yaml

flutter:
  assets:
    - assets/lang/en.json
    - assets/lang/hi.json
    - assets/lang/fr.json

3. Configure your AI provider

Run the interactive setup wizard once in your project:

dart run linguaflow:setup

It will ask you:

  ── Step 1 β€” Choose your AI provider

  [1]  OpenAI          default: GPT-4.1-mini      Best quality
  [2]  Google Gemini   default: Gemini 2.0 Flash  Fast & cheap
  [3]  Anthropic Claude  default: Haiku 4.5       Balanced
  [4]  DeepL                                      Translation-focused
  [5]  LibreTranslate                             Free & open source

  Enter choice [1–5]: _

  ── Step 2 β€” Enter your API key

  API key: _

  βœ“ Saved to .linguaflow_config.json
  βœ“ Added .linguaflow_config.json to .gitignore

4. Wrap your app

import 'package:linguaflow/linguaflow.dart';

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

  // Reads .linguaflow_config.json saved by `dart run linguaflow:setup`
  final aiProvider =
      await AiProviderFactory.fromConfig() ?? AiProviderFactory.fromEnv();

  runApp(
    LinguaFlowProvider(
      config: const LocaleConfig(
        fallbackLocale: 'en',
        supportedLocales: ['en', 'hi', 'fr'],
      ),
      aiProvider: aiProvider,
      child: const MyApp(),
    ),
  );
}

Usage

Translate a string

Text('welcome'.tr(context))

Switch language at runtime

LinguaFlow.of(context).setLocale('hi');

The selected locale is persisted automatically β€” next app launch restores it.

AI translation for missing keys (async)

FutureBuilder<String>(
  future: 'new_key'.trAsync(context),
  builder: (ctx, snap) => Text(snap.data ?? '...'),
)

Missing keys are automatically:

  1. Translated by AI
  2. Cached to disk
  3. Returned instantly on future calls

Configuring the AI Provider

There are three ways to supply the API key β€” use whichever fits your workflow.

dart run linguaflow:setup

Saves a .linguaflow_config.json that is auto-loaded at runtime and auto-added to .gitignore.

aiProvider: await AiProviderFactory.fromConfig()

No config file needed. The key is baked into the binary at compile time.

# OpenAI
flutter run --dart-define=OPENAI_API_KEY=sk-...

# Google Gemini
flutter run --dart-define=GEMINI_API_KEY=AIza...

# Anthropic Claude
flutter run --dart-define=ANTHROPIC_API_KEY=sk-ant-...

# NVIDIA NIM
flutter run --dart-define=NVIDIA_API_KEY=nvapi-...

# DeepL
flutter run --dart-define=DEEPL_API_KEY=your-key:fx

# LibreTranslate (public server β€” no key needed)
flutter run
aiProvider: AiProviderFactory.fromEnv()

Option C β€” Explicit provider (full control)

// OpenAI
aiProvider: OpenAiProvider(apiKey: 'sk-...')

// Google Gemini
aiProvider: GeminiProvider(apiKey: 'AIza...', model: 'gemini-2.0-flash')

// Anthropic Claude
aiProvider: ClaudeProvider(apiKey: 'sk-ant-...', model: 'claude-haiku-4-5-20251001')

// NVIDIA NIM (LLaMA, Nemotron, Mixtral, and more)
aiProvider: NvidiaProvider(apiKey: 'nvapi-...')
aiProvider: NvidiaProvider(apiKey: 'nvapi-...', model: 'nvidia/llama-3.1-nemotron-70b-instruct')

// DeepL (free tier key ends with :fx)
aiProvider: DeepLProvider(apiKey: 'your-key:fx')

// LibreTranslate β€” free, no key required on public servers
aiProvider: LibreTranslateProvider()

// LibreTranslate β€” self-hosted
aiProvider: LibreTranslateProvider(endpoint: 'http://localhost:5000')

CLI β€” Batch Translation Generator

Generate all translation files from your base JSON in one command:

dart run linguaflow:generate \
  --key=sk-YOUR_OPENAI_KEY \
  --source=assets/lang/en.json \
  --targets=hi,fr,de,es,ja

Output:

[LinguaFlow] Loaded 12 keys from assets/lang/en.json
[LinguaFlow] Translating β†’ Hindi...
[LinguaFlow] βœ“ Saved assets/lang/hi.json
[LinguaFlow] Translating β†’ French...
[LinguaFlow] βœ“ Saved assets/lang/fr.json
[LinguaFlow] Done.

Architecture

lib/
 β”œβ”€β”€ linguaflow.dart               ← Public barrel export
 └── src/
      β”œβ”€β”€ core/
      β”‚    β”œβ”€β”€ locale_manager.dart        ← ChangeNotifier, orchestrates everything
      β”‚    β”œβ”€β”€ translation_store.dart     ← In-memory translation map
      β”‚    β”œβ”€β”€ cache_manager.dart         ← SharedPreferences AI cache
      β”‚    └── constants.dart
      β”œβ”€β”€ models/
      β”‚    └── locale_config.dart         ← Config passed to LinguaFlowProvider
      β”œβ”€β”€ services/
      β”‚    β”œβ”€β”€ ai/
      β”‚    β”‚    β”œβ”€β”€ ai_provider.dart          ← Abstract interface
      β”‚    β”‚    β”œβ”€β”€ ai_provider_factory.dart  ← Factory: config / env / explicit
      β”‚    β”‚    β”œβ”€β”€ openai_provider.dart
      β”‚    β”‚    β”œβ”€β”€ gemini_provider.dart
      β”‚    β”‚    β”œβ”€β”€ claude_provider.dart
      β”‚    β”‚    β”œβ”€β”€ nvidia_provider.dart
      β”‚    β”‚    β”œβ”€β”€ deepl_provider.dart
      β”‚    β”‚    └── libretranslate_provider.dart
      β”‚    β”œβ”€β”€ file_loader.dart           ← Loads JSON from assets
      β”‚    └── storage_service.dart       ← Persists locale choice
      β”œβ”€β”€ extensions/
      β”‚    └── string_extension.dart     ← .tr() / .trAsync()
      β”œβ”€β”€ widgets/
      β”‚    └── linguaflow_provider.dart  ← Root widget + LinguaFlow accessor
      └── cli/
           β”œβ”€β”€ setup.dart               ← dart run linguaflow:setup
           └── generate_translations.dart ← dart run linguaflow:generate

Missing key resolution order

.tr() called
    β”‚
    β–Ό
In-memory store ──found──▢ return translation
    β”‚
   not found
    β–Ό
Persistent cache ──found──▢ warm store β†’ return
    β”‚
   not found
    β–Ό
AI provider ──success──▢ cache + store β†’ return
    β”‚
   fail / no provider
    β–Ό
Fallback locale ──found──▢ return
    β”‚
   not found
    β–Ό
Return raw key

Supported AI Providers

Provider Class Default model API key
OpenAI OpenAiProvider gpt-4.1-mini platform.openai.com
Google Gemini GeminiProvider gemini-2.0-flash aistudio.google.com
Anthropic Claude ClaudeProvider claude-haiku-4-5-20251001 console.anthropic.com
NVIDIA NIM NvidiaProvider meta/llama-3.3-70b-instruct build.nvidia.com (free credits)
DeepL DeepLProvider β€” deepl.com/account
LibreTranslate LibreTranslateProvider β€” Free β€” no key needed

Bring your own provider

Extend AiProvider to plug in any translation backend:

class MyProvider extends AiProvider {
  @override
  Future<String> translate({
    required String text,
    required String targetLanguage,
  }) async {
    // call your API and return translated string
  }
}

License

MIT Β© Ambit Misra

Libraries

linguaflow
LinguaFlow β€” AI-powered localization for Flutter apps.