crowdin-cli 0.2.0 → 0.2.1

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
  SHA1:
3
- metadata.gz: 66ad927a1e1132fbcd7e3423ea92d67ab4fcf9ee
4
- data.tar.gz: b82bd71053c5d79e1c710a0f24a272aae0d99289
3
+ metadata.gz: 9f6bb76e96af25bd099e35327e0affba41a15d99
4
+ data.tar.gz: 42379e5aefbf2d76b2650fff116ed5e89f609098
5
5
  SHA512:
6
- metadata.gz: 8bb8e237425d2bf49a2647e4006191cfbdb646b05f144dd96f2dc730bffb285b6d771493dfa2034e7ae86a8cb9c08effa92dad7d908991c8b7159acb729af857
7
- data.tar.gz: c5126f6fc09657b5a67808cdbf2492f515b8a28d421f8fd91b074c931e6e39e202c87cbc1129cb78f0e4bedbcc766e90e654f856e83e8e7a47871ccf0a9ac8d9
6
+ metadata.gz: 0efaaa136de06a8915600bd6c60d7ba6fb48ef5ecb7406c15e0206442577bbb08fe639a910c8a181a0cdef615cfe72ee1e33d0676312341675dcfe40ef1f017d
7
+ data.tar.gz: 585990c4a380dcda6caee000d2b50f7ec949202a00487c2e0092c96e46a7f85de50764f17a2fb1d89c5ca082937f81a476b5ec938f4feb75b9c03dc83f2d2a4b
data/README.md CHANGED
@@ -153,6 +153,50 @@ files:
153
153
 
154
154
  ```
155
155
 
156
+ ### Uploading CSV files via API
157
+
158
+ ```
159
+ ---
160
+ project_identifier: test
161
+ api_key: KeepTheAPIkeySecret
162
+ base_url: http://api.crowdin.net
163
+ base_path: /path/to/your/project
164
+
165
+ files:
166
+ -
167
+ source: '/*.csv'
168
+ translation: '%two_letters_code%/%original_file_name%'
169
+ # Defines whether first line should be imported or it contains columns headers
170
+ first_line_contains_header: true
171
+ # Used only when uploading CSV file to define data columns mapping.
172
+ scheme: "identifier,source_phrase,translation,context,max_length"
173
+ ```
174
+
175
+ #### Multicolumn CSV
176
+
177
+ In case when CSV file should contains translations to all target languages you can use per-file option `multilingual_spreadsheet`.
178
+
179
+ CSV file example:
180
+ ```
181
+ identifier,source_phrase,context,Ukrainian,Russian,French
182
+ ident1,Source 1,Context 1,,,
183
+ ident2,Source 2,Context 2,,,
184
+ ident3,Source 3,Context 3,,,
185
+ ```
186
+
187
+ Configuration file example:
188
+ ```
189
+ files:
190
+ -
191
+ source: multicolumn.csv
192
+ translation: multicolumn.csv
193
+ first_line_contains_header: true
194
+ scheme: "identifier,source_phrase,context,uk,ru,fr"
195
+ multilingual_spreadsheet: true
196
+
197
+ ```
198
+
199
+
156
200
  ## Example Configurations
157
201
 
158
202
  ### GetText Project
@@ -196,25 +240,6 @@ files:
196
240
  ru: ru
197
241
  ```
198
242
 
199
- ### Uploading CSV files via API
200
-
201
- ```
202
- ---
203
- project_identifier: test
204
- api_key: KeepTheAPIkeySecret
205
- base_url: http://api.crowdin.net
206
- base_path: /path/to/your/project
207
-
208
- files:
209
- -
210
- source: '/*.csv'
211
- translation: '%two_letters_code%/%original_file_name%'
212
- # Defines whether first line should be imported or it contains columns headers
213
- first_line_contains_header: true
214
- # Used only when uploading CSV file to define data columns mapping.
215
- scheme: "identifier,source_phrase,translation,context,max_length"
216
- ```
217
-
218
243
  ## Usage
