crowdin-cli 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Anton Maminov
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,108 @@
1
+ # Crowdin-CLI
2
+
3
+ A Command-Line Interface to sync files between your computer/server and [Crowdin](crowdin.net).
4
+
5
+ It is cross-platform and runs in a terminal (Linux, MacOS X) or in cmd.exe (Windows).
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```
12
+ gem 'crowdin-cli'
13
+ ```
14
+
15
+ And then execute:
16
+ ```
17
+ $ bundle
18
+ ```
19
+
20
+ Or install it yourself as:
21
+ ```
22
+ $ gem install crowdin-cli
23
+ ```
24
+
25
+ ## Configuration
26
+
27
+ Now that the tool in installed, you'll have to configure your project. Basically, `crowdin-cli` is to be run on a project directory, and looks for a `crowdin.yaml` file containing your project information.
28
+
29
+ Create a `crowdin.yaml` YAML file in your root project directory with the following structure:
30
+
31
+ ```
32
+ ---
33
+ project_id: test
34
+ api_key: KeepTheAPIkeySecret
35
+ base_url: http://api.crowdin.net
36
+ base_path: /path/to/your/project
37
+
38
+ files:
39
+ -
40
+ source: /locale/en/LC_MESSAGES/messages.po
41
+ translation: /locale/%two_letter_code%/LC_MESSAGES/%original_file_name%
42
+ ```
43
+
44
+ * `api_key` - Crowdin Project API key
45
+ * `project_id` - Crowdin project name
46
+ * `base_url` - (default: http://api.crowdin.net)
47
+ * `base_path` - defines what directory we have to scan(default: current directory)
48
+ * `files`
49
+ * `source` - defines only files we will upload as sources
50
+ * `translation` - attribute defines where translations should be placed after downloading (also we have to check those path to detect and upload existing translations)
51
+
52
+ Use the following placeholders to put appropriate variables into the resulting file name:
53
+ * `%language%` - Language name (i.e. Ukrainian)
54
+ * `%two_letter_code%` - Language code ISO 639-1 (i.e. uk)
55
+ * `%three_letter_code%` - Language code ISO 639-2/T (i.e. ukr)
56
+ * `%locale%` - Locale (like uk-UA)
57
+ * `%locale_with_underscore%` - Locale (i.e. uk_UA)
58
+ * `%original_file_name%` - Original file name
59
+ * `%android_code%` - Android Locale identifier used to name "values-" directories
60
+ * `%original_path%` - Take parent folders names in Crowdin project to build file path in resulted bundle
61
+ * `%file_extension%` - Original file extension
62
+ * `%file_name%` - File name without extension
63
+
64
+ Example for Android projects:
65
+ ```
66
+ /values-%android_code%/%original_file_name%
67
+ ```
68
+ Example for Gettext projects:
69
+ ```
70
+ /locale/%two_letter_code%/LC_MESSAGES/%original_file_name%
71
+ ```
72
+
73
+ Also you can add and upload all directories mathing the pattern including all nested files and localizable files.
74
+
75
+ Create a `crowdin.yaml` YAML file in your root project directory with the following structure:
76
+ ```
77
+ ---
78
+ project_id: test
79
+ api_key: KeepTheAPIkeySecret
80
+ base_url: http://api.crowdin.net
81
+ base_path: /path/to/your/project
82
+
83
+ files:
84
+ -
85
+ source: /locale/en/**/*.po
86
+ translation: /locale/%two_letter_code%/**/%original_file_name%
87
+ ```
88
+ ## Usage
89
+
90
+
91
+ ## Supported Rubies
92
+
93
+ Tested with the following Ruby versions:
94
+
95
+ - MRI 1.9.3
96
+ - JRuby 1.7.0
97
+
98
+ ## Contributing
99
+
100
+ 1. Fork it
101
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
102
+ 3. Commit your changes (`git commit -am 'Added some feature'`)
103
+ 4. Push to the branch (`git push origin my-new-feature`)
104
+ 5. Create new Pull Request
105
+
106
+ ## License
107
+
108
+ This library is distributed under the MIT license. Please see the LICENSE file.
@@ -1,13 +1,10 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'pp'
4
- require 'json'
5
- require 'gli'
6
- require 'zip/zip'
7
- require 'crowdin-api'
8
4
  require 'crowdin-cli'
9
5
 
10
- # повертає структуру директорій на сервері
6
+ # using for upload source files
7
+ # return existing directory structure in Crowdin project
11
8
  #
12
9
  def walk_remote_tree(files, root = '/', result = { dirs: [], files: [] })
13
10
  files.each do |node|
@@ -23,20 +20,18 @@ def walk_remote_tree(files, root = '/', result = { dirs: [], files: [] })
23
20
  return result
24
21
  end
25
22
 
26
-
27
- # Повертає локальну структуру директорій
28
- # На вході масив файлів, наприклад:
29
- # ['/path/to/admin/en.xml', '/path/to/user/settings/strings.xml']
30
- # Результат хеш { dirs:[послідовний масив директорій для створення], files: [] }
23
+ # using for upload source files
24
+ # return local directory structute
25
+ # first argument: ['/path/to/admin/en.xml', '/path/to/user/settings/strings.xml']
31
26
  #
32
27
  def walk_local_tree(files, result = { dirs: [], files: [] })
33
28
  result[:files] = files
34
29
 
35
- files = files.inject([]){ |res, a|
36
- res << a.split('/').drop(1).inject([]){ |res, s|
30
+ files = files.inject([]) do |res, a|
31
+ res << a.split('/').drop(1).inject([]) do |res, s|
37
32
  res << res.last.to_s + '/' + s
38
- }
39
- }
33
+ end
34
+ end
40
35
  # Ex: files = [["/path", "/path/to", "/path/to/admin", "/path/to/admin/en.xml"], ... ]
41
36
 
42
37
  files.map(&:pop) # delete last element from each array
@@ -69,7 +64,6 @@ def android_locale_code(locale_code)
69
64
  return locale_code.sub('-', '-r')
70
65
  end
71
66
 
72
-
73
67
  ###
74
68
  include GLI::App
75
69
 
@@ -85,7 +79,6 @@ default_value File.join(Dir.pwd, 'crowdin.yaml')
85
79
  arg_name '<s>'
86
80
  flag [:c, :config]
87
81
 
88
-
89
82
  desc 'Upload existing translations to Crowdin project'
90
83
  #arg_name 'Describe arguments to upload here'
91
84
  command :upload do |c|
@@ -109,27 +102,53 @@ command :upload do |c|
109
102
  c.desc 'Upload source files'
110
103
  c.command :sources do |c|
111
104
  c.action do |global_options, options, args|
112
- project_info = @crowdin.project_info(:json)
113
- project_info = JSON.parse(project_info)
105
+ project_info = @crowdin.project_info
114
106
 
115
- remote_project_tree = walk_remote_tree(project_info['files'])
107
+ #source_language = project_info['info']['source_language']
108
+ source_language = 'en'
109
+
110
+ # Crowdin supported languages list
111
+ supported_languages = @crowdin.supported_languages['languages']
112
+ source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language }
113
+
114
+ remote_project_tree = walk_remote_tree(project_info['info']['files']['items'])
116
115
 
