fastlane-plugin-translate_gpt 0.1.6 → 0.1.8

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be8140845fda90144346f59a44239c4baa066fc8b75f1afc26655783be3e3686
4
- data.tar.gz: 0a39de422d2b3760c4678df1053a61799cd444434399d8f3f0f22a9dfcf261b0
3
+ metadata.gz: 5e16882ee4e890369a5c14b579f362303a3196e4238d4d3b3f685a9e6b4fb21a
4
+ data.tar.gz: 59719d66698e72c02ae4c625a68a9b5fe8d7dfc34023a5c329d0625bed27b2e9
5
5
  SHA512:
6
- metadata.gz: a60eb486cf4a385386e429d85d6d53e833ff3afb80c8f60dae482a6596f55fce3218e6268669a4ad4f60e7868244ffaf62a772e2e481fd91e168e18d746f1dd2
7
- data.tar.gz: e4a68b0fa334c61c03dc8fdb26fcab4a1310fa9ca877f57522e21d138ea754c937d9ce11263e9dde2d184a23f05d76fc91566c4994167847dd32f2c220bd69a2
6
+ metadata.gz: 23f15a4ca667b24e958ca6775cd6894dc43b85ecf3e705f4270526af2428a1e7a947824b0bbf74132dbc0fa55059edd9020f1dad10946f5e345ae2d69d7997ac
7
+ data.tar.gz: d94703743059519b4e3c17ea988a7591c8f67b981d3d38a075ed8fc801ce952509c146e3fb3f92207102680b490cefbc103f325da85c0f7c7e1c2e0281255e0b
@@ -84,7 +84,9 @@ module Fastlane
84
84
  description: "The path to the Localizable.strings file to be translated",
85
85
  verify_block: proc do |value|
86
86
  UI.user_error!("Invalid file path: #{value}") unless File.exist?(value)
87
- UI.user_error!("Translation file must have .strings extension") unless File.extname(value) == ".strings"
87
+ extension = File.extname(value)
88
+ available_extensions = [".strings", ".xcstrings"]
89
+ UI.user_error!("Translation file must have any of these extensions: #{available_extensions}") unless available_extensions.include? extension
88
90
  end
89
91
  ),
90
92
  FastlaneCore::ConfigItem.new(
@@ -93,7 +95,9 @@ module Fastlane
93
95
  description: "Path to the translation file to update",
94
96
  verify_block: proc do |value|
95
97
  UI.user_error!("Invalid file path: #{value}") unless File.exist?(value)
96
- UI.user_error!("Translation file must have .strings extension") unless File.extname(value) == ".strings"
98
+ extension = File.extname(value)
99
+ available_extensions = [".strings", ".xcstrings"]
100
+ UI.user_error!("Translation file must have any of these extensions: #{available_extensions}") unless available_extensions.include? extension
97
101
  end
98
102
  ),
