localization_gen 2.3.1
localization_gen: ^2.3.1 copied to clipboard
Type-safe Flutter localization generator from JSON/JSONC, with nested keys, placeholders, and plural/gender/context variants.
Localization Generator #
Type-safe localization code generator for Flutter applications using nested JSON files.
Overview #
Generate type-safe, nested localization code from JSON files with compile-time checking, parameter interpolation, and strict validation support.
Repository: https://github.com/alpinnz/localization_gen
Features #
- Type-Safe: Compile-time checking of translation keys
- Nested Structure: Organize translations hierarchically (up to 10 levels)
- Watch Mode: Auto-regenerate on file changes
- Parameter Support: Named parameters with type checking
- Strict Validation: Ensure consistency across all locales
- Field Rename: Support multiple naming conventions (snake_case, kebab-case, etc.)
- Modular Organization: Feature-based file structure
- Monorepo Support: Multiple packages with independent localization
Installation #
Add to your pubspec.yaml:
dev_dependencies:
localization_gen: ^2.1.0
dependencies:
flutter_localizations:
sdk: flutter
Install dependencies:
dart pub get
Quick Start #
1. Configuration #
Add configuration to pubspec.yaml:
localization_gen:
input_dir: assets/localizations
output_dir: lib/assets
class_name: AppLocalizations
# Optional (defaults shown)
file_pattern: app_{module}_{locale}.json
file_prefix: app
# Optional (default: camel)
# JSON keys are recommended to be snake_case (e.g. welcome_user)
# Generated Dart API becomes camelCase (e.g. welcomeUser)
field_rename: camel # none, kebab, snake, pascal, camel, screamingSnake
2. Create JSON Files (modular-only) #
This package is modular-only. Every file MUST include:
@@locale@@module
Canonical spec:
.jsonc(commented, developer-readable). Generator input:.json(strict JSON).
Create assets/localizations/app_common_en.json:
{
"@@locale": "en",
"@@module": "common",
"strings": { "app_title": "Demo App" },
"simple": { "hello": "Hello" },
"placeholders": { "welcome_user": "Welcome, {name}." }
}
Create assets/localizations/app_common_id.json:
{
"@@locale": "id",
"@@module": "common",
"strings": { "app_title": "Aplikasi Demo" },
"simple": { "hello": "Halo" },
"placeholders": { "welcome_user": "Selamat datang, {name}." }
}
Supported Cases (CASE 1–15) #
The canonical dataset lives in this repository under:
assets/localizations/app_common_en.jsoncassets/localizations/app_common_id.jsonc
The dataset is designed to cover the most common localization cases, each appearing once:
@@localemetadata@@modulemetadata- Basic strings (namespace:
strings.*) - Nested keys (flattened dot-keys; recommended max depth 6)
- Placeholders
{name}(named parameters) - Multiple placeholders in one message
- Placeholder reordering across locales
- Per-key metadata (inline-only)
- Inline:
@description,@example,@placeholders, plus custom@<name> - For string keys with metadata: wrap using
@value
- Inline:
- Newline escaping (
\n) - Quote escaping (
\") - Unicode punctuation
- Symbols inside strings (URLs/email/bullets/legal marks)
- Literal tokens that are not placeholders (e.g.
{{...}},[x]) - Literal braces
{and} - Structured forms:
@plural,@gender,@context
If you need a working .json dataset for generation, mirror the JSONC structure into .json files (remove comments).
Development Commands #
Use full commands (cross-platform):
# Install
dart pub get
# Quality
dart format .
dart analyze
dart test
# Flutter (if you want to run the example app tests)
flutter test
# Generate once
dart run localization_gen generate
# Generate (watch mode)
dart run localization_gen generate --watch
# Validate
dart run localization_gen validate
# Clean generated output
dart run localization_gen clean
# Coverage
dart run localization_gen coverage
4. Setup Flutter App #
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'assets/app_localizations.gen.dart';
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
localizationsDelegates: [
AppLocalizationsExtension.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
GlobalCupertinoLocalizations.delegate,
],
supportedLocales: AppLocalizations.supportedLocales,
home: HomePage(),
);
}
}
5. Use Translations #
class HomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
// JSON: strings.app_title
// Dart: strings.appTitle
title: Text(AppLocalizations.of(context).strings.appTitle),
),
body: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// JSON: simple.hello
Text(AppLocalizations.of(context).simple.hello),
// JSON: placeholders.welcome_user
Text(AppLocalizations.of(context).placeholders.welcomeUser(name: 'John')),
// Runtime lookup (no placeholder interpolation; use typed API for placeholders)
Text(AppLocalizations.of(context).resolveByKey('strings.app_title', fallback: '<missing>') ?? '<missing>'),
Text(AppLocalizations.of(context).resolveByKey('app_title', namespace: 'strings', fallback: '<missing>') ?? '<missing>'),
],
),
);
}
}
Commands #
Generate #
# Generate once
dart run localization_gen generate
# Watch mode (auto-regenerate on changes)
dart run localization_gen generate --watch
Initialize #
# Create directory structure and sample files
dart run localization_gen init
Validate #
# Validate JSON files
dart run localization_gen validate
Clean #
# Remove generated files
dart run localization_gen clean
Coverage #
# Generate coverage report
dart run localization_gen coverage
# HTML format
dart run localization_gen coverage --format=html --output=coverage.html
Configuration Options #
localization_gen:
# Required
input_dir: assets/localizations
# Optional (defaults shown)
output_dir: lib/assets
class_name: AppLocalizations
# Optional: control naming of generated Dart identifiers (default: camel)
field_rename: camel
# Optional: modular file naming (defaults shown)
file_pattern: app_{module}_{locale}.json
file_prefix: app
Mandatory behavior (not configurable) #
This package always enforces the following:
- BuildContext access is always available:
AppLocalizations.of(context)is generated. - Non-nullable access:
of(context)returns a non-null instance. - Modular-only input: every file must include
@@localeand@@module. - Strict validation is always enabled: keys and placeholders must match across locales.
Field Rename Options #
Control how JSON keys are converted to Dart identifiers:
- none: Keep original naming
- kebab: user-name
- snake: user_name
- pascal: UserName
- camel: userName (default)
- screamingSnake: USER_NAME
Example:
localization_gen:
field_rename: camel
JSON:
{
"userProfile": {
"firstName": "First Name"
}
}
Generated (with camelCase):
AppLocalizations.of(context).userProfile.firstName;
Advanced Features #
Parameter Interpolation #
{
"greeting": "Hello, {name}!",
"items": "You have {count} items"
}
AppLocalizations.of(context).greeting(name: 'John');
AppLocalizations.of(context).items(count: '5');
Pluralization #
{
"items": {
"@plural": {
"zero": "No items",
"one": "One item",
"other": "{count} items"
}
}
}
Gender Forms #
{
"greeting": {
"@gender": {
"male": "Hello Mr. {name}",
"female": "Hello Ms. {name}",
"other": "Hello {name}"
}
}
}
Context Forms #
{
"invitation": {
"@context": {
"formal": "We cordially invite you",
"informal": "Come join us"
}
}
}
Nested Structure (10 Levels) #
{
"level1": {
"level2": {
"level3": {
"message": "Deeply nested translation"
}
}
}
}
AppLocalizations.of(context).level1.level2.level3.message;
Watch Mode #
dart run localization_gen generate --watch
Automatically regenerates code when JSON files change.
Strict Validation #
Strict validation is always enabled (no configuration needed).
Modular Organization #
This package is modular-only. File naming follows:
app_{module}_{locale}.json
Recommended file structure:
assets/localizations/
app_common_en.json
app_common_id.json
Files are merged by locale.
Examples #
See the example/ directory:
- example/ - Canonical example app
Migration Guide #
From v1.0.3 to v1.0.4+ #
Named parameters are now required:
// Before
AppLocalizations.of(context).welcome('John');
// After
AppLocalizations.of(context).welcome(name: 'John');
Troubleshooting #
Generated file not found #
By default the generator writes:
lib/assets/<class_name in snake_case>.gen.dart
If you override output_dir, adjust your imports accordingly.
Newline (\n) handling #
In JSON there is an important difference:
"Line 1\nLine 2"produces a real newline character at runtime."Line 1\\nLine 2"produces the two characters\andn(literal backslash-n).
The generator preserves the parsed string value. If you want a real newline in the UI, store \n (single backslash) in JSON.
Best Practices #
- Prefer direct access:
AppLocalizations.of(context).<namespace>.<key> - Group related translations in nested structure
- Use descriptive parameter names
- Strict validation is always enabled
- Use watch mode during development
- Consider modular organization for large apps
Contributing #
Contributions welcome! See CONTRIBUTING.md
License #
MIT License - see LICENSE
Links #
- Pub.dev: https://pub.dev/packages/localization_gen
- GitHub: https://github.com/alpinnz/localization_gen
- Issues: https://github.com/alpinnz/localization_gen/issues
- Changelog: https://github.com/alpinnz/localization_gen/blob/master/CHANGELOG.md
- Documentation: https://github.com/alpinnz/localization_gen