toln 0.0.3
toln: ^0.0.3 copied to clipboard
A revolutionary localization library for Flutter that automates the entire workflow, making multi-language support effortless and enjoyable.
toL: Revolutionary Flutter Localization
Zero keys. Zero hassle. Just code.
📖 Read in other languages: فارسی • العربية
🌟 What is toLn? #
toLn is not just another i18n package—it's a complete paradigm shift in Flutter localization. We eliminate the tedious, error-prone workflow of managing translation keys and manual file synchronization. With toLn, your Dart code becomes the single source of truth, and intelligent automation handles everything else.
The Problem We Solve #
Traditional localization is painful:
- 🔑 Inventing and managing hundreds of translation keys
- 📝 Manually updating multiple translation files
- 🔄 Rebuilding UI when language changes
- 🐛 Hunting down typos across dozens of files
- ⚡ Refactoring existing projects to add i18n
The toLn Solution #
// Traditional way❌
Text(AppLocalizations.of(context)!.welcomeMessage)
// The toLn way ✅
Text('Welcome to our app!'.toLn())
That's it. No keys, no context, no boilerplate. Just write your text.
🚀 Key Features #
| Feature | Description |
|---|---|
| 🎯 Zero-Key Workflow | Never invent or manage translation keys again. toLn generates them automatically. |
| 🪄 Auto-Refactor | dart run toln auto-apply automatically adds localization to your entire app. |
| 🧠 Smart Assistant | Detects typos and suggests reusing existing translations. |
| ⚡ Auto UI Update | Language changes trigger automatic UI rebuilds—no setState needed. |
| 🌍 RTL/LTR Auto | Automatic text direction switching for Arabic, Persian, Hebrew, etc. |
| 🔍 Language Discovery | Auto-detects all available languages in your project. |
| 🎨 Custom Names | Display "Español" instead of "ES" in language pickers. |
| 🔧 CLI Tools | Powerful commands: extract, sync, auto-apply, and migrate. |
⚡ Quick Start #
1. Installation #
Add toLn to your pubspec.yaml:
dependencies:
toln: ^0.0.3
Then run:
flutter pub get
2. Initial Setup (New Projects) #
In your main.dart:
import 'package:flutter/material.dart';
import 'package:toln/toln.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await ToLn.init(baseLocale: 'en'); // Your code's language
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return ValueListenableBuilder<Locale>(
valueListenable: ToLn.localeNotifier,
builder: (context, locale, child) {
return MaterialApp(
locale: locale,
builder: (context, child) {
return Directionality(
textDirection: ToLn.currentDirection,
child: child!,
);
},
home: HomePage(),
);
},
);
}
}
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('My Awesome App'.toLn()),
),
body: Center(
child: Text('Welcome to Flutter!'.toLn()),
),
);
}
}
3. Extract Translations #
Run the extractor to generate translation files:
dart run toln extract
This creates assets/locales/base.ln and assets/locales/key_map.ln.
4. Add More Languages #
Copy base.ln to create new language files:
cp assets/locales/base.ln assets/locales/es.ln
cp assets/locales/base.ln assets/locales/fa.ln
Edit each file with translations:
// assets/locales/es.ln
{
"ln_name": "Español",
"keLn1": "Mi Aplicación Increíble",
"keLn2": "¡Bienvenido a Flutter!"
}
5. Update pubspec.yaml #
Add your locale files to assets:
flutter:
assets:
- assets/locales/
🎉 Done! Your app is now fully localized!
🛠️ Advanced Usage #
Language Switcher #
Build a beautiful language picker with zero effort:
AppBar(
title: Text('Settings'.toLn()),
actions: [
FutureBuilder<List<LocaleInfo>>(
future: ToLn.getAvailableLocales(),
builder: (context, snapshot) {
if (!snapshot.hasData) return const SizedBox();
return PopupMenuButton<String>(
icon: const Icon(Icons.language),
tooltip: 'Change Language'.toLn(),
onSelected: (locale) => ToLn.loadLocale(locale),
itemBuilder: (context) => snapshot.data!.map((locale) {
return PopupMenuItem(
value: locale.code,
child: Text(locale.name),
);
}).toList(),
);
},
),
],
)
Dynamic Strings with Variables #
toLn automatically handles string interpolation:
final username = "Maria";
final points = 1250;
Text('Hello, $username!'.toLn())
Text('You have $points points'.toLn())
In your translation files, use $s as a placeholder:
{
"keLn1": "Hello, $s!",
"keLn2": "You have $s points"
}
Spanish translation:
{
"keLn1": "¡Hola, $s!",
"keLn2": "Tienes $s puntos"
}
Manual Key Override #
For rare cases where you want different source texts to use the same translation:
Text('OK'.toLn(key: 'confirm'))
Text('Confirm'.toLn(key: 'confirm'))
Both will use the same translation key.
Integration with Common Widgets #
toLn works seamlessly with all Flutter widgets:
// Text widgets
Text('Simple text'.toLn())
Text('Hello, $name!'.toLn())
// Tooltips
IconButton(
icon: Icon(Icons.save),
tooltip: 'Save changes'.toLn(),
onPressed: () {},
)
// SnackBars
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Item saved successfully!'.toLn())),
);
// Dialogs
AlertDialog(
title: Text('Confirm Delete'.toLn()),
content: Text('Are you sure you want to delete this item?'.toLn()),
actions: [
TextButton(
child: Text('Cancel'.toLn()),
onPressed: () => Navigator.pop(context),
),
TextButton(
child: Text('Delete'.toLn()),
onPressed: () {},
),
],
)
// Input Fields
TextField(
decoration: InputDecoration(
labelText: 'Email Address'.toLn(),
hintText: 'Enter your email'.toLn(),
helperText: 'We will never share your email'.toLn(),
),
)
🔧 CLI Commands #
auto-apply - Automatic Refactoring #
Transform an existing project to use toLn automatically:
dart run toln auto-apply
What it does:
- Scans your entire
lib/directory - Adds
.toLn()to text in widgets likeText,InputDecoration, etc. - Injects
import 'package:toln/toln.dart';where needed - Configures your
main()function with initialization - Runs
extractautomatically
Dry run mode (see changes without modifying files):
dart run toln auto-apply --dry-run
extract - Generate Translation Files #
Scan your code and create/update translation files:
dart run toln extract
Features:
- Finds all
.toLn()calls using static analysis - Generates
base.lnwith all texts - Creates
key_map.lnfor internal mapping - Smart Assistant: Detects typos and similar strings, suggests key reuse
sync - Synchronize Translation Files #
Add missing keys to all language files:
dart run toln sync
What it does:
- Compares all
.lnfiles withbase.ln - Adds missing keys to each language file
- Preserves existing translations
- Perfect for keeping translators up-to-date
migrate - From intl/arb to toLn #
Got an existing project using intl and .arb files? Migrate seamlessly:
dart run toln migrate
What it does:
- Reads your
l10n.yamlconfiguration - Converts
.arbfiles to.lnformat - Refactors all
AppLocalizations.of(context).keycalls to.toLn() - Removes old localization delegates
- Cleans up old files after success
📚 API Reference #
ToLn Class #
ToLn.init()
Initialize the localization system.
static Future<void> init({
required String baseLocale,
String? initialLocale,
})
Parameters:
baseLocale(required): Language of your source code (e.g., 'en', 'fa')initialLocale(optional): Starting language. Defaults to device language orbaseLocale
ToLn.loadLocale()
Change the app's current language.
static Future<void> loadLocale(String newLocale)
Parameters:
newLocale: Language code to switch to (e.g., 'es', 'ar')
Effects:
- Loads the corresponding
.lnfile - Updates text direction
- Triggers automatic UI rebuild via
localeNotifier
ToLn.getAvailableLocales()
Get all available languages in your app.
static Future<List<LocaleInfo>> getAvailableLocales()
Returns: List of LocaleInfo records: ({String code, String name})
Example:
final locales = await ToLn.getAvailableLocales();
// Result: [(code: 'en', name: 'English'), (code: 'es', name: 'Español')]
ToLn.currentDirection
Get the text direction for the current language.
static TextDirection get currentDirection
Returns: TextDirection.rtl or TextDirection.ltr
RTL Languages: ar, fa, he, ur (auto-detected)
ToLn.localeNotifier
ValueNotifier for reactive UI updates.
static final ValueNotifier<Locale> localeNotifier
Usage:
ValueListenableBuilder<Locale>(
valueListenable: ToLn.localeNotifier,
builder: (context, locale, child) {
return MaterialApp(locale: locale, ...);
},
)
Extension Methods #
.toLn()
Translate a string.
extension ToLnExtension on String {
String toLn({String? key})
}
Parameters:
key(optional): Manual translation key override
Examples:
'Hello World'.toLn() // Automatic key
'Goodbye'.toLn(key: 'farewell') // Manual key
'Welcome, $username!'.toLn() // With variables
⚠️ Common Pitfalls #
The const Problem #
Problem: Language changes but UI doesn't update.
Cause: The const keyword tells Flutter the widget never rebuilds.
❌ Incorrect:
home: const HomePage(), // This won't update!
✅ Correct:
home: HomePage(), // Now it can rebuild
Rule: Remove const from any widget containing translatable text or its ancestors.
Forgot to Add Assets #
Problem: App crashes with "Unable to load asset".
Solution: Add locale files to pubspec.yaml:
flutter:
assets:
- assets/locales/
🎯 Real-World Examples #
E-commerce App #
class ProductCard extends StatelessWidget {
final Product product;
@override
Widget build(BuildContext context) {
return Card(
child: Column(
children: [
Image.network(product.imageUrl),
Text(product.name), // Already in your database
Text('${product.price} USD'),
ElevatedButton(
onPressed: () {},
child: Text('Add to Cart'.toLn()),
),
Text('Free shipping on orders over $50!'.toLn()),
],
),
);
}
}
Form Validation #
String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'Email is required'.toLn();
}
if (!value.contains('@')) {
return 'Please enter a valid email'.toLn();
}
return null;
}
TextField(
decoration: InputDecoration(
labelText: 'Email'.toLn(),
errorText: validateEmail(email),
),
)
Settings Screen with Language Picker #
class SettingsScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ListView(
children: [
ListTile(
leading: Icon(Icons.language),
title: Text('Language'.toLn()),
subtitle: FutureBuilder<List<LocaleInfo>>(
future: ToLn.getAvailableLocales(),
builder: (context, snapshot) {
if (!snapshot.hasData) return Text('Loading...'.toLn());
final current = snapshot.data!.firstWhere(
(l) => l.code == ToLn.localeNotifier.value.languageCode,
);
return Text(current.name);
},
),
trailing: Icon(Icons.arrow_forward_ios),
onTap: () => _showLanguagePicker(context),
),
],
);
}
void _showLanguagePicker(BuildContext context) async {
final locales = await ToLn.getAvailableLocales();
showDialog(
context: context,
builder: (context) => AlertDialog(
title: Text('Select Language'.toLn()),
content: Column(
mainAxisSize: MainAxisSize.min,
children: locales.map((locale) {
return RadioListTile<String>(
title: Text(locale.name),
value: locale.code,
groupValue: ToLn.localeNotifier.value.languageCode,
onChanged: (value) {
if (value != null) {
ToLn.loadLocale(value);
Navigator.pop(context);
}
},
);
}).toList(),
),
),
);
}
}
🤝 Contributing #
We welcome contributions! Here's how you can help:
- Report Bugs: Open an issue
- Suggest Features: Share your ideas
- Submit PRs: Fix bugs or add features
- Improve Docs: Help us make documentation better
- Spread the Word: Star the repo ⭐
Development Setup #
git clone https://github.com/IrMaho/toLn.git
cd toLn
flutter pub get
dart test
📄 License #
This project is licensed under the MIT License - see the LICENSE file for details.
🙏 Acknowledgments #
Built with ❤️ by Shogh Shahadat
Special thanks to:
- The Flutter team for an amazing framework
- The Dart analyzer team for powerful AST tools
- All our contributors and users
📞 Support #
- 📧 Email: support@example.com
- 💬 GitHub Issues: Report a problem
- 📖 Documentation: Full docs
Made with ❤️ for the Flutter community