Localization Generator

Type-safe localization code generator for Flutter applications using nested JSON files.

Pub Version License

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: ^1.1.0

dependencies:
  flutter_localizations:
    sdk: flutter

Install dependencies:

dart pub get
# or
make install

Quick Start

1. Configuration

Add configuration to pubspec.yaml:

localization_gen:
  input_dir: assets/localizations
  output_dir: lib/assets
  class_name: AppLocalizations
  strict_validation: true
  field_rename: snake  # none, kebab, snake, pascal, camel, screamingSnake

2. Create JSON Files

Create assets/localizations/app_en.json:

{
  "@@locale": "en",
  "app": {
    "title": "My App",
    "welcome": "Welcome, {name}!"
  },
  "auth": {
    "login": {
      "title": "Login",
      "email": "Email",
      "password": "Password"
    }
  }
}

Create assets/localizations/app_id.json:

{
  "@@locale": "id",
  "app": {
    "title": "Aplikasi Saya",
    "welcome": "Selamat datang, {name}!"
  },
  "auth": {
    "login": {
      "title": "Masuk",
      "email": "Email",
      "password": "Kata Sandi"
    }
  }
}

3. Generate Code

dart run localization_gen
# or
make generate

Development Commands

This project includes a Makefile for common development tasks. Run make help to see all available commands.

# Development
make install          # Install dependencies
make test             # Run all tests
make test-file        # Run specific test file (FILE=path/to/test.dart)
make test-examples    # Run tests for all examples
make analyze          # Run dart analyze
make format           # Format all code
make format-check     # Check code formatting
make lint             # Run linter
make check            # Run all checks (analyze + format + test)
make coverage         # Generate test coverage report
make watch            # Run tests in watch mode

# Localization
make generate         # Generate localization (for testing)
make generate-watch   # Generate localization in watch mode
make validate         # Validate localization files

# Examples
make example-basic    # Run basic example
make example-modular  # Run modular example
make examples-setup   # Setup all examples

# Cleanup
make clean            # Remove build artifacts
make clean-all        # Deep clean (including cache)

# Publishing
make publish-dry      # Dry run publication
make publish          # Publish to pub.flutter-io.cn

# Maintenance
make update           # Update dependencies
make info             # Show package information
make check-release    # Check if ready for release

# Shortcuts
make all              # Run install + check
make run-all          # Run complete test suite (all + examples)

4. Setup Flutter App

import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
import 'assets/app_localizations.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) {
    final appLocalizations = AppLocalizations.of(context);
    
    return Scaffold(
      appBar: AppBar(
        title: Text(appLocalizations.app.title),
      ),
      body: Column(
        children: [
          Text(appLocalizations.app.welcome(name: 'John')),
          Text(appLocalizations.auth.login.title),
        ],
      ),
    );
  }
}

Commands

Generate

# Generate once
dart run localization_gen

# Watch mode (auto-regenerate on changes)
dart run localization_gen generate --watch

# Custom config file
dart run localization_gen generate --config=custom_pubspec.yaml

Initialize

# Create directory structure and sample files
dart run localization_gen init

# With options
dart run localization_gen init --locales=en,es,id --strict

Validate

# Validate JSON files
dart run localization_gen validate

Clean

# Remove generated files
dart run localization_gen clean
# or
make clean

Coverage

# Generate coverage report
dart run localization_gen coverage
# or
make coverage

# HTML format
dart run localization_gen coverage --format=html --output=coverage.html

Configuration Options

localization_gen:
  # Required: Input directory containing JSON files
  input_dir: assets/localizations
  
  # Optional: Output directory for generated code (default: lib/assets)
  output_dir: lib/assets
  
  # Optional: Generated class name (default: AppLocalizations)
  class_name: AppLocalizations
  
  # Optional: Generate static of(context) method (default: true)
  use_context: true
  
  # Optional: Make of(context) return nullable (default: false)
  nullable: false
  
  # Optional: Enable strict validation (default: false)
  strict_validation: true
  
  # Optional: Field naming convention (default: none)
  # Options: none, kebab, snake, pascal, camel, screamingSnake
  field_rename: snake
  
  # Optional: Modular file organization (default: false)
  modular: false
  
  # Optional: File pattern for modular mode
  file_pattern: app_{module}_{locale}.json
  
  # Optional: File prefix for modular mode
  file_prefix: app

Field Rename Options

Control how JSON keys are converted to Dart identifiers:

  • none: Keep original naming (default)
  • kebab: user-name
  • snake: user_name
  • pascal: UserName
  • camel: userName
  • screamingSnake: USER_NAME

Example:

localization_gen:
  field_rename: snake

JSON:

{
  "userProfile": {
    "firstName": "First Name"
  }
}

Generated (with snake_case):

appLocalizations.user_profile.first_name

Advanced Features

Parameter Interpolation

{
  "greeting": "Hello, {name}!",
  "items": "You have {count} items"
}
appLocalizations.greeting(name: 'John');
appLocalizations.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.level1.level2.level3.message;

Watch Mode

dart run localization_gen generate --watch

Automatically regenerates code when JSON files change.

Strict Validation

localization_gen:
  strict_validation: true

Ensures all locales have:

  • Same translation keys
  • Same parameter names
  • Consistent structure

Modular Organization

localization_gen:
  modular: true
  file_prefix: app

File structure:

assets/localizations/
  app_auth_en.json
  app_auth_id.json
  app_home_en.json
  app_home_id.json

Files are automatically merged by locale.

Examples

See the example/ directory:

Migration Guide

From v1.0.3 to v1.0.4+

Named parameters are now required:

// Before
appLocalizations.welcome('John');

// After
appLocalizations.welcome(name: 'John');

Troubleshooting

Generated file not found

Ensure output_dir exists and check file permissions.

Locale not switching

Verify localizationsDelegates and supportedLocales in MaterialApp.

Parameter type mismatch

All parameters are String type. Convert numbers before passing.

Validation errors

Run dart run localization_gen validate for detailed error messages.

Best Practices

  1. Use consistent naming: appLocalizations as variable name
  2. Group related translations in nested structure
  3. Use descriptive parameter names
  4. Enable strict validation in production
  5. Use watch mode during development
  6. Consider modular organization for large apps

Contributing

Contributions welcome! See CONTRIBUTING.md

License

MIT License - see LICENSE

Libraries

localization_gen
Strongly-typed localization generator for Flutter with nested JSON support