phraseapp_updater 3.2.0 → 3.3.1
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/bin/phraseapp_updater +16 -1
- data/lib/phraseapp_updater/phraseapp_api.rb +50 -21
- data/lib/phraseapp_updater/version.rb +1 -1
- data/lib/phraseapp_updater.rb +2 -2
- metadata +17 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5d137755330d9711327e6731a7b4ae1fc701ec705ce719055bca7479dcd3579a
|
4
|
+
data.tar.gz: ab2839920b873ed264759eadf926d6b9df837b511b163f1f18e4ef777bcfc820
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: afe9e8266f248e39c52095a762a64a9e1823bf94f825a4cbe7d166946892cd1c171252d2218b3dce0c47c6dd6e4cfe224c826a5ffea812d8f3011f07991c5034
|
7
|
+
data.tar.gz: ba81fe027f6016fc759e72b5cf27c88e1c31ca7e08e1580dd4c5b110ecaa83dcd6f603ec686978b21071fbb5bc9e02e5967e32a1a102612a5a16448094c3158a
|
data/bin/phraseapp_updater
CHANGED
@@ -9,6 +9,14 @@ class PhraseAppUpdaterCLI < Thor
|
|
9
9
|
class_option :file_format, type: :string, default: 'json', desc: 'Filetype of localization files.'
|
10
10
|
class_option :verbose, type: :boolean, default: false, desc: 'Verbose output'
|
11
11
|
|
12
|
+
# Options that mirror the PhraseApp API (https://developers.phrase.com/api/#post-/projects)
|
13
|
+
PHRASEAPP_CREATE_PROJECT_OPTIONS = {
|
14
|
+
zero_plural_form_enabled: {
|
15
|
+
type: :boolean,
|
16
|
+
desc: 'Displays the input fields for the \'ZERO\' plural form for every key as well although only some languages require the \'ZERO\' explicitly.'
|
17
|
+
},
|
18
|
+
}
|
19
|
+
|
12
20
|
desc 'setup <locale_path>',
|
13
21
|
'Create a new PhraseApp project, initializing it with locale files at <locale_path>. the new project ID is printed to STDOUT'
|
14
22
|
method_option :phraseapp_api_key, type: :string, required: true, desc: 'PhraseApp API key.'
|
@@ -16,16 +24,23 @@ class PhraseAppUpdaterCLI < Thor
|
|
16
24
|
method_option :parent_commit, type: :string, required: true, desc: 'git commit hash of initial locales'
|
17
25
|
method_option :remove_orphans, type: :boolean, default: true, desc: 'Remove keys not in the uploaded default locale'
|
18
26
|
|
27
|
+
PHRASEAPP_CREATE_PROJECT_OPTIONS.each do |name, params|
|
28
|
+
method_option(name, **params)
|
29
|
+
end
|
30
|
+
|
19
31
|
def setup(locales_path)
|
20
32
|
validate_readable_path!('locales', locales_path)
|
21
33
|
|
22
34
|
handle_errors do
|
35
|
+
phraseapp_opts = options.slice(*PHRASEAPP_CREATE_PROJECT_OPTIONS.keys)
|
36
|
+
|
23
37
|
updater, project_id = PhraseAppUpdater.for_new_project(
|
24
38
|
options[:phraseapp_api_key],
|
25
39
|
options[:phraseapp_project_name],
|
26
40
|
options[:file_format],
|
27
41
|
options[:parent_commit],
|
28
|
-
verbose: options[:verbose]
|
42
|
+
verbose: options[:verbose],
|
43
|
+
**phraseapp_opts)
|
29
44
|
|
30
45
|
updater.upload_directory(locales_path, remove_orphans: options[:remove_orphans])
|
31
46
|
|
@@ -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
|
|
@@ -25,10 +26,15 @@ class PhraseAppUpdater
|
|
25
26
|
@locale_file_class = locale_file_class
|
26
27
|
end
|
27
28
|
|
28
|
-
|
29
|
+
# @param [Hash] opts Options to be passed to the {https://developers.phrase.com/api/#post-/projects PhraseApp API}
|
30
|
+
def create_project(name, parent_commit, **opts)
|
29
31
|
params = Phrase::ProjectCreateParameters.new(
|
30
|
-
name
|
31
|
-
|
32
|
+
# Merges name and main_format into opts to prevent overriding these properties
|
33
|
+
opts.merge(
|
34
|
+
name: name,
|
35
|
+
main_format: @locale_file_class.phraseapp_type
|
36
|
+
)
|
37
|
+
)
|
32
38
|
|
33
39
|
project = phraseapp_request(Phrase::ProjectsApi, :project_create, params)
|
34
40
|
|
@@ -91,38 +97,60 @@ class PhraseAppUpdater
|
|
91
97
|
end
|
92
98
|
end
|
93
99
|
|
94
|
-
# Empirically, PhraseApp fails to parse the uploaded files when uploaded in
|
95
|
-
# parallel. Give it a better chance by uploading them one at a time.
|
96
100
|
def upload_files(locale_files, default_locale:)
|
97
|
-
|
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
|
98
104
|
|
99
|
-
# Ensure the locales all exist
|
100
|
-
STDERR.puts('Creating locales')
|
101
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')
|
102
126
|
threaded_request(locale_files) do |locale_file|
|
103
127
|
unless known_locales.has_key?(locale_file.locale_name)
|
104
|
-
create_locale(locale_file.locale_name, default:
|
128
|
+
create_locale(locale_file.locale_name, default: false)
|
105
129
|
end
|
106
130
|
end
|
107
131
|
|
108
|
-
|
109
|
-
locale_files.sort! do |a, b|
|
110
|
-
next -1 if is_default.(a)
|
111
|
-
next 1 if is_default.(b)
|
132
|
+
uploads = Concurrent::Hash.new
|
112
133
|
|
113
|
-
|
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
|
114
138
|
end
|
115
139
|
|
116
|
-
|
140
|
+
successful_uploads = verify_uploads(uploads)
|
117
141
|
|
118
|
-
|
119
|
-
|
120
|
-
upload_id = upload_file(locale_file)
|
121
|
-
[upload_id, locale_file]
|
142
|
+
if default_locale_file
|
143
|
+
successful_uploads = successful_uploads.merge(successful_default_upload)
|
122
144
|
end
|
123
145
|
|
124
|
-
|
125
|
-
|
146
|
+
successful_uploads
|
147
|
+
end
|
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
|
126
154
|
|
127
155
|
STDERR.puts('Verifying uploads...')
|
128
156
|
until uploads.empty?
|
@@ -152,6 +180,7 @@ class PhraseAppUpdater
|
|
152
180
|
successful_upload_ids
|
153
181
|
end
|
154
182
|
|
183
|
+
|
155
184
|
def remove_keys_not_in_uploads(upload_ids)
|
156
185
|
threaded_request(upload_ids) do |upload_id|
|
157
186
|
STDERR.puts "Removing keys not in upload #{upload_id}"
|
data/lib/phraseapp_updater.rb
CHANGED
@@ -10,9 +10,9 @@ require 'phraseapp_updater/yml_config_loader'
|
|
10
10
|
class PhraseAppUpdater
|
11
11
|
using IndexBy
|
12
12
|
|
13
|
-
def self.for_new_project(phraseapp_api_key, phraseapp_project_name, file_format, parent_commit, verbose: false)
|
13
|
+
def self.for_new_project(phraseapp_api_key, phraseapp_project_name, file_format, parent_commit, verbose: false, **phraseapp_opts)
|
14
14
|
api = PhraseAppAPI.new(phraseapp_api_key, nil, LocaleFile.class_for_file_format(file_format))
|
15
|
-
project_id = api.create_project(phraseapp_project_name, parent_commit)
|
15
|
+
project_id = api.create_project(phraseapp_project_name, parent_commit, **phraseapp_opts)
|
16
16
|
return self.new(phraseapp_api_key, project_id, file_format, verbose: verbose), project_id
|
17
17
|
end
|
18
18
|
|
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.
|
4
|
+
version: 3.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- iKnow Team
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-10-01 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
|
@@ -193,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
193
207
|
- !ruby/object:Gem::Version
|
194
208
|
version: '0'
|
195
209
|
requirements: []
|
196
|
-
rubygems_version: 3.3.
|
210
|
+
rubygems_version: 3.3.27
|
197
211
|
signing_key:
|
198
212
|
specification_version: 4
|
199
213
|
summary: A three-way differ for PhraseApp projects.
|