219
244
 
220
245
  When the configuration file is created you are ready to start using `crowdin-cli` to manage your localization resources and automate files synchronization.
@@ -270,4 +295,4 @@ Author: Anton Maminov (anton.maminov@gmail.com)
270
295
 
271
296
  Copyright: 2012-2013 [Crowdin.net](http://crowdin.net/)
272
297
 
273
- This project is licensed under the MIT license, a copy of which can be found in the LICENSE file.
298
+ This project is licensed under the MIT license, a copy of which can be found in the LICENSE file.
@@ -57,22 +57,22 @@ end
57
57
  # @option lang [String] :locale
58
58
  #
59
59
  def export_pattern_to_path(path, export_pattern, lang, languages_mapping = nil)
60
- original_path = File.dirname(path)
60
+ original_path = File.dirname(path)[1..-1]
61
61
  original_file_name = File.basename(path)
62
62
  file_extension = File.extname(path)[1..-1]
63
63
  file_name = File.basename(path, File.extname(path))
64
64
 
65
65
  pattern = {
66
+ '%original_file_name%' => original_file_name,
67
+ '%original_path%' => original_path,
68
+ '%file_extension%' => file_extension,
69
+ '%file_name%' => file_name,
66
70
  '%language%' => lang['name'],
67
71
  '%two_letters_code%' => lang['iso_639_1'],
68
72
  '%three_letters_code%' => lang['iso_639_3'],
69
73
  '%locale%' => lang['locale'],
70
74
  '%locale_with_underscore%' => lang['locale'].gsub('-', '_'),
71
75
  '%android_code%' => android_locale_code(lang['locale']),
72
- '%original_file_name%' => original_file_name,
73
- '%original_path%' => original_path,
74
- '%file_extension%' => file_extension,
75
- '%file_name%' => file_name,
76
76
  }
77
77
 
78
78
  placeholders = pattern.inject([]){ |memo, h| memo << h.first[/%(.*)%/, 1] }
@@ -98,7 +98,8 @@ def construct_export_pattern(path, source, translation)
98
98
  translation = translation.sub('**', double_asterisk)
99
99
  end
100
100
 
101
- export_pattern = translation.split('/').reject(&:empty?).join('/').insert(0, '/')
101
+ export_pattern = translation.split('/').reject(&:empty?).join('/')
102
+ export_pattern.insert(0, '/') if translation.start_with?('/')
102
103
 
103
104
  return export_pattern
104
105
  end
@@ -182,14 +183,16 @@ end
182
183
  #
183
184
  def unzip_file_with_translations(zipfile_name, dest_path, files_list)
184
185
  # overwrite files if they already exist inside of the extracted path
185
- Zip.options[:on_exists_proc] = true
186
+ Zip.on_exists_proc = true
186
187
 
187
188
  # files that exists in archive and doesn't match current project configuration
188
189
  unmatched_files = []
189
190
 
190
- Zip::ZipFile.open(zipfile_name) do |zipfile|
191
+ Zip::File.open(zipfile_name) do |zipfile|
191
192
  zipfile.select{ |zip_entry| zip_entry.file? }.each do |f|
192
- file = files_list['/' + f.name]
193
+ # XXX
194
+ # `f' - relative path in archive
195
+ file = files_list[f.name]
193
196
  if file
194
197
  fpath = File.join(dest_path, file)
195
198
  FileUtils.mkdir_p(File.dirname(fpath))
@@ -221,12 +224,12 @@ sort_help :manually # help commands are ordered in the order declared
221
224
  wrap_help_text :to_terminal
222
225
 
223
226
  desc I18n.t('app.switches.verbose.desc')
224
- switch [:verbose, :v], :negatable => false
227
+ switch [:v, :verbose], :negatable => false
225
228
 
226
229
  desc I18n.t('app.flags.config.desc')
227
230
  default_value File.join(Dir.pwd, 'crowdin.yaml')
228
231
  arg_name '<s>'
229
- flag [:config,:c]
232
+ flag [:c, :config]
230
233
 
231
234
  desc I18n.t('app.commands.upload.desc')
232
235
  long_desc I18n.t('app.commands.upload.long_desc')
@@ -237,6 +240,7 @@ command :upload do |c|
237
240
  c.command :sources do |c|
238
241
 
239
242
  c.desc I18n.t('app.commands.upload.commands.sources.switches.auto_update.desc')
243
+ c.default_value true
240
244
  c.switch ['auto-update']
241
245
 
242
246
  c.action do |global_options, options, args|
@@ -258,12 +262,12 @@ command :upload do |c|
258
262
  puts "Warning: #{placeholder} is not valid variable supported by Crowdin. See http://crowdin.net/page/cli-tool#configuration-file for more details."
259
263
  end
260
264
 
261
- if File.exist?("#{@base_path}#{file['source']}")
265
+ if File.exist?(File.join(@base_path, file['source']))
262
266
  dest = file['source']
263
267
  dest_files << dest
264
268
 
265
- local_file = { dest: dest, source: "#{@base_path}#{file['source']}", export_pattern: file['translation'] }
266
- # Used only when uploading CSV file to define data columns mapping.
269
+ local_file = { dest: dest, source: File.join(@base_path, file['source']), export_pattern: file['translation'] }
270
+ # Used only when uploading CSV file to define data columns mapping
267
271
  local_file.merge!({ sheme: file['scheme'] }) if file.has_key?('scheme')
268
272
  local_file.merge!({ first_line_contains_header: file['first_line_contains_header'] }) if file.has_key?('first_line_contains_header')
269
273
 
@@ -279,7 +283,7 @@ command :upload do |c|
279
283
  else
280
284
  next
281
285
  end
282
- elsif File.fnmatch?(file['source'], dest)
286
+ elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME)
283
287
  dest_files << dest
