toLn: The Revolutionary Flutter Localization Library
Forget keys. Forget manual setup. Just write your code.
toLn is not just another localization library; it's a complete paradigm shift. We've built an intelligent assistant that handles the entire tedious internationalization workflow, letting you focus on what truly matters: building amazing applications.
Table of Contents
- Table of Contents
- 🚀 The Revolution: What Makes
toLnDifferent? - ✨ Core Features at a Glance
- 🛠️ A Practical Walkthrough: Localizing an App in 5 Minutes
- ⚙️ The
toLnWorkflow - 📚 Deep Dive: API & CLI Reference
- ⚠️ The
constTrap: A Crucial Note - 💖 Contributing
- 📄 License
🚀 The Revolution: What Makes toLn Different?
Traditional localization is a nightmare of key management, manual file updates, and constant human error. toLn eliminates all of it. We believe your code should be the single source of truth.
| Feature | The Old Way (The Pain) | The toLn Way (The Magic) |
|---|---|---|
| Adding New Text | 1. Invent a key. 2. Open en.json. 3. Add the key. 4. Open fa.json. 5. Add it again... |
Write Text('Hello World'.toLn()). That's it. |
| Refactoring a Project | Impossible. You have to manually add localization to every string. | dart run toln auto-apply. The library intelligently refactors your entire codebase for you. |
| Fixing a Typo | Find the key, update it in all translation files, hope you didn't miss one. | Just fix the text in your code. Our Smart Assistant detects it and offers to reuse the old key. |
| Syncing Translations | Manually compare JSON files to find what's missing. | dart run toln sync. All missing keys are added to your translation files automatically. |
| Updating the UI | Use setState or complex state management solutions to trigger a rebuild. |
Fully Automatic. The UI rebuilds itself instantly when the language changes. |
✨ Core Features at a Glance
- ✅ Zero-Key Workflow: You will never have to invent or manage a translation key again.
- 🪄 Intelligent
auto-apply: Automatically refactors your existing unlocalized project to usetoLnwith a single command. - 🧠 Smart Assistant: Detects typos and corrections, suggesting to reuse existing translations to save you work.
- 🔄 Automatic UI Updates: The UI instantly updates on locale change with zero manual
setStatecalls, powered byValueNotifier. - 🌍 Automatic Text Direction: Switches between LTR and RTL layouts automatically based on the current language.
- ⚙️ Fully Automated CLI: A powerful command-line interface to
extract,sync, andauto-applytranslations. - 🌐 Dynamic Language Discovery: Automatically finds all available languages in your project to build language selection menus effortlessly.
- 💅 Customizable Language Names: Use the optional
ln_namekey in your files to give languages beautiful display names (e.g., "فارسی" instead of "FA").
🛠️ A Practical Walkthrough: Localizing an App in 5 Minutes
Let's take a real-world app and make it multilingual.
Step 1: The Unlocalized App
Imagine you have this simple Flutter page. It's written in English and has no localization.
// lib/main.dart (Before toLn)
import 'package:flutter/material.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'My App',
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage({super.key});
@override
Widget build(BuildContext context) {
final String username = "Maria";
return Scaffold(
appBar: AppBar(
title: Text("Home Page"),
),
body: Center(
child: Text("Welcome, ${username}!"),
),
);
}
}
Step 2: The Magic auto-apply Command
Open your terminal in the project root and run the single magic command:
dart run toln auto-apply
Step 3: The Generated Files
toLn has now performed several actions:
- Modified your code: It added
.toLn(),import, and theToLn.init()call. - Ran
extract: It scanned the modified code and created files inassets/locales/.
Your main.dart now looks like this:
// lib/main.dart (After toLn)
import 'package:flutter/material.dart';
import 'package:toln/toln.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await ToLn.init(baseLocale: 'en'); // 'en' is the language of your code
runApp(const MyApp());
}
// ... (MyApp is now wrapped in a ValueListenableBuilder)
class MyHomePage extends StatelessWidget {
// ...
@override
Widget build(BuildContext context) {
final String username = "Maria";
return Scaffold(
appBar: AppBar(
title: Text("Home Page".toLn()),
),
body: Center(
child: Text("Welcome, ${username}!".toLn()),
),
);
}
}
And your assets/locales/base.ln file has been created:
{
"ln_name": "",
"keLn1": "My App",
"keLn2": "Home Page",
"keLn3": "Welcome, $s!"
}
Step 4: Translating
- Copy
base.lnand rename it toes.lnfor Spanish. - Fill in the translations and the display name.
// assets/locales/es.ln
{
"ln_name": "Español",
"keLn1": "Mi Aplicación",
"keLn2": "Página de Inicio",
"keLn3": "¡Bienvenida, $s!"
}
Step 5: Making it Interactive
Now, let's add a language switcher to the AppBar. toLn makes this incredibly easy.
// In your MyHomePage build method, inside the AppBar
actions: [
FutureBuilder<List<LocaleInfo>>(
future: ToLn.getAvailableLocales(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const SizedBox();
return PopupMenuButton<String>(
icon: const Icon(Icons.language),
onSelected: ToLn.loadLocale, // Magic! No setState needed.
itemBuilder: (context) => snapshot.data!
.map((locale) => PopupMenuItem(value: locale.code, child: Text(locale.name)))
.toList(),
);
},
),
],
That's it! You now have a fully localized app with an automatic UI and a dynamic language menu.
⚙️ The toLn Workflow
toLn is designed to be a complete workflow, not just a library.
dart run toln auto-apply: Run this once on your project to make it localization-ready. It will automatically runextractfor you afterwards.dart run toln extract: Run this whenever you add or change texts in your UI to update yourbase.lnfile.dart run toln sync: Run this afterextractto add the new keys to all your other language files (fa.ln,de.ln, etc.), ready for translation.
📚 Deep Dive: API & CLI Reference
Here is a detailed breakdown of every component of the toLn ecosystem.
The ToLn Class
This is the main class that manages the localization state.
static Future<void> init({required String baseLocale, String? initialLocale})
The most important method. It sets up the entire library.
baseLocale: (Required) The language code of the text in your source code (e.g., 'en', 'fa').initialLocale: (Optional) The language to load at startup. If not provided,toLnwill intelligently try to use the device's system language. If the system language isn't available, it falls back to yourbaseLocale.
static Future<void> loadLocale(String newLocale)
Changes the app's current language.
newLocale: The language code to switch to (e.g., 'fa', 'de').- How it works: This method loads the corresponding
.lnfile, updates the text direction, and notifies all listeners viaToLn.localeNotifierto trigger an automatic UI rebuild.
static Future<List<LocaleInfo>> getAvailableLocales()
Automatically scans your assets/locales/ directory and returns a list of all available languages.
- Returns: A
ListofLocaleInfoobjects.LocaleInfois a record defined as({String code, String name}). code: The language code from the filename (e.g., 'en').name: The display name from theln_namekey inside the file. Ifln_nameis missing or empty, it defaults to the capitalized language code (e.g., 'EN').
static TextDirection get currentDirection
A static getter that returns the correct TextDirection (TextDirection.rtl or TextDirection.ltr) for the currently active locale.
static final ValueNotifier<Locale> localeNotifier
The engine behind automatic UI updates. You can wrap your MaterialApp (or any part of your UI) in a ValueListenableBuilder listening to this notifier. When loadLocale is called, this notifier fires, and your UI rebuilds with the new translations.
The .toLn() Extension Method
This is the method you will use most often.
String toLn({String? key})
- How it works: When called on a
String, it uses theToLnsingleton to find the correct translation for the current language. It intelligently handles strings with and without variables. key: (Optional) A manual key (e.g., 'keLn5'). This is for the rare case where you want two different source texts to point to the same translation key.
The Command-Line Interface (CLI)
The CLI is your intelligent assistant for managing translation files.
dart run toln auto-apply
The most powerful command. It analyzes your entire project and intelligently refactors it for localization.
- What it does:
- Adds
.toLn()to string literals inside common display widgets (Text,Tooltip, etc.) andInputDecorationproperties. - Automatically adds
import 'package:toln/toln.dart';to any file it modifies. - Checks your
main()function and ensures it isasyncand containsWidgetsFlutterBinding.ensureInitialized()andToLn.init(). - After it finishes, it automatically runs the
extractcommand to generate your translation files.
- Adds
- Options:
--dry-run: Shows a report of what would be changed without actually modifying any files.
dart run toln extract
Scans your project for all .toLn() calls and generates/updates the base.ln and key_map.ln files.
- Smart Assistant: If it finds a new string that is very similar to an existing one (e.g., you fixed a typo), it will ask you if you want to reuse the old key, saving your existing translations.
dart run toln sync
Synchronizes all your translation files (fa.ln, de.ln, etc.) with your master base.ln file.
- What it does: It finds any keys that exist in
base.lnbut are missing in your other language files and adds them. The value will be the original text frombase.ln, making it easy for you or your translator to find and translate new texts.
⚠️ The const Trap: A Crucial Note
Problem: My language changes, but the text on the screen doesn't!
This is almost always caused by the const keyword. When you declare a widget as const, you are telling Flutter: "This widget is immutable and will never need to be rebuilt."
When toLn changes the language, it needs to rebuild your UI. If it encounters a const widget in its path, it stops, and your old text remains.
Incorrect:
// This will NOT update when the language changes!
home: const MyAwesomePage(),
Correct:
// Now Flutter is allowed to rebuild the page.
home: MyAwesomePage(),
Rule of thumb: If a widget or any of its children contains text that needs to be translated, do not use const on it or its parents in the build method.
💖 Contributing
We have built toLn to be a game-changer, but we are just getting started. Contributions, issues, and feature requests are welcome! Feel free to check our issues page.
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.