crowdin-cli 0.6.0 → 0.6.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/README.md +1 -1
- data/bin/crowdin-cli +80 -67
- data/lib/crowdin-cli/version.rb +1 -1
- data/locales/en.yml +4 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca670246e92cc0a4e9af4f79a32762d67b4c33c6
|
4
|
+
data.tar.gz: deec43f00c30bb9d2c7cdeafa0142da169e0c1e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7009d7b1074c12834278b452c25ecd1f16cc337c071210e10e693201f00868b1dcdd8783a0b743eeb83a71b87f239b3e3767966d55fef3b46b007a517c71da6c
|
7
|
+
data.tar.gz: 7b8d0757f24bbfa593cf6a5137c0370a5fd5328fba279b2861354f0a427e3c1228c30edaf0f58c98e08b94baa026c9414f150383c8e7dda43a0ab15ac3deb137
|
data/README.md
CHANGED
@@ -74,7 +74,7 @@ files:
|
|
74
74
|
* `%file_extension%` - Original file extension
|
75
75
|
* `%file_name%` - File name without extension
|
76
76
|
* `%osx_code%` - OS X Locale identifier used to name ".lproj" directories
|
77
|
-
* `%
|
77
|
+
* `%osx_locale%` - OS X Locale identifier
|
78
78
|
|
79
79
|
Example for Android projects:
|
80
80
|
```
|
data/bin/crowdin-cli
CHANGED
@@ -20,14 +20,16 @@ I18n.locale = :en
|
|
20
20
|
#
|
21
21
|
# +files+ - basically, it's project files details from API method `project_info`
|
22
22
|
#
|
23
|
-
def get_remote_files_hierarchy(files, root = '/', hierarchy
|
23
|
+
def get_remote_files_hierarchy(files, root = '/', hierarchy: { dirs: [], files: [] }, include_branches: true)
|
24
24
|
files.each do |node|
|
25
25
|
case node['node_type']
|
26
26
|
when 'branch'
|
27
|
-
|
27
|
+
if include_branches
|
28
|
+
get_remote_files_hierarchy(node['files'], root + node['name'] + '/', hierarchy: hierarchy)
|
29
|
+
end
|
28
30
|
when 'directory'
|
29
31
|
hierarchy[:dirs] << "#{root}#{node['name']}"
|
30
|
-
get_remote_files_hierarchy(node['files'], root + node['name'] + '/', hierarchy)
|
32
|
+
get_remote_files_hierarchy(node['files'], root + node['name'] + '/', hierarchy: hierarchy)
|
31
33
|
when 'file'
|
32
34
|
hierarchy[:files] << "#{root}#{node['name']}"
|
33
35
|
end
|
@@ -36,6 +38,14 @@ def get_remote_files_hierarchy(files, root = '/', hierarchy = { dirs: [], files:
|
|
36
38
|
return hierarchy
|
37
39
|
end
|
38
40
|
|
41
|
+
# Return branches in Crowdin project
|
42
|
+
#
|
43
|
+
# +files+ - basically, it's project files details from API method `project_info`
|
44
|
+
#
|
45
|
+
def get_branches(files)
|
46
|
+
files.select { |node| node["node_type"] == "branch" }.map { |branch| branch["name"] }
|
47
|
+
end
|
48
|
+
|
39
49
|
# Return +hierarchy+ of local directories and files
|
40
50
|
#
|
41
51
|
# @params [Array] files a list of files in a local directory.
|
@@ -102,7 +112,7 @@ end
|
|
102
112
|
#
|
103
113
|
def construct_export_pattern(path, source, translation)
|
104
114
|
pattern_regexp = translate_pattern_to_regexp(source)
|
105
|
-
if pattern_regexp.names.include?('double_asterisk')
|
115
|
+
if pattern_regexp.names.include?('double_asterisk') && path.match(pattern_regexp)
|
106
116
|
double_asterisk = path.match(pattern_regexp)['double_asterisk']
|
107
117
|
translation = translation.sub('**', double_asterisk)
|
108
118
|
end
|
@@ -136,7 +146,7 @@ def translate_pattern_to_regexp(pat)
|
|
136
146
|
i = i + 1
|
137
147
|
if c == '*'
|
138
148
|
j = i
|
139
|
-
if j < n
|
149
|
+
if j < n && pat[j] == '*'
|
140
150
|
res[-1] = '(\/)?(?<double_asterisk>.*)?'
|
141
151
|
i = j + 1
|
142
152
|
else
|
@@ -149,16 +159,16 @@ def translate_pattern_to_regexp(pat)
|
|
149
159
|
# The following two statements check if the sequence we stumbled
|
150
160
|
# upon is '[]' or '[^]' because those are not valid character
|
151
161
|
# classes.
|
152
|
-
if j < n
|
162
|
+
if j < n && pat[j] == '^'
|
153
163
|
j = j + 1
|
154
164
|
end
|
155
|
-
if j < n
|
165
|
+
if j < n && pat[j] == ']'
|
156
166
|
j = j + 1
|
157
167
|
end
|
158
168
|
# Look for the closing ']' right off the bat. If one is not found,
|
159
169
|
# escape the opening '[' and continue. If it is found, process
|
160
170
|
# he contents of '[...]'.
|
161
|
-
while j < n
|
171
|
+
while j < n && pat[j] != ']'
|
162
172
|
j = j + 1
|
163
173
|
end
|
164
174
|
if j >= n
|
@@ -226,36 +236,37 @@ end
|
|
226
236
|
# +files_list+ is a Hash of key-value pairs. Where key is a possible archive filename based on current project configuration
|
227
237
|
# and value is the expanded filename
|
228
238
|
#
|
229
|
-
def unzip_file_with_translations(zipfile_name, dest_path, files_list, ignore_match)
|
239
|
+
def unzip_file_with_translations(zipfile_name, dest_path, files_list, ignore_match, ignored_paths = [])
|
230
240
|
# overwrite files if they already exist inside of the extracted path
|
231
241
|
Zip.on_exists_proc = true
|
232
242
|
|
233
243
|
# files that exists in archive and doesn't match current project configuration
|
234
244
|
unmatched_files = []
|
235
245
|
|
236
|
-
Zip::File.open(zipfile_name) do |
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
246
|
+
Zip::File.open(zipfile_name) do |zip_file|
|
247
|
+
zip_file.restore_permissions = false
|
248
|
+
zip_file.select(&:file?).each do |zip_entry|
|
249
|
+
next if zip_entry.name.start_with?(*ignored_paths)
|
250
|
+
|
251
|
+
filename = zip_entry.name
|
252
|
+
if @branch_name && @base_path_contains_branch_subfolders
|
241
253
|
# strip branch from filename
|
242
|
-
filename =
|
254
|
+
filename = zip_entry.name.sub(File.join(@branch_name, '/'), '')
|
243
255
|
end
|
244
256
|
|
245
|
-
# `f' - relative path in archive
|
246
257
|
file = files_list[filename]
|
247
258
|
if file
|
248
259
|
fpath = File.join(dest_path, file)
|
249
260
|
FileUtils.mkdir_p(File.dirname(fpath))
|
250
261
|
puts "Extracting: `#{file}'"
|
251
|
-
|
262
|
+
zip_file.extract(zip_entry, fpath)
|
252
263
|
else
|
253
|
-
unmatched_files <<
|
264
|
+
unmatched_files << zip_entry
|
254
265
|
end
|
255
266
|
end
|
256
267
|
end
|
257
268
|
|
258
|
-
unless unmatched_files.empty?
|
269
|
+
unless unmatched_files.empty? || ignore_match
|
259
270
|
puts "Warning: Downloaded translations do not match current project configuration. The following files will be omitted:"
|
260
271
|
unmatched_files.each { |file| puts " - `#{file}'" }
|
261
272
|
end
|
@@ -309,14 +320,6 @@ def display_tree(files_tree, level = -2, branches = [])
|
|
309
320
|
end
|
310
321
|
end
|
311
322
|
|
312
|
-
class String
|
313
|
-
def strip_heredoc
|
314
|
-
indent = scan(/^[ \t]*(?=\S)/).min.size || 0
|
315
|
-
gsub(/^[ \t]{#{indent}}/, '')
|
316
|
-
end
|
317
|
-
end
|
318
|
-
|
319
|
-
###
|
320
323
|
include GLI::App
|
321
324
|
|
322
325
|
version Crowdin::CLI::VERSION
|
@@ -719,18 +722,16 @@ command :download do |c|
|
|
719
722
|
c.desc I18n.t('app.commands.download.switches.ignore_match.desc')
|
720
723
|
c.switch ['ignore-match'], negatable: false
|
721
724
|
|
722
|
-
c.desc I18n.t('app.commands.download.switches.include_unchanged')
|
725
|
+
c.desc I18n.t('app.commands.download.switches.include_unchanged.desc')
|
723
726
|
c.switch ['include-unchanged'], negatable: false
|
724
727
|
|
725
728
|
c.action do |global_options, options, args|
|
726
|
-
|
727
|
-
branch = @project_info['files'].find { |h| h['node_type'] == 'branch' && h['name'] == @branch_name }
|
729
|
+
branches = get_branches(@project_info['files'])
|
728
730
|
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
end
|
731
|
+
if @branch_name && !branches.include?(@branch_name)
|
732
|
+
exit_now! <<~HEREDOC
|
733
|
+
path `#{@branch_name}' did not match any branch known to Crowdin
|
734
|
+
HEREDOC
|
734
735
|
end
|
735
736
|
|
736
737
|
language = options[:language]
|
@@ -842,7 +843,7 @@ command :download do |c|
|
|
842
843
|
begin
|
843
844
|
@crowdin.download_translation(language, params)
|
844
845
|
|
845
|
-
unzip_file_with_translations(zipfile_name, @base_path, downloadable_files_hash, options['ignore-match'])
|
846
|
+
unzip_file_with_translations(zipfile_name, @base_path, downloadable_files_hash, options['ignore-match'], branches)
|
846
847
|
ensure
|
847
848
|
tempfile.close
|
848
849
|
tempfile.unlink # delete the tempfile
|
@@ -865,20 +866,21 @@ command :list do |ls_cmd|
|
|
865
866
|
prj_cmd.flag [:b, :branch]
|
866
867
|
|
867
868
|
prj_cmd.action do |global_options, options, args|
|
869
|
+
branches = get_branches(@project_info['files'])
|
868
870
|
if @branch_name
|
869
871
|
branch = @project_info['files'].find { |h| h['node_type'] == 'branch' && h['name'] == @branch_name }
|
870
872
|
|
871
873
|
unless branch
|
872
|
-
exit_now!
|
874
|
+
exit_now! <<~HEREDOC
|
873
875
|
path `#{@branch_name}' did not match any branch known to Crowdin
|
874
|
-
|
876
|
+
HEREDOC
|
875
877
|
end
|
876
878
|
|
877
879
|
branch_files = [] << branch
|
878
880
|
|
879
881
|
remote_project_tree = get_remote_files_hierarchy(branch_files)
|
880
882
|
else
|
881
|
-
remote_project_tree = get_remote_files_hierarchy(@project_info['files'])
|
883
|
+
remote_project_tree = get_remote_files_hierarchy(@project_info['files'], include_branches: false)
|
882
884
|
end
|
883
885
|
|
884
886
|
if options[:tree]
|
@@ -890,6 +892,17 @@ command :list do |ls_cmd|
|
|
890
892
|
end
|
891
893
|
end
|
892
894
|
|
895
|
+
ls_cmd.desc I18n.t('app.commands.list.commands.branches.desc')
|
896
|
+
ls_cmd.command :branches do |branches_cmd|
|
897
|
+
branches_cmd.action do |global_options, options, args|
|
898
|
+
branches = get_branches(@project_info['files'])
|
899
|
+
branches.each do |branch|
|
900
|
+
puts "- #{branch}"
|
901
|
+
end
|
902
|
+
end
|
903
|
+
end
|
904
|
+
|
905
|
+
|
893
906
|
ls_cmd.desc I18n.t('app.commands.list.commands.sources.desc')
|
894
907
|
ls_cmd.command :sources do |src_cmd|
|
895
908
|
src_cmd.desc I18n.t('app.commands.list.switches.tree.desc')
|
@@ -1046,12 +1059,12 @@ pre do |globals, command, options, args|
|
|
1046
1059
|
]
|
1047
1060
|
|
1048
1061
|
unless File.exist?(globals[:config])
|
1049
|
-
exit_now!
|
1062
|
+
exit_now! <<~HEREDOC
|
1050
1063
|
Can't find configuration file (default `crowdin.yaml').
|
1051
1064
|
Type `crowdin-cli help` to know how to specify custom configuration file
|
1052
1065
|
|
1053
1066
|
See http://crowdin.com/page/cli-tool#configuration-file for more details
|
1054
|
-
|
1067
|
+
HEREDOC
|
1055
1068
|
end
|
1056
1069
|
|
1057
1070
|
# load project-specific configuration
|
@@ -1063,12 +1076,12 @@ pre do |globals, command, options, args|
|
|
1063
1076
|
#
|
1064
1077
|
@config = YAML.load(ERB.new(File.read(globals[:config])).result) || {}
|
1065
1078
|
rescue Psych::SyntaxError => err
|
1066
|
-
exit_now!
|
1079
|
+
exit_now! <<~HEREDOC
|
1067
1080
|
Could not parse YAML: #{err.message}
|
1068
1081
|
|
1069
1082
|
We were unable to successfully parse the crowdin.yaml file that you provided - most likely it is not well-formatted YAML.
|
1070
1083
|
Please check whether your crowdin.yaml is valid YAML - you can use the http://yamllint.com/ validator to do this - and make any necessary changes to fix it.
|
1071
|
-
|
1084
|
+
HEREDOC
|
1072
1085
|
end
|
1073
1086
|
|
1074
1087
|
# try to load the API credentials from an environment variable, e.g.
|
@@ -1096,37 +1109,37 @@ pre do |globals, command, options, args|
|
|
1096
1109
|
|
1097
1110
|
['api_key', 'project_identifier'].each do |key|
|
1098
1111
|
unless @config[key]
|
1099
|
-
exit_now!
|
1112
|
+
exit_now! <<~HEREDOC
|
1100
1113
|
Configuration file misses required option `#{key}`
|
1101
1114
|
|
1102
1115
|
See http://crowdin.com/page/cli-tool#configuration-file for more details
|
1103
|
-
|
1116
|
+
HEREDOC
|
1104
1117
|
end
|
1105
1118
|
end
|
1106
1119
|
|
1107
1120
|
unless @config['files']
|
1108
|
-
exit_now!
|
1121
|
+
exit_now! <<~HEREDOC
|
1109
1122
|
Configuration file misses required section `files`
|
1110
1123
|
|
1111
1124
|
See https://crowdin.com/page/cli-tool#configuration-file for more details
|
1112
|
-
|
1125
|
+
HEREDOC
|
1113
1126
|
end
|
1114
1127
|
|
1115
1128
|
@config['files'].each do |file|
|
1116
1129
|
unless file['source']
|
1117
|
-
exit_now!
|
1130
|
+
exit_now! <<~HEREDOC
|
1118
1131
|
Files section misses required parameter `source`
|
1119
1132
|
|
1120
1133
|
See https://crowdin.com/page/cli-tool#configuration-file for more details
|
1121
|
-
|
1134
|
+
HEREDOC
|
1122
1135
|
end
|
1123
1136
|
|
1124
1137
|
unless file['translation']
|
1125
|
-
exit_now!
|
1138
|
+
exit_now! <<~HEREDOC
|
1126
1139
|
Files section misses required parameter `translation`
|
1127
1140
|
|
1128
1141
|
See https://crowdin.com/page/cli-tool#configuration-file for more details
|
1129
|
-
|
1142
|
+
HEREDOC
|
1130
1143
|
end
|
1131
1144
|
|
1132
1145
|
file['source'] = '/' + file['source'] unless file['source'].start_with?('/')
|
@@ -1134,20 +1147,20 @@ pre do |globals, command, options, args|
|
|
1134
1147
|
|
1135
1148
|
if file['source'].include?('**')
|
1136
1149
|
if file['source'].scan('**').size > 1
|
1137
|
-
exit_now!
|
1150
|
+
exit_now! <<~HEREDOC
|
1138
1151
|
Source pattern `#{file['source']}` is not valid. The mask `**` can be used only once in the source pattern.
|
1139
|
-
|
1140
|
-
elsif file['source'].scan('**').size == 1
|
1141
|
-
exit_now!
|
1152
|
+
HEREDOC
|
1153
|
+
elsif file['source'].scan('**').size == 1 && !file['source'].match(/\/\*\*\//)
|
1154
|
+
exit_now! <<~HEREDOC
|
1142
1155
|
Source pattern `#{file['source']}` is not valid. The mask `**` must be surrounded by slashes `/` in the source pattern.
|
1143
|
-
|
1156
|
+
HEREDOC
|
1144
1157
|
end
|
1145
1158
|
else
|
1146
1159
|
if file['translation'].include?('**')
|
1147
|
-
exit_now!
|
1160
|
+
exit_now! <<~HEREDOC
|
1148
1161
|
Translation pattern `#{file['translation']}` is not valid. The mask `**` can't be used.
|
1149
1162
|
When using `**` in 'translation' pattern it will always contain sub-path from 'source' for certain file.
|
1150
|
-
|
1163
|
+
HEREDOC
|
1151
1164
|
end
|
1152
1165
|
end
|
1153
1166
|
|
@@ -1157,9 +1170,9 @@ pre do |globals, command, options, args|
|
|
1157
1170
|
@base_path = @config['base_path']
|
1158
1171
|
else
|
1159
1172
|
@base_path = Dir.pwd
|
1160
|
-
puts
|
1173
|
+
puts <<~HEREDOC
|
1161
1174
|
Warning: Configuration file misses parameter `base_path` that defines your project root directory. Using `#{@base_path}` as a root directory.
|
1162
|
-
|
1175
|
+
HEREDOC
|
1163
1176
|
end
|
1164
1177
|
|
1165
1178
|
@base_path_contains_branch_subfolders = false
|
@@ -1170,21 +1183,21 @@ pre do |globals, command, options, args|
|
|
1170
1183
|
when false
|
1171
1184
|
false
|
1172
1185
|
else
|
1173
|
-
exit_now!
|
1186
|
+
exit_now! <<~HEREDOC
|
1174
1187
|
Parameter `base_path_contains_branch_subfolders` allows values of true or false.
|
1175
|
-
|
1188
|
+
HEREDOC
|
1176
1189
|
end
|
1177
1190
|
end
|
1178
1191
|
|
1179
1192
|
@branch_name = options[:branch] || nil
|
1180
|
-
if @branch_name
|
1193
|
+
if @branch_name && @base_path_contains_branch_subfolders
|
1181
1194
|
@base_path = File.join(@base_path, @branch_name)
|
1182
1195
|
end
|
1183
1196
|
|
1184
1197
|
unless Dir.exist?(@base_path)
|
1185
|
-
exit_now!
|
1198
|
+
exit_now! <<~HEREDOC
|
1186
1199
|
No such directory `#{@base_path}`. Please make sure that the `base_path` is properly set.
|
1187
|
-
|
1200
|
+
HEREDOC
|
1188
1201
|
end
|
1189
1202
|
|
1190
1203
|
@preserve_hierarchy = false
|
@@ -1195,9 +1208,9 @@ pre do |globals, command, options, args|
|
|
1195
1208
|
when false
|
1196
1209
|
false
|
1197
1210
|
else
|
1198
|
-
exit_now!
|
1211
|
+
exit_now! <<~HEREDOC
|
1199
1212
|
Parameter `preserve_hierarchy` allows values of true or false.
|
1200
|
-
|
1213
|
+
HEREDOC
|
1201
1214
|
end
|
1202
1215
|
end
|
1203
1216
|
|
data/lib/crowdin-cli/version.rb
CHANGED
data/locales/en.yml
CHANGED
@@ -68,7 +68,6 @@ en:
|
|
68
68
|
include_unchanged:
|
69
69
|
desc: |
|
70
70
|
Download all translation files whether or not they have changes
|
71
|
-
|
72
71
|
list:
|
73
72
|
desc: Show a list of files (the current project)
|
74
73
|
long_desc: |
|
@@ -76,6 +75,8 @@ en:
|
|
76
75
|
commands:
|
77
76
|
project:
|
78
77
|
desc: List information about the files that already exists in current project
|
78
|
+
branches:
|
79
|
+
desc: List remote-tracking branches
|
79
80
|
sources:
|
80
81
|
desc: List information about the sources files in current project that match the wild-card pattern
|
81
82
|
translations:
|
@@ -83,3 +84,5 @@ en:
|
|
83
84
|
switches:
|
84
85
|
tree:
|
85
86
|
desc: list contents of directories in a tree-like format
|
87
|
+
include_branches:
|
88
|
+
desc: include branches
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: crowdin-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Crowdin
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pry
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rdoc
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,7 +150,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
136
150
|
requirements:
|
137
151
|
- - ">="
|
138
152
|
- !ruby/object:Gem::Version
|
139
|
-
version:
|
153
|
+
version: 2.4.0
|
140
154
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
141
155
|
requirements:
|
142
156
|
- - ">="
|