bisu 1.3.1 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae037a0d6145c6c2517b9ada533931cce6fbb028
4
- data.tar.gz: bb08d97f16d8a1fe65a8eced03d785961e7369d2
3
+ metadata.gz: 352d33d3ac9d54082135084e8cd3e03a6ace04d5
4
+ data.tar.gz: 3f07ec0e51bde13656405514a72aedefd63f9f65
5
5
  SHA512:
6
- metadata.gz: 3bf229024552eb4081d51aeaeffcb014c2f2787e8592eb166a5d2aa04fc980fa9789c605b4f796c1be68d6a56b5763a2b9662b8480c2ac472dd3e66fe3135254
7
- data.tar.gz: 3b2fdc69cade70b5a7d6d14e615dd129e8296adb2ab57b7ba82ca57fd17d9e0cf858391f84af839694b9cbed354284cdd5c7a8c29782d5c0ce7fd1f2e166646d
6
+ metadata.gz: 3126fa41a9805d8b1fb028e73c2ac4674ea73e981c5808b2cfc28324b31546f6ada14436294941fbf8278148f4987b32afe5dd0a3d2d1138fe3d8923aa6a9a12
7
+ data.tar.gz: 5f76fd4c33ac8dea50f8c5a9b5472d09f7ad245897b749af15a2c0327df603b04167739ae78244c15d750a33362561ce6c89e8d607048fc69dc48f3ac81b5e88
data/Gemfile CHANGED
@@ -4,6 +4,7 @@ ruby '2.3.1'
4
4
  gem 'safe_yaml', '~> 1.0'
5
5
  gem 'colorize', '~> 0.7'
6
6
  gem 'xml-simple', '~> 1.1'
7
+ gem 'onesky-ruby'
7
8
 
8
9
  gem 'webmock', '~> 1.20'
9
10
  gem 'rspec'
data/Gemfile.lock CHANGED
@@ -6,7 +6,19 @@ GEM
6
6
  crack (0.4.3)
7
7
  safe_yaml (~> 1.0.0)
8
8
  diff-lcs (1.2.5)
9
+ domain_name (0.5.20161021)
10
+ unf (>= 0.0.5, < 1.0.0)
9
11
  hashdiff (0.3.0)
12
+ http-cookie (1.0.3)
13
+ domain_name (~> 0.5)
14
+ mime-types (2.99.3)
15
+ netrc (0.11.0)
16
+ onesky-ruby (1.0.1)
17
+ rest-client (~> 1.8)
18
+ rest-client (1.8.0)
19
+ http-cookie (>= 1.0.2, < 2.0)
20
+ mime-types (>= 1.16, < 3.0)
21
+ netrc (~> 0.7)
10
22
  rspec (3.5.0)
11
23
  rspec-core (~> 3.5.0)
12
24
  rspec-expectations (~> 3.5.0)
@@ -24,6 +36,9 @@ GEM
24
36
  rspec-support (~> 3.5.0)
25
37
  rspec-support (3.5.0)
26
38
  safe_yaml (1.0.4)
39
+ unf (0.1.4)
40
+ unf_ext
41
+ unf_ext (0.0.7.2)
27
42
  webmock (1.24.6)
28
43
  addressable (>= 2.3.6)
29
44
  crack (>= 0.3.2)
@@ -35,6 +50,7 @@ PLATFORMS
35
50
 
36
51
  DEPENDENCIES
37
52
  colorize (~> 0.7)
53
+ onesky-ruby
38
54
  rspec
39
55
  rspec-its
40
56
  safe_yaml (~> 1.0)
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
1
  Bisu 홀
2
2
  ========
3
3
 
4
- Bisu manages your app iOS and Android localization files for you. No more copy+paste induced errors!
4
+ Bisu manages your app iOS, Android and RoR localization files for you. No more copy+paste induced errors!
5
5
 
6
6
  ---
7
7
 
8
8
  Instalation
9
9
  -----
10
-
10
+
11
11
  ```
12
12
  gem install bisu
13
13
  ```
@@ -24,25 +24,40 @@ Usage
24
24
  Configuration
25
25
  -----
26
26
 
27
- 1. Create in your **iOS/Android** app project base folder a translatable.yml:
27
+ 1. Create in your project base folder a translatable.yml:
28
28
 
