Export Formats
LangCTL exports translations to 6 different formats, each optimized for specific platforms and frameworks. This reference guide covers all supported formats in detail.
Supported Formats
| Format | Platform | Extension | Parameter Syntax |
|---|---|---|---|
| i18next JSON | Web (React, Vue, Angular) | .json | {{param}} |
| Android XML | Android Native | .xml | %1$s, %2$d |
| iOS Strings | iOS Native | .strings | %@, %1$@ |
| Flutter ARB | Flutter | .arb | {param} |
| Flat JSON | Generic | .json | {{param}} |
| Nested JSON | Generic | .json | {{param}} |
LangCTL automatically converts parameter syntax between formats. Write {{username}} once, and it becomes %1$s for Android, %@ for iOS, and {username} for Flutter.
i18next JSON Format
The most popular format for web applications using React, Vue, Angular, or any framework with i18next.
Format Specification
- File extension:
.json - Encoding: UTF-8
- Structure: Flat or nested object
- Parameters:
{{param}},{{count}},{{name}} - Plurals:
_one,_other,_zerosuffixes
Example Output
{
"home": {
"welcome": "Welcome, {{param}}!",
"title": "Dashboard",
"subtitle": "Get started with your projects"
},
"auth": {
"login": "Log In",
"signup": "Sign Up",
"logout": "Log Out"
},
"notifications": {
"message_one": "You have {{param}} new message",
"message_other": "You have {{param}} new messages"
}
} import { useTranslation } from 'react-i18next';
function WelcomeMessage() {
const { t } = useTranslation();
return (
<div>
<h1>{t('home.welcome', { username: 'John' })}</h1>
<p>{t('home.subtitle')}</p>
</div>
);
} <template>
<div>
<h1>{{ $t('home.welcome', { username: 'John' }) }}</h1>
<p>{{param}}</p>
</div>
</template> <div>
<h1>{{ 'home.welcome' | translate: {username: 'John'} }}</h1>
<p>{{param}}</p>
</div> langctl export my-project -l en -f i18n-json -o ./locales/en.json
langctl export my-project -l es -f i18n-json -o ./locales/es.json [IMAGE: i18next-export.png - i18next format in dashboard export]
Native Android string resources format for Kotlin and Java applications.
- File extension:
.xml - Encoding: UTF-8
- Structure: XML with
<resources>root - Parameters: Positional
%1$s(string),%1$d(integer),%1$f(float) - Plurals:
<plurals>element withquantityattribute
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">LangCTL Demo</string>
<string name="welcome_message">Welcome, %1$s!</string>
<string name="item_count">You have %1$d items</string>
</resources> LangCTL automatically converts dot notation to underscore:
home.welcome->home_welcomeauth.login.title->auth_login_title
// Simple string
val title = getString(R.string.home_title)
// With parameter
val welcome = getString(R.string.home_welcome, username)
// With multiple parameters
val info = getString(R.string.profile_info, name, followerCount)
// Plurals
val message = resources.getQuantityString(
R.plurals.notifications_message,
count,
count
) // Simple string
String title = getString(R.string.home_title);
// With parameter
String welcome = getString(R.string.home_welcome, username);
// Plurals
String message = getResources().getQuantityString(
R.plurals.notifications_message,
count,
count
); app/src/main/res/
βββ values/ # Default (English)
β βββ strings.xml
βββ values-es/ # Spanish
β βββ strings.xml
βββ values-fr/ # French
β βββ strings.xml
βββ values-de/ # German
βββ strings.xml langctl export my-project -l en -f android-xml -o ./app/src/main/res/values/strings.xml
langctl export my-project -l es -f android-xml -o ./app/src/main/res/values-es/strings.xml Android XML requires escaping:
| Character | Escaped Form | Example |
|---|---|---|
' (apostrophe) | \' | It\'s working |
" (quote) | \" | He said \"Hi\" |
< | < | x < 5 |
> | > | x > 3 |
& | & | Tom & Jerry |
\n | \n | Multi-line text |
LangCTL automatically handles XML escaping during export. You donβt need to escape characters in the dashboard or CLI.
[IMAGE: android-export.png - Android XML format export]
Native iOS and macOS localization format for Swift and Objective-C.
- File extension:
.strings - Encoding: UTF-8 or UTF-16
- Structure: Key-value pairs with comments
- Parameters: Positional
%@(object),%d(integer),%f(float) - Plurals: Handled via
.stringsdictfile
/* Home Screen */
"home.welcome" = "Welcome, %@!";
"home.title" = "Dashboard";
"home.subtitle" = "Get started with your projects";
/* Auth */
"auth.login" = "Log In";
"auth.signup" = "Sign Up";
"auth.logout" = "Log Out";
/* Multiple Parameters */
"profile.info" = "%@ has %d followers";
/* With numbered positions */
"order.details" = "Item: %1$@, Price: %2$@, Quantity: %3$d"; // Simple string
let title = NSLocalizedString("home.title", comment: "")
// With parameter
let welcome = String(format: NSLocalizedString("home.welcome", comment: ""), username)
// With multiple parameters
let info = String(format: NSLocalizedString("profile.info", comment: ""), name, followerCount)
// Using String interpolation (modern)
let welcome = String(localized: "home.welcome") // Simple string
NSString *title = NSLocalizedString(@"home.title", @"");
// With parameter
NSString *welcome = [NSString stringWithFormat:
NSLocalizedString(@"home.welcome", @""), username]; MyApp/
βββ en.lproj/
β βββ Localizable.strings
βββ es.lproj/
β βββ Localizable.strings
βββ fr.lproj/
β βββ Localizable.strings
βββ de.lproj/
βββ Localizable.strings langctl export my-project -l en -f ios-strings -o ./en.lproj/Localizable.strings
langctl export my-project -l es -f ios-strings -o ./es.lproj/Localizable.strings For complex plural rules, iOS uses .stringsdict:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>item.count</key>
<dict>
<key>NSStringLocalizedFormatKey</key>
<string>%#@items@</string>
<key>items</key>
<dict>
<key>NSStringFormatSpecTypeKey</key>
<string>NSStringPluralRuleType</string>
<key>NSStringFormatValueTypeKey</key>
<string>d</string>
<key>zero</key>
<string>No items</string>
<key>one</key>
<string>One item</string>
<key>other</key>
<string>%d items</string>
</dict>
</dict>
</dict>
</plist> [IMAGE: ios-export.png - iOS Strings format export]
Application Resource Bundle format for Flutter and Dart applications.
- File extension:
.arb - Encoding: UTF-8
- Structure: JSON with metadata
- Parameters:
{param},{count},{name} - Plurals: ICU message format
{
"@@locale": "en",
"@@last_modified": "2024-01-15T10:30:00.000Z",
"homeWelcome": "Welcome, {username}!",
"@homeWelcome": {
"description": "Welcome message on home screen",
"placeholders": {
"username": {
"type": "String"
}
}
},
"homeTitle": "Dashboard",
"@homeTitle": {
"description": "Home screen title"
},
"authLogin": "Log In",
"authSignup": "Sign Up",
"notificationsMessage": "{count, plural, =0{No messages} =1{You have {count} new message} other{You have {count} new messages}}",
"@notificationsMessage": {
"description": "New message notification",
"placeholders": {
"count": {
"type": "int"
}
}
}
} LangCTL converts dot notation to camelCase:
home.welcome->homeWelcomeauth.login.title->authLoginTitle
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
class HomeScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
return Column(
children: [
Text(l10n.homeWelcome('John')),
Text(l10n.homeTitle),
Text(l10n.notificationsMessage(5)),
],
);
}
} Add to pubspec.yaml:
flutter:
generate: true
dependencies:
flutter_localizations:
sdk: flutter
intl: ^0.18.0 Create l10n.yaml:
arb-dir: lib/l10n
template-arb-file: app_en.arb
output-localization-file: app_localizations.dart
nullable-getter: false langctl export my-project -l en -f flutter-arb -o ./lib/l10n/app_en.arb
langctl export my-project -l es -f flutter-arb -o ./lib/l10n/app_es.arb [IMAGE: flutter-export.png - Flutter ARB format export]
Simple key-value JSON format for generic use cases.
- File extension:
.json - Encoding: UTF-8
- Structure: Flat object (no nesting)
- Parameters:
{{param}}(configurable)
{
"home.welcome": "Welcome, {{param}}!",
"home.title": "Dashboard",
"home.subtitle": "Get started with your projects",
"auth.login": "Log In",
"auth.signup": "Sign Up",
"auth.logout": "Log Out",
"notifications.message": "You have {{param}} new messages"
} import translations from './locales/en.json';
function translate(key, params = {}) {
let text = translations[key] || key;
Object.entries(params).forEach(([key, value]) => {
text = text.replace(new RegExp(`{{\${key}}}`, 'g'), value);
});
return text;
}
// Usage
console.log(translate('home.welcome', { username: 'John' }));
// Output: "Welcome, John!" langctl export my-project -l en -f flat-json -o ./locales/en.json Hierarchical JSON format that preserves module structure.
- File extension:
.json - Encoding: UTF-8
- Structure: Nested objects matching module structure
- Parameters:
{{param}}(configurable)
{
"home": {
"welcome": "Welcome, {{param}}!",
"title": "Dashboard",
"subtitle": "Get started with your projects"
},
"auth": {
"login": "Log In",
"signup": "Sign Up",
"logout": "Log Out"
},
"notifications": {
"message": "You have {{param}} new messages"
}
} import translations from './locales/en.json';
function translate(key, params = {}) {
const keys = key.split('.');
let text = keys.reduce((obj, k) => obj?.[k], translations) || key;
Object.entries(params).forEach(([key, value]) => {
text = text.replace(new RegExp(`{{\${key}}}`, 'g'), value);
});
return text;
}
// Usage
console.log(translate('home.welcome', { username: 'John' }));
// Output: "Welcome, John!" langctl export my-project -l en -f nested-json -o ./locales/en.json LangCTL automatically converts parameter syntax between formats:
"Welcome, {{param}}! You have {{param}} items." | Format | Output |
|---|---|
| i18next JSON | Welcome, {{username}}! You have {{count}} items. |
| Android XML | Welcome, %1$s! You have %2$d items. |
| iOS Strings | Welcome, %@! You have %d items. |
| Flutter ARB | Welcome, {username}! You have {count} items. |
| Flat JSON | Welcome, {{username}}! You have {{count}} items. |
Parameters are converted in order of appearance. The first parameter becomes %1$s/%@, the second becomes %2$s/%@, and so on.
Export only specific modules:
langctl export my-project -l en -f i18n-json --module auth -o ./locales/auth-en.json
langctl export my-project -l en -f i18n-json --modules auth,home -o ./locales/en.json | Format | Best For | Pros | Cons |
|---|---|---|---|
| i18next JSON | Web apps | Most popular, great tooling | Web-only |
| Android XML | Native Android | Native integration | Android-only |
| iOS Strings | Native iOS | Native integration | iOS-only |
| Flutter ARB | Flutter apps | Full Flutter support | Flutter-only |
| Flat JSON | Custom solutions | Simple, universal | No structure |
| Nested JSON | Custom solutions | Organized structure | Custom parsing |
- React/Vue/Angular -> i18next JSON
- Android Native -> Android XML
- iOS Native -> iOS Strings
- Flutter -> Flutter ARB
- Node.js backends
- Custom solutions
- Static site generators "Welcome, {{param}}!"
"Hello, {{param}}!"
"{{param}}'s Profile"
"Welcome, {{param}}!"
"Hello, {{param}}!"
"{{param}}'s Profile" Always test exported files in your application before deploying:
langctl export my-project -l en -f i18n-json -o /tmp/en.json
cat /tmp/en.json | jq
langctl export my-project -l en -f i18n-json -o ./public/locales/en.json Commit exported files to version control:
public/locales/*.json
app/src/main/res/values*/strings.xml
ios/*/Localizable.strings
*.tmp
.langctl-cache/ Check parameter syntax matches your format:
t('message', { username: 'John' })
getString(R.string.message, username)
String(format: NSLocalizedString("message", comment: ""), username) Ensure UTF-8 encoding:
file -I locales/en.json
iconv -f ISO-8859-1 -t UTF-8 input.json > output.json Plurals Not Working
Different formats handle plurals differently:
- i18next: Use
_one,_othersuffix or ICU format - Android: Use
<plurals>element - iOS: Use
.stringsdictfile - Flutter: Use ICU message format in ARB
Next Steps
- Supported Languages - Language codes and coverage
- Export Guide - Dashboard export features
- CLI Export - CLI export commands
- Platform Integrations - Integration guides