284
288
 
285
289
  export_pattern = construct_export_pattern(dest, file['source'], file['translation'])
@@ -317,7 +321,7 @@ EOS
317
321
  @crowdin.add_directory(dir)
318
322
  end
319
323
 
320
- if options['auto-update'].nil? or options['auto-update']
324
+ if options['auto-update']
321
325
  # Update existing files in Crowdin project
322
326
  #
323
327
  # array containing elements common to the two arrays
@@ -365,7 +369,7 @@ EOS
365
369
  c.desc I18n.t('app.commands.upload.commands.translations.flags.language.desc')
366
370
  c.default_value 'all'
367
371
  c.arg_name 'crowdin_language_code'
368
- c.flag [:language, :l]
372
+ c.flag [:l, :language]
369
373
 
370
374
  c.desc I18n.t('app.commands.upload.commands.translations.switches.import_duplicates.desc')
371
375
  c.switch ['import-duplicates']
@@ -398,11 +402,12 @@ EOS
398
402
  end
399
403
 
400
404
  supported_languages = @crowdin.supported_languages
401
- translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) }
402
405
 
403
406
  source_language = project_info['details']['source_language']['code']
404
407
  source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language }
405
408
 
409
+ translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) }
410
+
406
411
  translated_files = Hash.new{ |hash, key| hash[key] = Array.new }
407
412
  dest_files = []
408
413
 
@@ -413,13 +418,22 @@ EOS
413
418
 
414
419
  languages_mapping = file['languages_mapping']
415
420
 
416
- if File.exists?("#{@base_path}#{file['source']}")
421
+ # CSV files only (default: false)
422
+ multilingual_spreadsheet = file['multilingual_spreadsheet'] || false
423
+
424
+ if multilingual_spreadsheet
425
+ file_translation_languages = [] << source_language
426
+ else
427
+ file_translation_languages = translation_languages
428
+ end
429
+
430
+ if File.exists?(File.join(@base_path, file['source']))
417
431
  dest = file['source'].sub("#{@base_path}", '')
418
432
  dest_files << dest
419
433
 
420
- translation_languages.each do |lang|
434
+ file_translation_languages.each do |lang|
421
435
  source = export_pattern_to_path(dest, file['translation'], lang, languages_mapping)
