translations_code_gen 1.3.6
translations_code_gen: ^1.3.6 copied to clipboard
An application to generate translations keys and values for a dart/flutter application from .json file.
Translations code generator #
This is a simple tool to generate the translations code for the Dart/Flutter projects.
Install #
1. Add the dependency #
dependencies:
translations_code_gen: ^1.3.4
2. Run this commend #
flutter pub get
Usage #
1. Create a translations files in assets folder #
Create a folder called assets in the root of your project and create a file called en.json and ar.json and add the following content:
example: assets/translations/en.json
{
"GENERAL": {
"HELLO": "Hello",
"WELCOME": "Welcome",
"WELCOME_USER": "Welcome {name}!",
"GREETING_WITH_TIME": "Good {timeOfDay}, {name}!"
},
"HOME": {
"TITLE": "Home"
},
"MESSAGES": {
"SIMPLE_MESSAGE": "This is a simple message",
"USER_PROFILE": "User {username} has {count} notifications",
"POSITIONAL_EXAMPLE": "First: {}, Second: {}, Third: {}",
"MIXED_PLACEHOLDERS": "Hello {name}, you have {} new messages and {} pending tasks"
}
}
example: assets/translations/ar.json
{
"GENERAL": {
"HELLO": "مرحبا",
"WELCOME": "أهلا بك",
"WELCOME_USER": "أهلا بك {name}!",
"GREETING_WITH_TIME": "{timeOfDay} طيب، {name}!"
},
"HOME": {
"TITLE": "الرئيسية"
},
"MESSAGES": {
"SIMPLE_MESSAGE": "هذه رسالة بسيطة",
"USER_PROFILE": "المستخدم {username} لديه {count} إشعارات",
"POSITIONAL_EXAMPLE": "الأول: {}، الثاني: {}، الثالث: {}",
"MIXED_PLACEHOLDERS": "مرحبا {name}، لديك {} رسائل جديدة و {} مهام معلقة"
}
}
2. Add the translations file paths to the pubspec.yaml or translations_code_gen.yaml file #
translations_code_gen:
keys:
input: 'assets/translations/en.json'
output: 'lib/translations/keys.dart'
values:
input: 'assets/translations/'
output: 'lib/translations/values/'
Run this command to generate the translations keys and values to the output:
flutter pub run translations_code_gen
The -g or --generate flag is optional, if you don't use it, the tool will normally generate dart keys and values code for you.
This will generate the following keys to the lib/translations/keys.dart file:
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: constant_identifier_names, camel_case_types
import 'package:easy_localization/easy_localization.dart';
class GENERAL {
static const String HELLO = "GENERAL.HELLO";
static String hello() => HELLO.tr();
static const String WELCOME = "GENERAL.WELCOME";
static String welcome() => WELCOME.tr();
static const String WELCOME_USER = "GENERAL.WELCOME_USER";
static String welcomeUser({String? name, }) => WELCOME_USER.tr(namedArgs: {if (name != null) 'name': name, });
static const String GREETING_WITH_TIME = "GENERAL.GREETING_WITH_TIME";
static String greetingWithTime({String? timeOfDay, String? name, }) => GREETING_WITH_TIME.tr(namedArgs: {if (timeOfDay != null) 'timeOfDay': timeOfDay, if (name != null) 'name': name, });
}
class HOME {
static const String TITLE = "HOME.TITLE";
static String title() => TITLE.tr();
}
class MESSAGES {
static const String SIMPLE_MESSAGE = "MESSAGES.SIMPLE_MESSAGE";
static String simpleMessage() => SIMPLE_MESSAGE.tr();
static const String USER_PROFILE = "MESSAGES.USER_PROFILE";
static String userProfile({String? username, String? count, }) => USER_PROFILE.tr(namedArgs: {if (username != null) 'username': username, if (count != null) 'count': count, });
static const String POSITIONAL_EXAMPLE = "MESSAGES.POSITIONAL_EXAMPLE";
static String positionalExample({List<String?>? args, }) => POSITIONAL_EXAMPLE.tr(args: args?.whereType<String>().toList(), );
static const String MIXED_PLACEHOLDERS = "MESSAGES.MIXED_PLACEHOLDERS";
static String mixedPlaceholders({String? name, List<String?>? args, }) => MIXED_PLACEHOLDERS.tr(args: args?.whereType<String>().toList(), namedArgs: {if (name != null) 'name': name, });
}
and the following values to the en.dart and ar.dart file to lib/translations/values/
example: lib/translations/values/en.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: constant_identifier_names
import '../keys.dart'; // sometimes you need to change this path to match your project structure
const Map<String, String> _general = {
GENERAL.HELLO: "Hello",
GENERAL.WELCOME: "Welcome",
GENERAL.WELCOME_USER: "Welcome {name}!",
GENERAL.GREETING_WITH_TIME: "Good {timeOfDay}, {name}!",
};
const Map<String, String> _home = {
HOME.TITLE: "Home",
};
const Map<String, String> _messages = {
MESSAGES.SIMPLE_MESSAGE: "This is a simple message",
MESSAGES.USER_PROFILE: "User {username} has {count} notifications",
MESSAGES.POSITIONAL_EXAMPLE: "First: {}, Second: {}, Third: {}",
MESSAGES.MIXED_PLACEHOLDERS: "Hello {name}, you have {} new messages and {} pending tasks",
};
final Map<String, String> enValues = {
..._general,
..._home,
..._messages,
};
example: lib/translations/values/ar.dart
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: constant_identifier_names
import '../keys.dart'; // sometimes you need to change this path to match your project structure
const Map<String, String> _general = {
GENERAL.HELLO: "مرحبا",
GENERAL.WELCOME: "أهلا بك",
GENERAL.WELCOME_USER: "أهلا بك {name}!",
GENERAL.GREETING_WITH_TIME: "{timeOfDay} طيب، {name}!",
};
const Map<String, String> _home = {
HOME.TITLE: "الرئيسية",
};
const Map<String, String> _messages = {
MESSAGES.SIMPLE_MESSAGE: "هذه رسالة بسيطة",
MESSAGES.USER_PROFILE: "المستخدم {username} لديه {count} إشعارات",
MESSAGES.POSITIONAL_EXAMPLE: "الأول: {}، الثاني: {}، الثالث: {}",
MESSAGES.MIXED_PLACEHOLDERS: "مرحبا {name}، لديك {} رسائل جديدة و {} مهام معلقة",
};
final Map<String, String> arValues = {
..._general,
..._home,
..._messages,
};
You might have to change the keys import path to match your project structure.
Placeholder Types and Usage #
This package supports three types of placeholders in your translation strings:
1. Named Placeholders {name} #
Named placeholders use curly braces with a parameter name inside. They generate methods with named parameters.
Translation JSON:
{
"WELCOME_USER": "Welcome {name}!",
"USER_STATS": "User {username} has {count} points"
}
Generated Dart Code:
static String welcomeUser({String? name, }) => _WELCOME_USER.tr(namedArgs: {if (name != null) 'name': name, });
static String userStats({String? username, String? count, }) => _USER_STATS.tr(namedArgs: {if (username != null) 'username': username, if (count != null) 'count': count, });
Usage:
Text(GENERAL.welcomeUser(name: 'John'))
Text(GENERAL.userStats(username: 'Alice', count: '150'))
2. Positional Placeholders {} #
Positional placeholders use empty curly braces {}. They generate methods that accept a list of arguments.
Translation JSON:
{
"ORDERED_LIST": "First: {}, Second: {}, Third: {}"
}
Generated Dart Code:
static String orderedList({List<String?>? args, }) => _ORDERED_LIST.tr(args: args?.whereType<String>().toList(), );
Usage:
Text(MESSAGES.orderedList(args: ['Apple', 'Banana', 'Cherry']))
3. Mixed Placeholders {name} + {} #
You can combine both named and positional placeholders in the same translation string.
Translation JSON:
{
"MIXED_MESSAGE": "Hello {name}, you have {} new messages and {} pending tasks"
}
Generated Dart Code:
static String mixedMessage({String? name, List<String?>? args, }) => _MIXED_MESSAGE.tr(args: args?.whereType<String>().toList(), namedArgs: {if (name != null) 'name': name, });
Usage:
Text(MESSAGES.mixedMessage(
name: 'Alice',
args: ['5', '3']
))
4. Simple Strings (No Placeholders) #
Strings without placeholders generate simple methods that call .tr() directly.
Translation JSON:
{
"SIMPLE_MESSAGE": "This is a simple message"
}
Generated Dart Code:
static String simpleMessage() => _SIMPLE_MESSAGE.tr();
Usage:
Text(MESSAGES.simpleMessage())
Key Features #
- Type Safety: All generated methods provide compile-time type checking
- Null Safety: All parameters are nullable with proper null checks
- easy_localization Integration: Generated code works seamlessly with the
easy_localizationpackage - Automatic Formatting: Translation keys are converted to camelCase method names
- Public Constants: Translation key constants are publicly accessible for direct usage and testing
- Flexible Access: Use either the generated methods or access the constants directly
4. Use the generated code #
import 'package:flutter/material.dart';
import './translations/keys.dart';
// any translation package
class MyHomePage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(HOME.title()),
),
body: Column(
children: [
// Simple translation without placeholders
Text(GENERAL.hello()),
// Named placeholder example
Text(GENERAL.welcomeUser(name: 'John')),
// Multiple named placeholders
Text(GENERAL.greetingWithTime(
timeOfDay: 'morning',
name: 'Sarah'
)),
// Positional placeholders
Text(MESSAGES.positionalExample(
args: ['Apple', 'Banana', 'Cherry']
)),
// Mixed placeholders (named + positional)
Text(MESSAGES.mixedPlaceholders(
name: 'Alice',
args: ['5', '3']
)),
// User profile with named placeholders
Text(MESSAGES.userProfile(
username: 'developer',
count: '12'
)),
],
),
);
}
}
5. Public Constant Accessibility #
Starting from version 1.3.6, all translation key constants are publicly accessible, allowing for more flexible usage patterns:
Direct Constant Access
You can now access the translation key constants directly:
// Access constants directly for custom usage
String keyValue = GENERAL.HELLO; // "GENERAL.HELLO"
String translatedText = keyValue.tr(); // "Hello"
// Use in custom translation logic
Map<String, String> customTranslations = {
GENERAL.HELLO: "Custom Hello",
HOME.TITLE: "Custom Title",
};
// Useful for testing and debugging
print('Translation key: ${MESSAGES.USER_PROFILE}');
Benefits of Public Constants
- Testing: Easily test translation keys in unit tests
- Custom Logic: Build custom translation logic around the constants
- Debugging: Access raw translation keys for debugging purposes
- Integration: Better integration with other localization tools
- Flexibility: Choose between method calls or direct constant access
Usage Patterns
// Method approach (recommended for most cases)
Text(GENERAL.hello())
// Direct constant approach (for custom logic)
Text(GENERAL.HELLO.tr())
// Both approaches are equivalent and produce the same result
6. Same as above but with the --generate flag #
flutter pub run translations_code_gen --generate=json-values
There are 4 types of code generation mode:
dart(default): generate dart keys and values codedart-keys: generate dart keys only.dart-values: generate dart values only.json-values: generate json values only.
Output with the --generate=json-values flag #
example: lib/translations/values/en.json
{
"GENERAL.HELLO": "Hello",
"GENERAL.WELCOME": "Welcome",
"GENERAL.WELCOME_USER": "Welcome {name}!",
"GENERAL.GREETING_WITH_TIME": "Good {timeOfDay}, {name}!",
"HOME.TITLE": "Home",
"MESSAGES.SIMPLE_MESSAGE": "This is a simple message",
"MESSAGES.USER_PROFILE": "User {username} has {count} notifications",
"MESSAGES.POSITIONAL_EXAMPLE": "First: {}, Second: {}, Third: {}",
"MESSAGES.MIXED_PLACEHOLDERS": "Hello {name}, you have {} new messages and {} pending tasks"
}
example: lib/translations/values/ar.json
{
"GENERAL.HELLO": "مرحبا",
"GENERAL.WELCOME": "أهلا بك",
"GENERAL.WELCOME_USER": "أهلا بك {name}!",
"GENERAL.GREETING_WITH_TIME": "{timeOfDay} طيب، {name}!",
"HOME.TITLE": "الرئيسية",
"MESSAGES.SIMPLE_MESSAGE": "هذه رسالة بسيطة",
"MESSAGES.USER_PROFILE": "المستخدم {username} لديه {count} إشعارات",
"MESSAGES.POSITIONAL_EXAMPLE": "الأول: {}، الثاني: {}، الثالث: {}",
"MESSAGES.MIXED_PLACEHOLDERS": "مرحبا {name}، لديك {} رسائل جديدة و {} مهام معلقة"
}
Development #
Requirements #
- Dart SDK:
>=3.1.0 <4.0.0(recommended:3.9.2or later) - Flutter SDK:
3.35.4or later (when using FVM)
Setting up with FVM (Flutter Version Manager) #
This project uses FVM for Flutter and Dart SDK version management to ensure consistent development environments.
1. Install FVM
# Using Homebrew (macOS)
brew tap leoafarias/fvm
brew install fvm
# Using pub global
dart pub global activate fvm
# Using Chocolatey (Windows)
choco install fvm
2. Install and use the project's Flutter version
# Install the required Flutter version
fvm install 3.35.4
# Use it for this project
fvm use 3.35.4
3. Run commands with FVM
# Get dependencies
fvm dart pub get
# Run the application
fvm dart run bin/translations_code_gen.dart
# Analyze code
fvm dart analyze
# Run tests
fvm dart test
Without FVM #
If you prefer not to use FVM, ensure you have Dart SDK 3.9.2 or later installed:
# Check your Dart version
dart --version
# Run the application
dart run bin/translations_code_gen.dart
Contributing #
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Install dependencies with
fvm dart pub get(ordart pub get) - Make your changes
- Run tests and ensure code analysis passes
- Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request