bisu 1.7.2 → 1.10.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 +4 -4
- data/.rspec +0 -1
- data/.ruby-version +1 -1
- data/CHANGELOG.md +18 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +21 -20
- data/README.md +9 -8
- data/bisu.gemspec +0 -3
- data/generic.translatable.yml +1 -2
- data/lib/bisu/config.rb +9 -9
- data/lib/bisu/localizer.rb +22 -8
- data/lib/bisu/source/google_sheet.rb +30 -34
- data/lib/bisu/version.rb +2 -2
- data/lib/bisu.rb +7 -5
- data/spec/fixtures/sample.translatable.yml +3 -3
- data/spec/fixtures/sample_google_response.csv +4 -0
- data/spec/lib/bisu/config_spec.rb +23 -24
- data/spec/lib/bisu/localizer_spec.rb +51 -8
- data/spec/lib/bisu/source/google_sheet_spec.rb +24 -49
- data/spec/lib/bisu_spec.rb +2 -1
- metadata +4 -33
- data/spec/fixtures/sample_kb_public_info.html +0 -1
- data/spec/fixtures/sample_kb_public_sheet.html +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1a7abda3e27e23715ea0f2fb7b3e4bcb916c7a12b7eb691f5a5e3e8e1288a5c
|
4
|
+
data.tar.gz: 9a82418e8e0783d4d78783f895a95749a011defaa39332bb6732816d6222454a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c5d8bdcc8bf58bed26a44d949a9094c20382b9853b562c63165e6211b76cb9aa4c2f70db7e0577bf94358a9d83b4b64d8c8d1dbabadc8e2e7da056c01fce5b1
|
7
|
+
data.tar.gz: 508e86e0a9c4db4f3e7d5e691d9d5e4bf42656de4fcd52f0acd42acbb92836dc84d928aae9125466622cbde55a3a6a9f31482f3853aa805c890ac87451c1ee15
|
data/.rspec
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.7.3
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,24 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
`Bisu` adheres to [Semantic Versioning](http://semver.org/).
|
4
4
|
|
5
|
+
## [1.9.0](https://github.com/hole19/bisu/releases/tag/v1.9.0)
|
6
|
+
Released on 2021/05/21
|
7
|
+
|
8
|
+
#### Added
|
9
|
+
- Adds a new option to surpress missing params when that's intentional: add "//ignore-params" to the end of the translation key
|
10
|
+
|
11
|
+
## [1.8.0](https://github.com/hole19/bisu/releases/tag/v1.8.0)
|
12
|
+
Released on 2020/04/30
|
13
|
+
|
14
|
+
#### Added
|
15
|
+
- Adds a new option: allows a single translation to have a specific fallback language (example: "es-MX" fallback to "es")
|
16
|
+
|
17
|
+
## [1.7.3](https://github.com/hole19/bisu/releases/tag/v1.7.3)
|
18
|
+
Released on 2020/03/09
|
19
|
+
|
20
|
+
#### Added
|
21
|
+
- Correctly handles percentage sign on iOS platform
|
22
|
+
|
5
23
|
## [1.7.2](https://github.com/hole19/bisu/releases/tag/v1.7.2)
|
6
24
|
Released on 2020/03/09
|
7
25
|
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,37 +1,38 @@
|
|
1
1
|
GEM
|
2
2
|
remote: https://rubygems.org/
|
3
3
|
specs:
|
4
|
-
addressable (2.
|
4
|
+
addressable (2.8.0)
|
5
5
|
public_suffix (>= 2.0.2, < 5.0)
|
6
6
|
colorize (0.8.1)
|
7
|
-
crack (0.4.
|
8
|
-
|
9
|
-
diff-lcs (1.
|
7
|
+
crack (0.4.5)
|
8
|
+
rexml
|
9
|
+
diff-lcs (1.4.4)
|
10
10
|
hashdiff (1.0.1)
|
11
|
-
public_suffix (4.0.
|
12
|
-
rake (13.0.
|
13
|
-
|
14
|
-
|
15
|
-
rspec-
|
16
|
-
rspec-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
public_suffix (4.0.6)
|
12
|
+
rake (13.0.3)
|
13
|
+
rexml (3.2.5)
|
14
|
+
rspec (3.10.0)
|
15
|
+
rspec-core (~> 3.10.0)
|
16
|
+
rspec-expectations (~> 3.10.0)
|
17
|
+
rspec-mocks (~> 3.10.0)
|
18
|
+
rspec-core (3.10.1)
|
19
|
+
rspec-support (~> 3.10.0)
|
20
|
+
rspec-expectations (3.10.1)
|
20
21
|
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
-
rspec-support (~> 3.
|
22
|
+
rspec-support (~> 3.10.0)
|
22
23
|
rspec-its (1.3.0)
|
23
24
|
rspec-core (>= 3.0.0)
|
24
25
|
rspec-expectations (>= 3.0.0)
|
25
|
-
rspec-mocks (3.
|
26
|
+
rspec-mocks (3.10.2)
|
26
27
|
diff-lcs (>= 1.2.0, < 2.0)
|
27
|
-
rspec-support (~> 3.
|
28
|
-
rspec-support (3.
|
28
|
+
rspec-support (~> 3.10.0)
|
29
|
+
rspec-support (3.10.2)
|
29
30
|
safe_yaml (1.0.5)
|
30
31
|
webmock (1.24.6)
|
31
32
|
addressable (>= 2.3.6)
|
32
33
|
crack (>= 0.3.2)
|
33
34
|
hashdiff
|
34
|
-
xml-simple (1.1.
|
35
|
+
xml-simple (1.1.8)
|
35
36
|
|
36
37
|
PLATFORMS
|
37
38
|
ruby
|
@@ -46,7 +47,7 @@ DEPENDENCIES
|
|
46
47
|
xml-simple (~> 1.1)
|
47
48
|
|
48
49
|
RUBY VERSION
|
49
|
-
ruby 2.
|
50
|
+
ruby 2.7.3p183
|
50
51
|
|
51
52
|
BUNDLED WITH
|
52
|
-
1.
|
53
|
+
2.1.4
|
data/README.md
CHANGED
@@ -24,7 +24,7 @@ Usage
|
|
24
24
|
1. Run: `bisu`
|
25
25
|
1. That's it!*
|
26
26
|
|
27
|
-
|
27
|
+
\*_given that someone already configured Bisu_
|
28
28
|
|
29
29
|
Setup your configuration file
|
30
30
|
-----
|
@@ -45,11 +45,12 @@ Setup your configuration file
|
|
45
45
|
out: path/to/2nd-%{locale}/strings.xml
|
46
46
|
|
47
47
|
languages:
|
48
|
-
- locale:
|
49
|
-
language: en
|
50
|
-
- locale:
|
51
|
-
language: en
|
52
|
-
|
48
|
+
- locale: en
|
49
|
+
language: en # the language as it appears in the dictionary
|
50
|
+
- locale: en-US
|
51
|
+
language: en-us
|
52
|
+
fallback_language: en
|
53
|
+
- locale: pt
|
53
54
|
language: pt
|
54
55
|
```
|
55
56
|
|
@@ -65,14 +66,14 @@ Setup your configuration file
|
|
65
66
|
|
66
67
|
1. First ["Publish to the web"](https://www.google.com/search?q=google+sheets+publish+to+web) your Google Sheet
|
67
68
|
1. Share only the sheet that contains the translations
|
69
|
+
1. Make sure you CSV format
|
68
70
|
1. First column should contain the translation keys
|
69
71
|
1. First row should contain the locale for each language
|
70
72
|
|
71
73
|
```
|
72
74
|
dictionary:
|
73
75
|
type: google_sheet
|
74
|
-
|
75
|
-
keys_column: <GOOGLE-DRIVE-KEY-COLUMN-TITLE>
|
76
|
+
url: <GOOGLE-DRIVE-SHEET-CSV-URL>
|
76
77
|
```
|
77
78
|
|
78
79
|
##### OneSky integration:
|
data/bisu.gemspec
CHANGED
data/generic.translatable.yml
CHANGED
data/lib/bisu/config.rb
CHANGED
@@ -27,7 +27,7 @@ module Bisu
|
|
27
27
|
@hash[:translate].each do |t|
|
28
28
|
@hash[:languages].each do |l|
|
29
29
|
downcase_locale = l[:locale].downcase.gsub("-", "_").gsub(" ", "_")
|
30
|
-
yield(t[:in], (t[:"out_#{downcase_locale}"] || t[:out]) % l, l[:language], l[:
|
30
|
+
yield(t[:in], (t[:"out_#{downcase_locale}"] || t[:out]) % l, l[:locale], l[:language], l[:fallback_language])
|
31
31
|
end
|
32
32
|
end
|
33
33
|
end
|
@@ -50,7 +50,8 @@ module Bisu
|
|
50
50
|
languages: { type: Array, elements: {
|
51
51
|
type: Hash, elements: {
|
52
52
|
locale: { type: String },
|
53
|
-
language: { type: String }
|
53
|
+
language: { type: String },
|
54
|
+
fallback_language: { type: String, optional: true }
|
54
55
|
}
|
55
56
|
} }
|
56
57
|
}
|
@@ -60,9 +61,8 @@ module Bisu
|
|
60
61
|
type: Hash,
|
61
62
|
elements: {
|
62
63
|
type: { type: String },
|
63
|
-
|
64
|
-
|
65
|
-
}
|
64
|
+
url: { type: String },
|
65
|
+
},
|
66
66
|
}
|
67
67
|
|
68
68
|
ONE_SKY_STRUCT = {
|
@@ -71,15 +71,15 @@ module Bisu
|
|
71
71
|
api_key: { type: String },
|
72
72
|
api_secret: { type: String },
|
73
73
|
project_id: { type: Integer },
|
74
|
-
file_name: { type: String }
|
75
|
-
}
|
74
|
+
file_name: { type: String },
|
75
|
+
},
|
76
76
|
}
|
77
77
|
|
78
78
|
URL_STRUCT = {
|
79
79
|
type: Hash,
|
80
80
|
elements: {
|
81
|
-
url: { type: String }
|
82
|
-
}
|
81
|
+
url: { type: String },
|
82
|
+
},
|
83
83
|
}
|
84
84
|
|
85
85
|
DICTIONARY_STRUCT = {
|
data/lib/bisu/localizer.rb
CHANGED
@@ -10,7 +10,7 @@ module Bisu
|
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
13
|
-
def localize(text, language, locale,
|
13
|
+
def localize(text, language, locale, fallback_languages=[])
|
14
14
|
t = text
|
15
15
|
t = t.gsub("$specialKLanguage$", language)
|
16
16
|
t = t.gsub("$specialKLocale$", locale)
|
@@ -18,7 +18,7 @@ module Bisu
|
|
18
18
|
t = t.gsub("$specialKComment2$", "Remember to CHANGE THE TEMPLATE and not this file!")
|
19
19
|
|
20
20
|
to_localize(t).map do |l|
|
21
|
-
if localized =
|
21
|
+
if localized = localize_key(l[:key], [language] + fallback_languages)
|
22
22
|
localized = process(localized)
|
23
23
|
|
24
24
|
l[:params].each do |param, value|
|
@@ -32,22 +32,32 @@ module Bisu
|
|
32
32
|
unless t.gsub!(l[:match], localized)
|
33
33
|
Logger.warn("Could not find translation for #{l[:match]} in #{language}")
|
34
34
|
end
|
35
|
+
|
36
|
+
unless @type.eql?(:ror) || l[:ignore_param_warn] == true
|
37
|
+
localized.scan(/%{[^}]+}/) { |match| Logger.error("Could not find translation param for #{match} in #{language}") }
|
38
|
+
end
|
35
39
|
else
|
36
40
|
Logger.warn("Could not find translation for #{l[:match]} in #{language}")
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
40
|
-
|
41
|
-
|
44
|
+
t
|
45
|
+
end
|
46
|
+
|
47
|
+
def localize_key(key, ordered_languages)
|
48
|
+
ordered_languages.each do |language|
|
49
|
+
if localized = @dict.localize(language, key)
|
50
|
+
return localized
|
51
|
+
end
|
42
52
|
end
|
43
53
|
|
44
|
-
|
54
|
+
nil
|
45
55
|
end
|
46
56
|
|
47
57
|
private
|
48
58
|
|
49
59
|
def to_localize(text)
|
50
|
-
all_matches = text.to_enum(:scan, /\$([^\$\{]+)(?:\{(.+)\})?\$/).map { Regexp.last_match }
|
60
|
+
all_matches = text.to_enum(:scan, /\$([^\$\{\/]+)(?:\{(.+)\})?(\/\/ignore-params)?\$/).map { Regexp.last_match }
|
51
61
|
all_matches.map do |match|
|
52
62
|
params = if match[2]
|
53
63
|
params = match[2].split(",").map(&:strip).map do |param|
|
@@ -57,9 +67,12 @@ module Bisu
|
|
57
67
|
Hash[params]
|
58
68
|
end
|
59
69
|
|
60
|
-
{
|
70
|
+
{
|
71
|
+
match: match[0],
|
61
72
|
key: match[1],
|
62
|
-
params: params || {}
|
73
|
+
params: params || {},
|
74
|
+
ignore_param_warn: text.include?("//ignore-params")
|
75
|
+
}
|
63
76
|
end
|
64
77
|
end
|
65
78
|
|
@@ -75,6 +88,7 @@ module Bisu
|
|
75
88
|
|
76
89
|
elsif @type.eql?(:ios)
|
77
90
|
text = text.gsub(/\"/, "\\\\\"")
|
91
|
+
text = text.gsub(/%(?!{)/, "%%")
|
78
92
|
end
|
79
93
|
|
80
94
|
text
|
@@ -1,64 +1,60 @@
|
|
1
1
|
require "net/https"
|
2
|
-
require "
|
2
|
+
require "csv"
|
3
3
|
|
4
4
|
module Bisu
|
5
5
|
module Source
|
6
6
|
class GoogleSheet
|
7
|
-
def initialize(
|
8
|
-
@
|
9
|
-
@key_column = keys_column
|
7
|
+
def initialize(url)
|
8
|
+
@url = url
|
10
9
|
end
|
11
10
|
|
12
11
|
def to_i18
|
13
|
-
|
12
|
+
Logger.info("Downloading Google Sheet from #{@url}...")
|
14
13
|
|
15
|
-
|
14
|
+
csv = get_csv(@url)
|
16
15
|
|
17
|
-
|
16
|
+
hash = {}
|
18
17
|
|
19
|
-
|
20
|
-
|
21
|
-
unless (key = entry[@key_column]) && key = key.first
|
22
|
-
raise "Bisu::Source::GoogleSheet: Cannot find key column '#{@key_column}'"
|
23
|
-
end
|
18
|
+
languages = csv.headers[1..]
|
19
|
+
languages.each { |lang| hash[lang] = {} }
|
24
20
|
|
25
|
-
|
26
|
-
|
27
|
-
|
21
|
+
csv.each do |row|
|
22
|
+
languages.each do |lang|
|
23
|
+
hash[lang][row["key"]] = row[lang] unless row[lang].nil?
|
28
24
|
end
|
29
25
|
end
|
30
26
|
|
31
27
|
Logger.info("Google Sheet parsed successfully!")
|
32
|
-
Logger.info("Found #{
|
28
|
+
Logger.info("Found #{languages.count} languages.")
|
33
29
|
|
34
|
-
|
30
|
+
hash
|
35
31
|
end
|
36
32
|
|
37
33
|
private
|
38
34
|
|
39
|
-
def
|
40
|
-
|
35
|
+
def get_csv(url)
|
36
|
+
data = get(url)
|
37
|
+
|
38
|
+
begin
|
39
|
+
CSV.parse(data, headers: true)
|
40
|
+
rescue StandardError => e
|
41
|
+
raise "Bisu::Source::GoogleSheet: Cannot parse. Expected CSV at #{url}: #{e}"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def get(url)
|
46
|
+
uri = URI(url)
|
47
|
+
|
41
48
|
http = Net::HTTP.new(uri.host, uri.port)
|
42
49
|
http.use_ssl = true
|
43
50
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
44
|
-
data = http.get(uri.path, headers)
|
45
51
|
|
46
|
-
|
47
|
-
|
48
|
-
end
|
52
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
53
|
+
response = http.request(request)
|
49
54
|
|
50
|
-
|
51
|
-
XmlSimple.xml_in(data.body, 'KeyAttr' => 'name')
|
52
|
-
rescue
|
53
|
-
raise "Bisu::Source::GoogleSheet: Cannot parse. Expected XML at #{uri}"
|
54
|
-
end
|
55
|
-
end
|
55
|
+
raise "Bisu::Source::GoogleSheet: Http Error #{response.body}" if response.code.to_i >= 400
|
56
56
|
|
57
|
-
|
58
|
-
Logger.info("Downloading Google Sheet...")
|
59
|
-
sheet = xml_data("https://spreadsheets.google.com/feeds/worksheets/#{sheet_id}/public/full")
|
60
|
-
url = sheet["entry"][0]["link"][0]["href"]
|
61
|
-
xml_data(url)
|
57
|
+
response.body
|
62
58
|
end
|
63
59
|
end
|
64
60
|
end
|
data/lib/bisu/version.rb
CHANGED
data/lib/bisu.rb
CHANGED
@@ -23,13 +23,15 @@ module Bisu
|
|
23
23
|
dictionary = dictionary_for(config: config.dictionary, options: options)
|
24
24
|
localizer = Bisu::Localizer.new(dictionary, config.type)
|
25
25
|
|
26
|
-
config.localize_files do |in_path, out_path, language,
|
26
|
+
config.localize_files do |in_path, out_path, locale, language, fallback_language|
|
27
27
|
unless dictionary.has_language?(language)
|
28
28
|
Logger.error("Unknown language #{language}")
|
29
29
|
return false
|
30
30
|
end
|
31
31
|
|
32
|
-
|
32
|
+
fallback_languages = ([fallback_language] + [options[:default_language]]).compact
|
33
|
+
|
34
|
+
localize_file(localizer, locale, language, fallback_languages, in_path, out_path)
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -57,7 +59,7 @@ module Bisu
|
|
57
59
|
source =
|
58
60
|
case config[:type]
|
59
61
|
when "google_sheet"
|
60
|
-
Bisu::Source::GoogleSheet.new(config[:
|
62
|
+
Bisu::Source::GoogleSheet.new(config[:url])
|
61
63
|
when "one_sky"
|
62
64
|
Bisu::Source::OneSky.new(config[:api_key], config[:api_secret], config[:project_id], config[:file_name])
|
63
65
|
when "url"
|
@@ -131,14 +133,14 @@ module Bisu
|
|
131
133
|
File.open(File.expand_path(file_name), method)
|
132
134
|
end
|
133
135
|
|
134
|
-
def localize_file(localizer, locale, language,
|
136
|
+
def localize_file(localizer, locale, language, fallback_languages, in_path, out_path)
|
135
137
|
Logger.info("Translating #{in_path} to #{language} > #{out_path}...")
|
136
138
|
|
137
139
|
return false unless in_file = open_file(in_path, "r", true)
|
138
140
|
return false unless out_file = open_file(out_path, "w", false)
|
139
141
|
|
140
142
|
in_file.each_line do |line|
|
141
|
-
out_file.write(localizer.localize(line, language, locale,
|
143
|
+
out_file.write(localizer.localize(line, language, locale, fallback_languages))
|
142
144
|
end
|
143
145
|
|
144
146
|
out_file.flush
|
@@ -2,8 +2,7 @@ type: iOS
|
|
2
2
|
|
3
3
|
dictionary:
|
4
4
|
type: google_sheet
|
5
|
-
|
6
|
-
keys_column: keys-column
|
5
|
+
url: sheet-public-url
|
7
6
|
|
8
7
|
translate:
|
9
8
|
- in: hole19/Localizable.strings.translatable
|
@@ -15,4 +14,5 @@ languages:
|
|
15
14
|
- locale: en
|
16
15
|
language: english
|
17
16
|
- locale: en-US
|
18
|
-
language: english
|
17
|
+
language: english-us
|
18
|
+
fallback_language: english
|
@@ -4,25 +4,24 @@ describe Bisu::Config do
|
|
4
4
|
let(:hash) { {
|
5
5
|
type: "BisuOS",
|
6
6
|
dictionary: {
|
7
|
-
type:
|
8
|
-
|
9
|
-
keys_column: "key_name"
|
7
|
+
type: "google_sheet",
|
8
|
+
url: "https://abc1234567890",
|
10
9
|
},
|
11
10
|
translate: [
|
12
|
-
{ in:
|
13
|
-
out:
|
11
|
+
{ in: "path/to/file/to/1.ext.translatable",
|
12
|
+
out: "path/to/final-%{locale}/1.ext",
|
14
13
|
out_en_us: "path/to/default/1.ext"
|
15
14
|
},
|
16
|
-
{ in:
|
17
|
-
out:
|
15
|
+
{ in: "path/to/file/to/2.ext.translatable",
|
16
|
+
out: "path/to/final-%{locale}/2.ext",
|
18
17
|
out_en_us: "path/to/default/2.ext"
|
19
18
|
},
|
20
19
|
],
|
21
20
|
languages: [
|
22
|
-
{ locale: "en-US",
|
23
|
-
{ locale: "pt",
|
24
|
-
{ locale: "pt-PT",
|
25
|
-
{ locale: "pt-Batatas", language: "portuguese" }
|
21
|
+
{ locale: "en-US", language: "english" },
|
22
|
+
{ locale: "pt", language: "portuguese" },
|
23
|
+
{ locale: "pt-PT", language: "portuguese" },
|
24
|
+
{ locale: "pt-Batatas", language: "portuguese-bt", fallback_language: "portuguese" }
|
26
25
|
]
|
27
26
|
} }
|
28
27
|
|
@@ -37,16 +36,16 @@ describe Bisu::Config do
|
|
37
36
|
describe "#dictionary" do
|
38
37
|
subject(:dictionary) { config.dictionary }
|
39
38
|
|
40
|
-
it { should eq({ type: "google_sheet",
|
39
|
+
it { should eq({ type: "google_sheet", url: "https://abc1234567890" }) }
|
41
40
|
|
42
41
|
context "when given a OneSky type dictionary" do
|
43
42
|
before do
|
44
43
|
hash[:dictionary] = {
|
45
|
-
type:
|
46
|
-
api_key:
|
44
|
+
type: "one_sky",
|
45
|
+
api_key: "as387oavh48",
|
47
46
|
api_secret: "bp0s5avo8a59",
|
48
47
|
project_id: 328742,
|
49
|
-
file_name:
|
48
|
+
file_name: "file.json"
|
50
49
|
}
|
51
50
|
end
|
52
51
|
|
@@ -57,7 +56,7 @@ describe Bisu::Config do
|
|
57
56
|
before do
|
58
57
|
hash[:dictionary] = {
|
59
58
|
type: "url",
|
60
|
-
url:
|
59
|
+
url: "a_url"
|
61
60
|
}
|
62
61
|
end
|
63
62
|
|
@@ -75,14 +74,14 @@ describe Bisu::Config do
|
|
75
74
|
expect { |b|
|
76
75
|
config.localize_files(&b)
|
77
76
|
}.to yield_successive_args(
|
78
|
-
["path/to/file/to/1.ext.translatable", "path/to/default/1.ext", "
|
79
|
-
["path/to/file/to/1.ext.translatable", "path/to/final-pt/1.ext", "
|
80
|
-
["path/to/file/to/1.ext.translatable", "path/to/final-pt-PT/1.ext", "
|
81
|
-
["path/to/file/to/1.ext.translatable", "path/to/final-pt-Batatas/1.ext", "
|
82
|
-
["path/to/file/to/2.ext.translatable", "path/to/default/2.ext", "
|
83
|
-
["path/to/file/to/2.ext.translatable", "path/to/final-pt/2.ext", "
|
84
|
-
["path/to/file/to/2.ext.translatable", "path/to/final-pt-PT/2.ext", "
|
85
|
-
["path/to/file/to/2.ext.translatable", "path/to/final-pt-Batatas/2.ext", "
|
77
|
+
["path/to/file/to/1.ext.translatable", "path/to/default/1.ext", "en-US", "english", nil ],
|
78
|
+
["path/to/file/to/1.ext.translatable", "path/to/final-pt/1.ext", "pt", "portuguese", nil ],
|
79
|
+
["path/to/file/to/1.ext.translatable", "path/to/final-pt-PT/1.ext", "pt-PT", "portuguese", nil ],
|
80
|
+
["path/to/file/to/1.ext.translatable", "path/to/final-pt-Batatas/1.ext", "pt-Batatas", "portuguese-bt", "portuguese"],
|
81
|
+
["path/to/file/to/2.ext.translatable", "path/to/default/2.ext", "en-US", "english", nil ],
|
82
|
+
["path/to/file/to/2.ext.translatable", "path/to/final-pt/2.ext", "pt", "portuguese", nil ],
|
83
|
+
["path/to/file/to/2.ext.translatable", "path/to/final-pt-PT/2.ext", "pt-PT", "portuguese", nil ],
|
84
|
+
["path/to/file/to/2.ext.translatable", "path/to/final-pt-Batatas/2.ext", "pt-Batatas", "portuguese-bt", "portuguese"]
|
86
85
|
)
|
87
86
|
end
|
88
87
|
end
|
@@ -1,4 +1,9 @@
|
|
1
1
|
describe Bisu::Localizer do
|
2
|
+
def translates(text, fallbacks: [], to:, lang: nil)
|
3
|
+
translation = localizer.localize(text, lang || language, locale, fallbacks)
|
4
|
+
expect(translation).to eq to
|
5
|
+
end
|
6
|
+
|
2
7
|
let(:language) { "Portuguese" }
|
3
8
|
let(:locale) { "pt-PT" }
|
4
9
|
|
@@ -19,6 +24,9 @@ describe Bisu::Localizer do
|
|
19
24
|
"kAtSign" => "\@johnsnow sabes alguma coisa?",
|
20
25
|
"kPercentage" => "Sabes 0% João das Neves."
|
21
26
|
},
|
27
|
+
"Spanish" => {
|
28
|
+
"kMissingTransKey" => "Sabes poco John Snow"
|
29
|
+
},
|
22
30
|
"English" => {
|
23
31
|
"kMissingTransKey" => "You know little John Snow"
|
24
32
|
}
|
@@ -30,11 +38,6 @@ describe Bisu::Localizer do
|
|
30
38
|
shared_examples_for "a localizer" do
|
31
39
|
it { expect { localizer }.not_to raise_error }
|
32
40
|
|
33
|
-
def translates(text, fallback: nil, to:, lang: nil)
|
34
|
-
translation = localizer.localize(text, lang || language, locale, fallback)
|
35
|
-
expect(translation).to eq to
|
36
|
-
end
|
37
|
-
|
38
41
|
it { translates("a line with no key", to: "a line with no key") }
|
39
42
|
|
40
43
|
it { translates("this special key: $specialKComment1$", to: "this special key: This file was automatically generated based on a translation template.") }
|
@@ -46,7 +49,8 @@ describe Bisu::Localizer do
|
|
46
49
|
it { translates("this key: $kTranslationKey$", to: "this key: Não sabes nada João das Neves", lang: "portuguese") }
|
47
50
|
it { translates("this unknown key: $kUnknownKey$", to: "this unknown key: $kUnknownKey$") }
|
48
51
|
it { translates("this key with missing translations: $kMissingTransKey$", to: "this key with missing translations: $kMissingTransKey$") }
|
49
|
-
it { translates("this key with missing translations: $kMissingTransKey$",
|
52
|
+
it { translates("this key with missing translations: $kMissingTransKey$", fallbacks: ["English"], to: "this key with missing translations: You know little John Snow") }
|
53
|
+
it { translates("this key with missing translations: $kMissingTransKey$", fallbacks: ["Spanish", "English"], to: "this key with missing translations: Sabes poco John Snow") }
|
50
54
|
it { translates("these 2 keys: $kTranslationKey$, $kTranslationKey2$", to: "these 2 keys: Não sabes nada João das Neves, Naaada!") }
|
51
55
|
|
52
56
|
it { translates("1 parameter: $k1ParameterKey$", to: "1 parameter: Não sabes nada %{name}") }
|
@@ -83,7 +87,7 @@ describe Bisu::Localizer do
|
|
83
87
|
.and not_change { Bisu::Logger.summary[:error] }
|
84
88
|
end
|
85
89
|
|
86
|
-
it "throws
|
90
|
+
it "throws a error when missing key parameters (expect on ruby on rails)" do
|
87
91
|
if type == :ror
|
88
92
|
expect {
|
89
93
|
localizer.localize("$k1ParameterKey$", language, locale)
|
@@ -110,6 +114,17 @@ describe Bisu::Localizer do
|
|
110
114
|
}.to not_change { Bisu::Logger.summary[:warn] }
|
111
115
|
.and change { Bisu::Logger.summary[:error] }.by(1)
|
112
116
|
end
|
117
|
+
|
118
|
+
# non localizable text with params
|
119
|
+
|
120
|
+
it "does not try to translate params outside $$" do
|
121
|
+
translates("%{some_text}", to: "%{some_text}")
|
122
|
+
|
123
|
+
expect {
|
124
|
+
localizer.localize("%{some_text}", language, locale)
|
125
|
+
}.to not_change { Bisu::Logger.summary[:warn] }
|
126
|
+
.and not_change { Bisu::Logger.summary[:error] }
|
127
|
+
end
|
113
128
|
end
|
114
129
|
|
115
130
|
let(:type_dependent_defaults) { {
|
@@ -125,10 +140,38 @@ describe Bisu::Localizer do
|
|
125
140
|
let(:type) { :ios }
|
126
141
|
|
127
142
|
let(:expected) { type_dependent_defaults.merge(
|
128
|
-
double_quoted: "Não sabes nada \\\"João das Neves\\\""
|
143
|
+
double_quoted: "Não sabes nada \\\"João das Neves\\\"",
|
144
|
+
percentage: "Sabes 0%% João das Neves."
|
129
145
|
) }
|
130
146
|
|
131
147
|
it_behaves_like "a localizer"
|
148
|
+
|
149
|
+
context "when a parameter replacemnt was not defined" do
|
150
|
+
let(:line) { "1 parameter: $k1ParameterKey$" }
|
151
|
+
let(:expected) { "1 parameter: Não sabes nada %{name}" }
|
152
|
+
|
153
|
+
it { translates(line, to: expected) }
|
154
|
+
|
155
|
+
it "returns an error" do
|
156
|
+
expect {
|
157
|
+
localizer.localize(line, language, locale)
|
158
|
+
}.to not_change { Bisu::Logger.summary[:warn] }
|
159
|
+
.and change { Bisu::Logger.summary[:error] }.by(1)
|
160
|
+
end
|
161
|
+
|
162
|
+
context "when passing //ignore-params" do
|
163
|
+
let(:line) { "1 parameter: $k1ParameterKey//ignore-params$" }
|
164
|
+
|
165
|
+
it { translates(line, to: expected) }
|
166
|
+
|
167
|
+
it "does not return an error" do
|
168
|
+
expect {
|
169
|
+
localizer.localize(line, language, locale)
|
170
|
+
}.to not_change { Bisu::Logger.summary[:warn] }
|
171
|
+
.and not_change { Bisu::Logger.summary[:error] }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
132
175
|
end
|
133
176
|
|
134
177
|
describe "of type Android" do
|
@@ -1,68 +1,43 @@
|
|
1
1
|
describe Bisu::Source::GoogleSheet do
|
2
|
-
subject(:to_i18) { Bisu::Source::GoogleSheet.new(
|
2
|
+
subject(:to_i18) { Bisu::Source::GoogleSheet.new(url).to_i18 }
|
3
3
|
|
4
|
-
let(:
|
5
|
-
let(:
|
6
|
-
let(:url_sheet) { "https://spreadsheets.google.com/feeds/list/#{sheet_id}/od6/public/full" }
|
4
|
+
let(:url) { "https://docs.google.com/spreadsheets/d/e/2PACX-1vTm6yu_zfbxKizC-PvUE1HVFCsplmiyz0s0qLSIGeokA7KtS3BgtqaA79CsfYfPsXH6xzUaP8HDTcj8/pub?gid=0&single=true&output=csv" }
|
5
|
+
let(:response) { File.read("spec/fixtures/sample_google_response.csv") }
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
let(:file_sheet) { File.read("spec/fixtures/sample_kb_public_sheet.html") }
|
13
|
-
|
14
|
-
before do
|
15
|
-
stub_request(:get, url_info).to_return(:status => 200, :body => file_info, :headers => {})
|
16
|
-
stub_request(:get, url_sheet).to_return(:status => 200, :body => file_sheet, :headers => {})
|
17
|
-
end
|
18
|
-
|
19
|
-
it do
|
20
|
-
expect { to_i18 }.not_to raise_error
|
21
|
-
end
|
22
|
-
|
23
|
-
it "returns an hash in i18 format" do
|
24
|
-
expect(to_i18).to eq({
|
25
|
-
"english" => { "kConnectFacebook" => "Connect with Facebook", "kConnectEmail" => "Connect with Email" },
|
26
|
-
"german" => { "kConnectFacebook" => "Mit Facebook verbinden", "kConnectEmail" => "Mit E-Mail verbinden" },
|
27
|
-
"portuguese" => { "kConnectFacebook" => "Registar com Facebook", "kConnectEmail" => "Registar com Email" },
|
28
|
-
"spanish" => { "kConnectFacebook" => "Conéctate con Facebook", "kConnectEmail" => "Conéctate con Email" },
|
29
|
-
"french" => { "kConnectFacebook" => "Connecter Facebook" },
|
30
|
-
"dutch" => { "kConnectFacebook" => "Facebook Verbinden", "kConnectEmail" => "Email Verbinden" },
|
31
|
-
"korean" => { "kConnectFacebook" => "페이스북으로 접속", "kConnectEmail" => "이메일로 접속" },
|
32
|
-
"japanese" => { "kConnectFacebook" => "フェイスブックへ接続", "kConnectEmail" => "電子メールアカウントに接続" }
|
33
|
-
})
|
34
|
-
end
|
7
|
+
def stub_url(status:, response:)
|
8
|
+
stub_request(:get, url).
|
9
|
+
to_return(:status => status, :body => response, :headers => {})
|
10
|
+
end
|
35
11
|
|
36
|
-
|
37
|
-
let(:key_column) { "expecting_another_key_column" }
|
12
|
+
before { stub_url(status: 200, response: response) }
|
38
13
|
|
39
|
-
|
40
|
-
|
41
|
-
end
|
42
|
-
end
|
14
|
+
it do
|
15
|
+
expect { to_i18 }.not_to raise_error
|
43
16
|
end
|
44
17
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
18
|
+
it "returns an hash in i18 format" do
|
19
|
+
expect(to_i18).to eq({
|
20
|
+
"en" => { "kConnectFacebook" => "Connect with Facebook", "kNoNoNoMr" => "No, no, no. Mr %{name} not here" },
|
21
|
+
"ja" => { "kConnectFacebook" => "フェイスブックへ接続" },
|
22
|
+
"fr" => { "kConnectFacebook" => "Connexion par Facebook" },
|
23
|
+
"de" => { "kConnectFacebook" => "Mit Facebook verbinden" },
|
24
|
+
"ko" => { "kConnectFacebook" => "페이스북으로 접속", "kTwitterServer" => "트위터 서버연결 실패. \\n잠시 후 재시도." }
|
25
|
+
})
|
51
26
|
end
|
52
27
|
|
53
|
-
context "when given
|
54
|
-
before {
|
28
|
+
context "when given an inexistent sheet" do
|
29
|
+
before { stub_url(status: 400, response: "Not Found") }
|
55
30
|
|
56
31
|
it do
|
57
|
-
expect { to_i18 }.to raise_error /
|
32
|
+
expect { to_i18 }.to raise_error /Http Error/
|
58
33
|
end
|
59
34
|
end
|
60
35
|
|
61
|
-
context "when url content is not
|
62
|
-
before {
|
36
|
+
context "when url content is not CSV" do
|
37
|
+
before { stub_url(status: 200, response: "{\"asdsa\": \"This is a json\"}") }
|
63
38
|
|
64
39
|
it do
|
65
|
-
expect { to_i18 }.to raise_error /Cannot parse. Expected
|
40
|
+
expect { to_i18 }.to raise_error /Cannot parse. Expected CSV/
|
66
41
|
end
|
67
42
|
end
|
68
43
|
end
|
data/spec/lib/bisu_spec.rb
CHANGED
@@ -7,7 +7,8 @@ describe Bisu do
|
|
7
7
|
before do
|
8
8
|
allow(Bisu).to receive(:open_file).and_return(file)
|
9
9
|
allow_any_instance_of(Bisu::Source::GoogleSheet).to receive(:to_i18).and_return({
|
10
|
-
"english" => { "kKey" => "Value" }
|
10
|
+
"english" => { "kKey" => "Value" },
|
11
|
+
"english-us" => { "kKey" => "Value" }
|
11
12
|
})
|
12
13
|
allow(Bisu).to receive(:localize_file)
|
13
14
|
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.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- joaoffcosta
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-08-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: safe_yaml
|
@@ -38,34 +38,6 @@ dependencies:
|
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0.7'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: xml-simple
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - "~>"
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.1'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - "~>"
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '1.1'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: webmock
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - "~>"
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '1.20'
|
62
|
-
type: :development
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - "~>"
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: '1.20'
|
69
41
|
description: Bisu manages your app iOS and Android localization files for you. No
|
70
42
|
more copy+paste induced errors!
|
71
43
|
email: joaostacosta@gmail.com
|
@@ -97,9 +69,8 @@ files:
|
|
97
69
|
- lib/bisu/source/url.rb
|
98
70
|
- lib/bisu/version.rb
|
99
71
|
- spec/fixtures/sample.translatable.yml
|
72
|
+
- spec/fixtures/sample_google_response.csv
|
100
73
|
- spec/fixtures/sample_json_response.json
|
101
|
-
- spec/fixtures/sample_kb_public_info.html
|
102
|
-
- spec/fixtures/sample_kb_public_sheet.html
|
103
74
|
- spec/fixtures/sample_one_sky_response.json
|
104
75
|
- spec/fixtures/sample_one_sky_response_with_bug.json
|
105
76
|
- spec/lib/bisu/config_spec.rb
|
@@ -131,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
131
102
|
- !ruby/object:Gem::Version
|
132
103
|
version: '0'
|
133
104
|
requirements: []
|
134
|
-
rubygems_version: 3.1.
|
105
|
+
rubygems_version: 3.1.6
|
135
106
|
signing_key:
|
136
107
|
specification_version: 4
|
137
108
|
summary: A localization automation service
|
@@ -1 +0,0 @@
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gs='http://schemas.google.com/spreadsheets/2006'><id>https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full</id><updated>2015-02-09T18:59:53.874Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#worksheet'/><title type='text'>H19: Translation Knowledge Base</title><link rel='alternate' type='application/atom+xml' href='https://docs.google.com/spreadsheets/d/abc1234567890/pubhtml'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full'/><author><name>anthony.douglas</name><email>anthony.douglas@hole19golf.com</email></author><openSearch:totalResults>1</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/od6</id><updated>2015-02-09T18:59:53.874Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#worksheet'/><title type='text'>Translations</title><content type='text'>Translations</content><link rel='http://schemas.google.com/spreadsheets/2006#listfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><link rel='http://schemas.google.com/spreadsheets/2006#cellsfeed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/cells/abc1234567890/od6/public/full'/><link rel='http://schemas.google.com/visualization/2008#visualizationApi' type='application/atom+xml' href='https://docs.google.com/spreadsheets/d/abc1234567890/gviz/tq?gid=0&pub=1'/><link rel='http://schemas.google.com/spreadsheets/2006#exportcsv' type='text/csv' href='https://docs.google.com/spreadsheets/d/abc1234567890/export?gid=0&format=csv'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/worksheets/abc1234567890/public/full/od6'/><gs:colCount>25</gs:colCount><gs:rowCount>665</gs:rowCount></entry></feed>
|
@@ -1 +0,0 @@
|
|
1
|
-
<?xml version='1.0' encoding='UTF-8'?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gsx='http://schemas.google.com/spreadsheets/2006/extended'><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full</id><updated>2015-02-09T18:59:53.874Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>Translations</title><link rel='alternate' type='application/atom+xml' href='https://docs.google.com/spreadsheets/d/abc1234567890/pubhtml'/><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full'/><author><name>anthony.douglas</name><email>anthony.douglas@hole19golf.com</email></author><openSearch:totalResults>664</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><entry><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cokwr</id><updated>2015-02-09T18:59:53.874Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>kConnectFacebook</title><content type='text'>english: Connect with Facebook, german: Mit Facebook verbinden, portuguese: Registar com Facebook, spanish: Conéctate con Facebook, french: Connecter Facebook, dutch: Facebook Verbinden, korean: 페이스북으로 접속, japanese: フェイスブックへ接続, key_column_2: kConnectFacebook</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cokwr'/><gsx:key_column>kConnectFacebook</gsx:key_column><gsx:english>Connect with Facebook</gsx:english><gsx:german>Mit Facebook verbinden</gsx:german><gsx:portuguese>Registar com Facebook</gsx:portuguese><gsx:spanish>Conéctate con Facebook</gsx:spanish><gsx:french>Connecter Facebook</gsx:french><gsx:dutch>Facebook Verbinden</gsx:dutch><gsx:korean>페이스북으로 접속</gsx:korean><gsx:japanese>フェイスブックへ接続</gsx:japanese></entry><entry><id>https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cpzh4</id><updated>2015-02-09T18:59:53.874Z</updated><category scheme='http://schemas.google.com/spreadsheets/2006' term='http://schemas.google.com/spreadsheets/2006#list'/><title type='text'>kConnectEmail</title><content type='text'>english: Connect with Email, german: Mit E-Mail verbinden, portuguese: Registar com Email, spanish: Conéctate con Email, dutch: Email Verbinden, korean: 이메일로 접속, japanese: 電子メールアカウントに接続, key_column_2: kConnectEmail</content><link rel='self' type='application/atom+xml' href='https://spreadsheets.google.com/feeds/list/abc1234567890/od6/public/full/cpzh4'/><gsx:key_column>kConnectEmail</gsx:key_column><gsx:english>Connect with Email</gsx:english><gsx:german>Mit E-Mail verbinden</gsx:german><gsx:portuguese>Registar com Email</gsx:portuguese><gsx:spanish>Conéctate con Email</gsx:spanish><gsx:french></gsx:french><gsx:dutch>Email Verbinden</gsx:dutch><gsx:korean>이메일로 접속</gsx:korean><gsx:japanese>電子メールアカウントに接続</gsx:japanese></entry></feed>
|