422
- translated_files[lang['crowdin_code']] << { source: "#{@base_path}#{source}", dest: dest }
436
+ translated_files[lang['crowdin_code']] << { source: File.join(@base_path, source), dest: dest }
423
437
  end
424
438
  else
425
439
  Find.find(@base_path) do |source_path|
@@ -432,17 +446,17 @@ EOS
432
446
  else
433
447
  next
434
448
  end
435
- elsif File.fnmatch?(file['source'], dest)
449
+ elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME)
436
450
  dest_files << dest
437
451
 
438
452
  export_pattern = construct_export_pattern(dest, file['source'], file['translation'])
439
453
 
440
- translation_languages.each do |lang|
454
+ file_translation_languages.each do |lang|
441
455
  source = export_pattern_to_path(dest, export_pattern, lang, languages_mapping)
442
- translated_files[lang['crowdin_code']] << { source: "#{@base_path}#{source}", dest: dest }
456
+ translated_files[lang['crowdin_code']] << { source: File.join(@base_path, source), dest: dest }
443
457
  end
444
- end
445
458
 
459
+ end
446
460
  end # Find
447
461
 
448
462
  end # if
@@ -494,7 +508,7 @@ command :download do |c|
494
508
 
495
509
  c.desc I18n.t('app.commands.download.flags.language.desc')
496
510
  c.arg_name 'language_code'
497
- c.flag [:language, :l], :default_value => 'all'
511
+ c.flag [:l, :language], :default_value => 'all'
498
512
 
499
513
  c.action do |global_options ,options, args|
500
514
  language = options[:language]
@@ -516,11 +530,12 @@ command :download do |c|
516
530
  @crowdin.export_translations
517
531
 
518
532
  supported_languages = @crowdin.supported_languages
519
- translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) }
520
533
 
521
534
  source_language = project_info['details']['source_language']['code']
522
535
  source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language }
523
536
 
537
+ translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) }
538
+
524
539
  # keys is all possible files in .ZIP archive
525
540
  # values is resulted local files
526
541
  downloadable_files_hash = {}
@@ -528,15 +543,25 @@ command :download do |c|
528
543
  @config['files'].each do |file|
529
544
  languages_mapping = file['languages_mapping'] # Hash or NilClass
530
545
 
531
- if File.exists?("#{@base_path}#{file['source']}")
546
+ # CSV files only (default: false)
547
+ multilingual_spreadsheet = file['multilingual_spreadsheet'] || false
548
+
549
+ if multilingual_spreadsheet
550
+ file_translation_languages = [] << source_language
551
+ else
552
+ file_translation_languages = translation_languages
553
+ end
554
+
555
+ if File.exists?(File.join(@base_path, file['source']))
532
556
  dest = file['source'].sub("#{@base_path}", '')
533
557
 
534
- translation_languages.each do |lang|
558
+ file_translation_languages.each do |lang|
535
559
  zipped_file = export_pattern_to_path(dest, file['translation'], lang)
