bisu 1.3.1 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +16 -0
- data/README.md +39 -24
- data/lib/bisu/config.rb +33 -4
- data/lib/bisu/google_sheet.rb +4 -4
- data/lib/bisu/one_sky.rb +31 -0
- data/lib/bisu/version.rb +2 -2
- data/lib/bisu.rb +26 -2
- data/spec/fixtures/sample.translatable.yml +1 -0
- data/spec/fixtures/sample_one_sky_response.txt +29 -0
- data/spec/lib/bisu/config_spec.rb +30 -5
- data/spec/lib/bisu/one_sky_spec.rb +36 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 352d33d3ac9d54082135084e8cd3e03a6ace04d5
|
4
|
+
data.tar.gz: 3f07ec0e51bde13656405514a72aedefd63f9f65
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3126fa41a9805d8b1fb028e73c2ac4674ea73e981c5808b2cfc28324b31546f6ada14436294941fbf8278148f4987b32afe5dd0a3d2d1138fe3d8923aa6a9a12
|
7
|
+
data.tar.gz: 5f76fd4c33ac8dea50f8c5a9b5472d09f7ad245897b749af15a2c0327df603b04167739ae78244c15d750a33362561ce6c89e8d607048fc69dc48f3ac81b5e88
|
data/Gemfile
CHANGED
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
|
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
|
27
|
+
1. Create in your project base folder a translatable.yml:
|
28
28
|
|
29
29
|
```
|
30
|
-
type: <iOS
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
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:
|
43
|
-
|
44
|
-
|
45
|
-
|
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!(
|
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
|
-
|
37
|
+
CONFIG_STRUCT = {
|
32
38
|
type: Hash,
|
33
39
|
elements: {
|
34
40
|
type: { type: String },
|
35
41
|
dictionary: { type: Hash, elements: {
|
36
|
-
|
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
|
data/lib/bisu/google_sheet.rb
CHANGED
@@ -3,15 +3,15 @@ require "xmlsimple"
|
|
3
3
|
|
4
4
|
module Bisu
|
5
5
|
class GoogleSheet
|
6
|
-
def initialize(sheet_id,
|
6
|
+
def initialize(sheet_id, keys_column)
|
7
7
|
@sheet_id = sheet_id
|
8
|
-
@key_column =
|
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("
|
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}
|
31
|
+
Logger.info("Found #{kb.count} languages.")
|
32
32
|
|
33
33
|
kb
|
34
34
|
end
|
data/lib/bisu/one_sky.rb
ADDED
@@ -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
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
|
-
|
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
|
@@ -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
|
-
|
8
|
-
|
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)
|
34
|
-
its(:type)
|
35
|
-
|
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.
|
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-
|
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
|