phraseapp_updater 3.3.0 → 3.3.2
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 +4 -4
- data/lib/phraseapp_updater/phraseapp_api.rb +78 -30
- data/lib/phraseapp_updater/version.rb +1 -1
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b44812204928f9576633c2d59bd8c4deb220cdd70e7cfb2f52cdc059368b7b8a
|
4
|
+
data.tar.gz: 13e282dcfc436150b6edecf384ae6b54c4133c8cb19a73bd5f723fe90bbb923b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bd3fe2ab57e511236b31902d21d31d3e80d2e07029c1c7f2d52c4983bf263d5839ab85a6eef904967f6560f387af4312170d3032307b73a2456a816ef97f59b
|
7
|
+
data.tar.gz: c0d4677afd153d1b8f0aa95d0f58bb2b1c1568abd6ee68b646610316c8cd7f28a82e0670e5302d6e39c4f4543a025fa867f4850e05922892d22276b5ba771f11
|
@@ -4,6 +4,7 @@ require 'phraseapp_updater/locale_file'
|
|
4
4
|
require 'phraseapp_updater/index_by'
|
5
5
|
require 'uri'
|
6
6
|
require 'phrase'
|
7
|
+
require 'concurrent'
|
7
8
|
require 'parallel'
|
8
9
|
require 'tempfile'
|
9
10
|
|
@@ -96,39 +97,61 @@ class PhraseAppUpdater
|
|
96
97
|
end
|
97
98
|
end
|
98
99
|
|
99
|
-
# Empirically, PhraseApp fails to parse the uploaded files when uploaded in
|
100
|
-
# parallel. Give it a better chance by uploading them one at a time.
|
101
100
|
def upload_files(locale_files, default_locale:)
|
102
|
-
|
101
|
+
locale_files = locale_files.sort_by(&:locale_name)
|
102
|
+
default_locale_file = locale_files.detect { |l| l.locale_name == default_locale }
|
103
|
+
locale_files.delete(default_locale_file) if default_locale_file
|
103
104
|
|
104
|
-
# Ensure the locales all exist
|
105
|
-
STDERR.puts('Creating locales')
|
106
105
|
known_locales = fetch_locales.index_by(&:name)
|
106
|
+
|
107
|
+
# Phraseapp appears to use to use the first file uploaded to resolve conflicts
|
108
|
+
# between pluralized and non-pluralized keys. Upload and verify the canonical
|
109
|
+
# default locale first before uploading translated locales.
|
110
|
+
if default_locale_file
|
111
|
+
unless known_locales.has_key?(default_locale_file.locale_name)
|
112
|
+
STDERR.puts("Creating default locale (#{default_locale_file})")
|
113
|
+
create_locale(default_locale_file.locale_name, default: true)
|
114
|
+
end
|
115
|
+
|
116
|
+
STDERR.puts("Uploading default locale (#{default_locale_file})")
|
117
|
+
upload_id = upload_file(default_locale_file)
|
118
|
+
|
119
|
+
successful_default_upload = verify_uploads({ upload_id => default_locale_file })
|
120
|
+
else
|
121
|
+
STDERR.puts("No upload for default locale (#{default_locale})")
|
122
|
+
end
|
123
|
+
|
124
|
+
# Ensure the locales all exist
|
125
|
+
STDERR.puts('Creating translation locales')
|
107
126
|
threaded_request(locale_files) do |locale_file|
|
108
127
|
unless known_locales.has_key?(locale_file.locale_name)
|
109
|
-
create_locale(locale_file.locale_name, default:
|
128
|
+
create_locale(locale_file.locale_name, default: false)
|
110
129
|
end
|
111
130
|
end
|
112
131
|
|
113
|
-
|
114
|
-
locale_files.sort! do |a, b|
|
115
|
-
next -1 if is_default.(a)
|
116
|
-
next 1 if is_default.(b)
|
132
|
+
uploads = Concurrent::Hash.new
|
117
133
|
|
118
|
-
|
134
|
+
threaded_request(locale_files) do |locale_file|
|
135
|
+
STDERR.puts("Uploading #{locale_file}")
|
136
|
+
upload_id = upload_file(locale_file)
|
137
|
+
uploads[upload_id] = locale_file
|
119
138
|
end
|
120
139
|
|
121
|
-
|
140
|
+
successful_uploads = verify_uploads(uploads)
|
122
141
|
|
123
|
-
|
124
|
-
|
125
|
-
upload_id = upload_file(locale_file)
|
126
|
-
[upload_id, locale_file]
|
142
|
+
if default_locale_file
|
143
|
+
successful_uploads = successful_uploads.merge(successful_default_upload)
|
127
144
|
end
|
128
145
|
|
129
|
-
|
130
|
-
|
146
|
+
successful_uploads
|
147
|
+
end
|
131
148
|
|
149
|
+
# Given a map of {upload_id => locale_file} pairs, use the upload_show
|
150
|
+
# API to verify that they're complete, and re-upload them if they failed.
|
151
|
+
# Return a map of locale name to upload id.
|
152
|
+
def verify_uploads(uploads)
|
153
|
+
successful_upload_ids = Concurrent::Hash.new
|
154
|
+
attempts = 1
|
132
155
|
STDERR.puts('Verifying uploads...')
|
133
156
|
until uploads.empty?
|
134
157
|
threaded_request(uploads.to_a) do |upload_id, locale_file|
|
@@ -151,12 +174,18 @@ class PhraseAppUpdater
|
|
151
174
|
end
|
152
175
|
end
|
153
176
|
|
154
|
-
|
177
|
+
unless uploads.empty?
|
178
|
+
delay = attempts ** 1.6 + 1
|
179
|
+
STDERR.puts("#{uploads.size} remaining, waiting #{delay.round} seconds...")
|
180
|
+
sleep(delay)
|
181
|
+
attempts += 1
|
182
|
+
end
|
155
183
|
end
|
156
184
|
|
157
185
|
successful_upload_ids
|
158
186
|
end
|
159
187
|
|
188
|
+
|
160
189
|
def remove_keys_not_in_uploads(upload_ids)
|
161
190
|
threaded_request(upload_ids) do |upload_id|
|
162
191
|
STDERR.puts "Removing keys not in upload #{upload_id}"
|
@@ -209,17 +238,30 @@ class PhraseAppUpdater
|
|
209
238
|
phraseapp_request(Phrase::TagsApi,:tag_create, @project_id, params)
|
210
239
|
end
|
211
240
|
|
212
|
-
def wrap_phrase_errors
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
241
|
+
def wrap_phrase_errors(retries: 10)
|
242
|
+
begin
|
243
|
+
yield
|
244
|
+
rescue Phrase::ApiError => e
|
245
|
+
if e.code == 401
|
246
|
+
raise BadAPIKeyError.new(e)
|
247
|
+
elsif e.code == 429
|
248
|
+
# If we bail mid-sync, it can be expensive to recover from a partial
|
249
|
+
# merge. Instead, aggressively try to retry.
|
250
|
+
if retries >= 0
|
251
|
+
retries -= 1
|
252
|
+
STDERR.puts('Rate limited, retrying in 5...')
|
253
|
+
sleep(5)
|
254
|
+
retry
|
255
|
+
end
|
256
|
+
|
257
|
+
raise RateLimitError.new(e)
|
258
|
+
elsif e.message.match?(/not found/)
|
259
|
+
raise BadProjectIDError.new(e, @project_id)
|
260
|
+
elsif e.message.match?(/has already been taken/)
|
261
|
+
raise ProjectNameTakenError.new(e)
|
262
|
+
else
|
263
|
+
raise
|
264
|
+
end
|
223
265
|
end
|
224
266
|
end
|
225
267
|
|
@@ -324,5 +366,11 @@ class PhraseAppUpdater
|
|
324
366
|
super(original_error.message)
|
325
367
|
end
|
326
368
|
end
|
369
|
+
|
370
|
+
class RateLimitError < RuntimeError
|
371
|
+
def initialize(original_error)
|
372
|
+
super(original_error.message)
|
373
|
+
end
|
374
|
+
end
|
327
375
|
end
|
328
376
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phraseapp_updater
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.3.
|
4
|
+
version: 3.3.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2025-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -94,6 +94,20 @@ dependencies:
|
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.23'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: concurrent-ruby
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: 1.0.2
|
104
|
+
type: :runtime
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: 1.0.2
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
112
|
name: bundler
|
99
113
|
requirement: !ruby/object:Gem::Requirement
|
@@ -178,7 +192,7 @@ homepage: https://github.com/iknow/phraseapp_updater
|
|
178
192
|
licenses:
|
179
193
|
- MIT
|
180
194
|
metadata: {}
|
181
|
-
post_install_message:
|
195
|
+
post_install_message:
|
182
196
|
rdoc_options: []
|
183
197
|
require_paths:
|
184
198
|
- lib
|
@@ -194,7 +208,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
208
|
version: '0'
|
195
209
|
requirements: []
|
196
210
|
rubygems_version: 3.3.27
|
197
|
-
signing_key:
|
211
|
+
signing_key:
|
198
212
|
specification_version: 4
|
199
213
|
summary: A three-way differ for PhraseApp projects.
|
200
214
|
test_files: []
|