560
+ zipped_file.sub!(/^\//, '')
536
561
  local_file = export_pattern_to_path(dest, file['translation'], lang, languages_mapping)
537
-
538
562
  downloadable_files_hash[zipped_file] = local_file
539
563
  end
564
+
540
565
  else
541
566
  Find.find(@base_path) do |source_path|
542
567
  dest = source_path.sub(@base_path, '') # relative path in Crowdin
@@ -548,19 +573,18 @@ command :download do |c|
548
573
  else
549
574
  next
550
575
  end
551
- elsif File.fnmatch?(file['source'], dest)
576
+ elsif File.fnmatch?(file['source'], dest, File::FNM_PATHNAME)
552
577
  export_pattern = construct_export_pattern(dest, file['source'], file['translation'])
553
578
 
554
- translation_languages.each do |lang|
579
+ file_translation_languages.each do |lang|
555
580
  zipped_file = export_pattern_to_path(dest, export_pattern, lang)
581
+ zipped_file.sub!(/^\//, '')
556
582
  local_file = export_pattern_to_path(dest, export_pattern, lang, languages_mapping)
557
-
558
583
  downloadable_files_hash[zipped_file] = local_file
559
584
  end
560
- end
561
585
 
586
+ end
562
587
  end # Find
563
-
564
588
  end # if
565
589
  end # @config['files']
566
590
 
@@ -618,7 +642,7 @@ EOS
618
642
 
619
643
  @config['files'].each do |file|
620
644
  file['source'] = '/' + file['source'] unless file['source'].start_with?('/')
621
- file['translation'] = '/' + file['translation'] unless file['translation'].start_with?('/')
645
+ #file['translation'] = '/' + file['translation'] unless file['translation'].start_with?('/')
622
646
 
623
647
  if file['source'].include?('**')
624
648
  if file['source'].scan('**').size > 1
@@ -650,13 +674,6 @@ Warning: Configuration file misses parameter `base_path` that defines your proje
650
674
  EOS
651
675
  end
652
676
 
653
- if @config['remote_path']
654
- @remote_path = @config['remote_path']
655
- @remote_path = '/' + @remote_path unless @remote_path.start_with?('/')
656
- else
657
- @remote_path = ''
658
- end
659
-
660
677
  @preserve_hierarchy = false
661
678
  if @config['preserve_hierarchy']
662
679
  @preserve_hierarchy = case @config['preserve_hierarchy']
@@ -672,7 +689,10 @@ EOS
672
689
  end
673
690
 
674
691
  Crowdin::API.log = Logger.new($stderr) if globals[:verbose]
675
- @crowdin = Crowdin::API.new(api_key: @config['api_key'], project_id: @config['project_identifier'], base_url: @config['base_url'] || 'http://api.crowdin.net')
692
+
693
+ base_url = @config['base_url'] || 'http://api.crowdin.net'
694
+ @crowdin = Crowdin::API.new(api_key: @config['api_key'], project_id: @config['project_identifier'], base_url: base_url)
695
+
676
696
  begin
677
697
  @crowdin.project_info
678
698
  rescue Crowdin::API::Errors::Error => err
@@ -7,6 +7,6 @@ require 'yaml'
7
7
  require 'json'
8
8
  require 'logger'
9
9
  require 'gli'
10
- require 'zip/zip'
10
+ require 'zip'
11
11
  require 'i18n'
12
12
  require 'crowdin-api'
@@ -1,5 +1,5 @@
1
1
  module Crowdin
2
2
  module CLI
3
- VERSION = '0.2.0'
3
+ VERSION = '0.2.1'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crowdin-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Crowdin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-05 00:00:00.000000000 Z
11
+ date: 2013-09-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -58,42 +58,42 @@ dependencies:
58
58
  requirements:
59
59
  - - '>='
60
60
  - !ruby/object:Gem::Version
61
- version: 2.6.0
61
+ version: 2.7.0
62
62
  type: :runtime
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '>='
67
67
  - !ruby/object:Gem::Version
68
- version: 2.6.0
68
+ version: 2.7.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rubyzip
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
73
  - - '>='
74
74
  - !ruby/object:Gem::Version
75
- version: 0.9.9
75
+ version: 1.0.0
76
76
  type: :runtime
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
80
  - - '>='
81
81
  - !ruby/object:Gem::Version
82
- version: 0.9.9
82
+ version: 1.0.0
83
83
  - !ruby/object:Gem::Dependency
84
84
  name: crowdin-api
85
85
  requirement: !ruby/object:Gem::Requirement
86
86
  requirements:
87
87
  - - '>='
88
88
  - !ruby/object:Gem::Version
89
- version: 0.0.11
89
+ version: 0.2.0
90
90
  type: :runtime
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - '>='
95
95
  - !ruby/object:Gem::Version
96
- version: 0.0.11
96
+ version: 0.2.0
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: i18n
99
99
  requirement: !ruby/object:Gem::Requirement