crowdin-cli 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
- - ">="
|