117
116
  local_files = []
118
117
  @config['files'].each do |file|
119
- local_file = "#{@local_path}#{@sources_root}#{file['source']}"
120
-
121
- if File.exist?(local_file)
122
- local_files << { dest: file['source'], source: local_file, export_pattern: file['translation'] }
118
+ if File.exist?("#{@base_path}#{file['source']}")
119
+ local_files << { dest: file['source'], source: "#{@base_path}#{file['source']}", export_pattern: file['translation'] }
123
120
  else
124
- Dir.glob(local_file).each do |f|
125
- local_files << { dest: f.sub("#{@local_path}#{@sources_root}", ''), source: f, export_pattern: file['translation'] }
121
+ Dir.glob("#{@base_path}#{file['source']}").each do |source|
122
+ dest = source.sub("#{@base_path}", '') # relative path in Crowdin
123
+ original_path = File.dirname(dest)
124
+ original_file_name = File.basename(dest)
125
+ file_extension = File.extname(dest)
126
+ file_name = File.basename(dest, file_extension)
127
+
128
+ file_pattern = file['translation'].gsub(/%.+?%/, {
129
+ '%language%' => source_language['name'],
130
+ '%two_letter_code%' => source_language['iso_639_1'],
131
+ '%tree_letter_code%' => source_language['iso_639_3'],
132
+ '%locale%' => source_language['locale'],
133
+ '%locale_with_underscore%' => source_language['locale'].gsub('-', '_'),
134
+ '%original_file_name%' => original_file_name,
135
+ '%android_code%' => android_locale_code(source_language['locale']),
136
+ '%original_path%' => original_path,
137
+ '%file_extension%' => file_extension,
138
+ '%file_name%' => file_extension,
139
+ })
140
+
141
+ diff = (dest.split('/') - file_pattern.split('/')).join('/')
142
+ export_pattern = file['translation'].sub('**', diff)
143
+
144
+ local_files << { dest: dest, source: source, export_pattern: export_pattern }
126
145
  end