99
103
  FastlaneCore::ConfigItem.new(
@@ -1,6 +1,7 @@
1
1
  require 'fastlane_core/ui/ui'
2
- require 'loco_strings'
2
+ require 'loco_strings/parsers/xcstrings_file'
3
3
  require 'json'
4
+ # rubocop:disable all
4
5
 
5
6
  module Fastlane
6
7
  UI = FastlaneCore::UI unless Fastlane.const_defined?("UI")
@@ -16,13 +17,50 @@ module Fastlane
16
17
  @timeout = params[:request_timeout]
17
18
  end
18
19
 
19
- # Get the strings from a file
20
- def prepare_hashes()
20
+ def prepare_xcstrings()
21
+ @xcfile = LocoStrings::XCStringsFile.new @params[:source_file]
22
+ @output_hash = {}
23
+ @to_translate = @xcfile.read
24
+
25
+ if @params[:skip_translated] == true
26
+ @to_translate = @to_translate.reject { |k, original|
27
+ !check_value_for_translate(
28
+ @xcfile.unit(k, @params[:target_language]),
29
+ original
30
+ )
31
+ }
32
+ end
33
+ end
34
+
35
+ def check_value_for_translate(string, orignal_string)
36
+ return true unless string
37
+ if string.is_a? LocoStrings::LocoString
38
+ return false if orignal_string.value.nil? || orignal_string.value.empty?
39
+ return string.value.empty?
40
+ elsif string.is_a? LocoStrings::LocoVariantions
41
+ orignal_string.strings.each do |key, _|
42
+ return true unless string.strings.has_key?(key)
43
+ return true if string.strings[key].value.empty?
44
+ end
45
+ end
46
+ return false
47
+ end
48
+
49
+ def prepare_strings()
21
50
  @input_hash = get_strings(@params[:source_file])
22
51
  @output_hash = get_strings(@params[:target_file])
23
52
  @to_translate = filter_translated(@params[:skip_translated], @input_hash, @output_hash)
24
53
  end
25
54
 
55
+ # Get the strings from a file
56
+ def prepare_hashes()
57
+ if File.extname(@params[:source_file]) == ".xcstrings"
58
+ prepare_xcstrings()
59
+ else
60
+ prepare_strings()
61
+ end
62
+ end
63
+
26
64
  # Log information about the input strings
27
65
  def log_input(bunch_size)
28
66
  @translation_count = @to_translate.size
@@ -66,8 +104,13 @@ module Fastlane
66
104
  def translate_bunch_of_strings(bunch_size)
67
105
  bunch_index = 0
68
106
  number_of_bunches = (@translation_count / bunch_size.to_f).ceil
107
+ @keys_associations = {}
69
108
  @to_translate.each_slice(bunch_size) do |bunch|
70
109
  prompt = prepare_bunch_prompt bunch
110
+ if prompt.empty?
111
+ UI.important "Empty prompt, skipping bunch"
112
+ next
113
+ end
71
114
  max_retries = 10
72
115
  times_retried = 0
73
116
 
@@ -109,7 +152,7 @@ module Fastlane
109
152
  def prepare_bunch_prompt(strings)
110
153
  prompt = "I want you to act as a translator for a mobile application strings. " + \
111
154
  "Try to keep length of the translated text. " + \
112
- "You need to response with a JSON only with the translation and nothing else until I say to stop it."
155
+ "You need to response with a JSON only with the translation and nothing else until I say to stop it. "
113
156
  if @params[:context] && !@params[:context].empty?
114
157
  prompt += "This app is #{@params[:context]}. "
115
158
  end
@@ -117,21 +160,46 @@ module Fastlane
117
160
 
118
161
  json_hash = []
119
162
  strings.each do |key, string|
163
+ UI.message "Translating #{key} - #{string}"
164
+ next if string.nil?
165
+
120
166
  string_hash = {}
121
167
  context = string.comment
122
- if context && !context.empty?
123
- string_hash["context"] = context
168
+ string_hash["context"] = context if context && !context.empty?
169
+
170
+ key = transform_string(string.key)
171
+ @keys_associations[key] = string.key
172
+ string_hash["key"] = key
173
+
174
+ if string.is_a? LocoStrings::LocoString
175
+ next if string.value.nil? || string.value.empty?
176
+ string_hash["string_to_translate"] = string.value
177
+ elsif string.is_a? LocoStrings::LocoVariantions
178
+ variants = {}
179
+ string.strings.each do |key, variant|
180
+ next if variant.nil? || variant.value.nil? || variant.value.empty?
181
+ variants[key] = variant.value
182
+ end
183
+ string_hash["strings_to_translate"] = variants
184
+ else
185
+ UI.warning "Unknown type of string: #{string.key}"
124
186
  end
125
- string_hash["key"] = string.key
126
- string_hash["string_to_translate"] = string.value
127
187
  json_hash << string_hash
128
188
  end
189
+ return '' if json_hash.empty?
129
190
  prompt += "'''\n"
130
191
  prompt += json_hash.to_json
131
192
  prompt += "\n'''"
193
+ UI.message "Prompt: #{prompt}"
132
194
  return prompt
133
195
  end
134
196
 
197
+ def transform_string(input_string)
198
+ uppercased_string = input_string.upcase
199
+ escaped_string = uppercased_string.gsub(/[^0-9a-zA-Z]+/, '_')
200
+ return escaped_string
201
+ end
202
+
135
203
  # Request a translation from the GPT API
136
204
  def request_translate(key, string, prompt, index)
137
205
  response = @client.chat(
@@ -195,12 +263,21 @@ module Fastlane
195
263
  string_hash.delete("key")
196
264
  string_hash.delete("context")
197
265
  translated_string = string_hash.values.first
198
- if key && !key.empty? && translated_string && !translated_string.empty?
199
- UI.message "#{index_log} Translating #{key} - #{translated_string}"
200
- string = LocoStrings::LocoString.new(key, translated_string, context)
201
- @output_hash[key] = string
202
- keys_to_translate.delete(key)
266
+ return unless key && !key.empty?
267
+ real_key = @keys_associations[key]
268
+ if translated_string.is_a? Hash
269
+ strings = {}
270
+ translated_string.each do |pl_key, value|
271
+ UI.message "#{index_log} Translating #{real_key} > #{pl_key} - #{value}"
272
+ strings[pl_key] = LocoStrings::LocoString.new(pl_key, value, context)
273
+ end
274
+ string = LocoStrings::LocoVariantions.new(real_key, strings, context)
275
+ elsif translated_string && !translated_string.empty?
276
+ UI.message "#{index_log} Translating #{real_key} - #{translated_string}"
277
+ string = LocoStrings::LocoString.new(real_key, translated_string, context)
203
278
  end
279
+ @output_hash[real_key] = string
280
+ keys_to_translate.delete(key)
204
281
  end
205
282
 
206
283
  if keys_to_translate.length > 0
@@ -215,12 +292,26 @@ module Fastlane
215
292
  target_string = Colorizer::colorize(@params[:target_file], :white)
216
293
  UI.message "Writing #{number_of_strings} strings to #{target_string}..."
217
294
 
218
- file = LocoStrings.load(@params[:target_file])
219
- file.read
220
- @output_hash.each do |key, value|
221
- file.update(key, value.value, value.comment)
295
+ if @xcfile.nil?
296
+ file = LocoStrings.load(@params[:target_file])
297
+ file.read
298
+ @output_hash.each do |key, value|
299
+ file.update(key, value.value, value.comment)
300
+ end
301
+ file.write
302
+ else
303
+ @xcfile.update_file_path(@params[:target_file])
304
+ @output_hash.each do |key, value|
305
+ if value.is_a? LocoStrings::LocoString
306
+ @xcfile.update(key, value.value, value.comment, "translated", @params[:target_language])
307
+ elsif value.is_a? LocoStrings::LocoVariantions
308
+ value.strings.each do |pl_key, variant|
309
+ @xcfile.update_variation(key, pl_key, variant.value, variant.comment, "translated", @params[:target_language])
310
+ end
311
+ end
312
+ end
313
+ @xcfile.write
222
314
  end
223
- file.write
224
315
  end
225
316
 
226
317
  # Read the strings file into a hash
@@ -298,3 +389,5 @@ module Fastlane
298
389
  end
299
390
  end
300
391
  end
392
+
393
+ # rubocop:enable all
@@ -1,5 +1,5 @@
1
1
  module Fastlane
2
2
  module TranslateGpt
3
- VERSION = "0.1.6"
3
+ VERSION = "0.1.8"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fastlane-plugin-translate_gpt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksei Cherepanov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-24 00:00:00.000000000 Z
11
+ date: 2024-02-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-openai
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: 0.1.1
33
+ version: 0.1.4.1
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: 0.1.1
40
+ version: 0.1.4.1
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -212,7 +212,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
212
212
  - !ruby/object:Gem::Version
213
213
  version: '0'
214
214
  requirements: []
215
- rubygems_version: 3.4.13
215
+ rubygems_version: 3.4.19
216
216
  signing_key:
217
217
  specification_version: 4
218
218
  summary: This fastlane plugin provides an easy way to use the OpenAI GPT language