bisu 1.7.2 → 1.10.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: de4d41b8e81de051cee161b99f77b0e6e81fe7cdb878191beb46a9427db39db5
4
- data.tar.gz: f840f4d92ebc448ad43e298dcb95f3223c323a81f9441a1967689b278a501282
3
+ metadata.gz: a1a7abda3e27e23715ea0f2fb7b3e4bcb916c7a12b7eb691f5a5e3e8e1288a5c
4
+ data.tar.gz: 9a82418e8e0783d4d78783f895a95749a011defaa39332bb6732816d6222454a
5
5
  SHA512:
6
- metadata.gz: dc08b4b71b33d3db13a04302905d1846b190aa7e9febbf5eea69a97da4d2147be3ae97c270f2d658b9c2d7b1f598e8cdeb32daba762927cd508164b3a305d9c0
7
- data.tar.gz: ad976c7db6db95a592d9306e90e9c9051276cb2bc3dab784e97bef92d947386445c7f0d315b589df29e60833ac665039c4445d3d178dc1b21a30da6acb59892b
6
+ metadata.gz: 6c5d8bdcc8bf58bed26a44d949a9094c20382b9853b562c63165e6211b76cb9aa4c2f70db7e0577bf94358a9d83b4b64d8c8d1dbabadc8e2e7da056c01fce5b1
7
+ data.tar.gz: 508e86e0a9c4db4f3e7d5e691d9d5e4bf42656de4fcd52f0acd42acbb92836dc84d928aae9125466622cbde55a3a6a9f31482f3853aa805c890ac87451c1ee15
data/.rspec CHANGED
@@ -1,5 +1,4 @@
1
1
  --color
2
2
  --format documentation
3
3
  --profile
4
- --drb
5
4
  --require spec_helper
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.5.0
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
@@ -1,9 +1,8 @@
1
1
  source 'https://rubygems.org'
2
- ruby '2.5.0'
2
+ ruby '2.7.3'
3
3
 
4
4
  gem 'safe_yaml', '~> 1.0'
5
5
  gem 'colorize', '~> 0.7'
6
- gem 'xml-simple', '~> 1.1'
7
6
 
8
7
  group :test do
9
8
  gem 'rake'
data/Gemfile.lock CHANGED
@@ -1,37 +1,38 @@
1
1
  GEM
2
2
  remote: https://rubygems.org/
3
3
  specs:
4
- addressable (2.7.0)
4
+ addressable (2.8.0)
5
5
  public_suffix (>= 2.0.2, < 5.0)
6
6
  colorize (0.8.1)
7
- crack (0.4.3)
8
- safe_yaml (~> 1.0.0)
9
- diff-lcs (1.3)
7
+ crack (0.4.5)
8
+ rexml
9
+ diff-lcs (1.4.4)
10
10
  hashdiff (1.0.1)
11
- public_suffix (4.0.3)
12
- rake (13.0.1)
13
- rspec (3.9.0)
14
- rspec-core (~> 3.9.0)
15
- rspec-expectations (~> 3.9.0)
16
- rspec-mocks (~> 3.9.0)
17
- rspec-core (3.9.1)
18
- rspec-support (~> 3.9.1)
19
- rspec-expectations (3.9.0)
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.9.0)
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.9.1)
26
+ rspec-mocks (3.10.2)
26
27
  diff-lcs (>= 1.2.0, < 2.0)
27
- rspec-support (~> 3.9.0)
28
- rspec-support (3.9.2)
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.5)
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.5.0p0
50
+ ruby 2.7.3p183
50
51
 
51
52
  BUNDLED WITH
52
- 1.17.2
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
- *given that someone already configured Bisu
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: en
49
- language: en
50
- - locale: en-US
51
- language: en
52
- - locale: pt
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
- sheet_id: <GOOGLE-DRIVE-SHEET-ID>
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
@@ -18,7 +18,4 @@ Gem::Specification.new do |s|
18
18
 
19
19
  s.add_runtime_dependency 'safe_yaml', '~> 1.0'
20
20
  s.add_runtime_dependency 'colorize', '~> 0.7'