146
+
127
147
  end
128
148
  end
129
149
 
130
150
  local_project_tree = walk_local_tree(local_files.collect{ |h| h[:dest] })
131
151
 
132
- #=begin
133
152
  # Create directory tree
134
153
  #
135
154
  create_dirs = local_project_tree[:dirs] - remote_project_tree[:dirs]
@@ -157,12 +176,10 @@ command :upload do |c|
157
176
  puts "Add new file `#{file[:dest]}`"
158
177
  @crowdin.add_file([] << file)
159
178
  end
160
- #=end
161
179
 
162
180
  end # action
163
181
  end # command
164
182
 
165
-
166
183
  c.desc 'Upload translation files'
167
184
  c.command :translations do |c|
168
185
 
@@ -184,46 +201,34 @@ command :upload do |c|
184
201
  c.action do |global_options, options, args|
185
202
  language = options[:language]
186
203
 
187
- project_info = @crowdin.project_info(:json)
188
- project_info = JSON.parse(project_info)
204
+ project_info = @crowdin.project_info
205
+
206
+ remote_project_tree = walk_remote_tree(project_info['info']['files']['items'])
189
207
 
190
- # Array of project languages
191
208
  if language == 'all'
192
- project_languages = project_info['languages'].collect{ |h| h['code'] }
209
+ project_languages = project_info['info']['languages']['items'].collect{ |h| h['code'] }
193
210
  else
194
211
  project_languages = [] << language
195
212
  end
196
213
 
197
- # Crowdin supported languages list
198
- supported_languages = @crowdin.supported_languages(:json)
199
- supported_languages = JSON.parse(supported_languages)
200
- supported_languages.select!{ |lang| project_languages.include?(lang['crowdin_code']) }
214
+ supported_languages = @crowdin.supported_languages['languages']
215
+ translation_languages = supported_languages.select{ |lang| project_languages.include?(lang['crowdin_code']) }
216
+
217
+ source_language = 'en'
218
+ source_language = supported_languages.find{ |lang| lang['crowdin_code'] == source_language }
201
219
 
202
220
  translated_files = Hash.new{ |hash, key| hash[key] = Array.new }
203
221
 
204
- # Тут робиться багато припіздатєнької роботи :)
205
- # TODO тут тре всьо нахуй переписати!!! НЕНАВИСТЬ
206
222
  @config['files'].each do |file|
