Automatically translate iOS Localizable.xcstrings files and App Store metadata using DeepL API. This plugin helps you efficiently manage app localization by translating untranslated strings while preserving your existing translations, and seamlessly translate App Store metadata files like release notes and descriptions to all your supported languages.
- Language selection with progress: Shows translation completeness for each language
- Smart targeting: Only translates missing strings, preserves existing translations
- Formality options: Formal/informal translation styles for supported languages
- Context-aware translation: Uses xcstrings comments to improve translation quality
- Progress tracking: Resume interrupted translations without starting over
- Automatic backups: Safe translation with rollback capability
- Error recovery: Handle API failures gracefully with retry options
- Auto-detection: Automatically detects target languages from existing metadata directories
- Smart mapping: Handles App Store locale directory names to DeepL language codes
- Multiple files: Translate release notes, descriptions, keywords, or any metadata file
- Batch translation: Translate to all supported languages in one command
- Error resilience: Continues translating other languages if one fails
fastlane add_plugin translateAdd to your Gemfile:
gem "fastlane-plugin-translate", git: "https://github.com/tijs/fastlane-plugin-translate"Then run:
bundle install-
Get a DeepL API key from https://www.deepl.com/pro#developer
-
Set your API key as an environment variable:
export DEEPL_AUTH_KEY="your-deepl-api-key-here"
After installation, create a lane in your Fastfile and run it:
fastlane ios translateSimple dedicated lane:
lane :translate do
translate_with_deepl
endWithin complex workflows:
lane :prepare_release do
build_app
translate_with_deepl(target_language: "de")
upload_to_testflight
slack(message: "New build with German translations available!")
end# Translate to German
translate_with_deepl(target_language: "de")
# Translate to French with formal style
translate_with_deepl(
target_language: "fr",
formality: "more"
)# Full configuration example
translate_with_deepl(
xcstrings_path: "./MyApp/Localizable.xcstrings",
target_language: "es",
formality: "prefer_more",
batch_size: 15,
free_api: true
)In addition to translating app strings, the plugin can translate App Store metadata files like release notes, descriptions, and keywords using the translate_metadata_with_deepl action.
- Auto-detection: Automatically detects target languages from existing metadata directories
- Smart mapping: Handles App Store locale directory names (e.g.,
de-DE,fr-FR) to DeepL language codes - Multiple files: Translate
release_notes.txt,description.txt,keywords.txt, or any metadata file - Backup creation: Creates backups before translation for safety
- Progress tracking: Shows translation progress for each language
- Error resilience: Continues translating other languages if one fails
# Translate release notes to all detected languages
translate_metadata_with_deepl(
file_name: "release_notes.txt"
)# Translate release notes to all supported languages
lane :release_notes_translate do
translate_metadata_with_deepl(
metadata_path: "./fastlane/metadata",
source_locale: "en-US",
file_name: "release_notes.txt",
formality: "prefer_less"
)
end
# Translate app description
lane :description_translate do
translate_metadata_with_deepl(
file_name: "description.txt",
formality: "prefer_more"
)
end
# Translate any metadata file
lane :translate_metadata do |options|
file_name = options[:file] || UI.input("Enter metadata file name: ")
translate_metadata_with_deepl(
file_name: file_name,
formality: "prefer_less"
)
end# Translate only to specific languages
translate_metadata_with_deepl(
file_name: "release_notes.txt",
target_languages: ["de", "fr", "es", "ja"],
formality: "more"
)
# Use custom metadata path and source locale
translate_metadata_with_deepl(
metadata_path: "./custom/metadata",
source_locale: "en-GB",
file_name: "keywords.txt",
formality: "prefer_less"
)| Parameter | Description | Default | Required |
|---|---|---|---|
metadata_path |
Path to fastlane metadata directory | ./fastlane/metadata |
No |
source_locale |
Source language locale (e.g., en-US) | en-US |
No |
file_name |
Metadata file to translate | release_notes.txt |
No |
target_languages |
Specific languages to translate to | Auto-detected | No |
formality |
Translation formality setting | Language default | No |
api_token |
DeepL API authentication key | ENV['DEEPL_AUTH_KEY'] |
Yes |
free_api |
Use DeepL Free API endpoint | false |
No |
๐ Auto-detecting target languages from metadata directories...
๐ Found metadata directories for: de, fr, es, ja, ko, zh-Hans
โ
DeepL API key validated
๐พ Backup created: ./fastlane/metadata/en-US/release_notes.txt.backup_20241201_163535
๐ Translating release_notes.txt from en-US to 6 languages:
โข German (de)
โข French (fr)
โข Spanish (es)
โข Japanese (ja)
โข Korean (ko)
โข Chinese (Simplified) (zh-Hans)
๐ Translating to German (de)...
โ
de: Translation completed
๐ Translating to French (fr)...
โ
fr: Translation completed
๐ Translating to Spanish (es)...
โ
es: Translation completed
๐ Metadata translation completed!
๐ Successfully translated release_notes.txt for 6 languages
๐ Backup saved: ./fastlane/metadata/en-US/release_notes.txt.backup_20241201_163535
The action expects and maintains the standard fastlane metadata structure:
fastlane/
โโโ metadata/
โโโ en-US/ # Source locale
โ โโโ release_notes.txt
โ โโโ description.txt
โ โโโ keywords.txt
โโโ de-DE/ # German
โ โโโ release_notes.txt
โ โโโ description.txt
โโโ fr-FR/ # French
โ โโโ release_notes.txt
โโโ ja/ # Japanese
โโโ release_notes.txt
The plugin automatically handles App Store locale directory naming:
| App Store Directory | DeepL Language Code | Language |
|---|---|---|
de-DE |
de |
German |
fr-FR |
fr |
French |
es-ES |
es |
Spanish |
nl-NL |
nl |
Dutch |
no |
nb |
Norwegian Bokmรฅl |
pt-BR |
pt-BR |
Portuguese (Brazil) |
pt-PT |
pt-PT |
Portuguese (Portugal) |
zh-Hans |
zh |
Chinese (Simplified) |
The metadata translation action sets these shared values:
TRANSLATE_METADATA_WITH_DEEPL_TRANSLATED_COUNT- Number of languages successfully translatedTRANSLATE_METADATA_WITH_DEEPL_TARGET_LANGUAGES- Array of target language codes that were translatedTRANSLATE_METADATA_WITH_DEEPL_BACKUP_FILE- Path to the backup file created
lane :translate_and_upload do
count = translate_metadata_with_deepl(file_name: "release_notes.txt")
if count > 0
upload_to_app_store(skip_binary_upload: true)
slack(message: "โ
Translated release notes for #{count} languages and uploaded!")
end
endThe plugin supports all languages available in both Apple's App Store Connect and DeepL API:
- ๐ฉ๐ช German (de) - supports formality
- ๐ซ๐ท French (fr) - supports formality
- ๐ฎ๐น Italian (it) - supports formality
- ๐ช๐ธ Spanish (es) - supports formality
- ๐ณ๐ฑ Dutch (nl) - supports formality
- ๐ต๐ฑ Polish (pl) - supports formality
- ๐ต๐น Portuguese (pt-BR, pt-PT) - supports formality
- ๐ฏ๐ต Japanese (ja) - supports formality
- ๐ท๐บ Russian (ru) - supports formality
- ๐ฌ๐ง English (en-US, en-GB)
- ๐จ๐ณ Chinese (zh-Hans, zh-Hant)
- ๐ฐ๐ท Korean (ko)
- And many more...
Languages marked with "supports formality" offer formal/informal translation options
| Parameter | Description | Default | Required |
|---|---|---|---|
api_token |
DeepL API authentication key | ENV['DEEPL_AUTH_KEY'] |
Yes |
xcstrings_path |
Path to Localizable.xcstrings file | Auto-detected | No |
target_language |
Target language code (e.g., "de", "fr") | User prompted | No |
batch_size |
Number of strings per API call | 20 | No |
free_api |
Use DeepL Free API endpoint | false | No |
formality |
Translation formality level | Auto-detected | No |
For supported languages, you can specify:
default- Standard formalitymore- More formal languageless- Less formal languageprefer_more- Formal if available, otherwise defaultprefer_less- Informal if available, otherwise default
๐ Found xcstrings file: ./Kilowatt/Localizable.xcstrings
โ
DeepL API key validated
๐พ Backup created: ./Kilowatt/Localizable.xcstrings.backup_20241201_143022
๐ Available languages for translation:
1. German (de): 45.2% translated (127 remaining) [supports formality]
2. French (fr): 21.8% translated (220 remaining) [supports formality]
3. Spanish (es): 18.1% translated (231 remaining) [supports formality]
๐ญ German supports formality options. Choose style:
โ more (formal)
๐ Translating from EN to DE
๐ Found 127 untranslated strings
๐ Translating batch 1/7 (20 strings)...
โ
Batch 1 completed (20 strings)
๐ Translating batch 2/7 (20 strings)...
โ
Batch 2 completed (20 strings)
...
๐ Updating xcstrings file with 127 translations...
๐พ Updated xcstrings file
โ
Updated xcstrings file is valid JSON
๐ Translation completed!
๐ Translated 127 strings for German (de)
๐ Backup saved: ./Kilowatt/Localizable.xcstrings.backup_20241201_143022
๐๏ธ You can delete the backup after verifying results
The plugin provides comprehensive error recovery:
โ ๏ธ Rate limit exceeded for batch 3/10
1. Wait 60s and retry
2. Skip this batch
3. Abort translation
โ Translation error for batch 2/10: Network timeout
1. Skip this batch
2. Retry batch
3. Abort translation
โ DeepL quota exceeded. Upgrade your plan or wait for reset.
The action sets the following shared values for use in other lanes:
TRANSLATE_WITH_DEEPL_TRANSLATED_COUNT- Number of translated stringsTRANSLATE_WITH_DEEPL_TARGET_LANGUAGE- Target language codeTRANSLATE_WITH_DEEPL_BACKUP_FILE- Path to backup file
lane :translate_and_notify do
count = translate_with_deepl(target_language: "de")
slack(
message: "โ
Translated #{count} German strings!",
channel: "#localization"
)
endThe plugin automatically saves translation progress:
๐ Found existing progress: 45 strings translated
Continue from where you left off?
1. Yes, continue
2. No, start fresh
Progress files are automatically cleaned up after successful completion.
When xcstrings files contain comments, they're used as translation context:
{
"Hello World": {
"comment": "Greeting message shown on app launch",
"localizations": { ... }
}
}This comment becomes context for better translation quality.
- Ruby >= 2.6
- Fastlane >= 2.0.0
- DeepL API account (Free or Pro)
- Clone the repository
- Run
bundle install
Run the full test suite:
bundle exec rspecRun specific test files:
bundle exec rspec spec/translate_with_deepl_action_spec.rb
bundle exec rspec spec/language_registry_spec.rb
bundle exec rspec spec/deepl_language_mapper_spec.rbRun RuboCop for style checking:
bundle exec rubocopAuto-fix correctable issues:
bundle exec rubocop -aTo test the plugin manually with a real project:
# Export your DeepL API key
export DEEPL_AUTH_KEY="your-api-key-here"
# Test the plugin
bundle exec fastlane translate_with_deepl- Ruby >= 3.4
- Fastlane >= 2.0.0
- DeepL API account (Free or Pro) for manual testing
For bugs, feature requests, or questions, please create an issue.
This project is licensed under the MIT License - see the LICENSE file for details.
fastlane is the easiest way to automate beta deployments and releases for your iOS and Android apps. To get started with fastlane, check out fastlane.tools.