29
29
  ```
30
- type: <iOS/Android/RoR>
31
-
32
- sheet_id: <GOOGLE-DRIVE-SHEET-ID>
33
- keys_column: <GOOGLE-DRIVE-KEY-COLUMN-TITLE>
34
-
35
- in:
36
- - path/to/1st/file.translatable
37
- - path/to/2nd/file.translatable
38
-
39
- out_path: path/to/%{locale}.lproj/%{out_name}
40
- out:
30
+ type: <iOS|Android|RoR>
31
+
32
+ dictionary:
33
+ type: google_sheet
34
+ sheet_id: <GOOGLE-DRIVE-SHEET-ID>
35
+ keys_column: <GOOGLE-DRIVE-KEY-COLUMN-TITLE>
36
+
37
+ translate:
38
+ - in: path/to/1st/file.translatable
39
+ out: path/to/%{locale}/strings.xml
40
+ out_en: path/to/default/strings.xml
41
+ - in: path/to/2nd/file.translatable
42
+ out: path/to/2nd-%{locale}/strings.xml
43
+
44
+ languages:
41
45
  - locale: en
42
- language: english
43
- path: default_path/%{out_name}
44
- - locale: ko
45
- language: korean
46
+ language: en
47
+ - locale: en-US
48
+ language: en
49
+ - locale: pt
50
+ language: pt
51
+ ```
52
+
53
+ Also available [OneSky](https://www.oneskyapp.com) integration:
54
+ ```
55
+ dictionary:
56
+ type: one_sky
57
+ api_key: <ONE-SKY-API-KEY>
58
+ api_secret: <ONE-SKY-API-SECRET>
59
+ project_id: <ONE-SKY-PROJECT-ID>
60
+ file_name: <ONE-SKY-FILE-NAME>
46
61
  ```
47
62
 
48
63
  1. Create a \*.translatable version for your **iOS** localization files:
@@ -50,13 +65,13 @@ Configuration
50
65
  ```
51
66
  // $specialKComment1$
52
67
  // $specialKComment2$
53
-
68
+
54
69
  // Locale: $specialKLocale$; Language used: $specialKLanguage$
55
-
70
+
56
71
  /***********
57
72
  * General
58
73
  ************/
59
-
74
+
60
75
  "klGeneral_Delete" = "$kDelete$";
61
76
  "klGeneral_Cancel" = "$kCancel$";
62
77
  "klGeneral_Close" = "$kClose$";
@@ -67,11 +82,11 @@ Configuration
67
82
 
68
83
  ```
69
84
  <?xml version="1.0" encoding="utf-8"?>
70
-
85
+
71
86
  <!-- $specialKComment1$ -->
72
87
  <!-- $specialKComment2$ -->
73
88
  <!-- Locale: $specialKLocale$; Language used: $specialKLanguage$ -->
74
-
89
+
75
90
  <resources>
76
91
  <string name="delete">$kDelete$</string>
77
92
  <string name="cancel">$kCancel$</string>
@@ -79,7 +94,7 @@ Configuration
79
94
  <string name="request_name">$kRequestName%{user_name: %s}$</string>
80
95
  </resources>
81
96
  ```
82
-
97
+
83
98
  1. Create a \*.translatable version for your **RoR** localization files:
84
99
 
85
100
  ```
data/lib/bisu/config.rb CHANGED
@@ -2,7 +2,13 @@ module Bisu
2
2
  class Config
3
3
  def initialize(hash:)
4
4
  @hash = hash.deep_symbolize
5
- @hash.validate_structure!(EXPECTED_HASH)
5
+ @hash.validate_structure!(CONFIG_STRUCT)
6
+
7
+ unless dict_struct = DICTIONARY_STRUCT[@hash[:dictionary][:type]]
8
+ raise ArgumentError.new("unknown dictionary type '#{@hash[:dictionary][:type]}'")
9
+ end
10
+
11
+ @hash[:dictionary].validate_structure!(dict_struct)
6
12
  end
7
13
 
8
14
  def to_h
@@ -28,13 +34,12 @@ module Bisu
28
34
 
29
35
  private
30
36
 
31
- EXPECTED_HASH = {
37
+ CONFIG_STRUCT = {
32
38
  type: Hash,
33
39
  elements: {
34
40
  type: { type: String },
35
41
  dictionary: { type: Hash, elements: {
36
- sheet_id: { type: String },
37
- keys_column: { type: String }
42
+ type: { type: String }
38
43
  } },
39
44
  translate: { type: Array, elements: {
40
45
  type: Hash, elements: {
@@ -50,5 +55,29 @@ module Bisu
50
55
  } }
51
56
  }
52
57
  }
58
+
59
+ GOOGLE_SHEET_STRUCT = {
60
+ type: Hash,
61
+ elements: {
62
+ type: { type: String },
63
+ sheet_id: { type: String },
64
+ keys_column: { type: String }
65
+ }
66
+ }
67
+
68
+ ONE_SKY_STRUCT = {
69
+ type: Hash,
70
+ elements: {
71
+ api_key: { type: String },
72
+ api_secret: { type: String },
73
+ project_id: { type: Integer },
74
+ file_name: { type: String }
75
+ }
76
+ }
77
+
78
+ DICTIONARY_STRUCT = {
79
+ "google_sheet" => GOOGLE_SHEET_STRUCT,
80
+ "one_sky" => ONE_SKY_STRUCT
81
+ }
53
82
  end
54
83
  end
@@ -3,15 +3,15 @@ require "xmlsimple"
3
3
 
4
4
  module Bisu
5
5
  class GoogleSheet
6
- def initialize(sheet_id, keys_column_title)
6
+ def initialize(sheet_id, keys_column)
7
7
  @sheet_id = sheet_id
8
- @key_column = keys_column_title
8
+ @key_column = keys_column
9
9
  end
10
10
 
11
11
  def to_i18
12
12
  raw = raw_data(@sheet_id)
13
13
 
14
- Logger.info("Parsing Google Sheet...")
14
+ Logger.info("Downloading dictionary from Google Sheet...")
15
15
 
16
16
  non_language_columns = ["id", "updated", "category", "title", "content", "link", @key_column]
17
17
 
@@ -28,7 +28,7 @@ module Bisu
28
28
  end
29
29
 
30
30
  Logger.info("Google Sheet parsed successfully!")
31
- Logger.info("Found #{kb.count} keys in #{kb.values.first.keys.count} languages.")
31
+ Logger.info("Found #{kb.count} languages.")
32
32
 
33
33
  kb
34
34
  end
@@ -0,0 +1,31 @@
1
+ require 'onesky'
2
+
3
+ module Bisu
4
+ class OneSky
5
+ def initialize(api_key, api_secret, project_id, file_name)
6
+ @client = Onesky::Client.new(api_key, api_secret)
7
+ @project_id = project_id
8
+ @file_name = file_name
9
+ end
10
+
11
+ def to_i18
12
+ Logger.info("Downloading dictionary from OneSky...")
13
+
14
+ proj = @client.project(@project_id)
15
+ file = proj.export_multilingual(source_file_name: @file_name, file_format: "I18NEXT_MULTILINGUAL_JSON")
16
+
17
+ hash = JSON.parse(file)
18
+ hash.each do |lang, v|
19
+ hash[lang] = v["translation"]
20
+ hash[lang].each do |key, text|
21
+ hash[lang][key] = hash[lang][key].join("\n") if hash[lang][key].is_a? Array
22
+ end
23
+ end
24
+
25
+ Logger.info("OneSky response parsed successfully!")
26
+ Logger.info("Found #{hash.count} languages.")
27
+
28
+ hash
29
+ end
30
+ end
31
+ end
data/lib/bisu/version.rb CHANGED
@@ -1,4 +1,4 @@
1
1
  module Bisu
2
- VERSION = '1.3.1'
3
- VERSION_UPDATED_AT = '2016-11-15'
2
+ VERSION = '1.4.0'
3
+ VERSION_UPDATED_AT = '2016-11-18'
4
4
  end
data/lib/bisu.rb CHANGED
@@ -5,6 +5,7 @@ require 'bisu/logger'
5
5
  require 'bisu/object_extension'
6
6
  require 'bisu/config'
7
7
  require 'bisu/google_sheet'
8
+ require 'bisu/one_sky'
8
9
  require 'bisu/dictionary'
9
10
  require 'bisu/localizer'
10
11
  require 'bisu/version'
@@ -17,8 +18,7 @@ module Bisu
17
18
 
18
19
  if config_file = open_file("translatable.yml", "r", true)
19
20
  config = Bisu::Config.new(hash: YAML::load(config_file))
20
- google_sheet = Bisu::GoogleSheet.new(config.dictionary[:sheet_id], config.dictionary[:keys_column])
21
- dictionary = Bisu::Dictionary.new(google_sheet.to_i18)
21
+ dictionary = dictionary_for(config: config.dictionary, save_to_path: options[:dictionary_save_path])
22
22
  localizer = Bisu::Localizer.new(dictionary, config.type)
23
23
 
24
24
  config.localize_files do |in_path, out_path, language, locale|
@@ -36,6 +36,26 @@ module Bisu
36
36
 
37
37
  private
38
38
 
39
+ def dictionary_for(config:, save_to_path:)
40
+ source =
41
+ case config[:type]
42
+ when "google_sheet"
43
+ Bisu::GoogleSheet.new(config[:sheet_id], config[:keys_column])
44
+ when "one_sky"
45
+ Bisu::OneSky.new(config[:api_key], config[:api_secret], config[:project_id], config[:file_name])
46
+ end
47
+
48
+ source = source.to_i18
49
+
50
+ if save_to_path && file = open_file(save_to_path, "w", false)
51
+ file.write(source.to_json)
52
+ file.flush
53
+ file.close
54
+ end
55
+
56
+ Bisu::Dictionary.new(source)
57
+ end
58
+
39
59
  def command_line_options(options)
40
60
  opts_hash = {}
41
61
 
@@ -44,6 +64,10 @@ module Bisu
44
64
  opts_hash[:default_language] = language
45
65
  end
46
66
 
67
+ opts.on("--save-dictionary PATH", "Save downloaded dictionary locally at given path") do |path|
68
+ opts_hash[:dictionary_save_path] = path
69
+ end
70
+
47
71
  opts.on_tail("-h", "--help", "Show this message") do
48
72
  puts opts
49
73
  exit
@@ -1,6 +1,7 @@
1
1
  type: iOS
2
2
 
3
3
  dictionary:
4
+ type: google_sheet
4
5
  sheet_id: sheet-id
5
6
  keys_column: keys-column
6
7
 
@@ -0,0 +1,29 @@
1
+ {
2
+ "en": {
3
+ "translation": {
4
+ "kConnectFacebook": "Connect with Facebook",
5
+ "kNoNoNoMr": "No, no, no. Mr %{name} not here"
6
+ }
7
+ },
8
+ "ja": {
9
+ "translation": {
10
+ "kConnectFacebook": "\u30d5\u30a7\u30a4\u30b9\u30d6\u30c3\u30af\u3078\u63a5\u7d9a"
11
+ }
12
+ },
13
+ "fr": {
14
+ "translation": {
15
+ "kConnectFacebook": "Connexion par Facebook"
16
+ }
17
+ },
18
+ "de": {
19
+ "translation": {
20
+ "kConnectFacebook": "Mit Facebook verbinden"
21
+ }
22
+ },
23
+ "ko": {
24
+ "translation": {
25
+ "kConnectFacebook": "\ud398\uc774\uc2a4\ubd81\uc73c\ub85c \uc811\uc18d",
26
+ "kTwitterServer": ["트위터 서버연결 실패. ", "잠시 후 재시도."]
27
+ }
28
+ }
29
+ }
@@ -4,8 +4,9 @@ describe Bisu::Config do
4
4
  let(:hash) { {
5
5
  type: "BisuOS",
6
6
  dictionary: {
7
- sheet_id: "abc1234567890",
8
- keys_column: "key_name"
7
+ type: "google_sheet",
8
+ sheet_id: "abc1234567890",
9
+ keys_column: "key_name"
9
10
  },
10
11
  translate: [
11
12
  { in: "path/to/file/to/1.ext.translatable",
@@ -30,9 +31,33 @@ describe Bisu::Config do
30
31
  it { expect { config }.to raise_error /missing keys/i }
31
32
  end
32
33
 
33
- its(:to_h) { should eq(hash) }
34
- its(:type) { should eq("BisuOS") }
35
- its(:dictionary) { should eq({ sheet_id: "abc1234567890", keys_column: "key_name" }) }
34
+ its(:to_h) { should eq(hash) }
35
+ its(:type) { should eq("BisuOS") }
36
+
37
+ describe "#dictionary" do
38
+ subject(:dictionary) { config.dictionary }
39
+
40
+ it { should eq({ type: "google_sheet", sheet_id: "abc1234567890", keys_column: "key_name" }) }
41
+
42
+ context "when given a OneSky type dictionary" do
43
+ before do
44
+ hash[:dictionary] = {
45
+ type: "one_sky",
46
+ api_key: "as387oavh48",
47
+ api_secret: "bp0s5avo8a59",
48
+ project_id: 328742,
49
+ file_name: "file.json"
50
+ }
51
+ end
52
+
53
+ it { should eq({ type: "one_sky", api_key: "as387oavh48", api_secret: "bp0s5avo8a59", project_id: 328742, file_name: "file.json" }) }
54
+ end
55
+
56
+ context "when given an unknown type dictionary" do
57
+ before { hash[:dictionary] = { type: "i_dunno" } }
58
+ it { expect { config }.to raise_error /unknown dictionary type 'i_dunno'/i }
59
+ end
60
+ end
36
61
 
37
62
  describe "#localize_files" do
38
63
  it "yields 5 times with the expected arguments" do
@@ -0,0 +1,36 @@
1
+ describe Bisu::OneSky do
2
+ subject(:to_i18) { Bisu::OneSky.new(api_key, api_secret, project_id, file_name).to_i18 }
3
+
4
+ let(:api_key) { "a123" }
5
+ let(:api_secret) { "b123" }
6
+ let(:project_id) { 98765 }
7
+ let(:file_name) { "file456.json" }
8
+
9
+ let(:os_response) { File.read("spec/fixtures/sample_one_sky_response.txt") }
10
+
11
+ before do
12
+ project = double("OSProject")
13
+ allow_any_instance_of(Onesky::Client).to receive(:project).with(project_id).and_return(project)
14
+ allow(project).to receive(:export_multilingual).with(source_file_name: file_name, file_format: "I18NEXT_MULTILINGUAL_JSON").and_return(os_response)
15
+ end
16
+
17
+ it { expect { to_i18 }.not_to raise_error }
18
+
19
+ it "returns an hash in i18 format" do
20
+ expect(to_i18).to eq({
21
+ "en" => { "kConnectFacebook" => "Connect with Facebook", "kNoNoNoMr" => "No, no, no. Mr %{name} not here" },
22
+ "ja" => { "kConnectFacebook" => "フェイスブックへ接続" },
23
+ "fr" => { "kConnectFacebook" => "Connexion par Facebook" },
24
+ "de" => { "kConnectFacebook" => "Mit Facebook verbinden" },
25
+ "ko" => { "kConnectFacebook" => "페이스북으로 접속", "kTwitterServer" => "트위터 서버연결 실패. \n잠시 후 재시도." }
26
+ })
27
+ end
28
+
29
+ context "when OneSky raises an error" do
30
+ before { allow_any_instance_of(Onesky::Client).to receive(:project).and_raise("ups... not allowed!") }
31
+
32
+ it "raises that same error" do
33
+ expect { to_i18 }.to raise_error /not allowed/
34
+ end
35
+ end
36
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bisu
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - joaoffcosta
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-11-15 00:00:00.000000000 Z
11
+ date: 2016-11-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -90,16 +90,19 @@ files:
90
90
  - lib/bisu/localizer.rb
91
91
  - lib/bisu/logger.rb
92
92
  - lib/bisu/object_extension.rb
93
+ - lib/bisu/one_sky.rb
93
94
  - lib/bisu/version.rb
94
95
  - spec/fixtures/sample.translatable.yml
95
96
  - spec/fixtures/sample_kb_public_info.html
96
97
  - spec/fixtures/sample_kb_public_sheet.html
98
+ - spec/fixtures/sample_one_sky_response.txt
97
99
  - spec/lib/bisu/config_spec.rb
98
100
  - spec/lib/bisu/dictionary_spec.rb
99
101
  - spec/lib/bisu/google_sheet_spec.rb
100
102
  - spec/lib/bisu/localizer_spec.rb
101
103
  - spec/lib/bisu/logger_spec.rb
102
104
  - spec/lib/bisu/object_extension_spec.rb
105
+ - spec/lib/bisu/one_sky_spec.rb
103
106
  - spec/lib/bisu_spec.rb
104
107
  - spec/spec_helper.rb
105
108
  homepage: https://github.com/hole19/bisu