21
- s.add_runtime_dependency 'xml-simple', '~> 1.1'
22
-
23
- s.add_development_dependency 'webmock', '~> 1.20'
24
21
  end
@@ -3,8 +3,7 @@ type: iOS
3
3
 
4
4
  dictionary:
5
5
  type: google_sheet
6
- sheet_id: <GOOGLE-DRIVE-SHEET-ID>
7
- keys_column: <GOOGLE-DRIVE-KEY-COLUMN-TITLE>
6
+ url: <GOOGLE-DRIVE-SHEET-CSV-URL>
8
7
 
9
8
  translate:
10
9
  - in: path/to/1st/file.translatable
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[:locale])
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
- sheet_id: { type: String },
64
- keys_column: { type: String }
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 = {
@@ -10,7 +10,7 @@ module Bisu
10
10
  end
11
11
  end
12
12
 
13
- def localize(text, language, locale, fallback_language=nil)
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 = @dict.localize(language, l[:key]) || @dict.localize(fallback_language, l[:key])
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
- unless @type.eql?(:ror)
41
- t.scan(/%{[^}]+}/) { |match| Logger.error("Could not find translation param for #{match} in #{language}") }
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
- t
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
- { match: match[0],
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 "xmlsimple"
2
+ require "csv"
3
3
 
4
4
  module Bisu
5
5
  module Source
6
6
  class GoogleSheet
7
- def initialize(sheet_id, keys_column)
8
- @sheet_id = sheet_id
9
- @key_column = keys_column
7
+ def initialize(url)
8
+ @url = url
10
9
  end
11
10
 
12
11
  def to_i18
13
- raw = raw_data(@sheet_id)
12
+ Logger.info("Downloading Google Sheet from #{@url}...")
14
13
 
15
- Logger.info("Downloading dictionary from Google Sheet...")
14
+ csv = get_csv(@url)
16
15
 
17
- non_language_columns = ["id", "updated", "category", "title", "content", "link", @key_column]
16
+ hash = {}
18
17
 
19
- kb = {}
20
- raw["entry"].each do |entry|
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
- entry.select { |c| !non_language_columns.include?(c) }.each do |lang, texts|
26
- kb[lang] ||= {}
27
- kb[lang][key] = texts.first unless texts.first == {}
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 #{kb.count} languages.")
28
+ Logger.info("Found #{languages.count} languages.")
33
29
 
34
- kb
30
+ hash
35
31
  end
36
32
 
37
33
  private
38
34
 
39
- def xml_data(uri, headers=nil)
40
- uri = URI.parse(uri)
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
- unless data.code.to_i == 200
47
- raise "Bisu::Source::GoogleSheet: Cannot access sheet at #{uri} - HTTP #{data.code}"
48
- end
52
+ request = Net::HTTP::Get.new(uri.request_uri)
53
+ response = http.request(request)
49
54
 
50
- begin
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
- def raw_data(sheet_id)
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
@@ -1,4 +1,4 @@
1
1
  module Bisu
2
- VERSION = '1.7.2'
3
- VERSION_UPDATED_AT = '2020-03-09'
2
+ VERSION = '1.10.0'
3
+ VERSION_UPDATED_AT = '2021-08-30'
4
4
  end
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, locale|
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
- localize_file(localizer, locale, language, options[:default_language], in_path, out_path)
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[:sheet_id], config[:keys_column])
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, default_language, in_path, out_path)
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, default_language))
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
- sheet_id: sheet-id
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
@@ -0,0 +1,4 @@
1
+ key,en,ja,fr,de,ko
2
+ kConnectFacebook,Connect with Facebook,フェイスブックへ接続,Connexion par Facebook,Mit Facebook verbinden,페이스북으로 접속
3
+ kNoNoNoMr,"No, no, no. Mr %{name} not here",,,,
4
+ kTwitterServer,,,,,트위터 서버연결 실패. \n잠시 후 재시도.
@@ -4,25 +4,24 @@ describe Bisu::Config do
4
4
  let(:hash) { {
5
5
  type: "BisuOS",
6
6
  dictionary: {
7
- type: "google_sheet",
8
- sheet_id: "abc1234567890",
9
- keys_column: "key_name"
7
+ type: "google_sheet",
8
+ url: "https://abc1234567890",
10
9
  },
11
10
  translate: [
12
- { in: "path/to/file/to/1.ext.translatable",
13
- out: "path/to/final-%{locale}/1.ext",
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: "path/to/file/to/2.ext.translatable",
17
- out: "path/to/final-%{locale}/2.ext",
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", language: "english" },
23
- { locale: "pt", language: "portuguese" },
24
- { locale: "pt-PT", language: "portuguese" },
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", sheet_id: "abc1234567890", keys_column: "key_name" }) }
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: "one_sky",
46
- api_key: "as387oavh48",
44
+ type: "one_sky",
45
+ api_key: "as387oavh48",
47
46
  api_secret: "bp0s5avo8a59",
48
47
  project_id: 328742,
49
- file_name: "file.json"
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: "a_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", "english", "en-US" ],
79
- ["path/to/file/to/1.ext.translatable", "path/to/final-pt/1.ext", "portuguese", "pt" ],
80
- ["path/to/file/to/1.ext.translatable", "path/to/final-pt-PT/1.ext", "portuguese", "pt-PT" ],
81
- ["path/to/file/to/1.ext.translatable", "path/to/final-pt-Batatas/1.ext", "portuguese", "pt-Batatas"],
82
- ["path/to/file/to/2.ext.translatable", "path/to/default/2.ext", "english", "en-US" ],
83
- ["path/to/file/to/2.ext.translatable", "path/to/final-pt/2.ext", "portuguese", "pt" ],
84
- ["path/to/file/to/2.ext.translatable", "path/to/final-pt-PT/2.ext", "portuguese", "pt-PT" ],
85
- ["path/to/file/to/2.ext.translatable", "path/to/final-pt-Batatas/2.ext", "portuguese", "pt-Batatas"]
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$", fallback: "English", to: "this key with missing translations: You know little John Snow") }
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 an error when missing key parameters (expect on ruby on rails)" do
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(sheet_id, key_column).to_i18 }
2
+ subject(:to_i18) { Bisu::Source::GoogleSheet.new(url).to_i18 }
3
3
 
4
- let(:sheet_id) { "abc1234567890" }
5
- let(:url_info) { "https://spreadsheets.google.com/feeds/worksheets/#{sheet_id}/public/full" }
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
- let(:key_column) { "key_column" }
9
-
10
- context "when given a valid sheet" do
11
- let(:file_info) { File.read("spec/fixtures/sample_kb_public_info.html") }
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
- context "but the key column is not present in the first sheet" do
37
- let(:key_column) { "expecting_another_key_column" }
12
+ before { stub_url(status: 200, response: response) }
38
13
 
39
- it do
40
- expect { to_i18 }.to raise_error /Cannot find key column/
41
- end
42
- end
14
+ it do
15
+ expect { to_i18 }.not_to raise_error
43
16
  end
44
17
 
45
- context "when given an inexistent sheet" do
46
- before { stub_request(:get, url_info).to_return(:status => 400, :body => "Not Found", :headers => {}) }
47
-
48
- it do
49
- expect { to_i18 }.to raise_error /Cannot access sheet/
50
- end
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 a private sheet" do
54
- before { stub_request(:get, url_info).to_return(:status => 302, :body => "<HTML></HTML>", :headers => {}) }
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 /Cannot access sheet/
32
+ expect { to_i18 }.to raise_error /Http Error/
58
33
  end
59
34
  end
60
35
 
61
- context "when url content is not XML" do
62
- before { stub_request(:get, url_info).to_return(:status => 200, :body => "This is not XML; { this: \"is json\" }", :headers => {}) }
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 XML/
40
+ expect { to_i18 }.to raise_error /Cannot parse. Expected CSV/
66
41
  end
67
42
  end
68
43
  end
@@ -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.7.2
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: 2020-03-09 00:00:00.000000000 Z
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.2
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&amp;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&amp;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>