207
- translation = file['translation']
208
- source = file['source'] # relative path to source file in Crowdin project
209
-
210
- sources = []
211
- if File.exists?("#{@local_path}#{@sources_root}#{source}")
212
- sources << source
213
- else
214
- Dir.glob("#{@local_path}#{@sources_root}#{source}").each do |f|
215
- sources << f.sub("#{@local_path}#{@sources_root}", '')
216
- end
217
- end
218
-
219
- sources.each do |source|
220
- original_path = source.split('/')[1...-1].join('/')
221
- original_file_name = source.split('/').last
222
- file_extension = original_file_name.split('.').last
223
- file_name = original_file_name.split('.').shift
224
-
225
- supported_languages.each do |lang|
226
- file = translation.gsub(/%.+?%/, {
223
+ if File.exists?("#{@base_path}#{file['source']}")
224
+ dest = file['source'].sub("#{@base_path}", '')
225
+ original_path = File.dirname(dest)
226
+ original_file_name = File.basename(dest)
227
+ file_extension = File.extname(dest)[1..-1]
228
+ file_name = File.basename(dest, file_extension)
229
+
230
+ translation_languages.each do |lang|
231
+ source = file['translation'].gsub(/%.+?%/, {
227
232
  '%language%' => lang['name'],
228
233
  '%two_letter_code%' => lang['iso_639_1'],
229
234
  '%tree_letter_code%' => lang['iso_639_3'],
@@ -235,18 +240,60 @@ command :upload do |c|
235
240
  '%file_extension%' => file_extension,
236
241
  '%file_name%' => file_extension,
237
242
  })
238
- translated_files[lang['crowdin_code']] << { source: @local_path + file, dest: source }
243
+
244
+ translated_files[lang['crowdin_code']] << { source: "#{@base_path}#{source}", dest: dest }
239
245
  end
246
+ else
247
+ Dir.glob("#{@base_path}#{file['source']}").each do |source|
248
+ dest = source.sub("#{@base_path}", '')
249
+ original_path = File.dirname(dest)
250
+ original_file_name = File.basename(dest)
251
+ file_extension = File.extname(dest)
252
+ file_name = File.basename(dest, file_extension)
253
+
254
+ file_pattern = file['translation'].gsub(/%.+?%/, {
255
+ '%language%' => source_language['name'],
256
+ '%two_letter_code%' => source_language['iso_639_1'],
257
+ '%tree_letter_code%' => source_language['iso_639_3'],
258
+ '%locale%' => source_language['locale'],
259
+ '%locale_with_underscore%' => source_language['locale'].gsub('-', '_'),
260
+ '%original_file_name%' => original_file_name,
261
+ '%android_code%' => android_locale_code(source_language['locale']),
262
+ '%original_path%' => original_path,
263
+ '%file_extension%' => file_extension,
264
+ '%file_name%' => file_extension,
265
+ })
240
266
 
241
- end
267
+ diff = (dest.split('/') - file_pattern.split('/')).join('/')
268
+ export_pattern = file['translation'].sub('**', diff)
269
+
270
+ translation_languages.each do |lang|
271
+ source = export_pattern.gsub(/%.+?%/, {
272
+ '%language%' => lang['name'],
273
+ '%two_letter_code%' => lang['iso_639_1'],
274
+ '%tree_letter_code%' => lang['iso_639_3'],
275
+ '%locale%' => lang['locale'],
276
+ '%locale_with_underscore%' => lang['locale'].gsub('-', '_'),
277
+ '%original_file_name%' => original_file_name,
278
+ '%android_code%' => android_locale_code(lang['locale']),
279
+ '%original_path%' => original_path,
280
+ '%file_extension%' => file_extension,
281
+ '%file_name%' => file_extension,
282
+ })
283
+
284
+ translated_files[lang['crowdin_code']] << { source: "#{@base_path}#{source}", dest: dest }
285
+ end
242
286
 
243
- end
287
+ end
288
+ end # if
289
+ end # @config['files']
244
290
 
245
291
  params = {}
246
292
  params[:import_duplicates] = options[:import_dublicates] ? 1 : 0
247
293
  params[:import_eq_suggestions] = options[:import_eq_suggestions] ? 1 : 0
248
294
  params[:auto_approve_imported] = options[:auto_approve_imported] ? 1 : 0
249
295
 
296
+
250
297
  translated_files.each do |language, files|
251
298
  files.each do |file|
252
299
  if File.exist?(file[:source])
@@ -263,7 +310,6 @@ command :upload do |c|
263
310
 
264
311
  end
265
312
 
266
-
267
313
  desc 'Download existing translations'
268
314
  #arg_name 'Describe arguments to download here'
269
315
  command :download do |c|
@@ -281,7 +327,7 @@ command :download do |c|
281
327
  file = Tempfile.new(language)
282
328
  begin
283
329
  @crowdin.download_translation(language, :output => file)
284
- unzip_file(file, @local_path)
330
+ unzip_file(file, @base_path)
285
331
  ensure
286
332
  file.close
287
333
  file.unlink # delete the temp file
@@ -299,20 +345,18 @@ pre do |global ,command, options, args|
299
345
 
300
346
  @config = YAML.load_file(global[:config])
301
347
 
302
- #@local_path = @config['local_path'] || Dir.pwd
303
- if @config['local_path']
304
- if @config['local_path'].start_with?('/')
305
- @local_path = @config['local_path']
348
+ #@base_path = @config['base_path'] || Dir.pwd
349
+ if @config['base_path']
350
+ if @config['base_path'].start_with?('/')
351
+ @base_path = @config['base_path']
306
352
  else
307
- @local_path = Dir.pwd + '/' + @config['local_path']
353
+ @base_path = Dir.pwd + '/' + @config['base_path']
308
354
  end
309
355
  else
310
- @local_path = Dir.pwd
356
+ @base_path = Dir.pwd
311
357
  end
312
358
 
313
- @sources_root = @config['sources_root']
314
-
315
- @crowdin = Crowdin::API.new(api_key: @config['api_key'], project_id: @config['project_id'], base_url: @config['base_url'])
359
+ @crowdin = Crowdin::API.new(api_key: @config['api_key'], project_id: @config['project_id'], base_url: @config['base_url'] || 'http://api.crowdin.net')
316
360
 
317
361
  puts "Executing #{command.name}" if global[:v]
318
362
  true
@@ -4,3 +4,7 @@ require 'crowdin-cli/version.rb'
4
4
  # you just need to require this one file in your bin file
5
5
 
6
6
  require 'yaml'
7
+ require 'json'
8
+ require 'gli'
9
+ require 'zip/zip'
10
+ require 'crowdin-api'
@@ -1,5 +1,5 @@
1
1
  module Crowdin
2
2
  module CLI
3
- VERSION = '0.0.3'
3
+ VERSION = '0.0.4'
4
4
  end
5
5
  end
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.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-27 00:00:00.000000000 Z
12
+ date: 2012-10-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -98,7 +98,7 @@ dependencies:
98
98
  requirements:
99
99
  - - '='
100
100
  - !ruby/object:Gem::Version
101
- version: 0.0.3
101
+ version: 0.0.4
102
102
  type: :runtime
103
103
  prerelease: false
104
104
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,30 +106,25 @@ dependencies:
106
106
  requirements:
107
107
  - - '='
108
108
  - !ruby/object:Gem::Version
109
- version: 0.0.3
109
+ version: 0.0.4
110
110
  description:
111
- email: anton.linux@gmail.com
111
+ email:
112
+ - anton.linux@gmail.com
112
113
  executables:
113
114
  - crowdin-cli
114
115
  extensions: []
115
- extra_rdoc_files:
116
- - README.rdoc
117
- - crowdin-cli.rdoc
116
+ extra_rdoc_files: []
118
117
  files:
119
118
  - bin/crowdin-cli
120
119
  - lib/crowdin-cli/version.rb
121
120
  - lib/crowdin-cli.rb
122
- - README.rdoc
123
- - crowdin-cli.rdoc
121
+ - README.md
122
+ - LICENSE
124
123
  homepage: https://github.com/mamantoha/crowdin-cli
125
- licenses: []
124
+ licenses:
125
+ - LICENSE
126
126
  post_install_message:
127
- rdoc_options:
128
- - --title
129
- - crowdin-cli
130
- - --main
131
- - README.rdoc
132
- - -ri
127
+ rdoc_options: []
133
128
  require_paths:
134
129
  - lib
135
130
  - lib
@@ -138,7 +133,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
138
133
  requirements:
139
134
  - - ! '>='
140
135
  - !ruby/object:Gem::Version
141
- version: '0'
136
+ version: 1.9.3
142
137
  required_rubygems_version: !ruby/object:Gem::Requirement
143
138
  none: false
144
139
  requirements:
@@ -150,5 +145,5 @@ rubyforge_project:
150
145
  rubygems_version: 1.8.24
151
146
  signing_key:
152
147
  specification_version: 3
153
- summary: A description of your project
148
+ summary: Crowdin CLI
154
149
  test_files: []
@@ -1,21 +0,0 @@
1
- = crowdin-cli
2
-
3
- Describe your project here
4
-
5
- == Configuration
6
- Create a `.crowdin` YAML file in your root project directory with the following structure:
7
-
8
- ```yaml
9
- ---
10
- project_id: ''
11
- api_key: ''
12
- server: 'http://api.crowdin.net'
13
-
14
- files:
15
- -
16
- source-file-path: locale/en/LC_MESSAGES/messages.po
17
- translations: locale/<two-letters-code>/LC_MESSAGES/<original-file-name>
18
- ```
19
-
20
- :include:crowdin-cli.rdoc
21
-
@@ -1,5 +0,0 @@
1
- = crowdin-cli
2
-
3
- Generate this with
4
- crowdin-cli rdoc
5
- After you have described your command line interface