i18n_flutter 0.2.3
i18n_flutter: ^0.2.3 copied to clipboard
A blazing fast, cross-platform i18n SDK powered by Rust and Flutter.
i18n_flutter 🚀 #
A blazing fast, zero-lookup Internationalization (i18n) engine for Flutter, powered by a native Rust core.
i18n_flutter binds the same I18NEngine Rust engine that powers @encheco/i18n for Node.js directly into your Flutter app, via flutter_rust_bridge. Translations are compiled once into an AST inside Rust, so every t() call is a direct, synchronous, zero-lookup render — no JSON parsing or regex on the hot path.
Table of Contents #
- Features
- Installation
- Supported Platforms
- Quick Start
- Diagnostics & Debugging
- Pluralization
- API Reference
- How It Works (The Rust Core)
- License
✨ Features #
- Blazing Fast (Zero-Lookup): Translation strings are compiled into memory tokens via a Rust AST the first time a bundle is added — no regex or string manipulation at render time.
- Native Rust Core: Runs through
flutter_rust_bridge, calling into the sameI18NEngineRust engine used by the Node.js/WASM version of this library — same core, consistent behavior across platforms. - Fully Synchronous API: Once the bridge is initialized,
t(),addBundle(),setLocale()and friends are plain synchronous Dart calls — noFuture/awaitin your widget tree. - Native Plurals: CLDR-compliant pluralization resolved entirely inside the Rust core, covering all six plural categories (
zero,one,two,few,many,other) across 60+ locales. - Built-in Diagnostics: Toggle debug mode to catch missing keys, and pull a memory report of every cached bundle straight from the Rust backend.
- Lightweight Surface: A small, focused API — create an engine, register bundles, translate. No codegen step, no build-time schema generation required.
📦 Installation #
flutter pub add i18n_flutter
Or add it manually to your pubspec.yaml:
dependencies:
i18n_flutter: ^0.2.3
The package ships with prebuilt Rust bindings wired up through flutter_rust_bridge — no local Rust toolchain is required to consume it.
🛠️ Post‑Install Setup #
Since this package uses a high‑performance pre‑compiled Rust core, you must run the following setup script after installation.
This will automatically fetch the correct native binaries (and WebAssembly files) for your target platform:
dart run i18n_flutter:setup
🖥️ Supported Platforms #
| Platform | Support |
|---|---|
| Android | ✅ |
| iOS | ✅ |
| Linux | ✅ |
| macOS | ✅ |
| Windows | ✅ |
| Web | ✅ |
🚀 Quick Start #
Before using the engine, initialize the Rust bridge once — typically in main():
import 'package:flutter/material.dart';
import 'package:i18n_flutter/src/rust/frb_generated.dart';
import 'package:i18n_flutter/src/rust/api/engine.dart';
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await RustLib.init();
runApp(const MyApp());
}
Once initialized, create an engine, register a bundle, and translate:
final engine = I18NEngine(defaultLocale: 'en', fallbackLocale: 'en');
engine.addBundle(
locale: 'en',
namespace: 'home',
jsonString: '{"welcome": "Hello {name}"}',
);
final greeting = engine.t(
namespace: 'home',
key: 'welcome',
argsJson: '{"name": "Arsalan"}',
);
print(greeting); // "Hello Arsalan"
Switch the active locale at any time:
engine.setLocale(locale: 'fa');
RustLib.init()only needs to be called once per app lifecycle, before the firstI18NEngineis created.
🩺 Diagnostics & Debugging #
Enable debug mode to catch missing translation keys, and print a memory report of everything cached in the Rust backend:
engine.setDebugMode(enabled: true);
print(engine.diagnostics());
🔢 Pluralization #
Plural resolution runs entirely inside the Rust core — given a locale and a count embedded in your translation string, the engine resolves the correct CLDR category: zero, one, two, few, many, or other. There's no JSON plural table to maintain and no runtime ICU parsing on the Dart side — the rule for each locale is compiled straight into the native binary.
Locale matching uses the language subtag only (e.g. en-US and en-GB both resolve as en), so regional variants are covered automatically.
Locale coverage #
| Category rule | Locales |
|---|---|
| No plural distinction beyond one/zero | fa ja ko zh vi th id ms my km lo dz ig yo |
Germanic / Romance (one = 1 only) |
en de es it nl sv da no nn nb bg el fi hu et ca eo fo gl sw ur |
one covers 0–2 (French-style) |
fr pt-br hi am bn gu mr pa zu |
| Arabic — full 6-category system | ar |
| East Slavic | ru uk be |
| Polish | pl |
| West Slavic | cs sk |
| Romanian / Moldavian | ro mo |
| South Slavic | hr sr bs sh |
| Slovenian | sl |
| Hebrew | he iw |
| Lithuanian | lt |
| Latvian | lv |
| Welsh | cy |
| Irish | ga |
| Icelandic / Macedonian | is mk |
| Any other locale | Falls back to a simple one (n = 1) / other split |
Example #
engine.addBundle(
locale: 'ar',
namespace: 'cart',
jsonString:
'{"items": "{count, plural, zero {سبد خالی است} one {یک محصول} two {دو محصول} few {# محصول} many {# محصول} other {# محصول}}"}',
);
// engine.t(namespace: 'cart', key: 'items', argsJson: '{"count": 2}')
// resolves the correct branch for the active locale's CLDR category.
The exact plural-message syntax (e.g. ICU-style
{count, plural, ...}) is handled by the template compiler — pass whichevercountyour bundle expects, and the Rust core resolves the correct branch for the active locale.
📚 API Reference #
| Member | Description |
|---|---|
I18NEngine({required String defaultLocale, String? fallbackLocale}) |
Creates a new engine instance. |
.setLocale({required String locale}) |
Switches the engine's active locale. |
.addBundle({required String locale, required String namespace, required String jsonString}) |
Registers a namespace's translations for a locale from a JSON string. |
.t({required String namespace, required String key, String? argsJson}) |
Renders a translation, optionally interpolating a JSON-encoded args object. |
.setDebugMode({required bool enabled}) |
Toggles verbose logging for missing keys. |
.diagnostics() |
Returns a string report of cached bundles/keys in the Rust backend. |
RustLib.init() |
Initializes the native Rust bridge. Call once, before creating an I18NEngine. |
⚙️ How It Works (The Rust Core) #
Unlike traditional i18n libraries that parse JSON and run string replacements on every render, i18n_flutter uses a custom Rust parser to convert translation strings into an AST (Abstract Syntax Tree) the first time a bundle is added via addBundle().
These tokens are cached inside the I18NEngine Rust struct. When a translation is requested via .t(), the call crosses the Dart↔Rust bridge and the engine directly renders the pre-compiled tokens — bypassing string lookups and regex entirely, whether running natively on Android/iOS/desktop.
This is the same engine used by @encheco/i18n on the Node.js/WebAssembly side, so translation behavior stays consistent if you share a backend or SSR layer with a JavaScript app.
📄 License #
MIT