poeditor-cli 0.1.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c3981c762a561c1d20ae5e66b5f200f00a2e3e6b
4
+ data.tar.gz: adfdd3ff5b171bc1d4098af35299e87d677bb086
5
+ SHA512:
6
+ metadata.gz: 21c12379f59d9d8bfd10c4f56e5f22c6c230906cf9053d0ab358247ed46db22ef3d2d088623ebd35ccb249f20f8d8e5ad903811f374f96bcc8435b3af8ad3bfd
7
+ data.tar.gz: 8cd8959d0dec9bd5e33b962ecb493fe75d936df16eac5bda2d9dff3e41afdb624e7bbd24781986c1dc8d69d39a23b4af89072c7529702a22118f06ad63f9310e
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2017 Suyeol Jeon (xoul.kr)
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # poeditor-cli
2
+
3
+ [![Gem](https://img.shields.io/gem/v/cocoaseeds.svg)](https://rubygems.org/gems/cocoaseeds)
4
+ [![Build Status](https://travis-ci.org/StyleShare/poeditor-cli.svg?branch=master)](https://travis-ci.org/StyleShare/poeditor-cli)
5
+
6
+ Command line application for [POEditor](https://poeditor.com).
7
+
8
+ <img width="682" alt="poeditor-cli" src="https://cloud.githubusercontent.com/assets/931655/22509884/2aebebc2-e8d3-11e6-86e2-a9915ca755b5.png">
9
+
10
+ ## Usage
11
+
12
+ 1. **Create `poeditor.yml` file**
13
+
14
+ Here is an example.
15
+
16
+ ```yaml
17
+ api_key: YOUR_API_KEY
18
+ project_id: PROJECT_ID
19
+ languages: [en, ko, jp, zh-Hans, zh-Hant, fr, es]
20
+ path: example/Resources/{LANGUAGE}.lproj/Localizable.strings
21
+ type: apple_strings
22
+ tags: [ios] # optional
23
+ ```
24
+
25
+ | Field | Description |
26
+ |---|---|
27
+ | `api_key` | Your POEditor API key. You can check it on [POEditor API Access](https://poeditor.com/account/api). |
28
+ | `project_id` | POEditor project ID. You can check this value on the web browser's address bar.<br />For example: `https://poeditor.com/projects/view?id=XXXXX` |
29
+ | `languages` | Language codes to export. Use your project's language code.<br />For example, use `zh-Hans` if you're working on Xcode project even though POEditor uses `zh-CN` for simplified chinese. |
30
+ | `path` | The path for translation files to be downloaded. Each values of `languages` will be used for filling `{LANGUAGE}` placeholder. |
31
+ | `type` | Translation file format. (po, pot, mo, xls, csv, resw, resx, android_strings, apple_strings, xliff, properties, key_value_json, json, xmb, xtb) |
32
+ | `tags` | (Optional) Terms which contain whole tags will be exported. (`&&`) |
33
+
34
+ 2. **Export using CLI**
35
+
36
+ ```console
37
+ $ poeditor export
38
+ ```
39
+
40
+ 3. **You're done! 🎉**
41
+
42
+ ## Installation
43
+
44
+ ```console
45
+ $ [sudo] gem install poeditor-cli
46
+ ```
47
+
48
+ ## License
49
+
50
+ **poeditor-cli** is written by [Suyeol Jeon](https://github.com/devxoul) and available under MIT license.
data/bin/poeditor ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "poeditor"
4
+
5
+ POEditor::Command.run(ARGV)
data/lib/poeditor.rb ADDED
@@ -0,0 +1,23 @@
1
+ require "colorize"
2
+ require "fileutils"
3
+ require "shellwords"
4
+ require "yaml"
5
+
6
+ module POEditor
7
+ autoload :Version, "poeditor/version"
8
+ autoload :Exception, "poeditor/exception"
9
+ autoload :UI, "poeditor/ui"
10
+
11
+ # core
12
+ autoload :Exporter, "poeditor/core/exporter"
13
+ autoload :Formatter, "poeditor/core/formatter"
14
+
15
+ # command
16
+ autoload :Command, "poeditor/commands/command"
17
+ autoload :ExportCommand, "poeditor/commands/export_command"
18
+ autoload :HelpCommand, "poeditor/commands/help_command"
19
+ autoload :VersionCommand, "poeditor/commands/version_command"
20
+
21
+ # configuration
22
+ autoload :ExportConfiguration, "poeditor/configurations/export_configuration"
23
+ end
@@ -0,0 +1,25 @@
1
+ module POEditor
2
+ class Command
3
+ # The entry point of the CLI application
4
+ def self.run(argv)
5
+ UI.enabled = true
6
+ command = self.command_class(argv).new
7
+ begin
8
+ command.run(argv)
9
+ rescue POEditor::Exception => e
10
+ puts "[!] #{e.message}".red
11
+ end
12
+ end
13
+
14
+ def self.command_class(argv)
15
+ case argv[0]
16
+ when "export"
17
+ ExportCommand
18
+ when "--version"
19
+ VersionCommand
20
+ else
21
+ HelpCommand
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,64 @@
1
+ module POEditor
2
+ class ExportCommand
3
+ def run(argv)
4
+ UI.puts "Reading configuration"
5
+ configuration = get_configuration(argv)
6
+ UI.puts configuration
7
+ exporter = POEditor::Exporter.new(configuration)
8
+ exporter.export_all()
9
+ end
10
+
11
+ # Detects and returns the location of `poeditor.yml` file from the given
12
+ # system arguments.
13
+ #
14
+ # @param argv [Array<String>] System arguments
15
+ #
16
+ # @return [String] The detected path of `poeditor.yml` file
17
+ def get_configuration_file_path(argv)
18
+ config_index = argv.index("-c") or argv.index("--config")
19
+ if config_index
20
+ config_path = argv[config_index + 1]
21
+ else
22
+ config_path = "poeditor.yml"
23
+ end
24
+ end
25
+
26
+ # Returns {#POEditor::ExportConfiguration} from the given system arguments.
27
+ #
28
+ # @param argv [Array<String>] System arguments
29
+ #
30
+ # @return [POEditor::ExportConfiguration] The export configuration
31
+ def get_configuration(argv)
32
+ config_path = get_configuration_file_path(argv)
33
+ unless File.exist?(config_path)
34
+ raise POEditor::Exception.new %{\
35
+ Configuration file doesn't exist: #{config_path}.
36
+ Try creating `poeditor.yml` or specifying the path using '--config'.\
37
+ }
38
+ end
39
+ yaml = YAML.load(File.read(config_path))
40
+ ExportConfiguration.new(
41
+ api_key: get_or_raise(yaml, "api_key"),
42
+ project_id: get_or_raise(yaml, "project_id"),
43
+ languages: get_or_raise(yaml, "languages"),
44
+ type: get_or_raise(yaml, "type"),
45
+ tags: yaml["tags"],
46
+ path: get_or_raise(yaml, "path"),
47
+ )
48
+ end
49
+
50
+ # Returns the value of specified key from the given yaml instance. Raise
51
+ # exception when there's no key in the yaml.
52
+ #
53
+ # @param yaml [YAML]
54
+ # @param key [String]
55
+ #
56
+ # @return The value for the specified key from yaml
57
+ # @raise [POEditor::Exception]
58
+ def get_or_raise(yaml, key)
59
+ yaml[key] or raise POEditor::Exception.new \
60
+ "Missing configuration key: '#{key}'"
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,7 @@
1
+ module POEditor
2
+ class HelpCommand
3
+ def run(argv)
4
+ puts "Usage: poeditor export"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ module POEditor
2
+ class VersionCommand
3
+ def run(argv)
4
+ puts POEditor::VERSION
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ module POEditor
2
+ class ExportConfiguration
3
+ # @return [String] POEditor API key
4
+ # @see https://poeditor.com/account/api POEditor API Access
5
+ attr_accessor :api_key
6
+
7
+ # @return [String] POEditor project ID
8
+ attr_accessor :project_id
9
+
10
+ # @return [Array<String>] The languages codes
11
+ attr_accessor :languages
12
+
13
+ # @return [String] Export file type (po, apple_strings, android_strings)
14
+ attr_accessor :type
15
+
16
+ # @return [Array<String>] Tag filters (optional)
17
+ attr_accessor :tags
18
+
19
+ attr_accessor :path
20
+
21
+ def initialize(api_key:, project_id:, languages:, type:, tags:nil, path:)
22
+ @api_key = api_key
23
+ @project_id = project_id
24
+ @languages = languages
25
+ @type = type
26
+ @tags = tags or []
27
+ @path = path
28
+ end
29
+
30
+ def default_path(type)
31
+ Formatter.cls(type).default_path
32
+ end
33
+
34
+ def to_s
35
+ values = {
36
+ "api_key" => self.api_key,
37
+ "project_id" => self.project_id,
38
+ "languages" => self.languages,
39
+ "type" => self.type,
40
+ "tags" => self.tags,
41
+ "path" => self.path,
42
+ }
43
+ values.map { |key, value| " - #{key}: #{value}" }.join "\n"
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,96 @@
1
+ require "json"
2
+ require "net/http"
3
+
4
+ module POEditor
5
+ class Exporter
6
+ # @return [POEditor::ExportConfiguration] The configuration for export
7
+ attr_accessor :configuration
8
+
9
+ # @param configuration [POEditor::ExportConfiguration]
10
+ def initialize(configuration)
11
+ unless configuration.is_a? ExportConfiguration
12
+ raise POEditor::Exception.new \
13
+ "`configuration` should be an `ExportConfiguration`"
14
+ end
15
+ @configuration = configuration
16
+ end
17
+
18
+ # Request POEditor API
19
+ #
20
+ # @param action [String]
21
+ # @param api_token [String]
22
+ # @param options [Hash{Sting => Object}]
23
+ #
24
+ # @return [Net::HTTPResponse] The response object of API request
25
+ #
26
+ # @see https://poeditor.com/api_reference/ POEditor API Reference
27
+ def api(action, api_token, options={})
28
+ uri = URI("https://poeditor.com/api/")
29
+ options["action"] = action
30
+ options["api_token"] = api_token
31
+ return Net::HTTP.post_form(uri, options)
32
+ end
33
+
34
+ # Exports all translations
35
+ def export_all()
36
+ UI.puts "\nExport translations"
37
+ for language in @configuration.languages
38
+ UI.puts " - Exporting '#{language}'"
39
+ content = self.export(:api_key => @configuration.api_key,
40
+ :project_id => @configuration.project_id,
41
+ :language => language,
42
+ :type => @configuration.type,
43
+ :tags => @configuration.tags)
44
+ Formatter.write(@configuration.path, language, content)
45
+ end
46
+ end
47
+
48
+ # Export translation for specific language
49
+ #
50
+ # @param api_key [String]
51
+ # @param project_jd [String]
52
+ # @param language [String]
53
+ # @param type [String]
54
+ # @param tags [Array<String>]
55
+ #
56
+ # @return Downloaded translation content
57
+ def export(api_key:, project_id:, language:, type:, tags:nil)
58
+ options = {
59
+ "id" => project_id,
60
+ "language" => convert_to_poeditor_language(language),
61
+ "type" => type,
62
+ "tags" => (tags or []).join(","),
63
+ }
64
+ response = self.api("export", api_key, options)
65
+ data = JSON(response.body)
66
+ unless data["response"]["status"] == "success"
67
+ code = data["response"]["code"]
68
+ message = data["response"]["message"]
69
+ raise POEditor::Exception.new "#{message} (#{code})"
70
+ end
71
+
72
+ download_uri = URI(data["item"])
73
+ content = Net::HTTP.get(download_uri)
74
+
75
+ case type
76
+ when "apple_strings"
77
+ content.gsub!(/(%(\d+\$)?)s/, '\1@') # %s -> %@
78
+ when "android_strings"
79
+ content.gsub!(/(%(\d+\$)?)@/, '\1s') # %@ -> %s
80
+ end
81
+
82
+ return content
83
+ end
84
+
85
+ def convert_to_poeditor_language(language)
86
+ if language.downcase.match(/zh.+hans/)
87
+ 'zh-CN'
88
+ elsif language.downcase.match(/zh.+hant/)
89
+ 'zh-TW'
90
+ else
91
+ language
92
+ end
93
+ end
94
+
95
+ end
96
+ end
@@ -0,0 +1,16 @@
1
+ module POEditor
2
+ class Formatter
3
+ def self.build_path(path_template, language)
4
+ path_template.gsub "{LANGUAGE}", language
5
+ end
6
+
7
+ def self.write(path_template, language, content)
8
+ path = build_path(path_template, language)
9
+ unless File.exist?(path)
10
+ raise POEditor::Exception.new "#{path} doesn't exist"
11
+ end
12
+ File.write(path, content)
13
+ UI.puts " #{"\xe2\x9c\x93".green} Saved at '#{path}'"
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,4 @@
1
+ module POEditor
2
+ class Exception < Exception
3
+ end
4
+ end
@@ -0,0 +1,17 @@
1
+ module POEditor
2
+ class UI
3
+ @@enabled = false
4
+
5
+ def self.enabled
6
+ @@enabled
7
+ end
8
+
9
+ def self.enabled=enabled
10
+ @@enabled = enabled
11
+ end
12
+
13
+ def self.puts(*args)
14
+ Kernel.puts args.map { |x| x.to_s }.join(" ") if @@enabled
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module POEditor
2
+ VERSION = "0.1.0"
3
+ end
metadata ADDED
@@ -0,0 +1,72 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: poeditor-cli
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Suyeol Jeon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-02-01 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: colorize
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '0.8'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '0.8'
27
+ description: POEditor CLI
28
+ email: devxoul@gmail.com
29
+ executables:
30
+ - poeditor
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - LICENSE
35
+ - README.md
36
+ - bin/poeditor
37
+ - lib/poeditor.rb
38
+ - lib/poeditor/commands/command.rb
39
+ - lib/poeditor/commands/export_command.rb
40
+ - lib/poeditor/commands/help_command.rb
41
+ - lib/poeditor/commands/version_command.rb
42
+ - lib/poeditor/configurations/export_configuration.rb
43
+ - lib/poeditor/core/exporter.rb
44
+ - lib/poeditor/core/formatter.rb
45
+ - lib/poeditor/exception.rb
46
+ - lib/poeditor/ui.rb
47
+ - lib/poeditor/version.rb
48
+ homepage: https://github.com/devxoul/poeditor-cli
49
+ licenses:
50
+ - MIT
51
+ metadata: {}
52
+ post_install_message:
53
+ rdoc_options: []
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ version: '0'
61
+ required_rubygems_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ requirements: []
67
+ rubyforge_project:
68
+ rubygems_version: 2.5.1
69
+ signing_key:
70
+ specification_version: 4
71
+ summary: POEditor CLI
72
+ test_files: []