fastlane-plugin-translate 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cb50e549d9a01fa0537ad44d52a80ddb8fb372417336eb31e2455b684f84ecba
|
4
|
+
data.tar.gz: c9a6afa40d2c1d40fc07cc1bf4a143f71db9603519c4a9c20cbdd356adf56ce9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce8b51d5e1c16e0249d56b90c2b1500dcbcb4d82560e6d64da3c1a88753e0f13a96d21110c9f743613ec168a029f0f2dc9dd7ad48dc988d258e3d4d7ef8942e2
|
7
|
+
data.tar.gz: 682624a1f320c81a3304d3a6dab231909e3c6dce4a0e7c7b7c624db178afc312a57d7dd760df983a8f126352149b5610db5c077a07f9a92bf0250be036d44936
|
data/README.md
CHANGED
@@ -6,14 +6,16 @@
|
|
6
6
|
|
7
7
|
[](https://rubygems.org/gems/fastlane-plugin-translate)
|
8
8
|
[](https://badge.fury.io/rb/fastlane-plugin-translate)
|
9
|
-
[](https://ko-fi.com/D1D6P4LAR)
|
10
10
|
|
11
11
|
## About translate
|
12
12
|
|
13
|
-
Automatically translate iOS `Localizable.xcstrings` files using DeepL API. This plugin helps you efficiently manage app localization by translating untranslated strings while preserving your existing translations.
|
13
|
+
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.
|
14
14
|
|
15
15
|
## Features
|
16
16
|
|
17
|
+
### App Strings Translation
|
18
|
+
|
17
19
|
- **Language selection with progress**: Shows translation completeness for each language
|
18
20
|
- **Smart targeting**: Only translates missing strings, preserves existing translations
|
19
21
|
- **Formality options**: Formal/informal translation styles for supported languages
|
@@ -22,6 +24,14 @@ Automatically translate iOS `Localizable.xcstrings` files using DeepL API. This
|
|
22
24
|
- **Automatic backups**: Safe translation with rollback capability
|
23
25
|
- **Error recovery**: Handle API failures gracefully with retry options
|
24
26
|
|
27
|
+
### App Store Metadata Translation
|
28
|
+
|
29
|
+
- **Auto-detection**: Automatically detects target languages from existing metadata directories
|
30
|
+
- **Smart mapping**: Handles App Store locale directory names to DeepL language codes
|
31
|
+
- **Multiple files**: Translate release notes, descriptions, keywords, or any metadata file
|
32
|
+
- **Batch translation**: Translate to all supported languages in one command
|
33
|
+
- **Error resilience**: Continues translating other languages if one fails
|
34
|
+
|
25
35
|
## Getting Started
|
26
36
|
|
27
37
|
### Install from RubyGems (Recommended)
|
@@ -108,6 +118,173 @@ translate_with_deepl(
|
|
108
118
|
)
|
109
119
|
```
|
110
120
|
|
121
|
+
## App Store Metadata Translation
|
122
|
+
|
123
|
+
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.
|
124
|
+
|
125
|
+
### Features
|
126
|
+
|
127
|
+
- **Auto-detection**: Automatically detects target languages from existing metadata directories
|
128
|
+
- **Smart mapping**: Handles App Store locale directory names (e.g., `de-DE`, `fr-FR`) to DeepL language codes
|
129
|
+
- **Multiple files**: Translate `release_notes.txt`, `description.txt`, `keywords.txt`, or any metadata file
|
130
|
+
- **Backup creation**: Creates backups before translation for safety
|
131
|
+
- **Progress tracking**: Shows translation progress for each language
|
132
|
+
- **Error resilience**: Continues translating other languages if one fails
|
133
|
+
|
134
|
+
### Basic Metadata Translation
|
135
|
+
|
136
|
+
```ruby
|
137
|
+
# Translate release notes to all detected languages
|
138
|
+
translate_metadata_with_deepl(
|
139
|
+
file_name: "release_notes.txt"
|
140
|
+
)
|
141
|
+
```
|
142
|
+
|
143
|
+
### Fastfile Examples
|
144
|
+
|
145
|
+
```ruby
|
146
|
+
# Translate release notes to all supported languages
|
147
|
+
lane :release_notes_translate do
|
148
|
+
translate_metadata_with_deepl(
|
149
|
+
metadata_path: "./fastlane/metadata",
|
150
|
+
source_locale: "en-US",
|
151
|
+
file_name: "release_notes.txt",
|
152
|
+
formality: "prefer_less"
|
153
|
+
)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Translate app description
|
157
|
+
lane :description_translate do
|
158
|
+
translate_metadata_with_deepl(
|
159
|
+
file_name: "description.txt",
|
160
|
+
formality: "prefer_more"
|
161
|
+
)
|
162
|
+
end
|
163
|
+
|
164
|
+
# Translate any metadata file
|
165
|
+
lane :translate_metadata do |options|
|
166
|
+
file_name = options[:file] || UI.input("Enter metadata file name: ")
|
167
|
+
|
168
|
+
translate_metadata_with_deepl(
|
169
|
+
file_name: file_name,
|
170
|
+
formality: "prefer_less"
|
171
|
+
)
|
172
|
+
end
|
173
|
+
```
|
174
|
+
|
175
|
+
### Advanced Configuration
|
176
|
+
|
177
|
+
```ruby
|
178
|
+
# Translate only to specific languages
|
179
|
+
translate_metadata_with_deepl(
|
180
|
+
file_name: "release_notes.txt",
|
181
|
+
target_languages: ["de", "fr", "es", "ja"],
|
182
|
+
formality: "more"
|
183
|
+
)
|
184
|
+
|
185
|
+
# Use custom metadata path and source locale
|
186
|
+
translate_metadata_with_deepl(
|
187
|
+
metadata_path: "./custom/metadata",
|
188
|
+
source_locale: "en-GB",
|
189
|
+
file_name: "keywords.txt",
|
190
|
+
formality: "prefer_less"
|
191
|
+
)
|
192
|
+
```
|
193
|
+
|
194
|
+
### Metadata Translation Parameters
|
195
|
+
|
196
|
+
| Parameter | Description | Default | Required |
|
197
|
+
|-----------|-------------|---------|----------|
|
198
|
+
| `metadata_path` | Path to fastlane metadata directory | `./fastlane/metadata` | No |
|
199
|
+
| `source_locale` | Source language locale (e.g., en-US) | `en-US` | No |
|
200
|
+
| `file_name` | Metadata file to translate | `release_notes.txt` | No |
|
201
|
+
| `target_languages` | Specific languages to translate to | Auto-detected | No |
|
202
|
+
| `formality` | Translation formality setting | Language default | No |
|
203
|
+
| `api_token` | DeepL API authentication key | `ENV['DEEPL_AUTH_KEY']` | Yes |
|
204
|
+
| `free_api` | Use DeepL Free API endpoint | `false` | No |
|
205
|
+
|
206
|
+
### Example Output
|
207
|
+
|
208
|
+
```
|
209
|
+
🔍 Auto-detecting target languages from metadata directories...
|
210
|
+
📁 Found metadata directories for: de, fr, es, ja, ko, zh-Hans
|
211
|
+
✅ DeepL API key validated
|
212
|
+
💾 Backup created: ./fastlane/metadata/en-US/release_notes.txt.backup_20241201_163535
|
213
|
+
|
214
|
+
📋 Translating release_notes.txt from en-US to 6 languages:
|
215
|
+
• German (de)
|
216
|
+
• French (fr)
|
217
|
+
• Spanish (es)
|
218
|
+
• Japanese (ja)
|
219
|
+
• Korean (ko)
|
220
|
+
• Chinese (Simplified) (zh-Hans)
|
221
|
+
|
222
|
+
🔄 Translating to German (de)...
|
223
|
+
✅ de: Translation completed
|
224
|
+
🔄 Translating to French (fr)...
|
225
|
+
✅ fr: Translation completed
|
226
|
+
🔄 Translating to Spanish (es)...
|
227
|
+
✅ es: Translation completed
|
228
|
+
|
229
|
+
🎉 Metadata translation completed!
|
230
|
+
📊 Successfully translated release_notes.txt for 6 languages
|
231
|
+
📄 Backup saved: ./fastlane/metadata/en-US/release_notes.txt.backup_20241201_163535
|
232
|
+
```
|
233
|
+
|
234
|
+
### Directory Structure
|
235
|
+
|
236
|
+
The action expects and maintains the standard fastlane metadata structure:
|
237
|
+
|
238
|
+
```
|
239
|
+
fastlane/
|
240
|
+
└── metadata/
|
241
|
+
├── en-US/ # Source locale
|
242
|
+
│ ├── release_notes.txt
|
243
|
+
│ ├── description.txt
|
244
|
+
│ └── keywords.txt
|
245
|
+
├── de-DE/ # German
|
246
|
+
│ ├── release_notes.txt
|
247
|
+
│ └── description.txt
|
248
|
+
├── fr-FR/ # French
|
249
|
+
│ └── release_notes.txt
|
250
|
+
└── ja/ # Japanese
|
251
|
+
└── release_notes.txt
|
252
|
+
```
|
253
|
+
|
254
|
+
### Language Mapping
|
255
|
+
|
256
|
+
The plugin automatically handles App Store locale directory naming:
|
257
|
+
|
258
|
+
| App Store Directory | DeepL Language Code | Language |
|
259
|
+
|---------------------|---------------------|----------|
|
260
|
+
| `de-DE` | `de` | German |
|
261
|
+
| `fr-FR` | `fr` | French |
|
262
|
+
| `es-ES` | `es` | Spanish |
|
263
|
+
| `nl-NL` | `nl` | Dutch |
|
264
|
+
| `no` | `nb` | Norwegian Bokmål |
|
265
|
+
| `pt-BR` | `pt-BR` | Portuguese (Brazil) |
|
266
|
+
| `pt-PT` | `pt-PT` | Portuguese (Portugal) |
|
267
|
+
| `zh-Hans` | `zh` | Chinese (Simplified) |
|
268
|
+
|
269
|
+
### Shared Values
|
270
|
+
|
271
|
+
The metadata translation action sets these shared values:
|
272
|
+
|
273
|
+
- `TRANSLATE_METADATA_WITH_DEEPL_TRANSLATED_COUNT` - Number of languages successfully translated
|
274
|
+
- `TRANSLATE_METADATA_WITH_DEEPL_TARGET_LANGUAGES` - Array of target language codes that were translated
|
275
|
+
- `TRANSLATE_METADATA_WITH_DEEPL_BACKUP_FILE` - Path to the backup file created
|
276
|
+
|
277
|
+
```ruby
|
278
|
+
lane :translate_and_upload do
|
279
|
+
count = translate_metadata_with_deepl(file_name: "release_notes.txt")
|
280
|
+
|
281
|
+
if count > 0
|
282
|
+
upload_to_app_store(skip_binary_upload: true)
|
283
|
+
slack(message: "✅ Translated release notes for #{count} languages and uploaded!")
|
284
|
+
end
|
285
|
+
end
|
286
|
+
```
|
287
|
+
|
111
288
|
## Supported Languages
|
112
289
|
|
113
290
|
The plugin supports all languages available in both Apple's App Store Connect and DeepL API:
|
@@ -0,0 +1,315 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'deepl'
|
6
|
+
|
7
|
+
module Fastlane
|
8
|
+
module Actions
|
9
|
+
module SharedValues
|
10
|
+
TRANSLATE_METADATA_WITH_DEEPL_TRANSLATED_COUNT = :TRANSLATE_METADATA_WITH_DEEPL_TRANSLATED_COUNT
|
11
|
+
TRANSLATE_METADATA_WITH_DEEPL_TARGET_LANGUAGES = :TRANSLATE_METADATA_WITH_DEEPL_TARGET_LANGUAGES
|
12
|
+
TRANSLATE_METADATA_WITH_DEEPL_BACKUP_FILE = :TRANSLATE_METADATA_WITH_DEEPL_BACKUP_FILE
|
13
|
+
end
|
14
|
+
|
15
|
+
class TranslateMetadataWithDeeplAction < Action
|
16
|
+
def self.run(params)
|
17
|
+
# Setup and validation
|
18
|
+
setup_deepl_client(params)
|
19
|
+
|
20
|
+
metadata_path = params[:metadata_path]
|
21
|
+
source_locale = params[:source_locale]
|
22
|
+
file_name = params[:file_name]
|
23
|
+
|
24
|
+
# Validate source file exists
|
25
|
+
source_file_path = File.join(metadata_path, source_locale, file_name)
|
26
|
+
UI.user_error!("❌ Source file not found: #{source_file_path}") unless File.exist?(source_file_path)
|
27
|
+
|
28
|
+
# Read source content
|
29
|
+
source_content = File.read(source_file_path).strip
|
30
|
+
UI.user_error!("❌ Source file is empty: #{source_file_path}") if source_content.empty?
|
31
|
+
|
32
|
+
# Create backup
|
33
|
+
backup_file = create_backup(source_file_path)
|
34
|
+
|
35
|
+
# Detect available target languages
|
36
|
+
target_languages = detect_target_languages(metadata_path, source_locale, params[:target_languages])
|
37
|
+
|
38
|
+
# Filter by DeepL support
|
39
|
+
supported_languages = Helper::DeeplLanguageMapperHelper.supported_languages_from_list(target_languages)
|
40
|
+
unsupported_languages = Helper::DeeplLanguageMapperHelper.unsupported_languages(target_languages)
|
41
|
+
|
42
|
+
UI.important("⚠️ Languages not supported by DeepL: #{unsupported_languages.map { |l| "#{Helper::LanguageRegistryHelper.language_name(l)} (#{l})" }.join(', ')}") if unsupported_languages.any?
|
43
|
+
|
44
|
+
UI.user_error!('❌ No DeepL-supported languages found') if supported_languages.empty?
|
45
|
+
|
46
|
+
UI.message("📋 Translating #{file_name} from #{source_locale} to #{supported_languages.size} languages:")
|
47
|
+
supported_languages.each { |lang| UI.message(" • #{Helper::LanguageRegistryHelper.language_name(lang)} (#{lang})") }
|
48
|
+
|
49
|
+
# Translate to each target language
|
50
|
+
total_translated = 0
|
51
|
+
successful_languages = []
|
52
|
+
|
53
|
+
supported_languages.each do |target_language|
|
54
|
+
UI.message("🔄 Translating to #{Helper::LanguageRegistryHelper.language_name(target_language)} (#{target_language})...")
|
55
|
+
|
56
|
+
begin
|
57
|
+
# Determine formality for this language
|
58
|
+
formality = determine_formality(target_language, params[:formality])
|
59
|
+
|
60
|
+
# Translate content
|
61
|
+
translated_content = translate_content(source_content, source_locale, target_language, formality)
|
62
|
+
|
63
|
+
# Write to target file
|
64
|
+
target_file_path = File.join(metadata_path, map_to_metadata_directory(target_language), file_name)
|
65
|
+
ensure_directory_exists(File.dirname(target_file_path))
|
66
|
+
File.write(target_file_path, translated_content)
|
67
|
+
|
68
|
+
UI.success("✅ #{target_language}: Translation completed")
|
69
|
+
total_translated += 1
|
70
|
+
successful_languages << target_language
|
71
|
+
rescue StandardError => e
|
72
|
+
UI.error("❌ #{target_language}: Translation failed - #{e.message}")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Set shared values
|
77
|
+
Actions.lane_context[SharedValues::TRANSLATE_METADATA_WITH_DEEPL_TRANSLATED_COUNT] = total_translated
|
78
|
+
Actions.lane_context[SharedValues::TRANSLATE_METADATA_WITH_DEEPL_TARGET_LANGUAGES] = successful_languages
|
79
|
+
Actions.lane_context[SharedValues::TRANSLATE_METADATA_WITH_DEEPL_BACKUP_FILE] = backup_file
|
80
|
+
|
81
|
+
UI.success('🎉 Metadata translation completed!')
|
82
|
+
UI.message("📊 Successfully translated #{file_name} for #{total_translated} languages")
|
83
|
+
UI.message("📄 Backup saved: #{backup_file}")
|
84
|
+
UI.message('🗑️ You can delete the backup after verifying results')
|
85
|
+
|
86
|
+
total_translated
|
87
|
+
end
|
88
|
+
|
89
|
+
def self.setup_deepl_client(params)
|
90
|
+
DeepL.configure do |config|
|
91
|
+
config.auth_key = params[:api_token]
|
92
|
+
config.host = params[:free_api] ? 'https://api-free.deepl.com' : 'https://api.deepl.com'
|
93
|
+
end
|
94
|
+
|
95
|
+
# Test API key
|
96
|
+
begin
|
97
|
+
DeepL.usage
|
98
|
+
UI.success('✅ DeepL API key validated')
|
99
|
+
rescue DeepL::Exceptions::AuthorizationFailed
|
100
|
+
UI.user_error!('❌ Invalid DeepL API key. Get one at: https://www.deepl.com/pro#developer')
|
101
|
+
rescue StandardError => e
|
102
|
+
UI.user_error!("❌ DeepL API connection failed: #{e.message}")
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.create_backup(source_file_path)
|
107
|
+
timestamp = Time.now.strftime('%Y%m%d_%H%M%S')
|
108
|
+
backup_path = "#{source_file_path}.backup_#{timestamp}"
|
109
|
+
FileUtils.cp(source_file_path, backup_path)
|
110
|
+
UI.message("💾 Backup created: #{backup_path}")
|
111
|
+
backup_path
|
112
|
+
end
|
113
|
+
|
114
|
+
def self.detect_target_languages(metadata_path, source_locale, specified_languages)
|
115
|
+
if specified_languages && !specified_languages.empty?
|
116
|
+
UI.message("🎯 Using specified target languages: #{specified_languages.join(', ')}")
|
117
|
+
return specified_languages
|
118
|
+
end
|
119
|
+
|
120
|
+
# Auto-detect from existing metadata directories
|
121
|
+
UI.message('🔍 Auto-detecting target languages from metadata directories...')
|
122
|
+
|
123
|
+
detected_languages = []
|
124
|
+
Dir.glob(File.join(metadata_path, '*')).each do |dir|
|
125
|
+
next unless File.directory?(dir)
|
126
|
+
|
127
|
+
locale = File.basename(dir)
|
128
|
+
next if locale == source_locale # Skip source locale
|
129
|
+
next if locale == 'default' # Skip special directories
|
130
|
+
next if locale == 'review_information'
|
131
|
+
|
132
|
+
# Map metadata directory names to DeepL-compatible language codes
|
133
|
+
deepl_language = map_metadata_directory_to_language(locale)
|
134
|
+
detected_languages << deepl_language
|
135
|
+
end
|
136
|
+
|
137
|
+
UI.message("📁 Found metadata directories for: #{detected_languages.join(', ')}")
|
138
|
+
detected_languages
|
139
|
+
end
|
140
|
+
|
141
|
+
def self.map_metadata_directory_to_language(metadata_dir)
|
142
|
+
# Map App Store metadata directory names to DeepL-compatible language codes
|
143
|
+
case metadata_dir
|
144
|
+
when 'de-DE'
|
145
|
+
'de' # German metadata directory -> de for DeepL
|
146
|
+
when 'es-ES'
|
147
|
+
'es' # Spanish (Spain) metadata directory -> es for DeepL
|
148
|
+
when 'fr-FR'
|
149
|
+
'fr' # French metadata directory -> fr for DeepL
|
150
|
+
when 'nl-NL'
|
151
|
+
'nl' # Dutch metadata directory -> nl for DeepL
|
152
|
+
when 'no'
|
153
|
+
'nb' # Norwegian metadata directory -> nb (Bokmål) for DeepL
|
154
|
+
else
|
155
|
+
metadata_dir # Direct mapping for most languages
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def self.determine_formality(target_language, formality_param)
|
160
|
+
return formality_param if formality_param
|
161
|
+
|
162
|
+
if Helper::DeeplLanguageMapperHelper.supports_formality?(target_language)
|
163
|
+
UI.message("🎭 #{Helper::LanguageRegistryHelper.language_name(target_language)} supports formality options")
|
164
|
+
return 'prefer_more' # Default to more formal for App Store metadata
|
165
|
+
end
|
166
|
+
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
|
170
|
+
def self.translate_content(source_content, source_language, target_language, formality)
|
171
|
+
source_lang = Helper::DeeplLanguageMapperHelper.get_source_language(source_language)
|
172
|
+
target_lang = Helper::DeeplLanguageMapperHelper.get_target_language(target_language)
|
173
|
+
|
174
|
+
translation_options = {}
|
175
|
+
translation_options[:formality] = formality if formality
|
176
|
+
|
177
|
+
# DeepL.translate expects: texts, source_lang, target_lang, options
|
178
|
+
result = DeepL.translate([source_content], source_lang, target_lang, translation_options)
|
179
|
+
|
180
|
+
# Handle both single and array responses
|
181
|
+
result.is_a?(Array) ? result.first.text : result.text
|
182
|
+
rescue StandardError => e
|
183
|
+
raise "DeepL translation failed: #{e.message}"
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.map_to_metadata_directory(language_code)
|
187
|
+
# Map DeepL language codes back to App Store metadata directory names
|
188
|
+
case language_code
|
189
|
+
when 'nb'
|
190
|
+
'no' # Norwegian Bokmål -> no
|
191
|
+
when 'de'
|
192
|
+
'de-DE' # German -> de-DE
|
193
|
+
when 'es'
|
194
|
+
'es-ES' # Spanish -> es-ES
|
195
|
+
when 'fr'
|
196
|
+
'fr-FR' # French -> fr-FR
|
197
|
+
when 'nl'
|
198
|
+
'nl-NL' # Dutch -> nl-NL
|
199
|
+
else
|
200
|
+
language_code # Direct mapping for most languages
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.ensure_directory_exists(directory_path)
|
205
|
+
FileUtils.mkdir_p(directory_path) unless File.directory?(directory_path)
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.description
|
209
|
+
'Translate App Store metadata files using DeepL API'
|
210
|
+
end
|
211
|
+
|
212
|
+
def self.details
|
213
|
+
'This action translates App Store metadata files (like release_notes.txt, description.txt) ' \
|
214
|
+
'from a source language to all supported target languages using DeepL API. ' \
|
215
|
+
'It automatically detects target languages from existing metadata directories ' \
|
216
|
+
'and only translates to languages supported by both App Store and DeepL.'
|
217
|
+
end
|
218
|
+
|
219
|
+
def self.available_options
|
220
|
+
[
|
221
|
+
FastlaneCore::ConfigItem.new(
|
222
|
+
key: :api_token,
|
223
|
+
env_name: 'DEEPL_AUTH_KEY',
|
224
|
+
description: 'DeepL API authentication key',
|
225
|
+
sensitive: true,
|
226
|
+
default_value: ENV.fetch('DEEPL_AUTH_KEY', nil)
|
227
|
+
),
|
228
|
+
FastlaneCore::ConfigItem.new(
|
229
|
+
key: :metadata_path,
|
230
|
+
description: 'Path to fastlane metadata directory',
|
231
|
+
default_value: './fastlane/metadata',
|
232
|
+
verify_block: proc do |value|
|
233
|
+
UI.user_error!("Metadata directory not found: #{value}") unless File.directory?(value)
|
234
|
+
end
|
235
|
+
),
|
236
|
+
FastlaneCore::ConfigItem.new(
|
237
|
+
key: :source_locale,
|
238
|
+
description: 'Source language locale (e.g., en-US)',
|
239
|
+
default_value: 'en-US'
|
240
|
+
),
|
241
|
+
FastlaneCore::ConfigItem.new(
|
242
|
+
key: :file_name,
|
243
|
+
description: 'Metadata file to translate (e.g., release_notes.txt, description.txt)',
|
244
|
+
default_value: 'release_notes.txt'
|
245
|
+
),
|
246
|
+
FastlaneCore::ConfigItem.new(
|
247
|
+
key: :target_languages,
|
248
|
+
description: 'Specific target languages to translate to (optional, auto-detects if not specified)',
|
249
|
+
type: Array,
|
250
|
+
optional: true
|
251
|
+
),
|
252
|
+
FastlaneCore::ConfigItem.new(
|
253
|
+
key: :formality,
|
254
|
+
description: 'Formality setting for translation (default, more, less, prefer_more, prefer_less)',
|
255
|
+
optional: true,
|
256
|
+
verify_block: proc do |value|
|
257
|
+
valid_options = %w[default more less prefer_more prefer_less]
|
258
|
+
UI.user_error!("Invalid formality option. Must be one of: #{valid_options.join(', ')}") unless valid_options.include?(value)
|
259
|
+
end
|
260
|
+
),
|
261
|
+
FastlaneCore::ConfigItem.new(
|
262
|
+
key: :free_api,
|
263
|
+
description: 'Use DeepL Free API endpoint',
|
264
|
+
type: Boolean,
|
265
|
+
default_value: false
|
266
|
+
)
|
267
|
+
]
|
268
|
+
end
|
269
|
+
|
270
|
+
def self.output
|
271
|
+
[
|
272
|
+
['TRANSLATE_METADATA_WITH_DEEPL_TRANSLATED_COUNT', 'Number of languages successfully translated'],
|
273
|
+
['TRANSLATE_METADATA_WITH_DEEPL_TARGET_LANGUAGES', 'Array of target language codes that were translated'],
|
274
|
+
['TRANSLATE_METADATA_WITH_DEEPL_BACKUP_FILE', 'Path to the backup file created before translation']
|
275
|
+
]
|
276
|
+
end
|
277
|
+
|
278
|
+
def self.return_value
|
279
|
+
'Number of languages that were successfully translated'
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.authors
|
283
|
+
['tijs']
|
284
|
+
end
|
285
|
+
|
286
|
+
def self.is_supported?(platform)
|
287
|
+
%i[ios android].include?(platform)
|
288
|
+
end
|
289
|
+
|
290
|
+
def self.example_code
|
291
|
+
[
|
292
|
+
'# Translate release notes to all detected languages',
|
293
|
+
'translate_metadata_with_deepl',
|
294
|
+
'',
|
295
|
+
'# Translate description file with specific settings',
|
296
|
+
'translate_metadata_with_deepl(',
|
297
|
+
' file_name: "description.txt",',
|
298
|
+
' source_locale: "en-US",',
|
299
|
+
' formality: "prefer_more"',
|
300
|
+
')',
|
301
|
+
'',
|
302
|
+
'# Translate only to specific languages',
|
303
|
+
'translate_metadata_with_deepl(',
|
304
|
+
' file_name: "release_notes.txt",',
|
305
|
+
' target_languages: ["de", "fr-FR", "es-ES", "ja"]',
|
306
|
+
')'
|
307
|
+
]
|
308
|
+
end
|
309
|
+
|
310
|
+
def self.category
|
311
|
+
:misc
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fastlane-plugin-translate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tijs Teulings
|
@@ -164,8 +164,8 @@ dependencies:
|
|
164
164
|
- !ruby/object:Gem::Version
|
165
165
|
version: '0'
|
166
166
|
description: A fastlane plugin to automatically translate iOS Localizable.xcstrings
|
167
|
-
files using DeepL API. Supports progress tracking,
|
168
|
-
and more.
|
167
|
+
files and App Store metadata files using DeepL API. Supports progress tracking,
|
168
|
+
formality options, error recovery, auto-detection of target languages, and more.
|
169
169
|
email: hello@tijs.org
|
170
170
|
executables: []
|
171
171
|
extensions: []
|
@@ -174,6 +174,7 @@ files:
|
|
174
174
|
- LICENSE
|
175
175
|
- README.md
|
176
176
|
- lib/fastlane/plugin/translate.rb
|
177
|
+
- lib/fastlane/plugin/translate/actions/translate_metadata_with_deepl.rb
|
177
178
|
- lib/fastlane/plugin/translate/actions/translate_with_deepl.rb
|
178
179
|
- lib/fastlane/plugin/translate/helper/batch_translation_processor.rb
|
179
180
|
- lib/fastlane/plugin/translate/helper/deepl_language_mapper_helper.rb
|
@@ -202,5 +203,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
203
|
requirements: []
|
203
204
|
rubygems_version: 3.6.9
|
204
205
|
specification_version: 4
|
205
|
-
summary: Automatically translate iOS Localizable.xcstrings files
|
206
|
+
summary: Automatically translate iOS Localizable.xcstrings files and App Store metadata
|
207
|
+
using DeepL API
|
206
208
|
test_files: []
|