wovnrb 3.3.1 → 3.6.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +5 -0
  3. data/README.en.md +30 -13
  4. data/Rakefile +0 -1
  5. data/build.sh +7 -0
  6. data/docker/nginx/Dockerfile +18 -0
  7. data/docker/nginx/README.md +13 -0
  8. data/docker/nginx/build.sh +8 -0
  9. data/docker/nginx/scripts/configure_sshd.sh +25 -0
  10. data/docker/nginx/scripts/startup.sh +10 -0
  11. data/docker/nginx/wovnrb.conf +19 -0
  12. data/docker/rails/Dockerfile +9 -0
  13. data/docker/rails/Dockerfile.ECS +17 -0
  14. data/docker/rails/TestSite/Gemfile +0 -2
  15. data/docker/rails/TestSite/app/controllers/custom_response_controller.rb +1 -1
  16. data/docker/rails/TestSite/config/environments/development.rb +2 -0
  17. data/docker/rails/TestSite/config/environments/production.rb +2 -0
  18. data/docker/rails/TestSite/config/environments/test.rb +2 -0
  19. data/docker/rails/TestSite/public/index.html +1 -1
  20. data/docker/rails/TestSite/start.sh +2 -12
  21. data/docker/rails/TestSite/start_rails.sh +9 -0
  22. data/docker/rails/TestSite/yarn.lock +6 -6
  23. data/docker/scripts/jenkins/build.sh +45 -0
  24. data/docker/scripts/jenkins/tag_and_push_image.sh +30 -0
  25. data/docker/scripts/jenkins/taskdef.json +104 -0
  26. data/docker/scripts/jenkins/taskdef.json.bak +99 -0
  27. data/lib/wovnrb/api_translator.rb +19 -19
  28. data/lib/wovnrb/headers.rb +23 -6
  29. data/lib/wovnrb/helpers/nokogumbo_helper.rb +1 -1
  30. data/lib/wovnrb/lang.rb +3 -3
  31. data/lib/wovnrb/services/html_converter.rb +21 -1
  32. data/lib/wovnrb/services/url.rb +136 -0
  33. data/lib/wovnrb/store.rb +9 -3
  34. data/lib/wovnrb/url_language_switcher.rb +124 -0
  35. data/lib/wovnrb/version.rb +1 -1
  36. data/lib/wovnrb.rb +6 -4
  37. data/test/lib/api_translator_test.rb +66 -19
  38. data/test/lib/services/html_converter_test.rb +212 -39
  39. data/test/lib/services/url_test.rb +308 -0
  40. data/test/lib/url_language_switcher_test.rb +798 -0
  41. data/test/lib/wovnrb_test.rb +2 -1
  42. data/test/test_helper.rb +5 -2
  43. data/wovnrb.gemspec +3 -2
  44. metadata +42 -28
@@ -10,20 +10,24 @@ module Wovnrb
10
10
 
11
11
  def test_translate_falls_back_to_original_body_if_exception
12
12
  Net::HTTP.any_instance.expects(:request).raises
13
- assert_translation('test.html', 'test_translated.html', false, nil)
13
+ assert_translation('test.html', 'test_translated.html', false, response: nil)
14
14
  end
15
15
 
16
16
  def test_translate_falls_back_to_original_body_if_api_error
17
- assert_translation('test.html', 'test_translated.html', false, status_code: 500)
17
+ assert_translation('test.html', 'test_translated.html', false, response: { encoding: 'text/json', status_code: 500 })
18
18
  end
19
19
 
20
- def test_translate_falls_back_to_original_body_if_api_response_is_not_compressed
21
- assert_translation('test.html', 'test_translated.html', false, encoding: 'unknown')
20
+ def test_translate_continues_if_api_response_is_not_compressed
21
+ assert_translation('test.html', 'test_translated.html', true, response: { encoding: 'unknown', status: 200 }, compress_data: false)
22
+ end
23
+
24
+ def test_translate_continues_if_api_response_is_compressed
25
+ assert_translation('test.html', 'test_translated.html', true, response: { encoding: 'unknown', status: 200 })
22
26
  end
23
27
 
24
28
  def test_translate_accepts_uncompressed_response_from_api_in_dev_mode
25
29
  Wovnrb::Store.instance.update_settings('wovn_dev_mode' => true)
26
- assert_translation('test.html', 'test_translated.html', true, encoding: 'text/json')
30
+ assert_translation('test.html', 'test_translated.html', true, response: { encoding: 'text/json', status: 200 }, compress_data: false)
27
31
  end
28
32
 
29
33
  def test_translate_without_api_compression_sends_json
@@ -50,6 +54,7 @@ module Wovnrb
50
54
  'lang_code' => 'fr',
51
55
  'url_pattern' => 'subdomain',
52
56
  'lang_param_name' => 'lang',
57
+ 'translate_canonical_tag' => true,
53
58
  'product' => 'WOVN.rb',
54
59
  'version' => VERSION,
55
60
  'body' => 'foo',
@@ -58,12 +63,52 @@ module Wovnrb
58
63
  times: 1
59
64
  end
60
65
 
66
+ def test_api_timeout_is_search_engine_user_higher_default
67
+ settings = {
68
+ 'project_token' => '123456',
69
+ 'custom_lang_aliases' => { 'ja' => 'Japanese' },
70
+ 'default_lang' => 'en',
71
+ 'url_pattern' => 'subdomain',
72
+ 'url_pattern_reg' => '^(?<lang>[^.]+).',
73
+ 'lang_param_name' => 'lang'
74
+ }
75
+ store = Wovnrb::Store.instance
76
+ store.update_settings(settings)
77
+ headers = Wovnrb::Headers.new(
78
+ Wovnrb.get_env('url' => 'http://fr.wovn.io/test', 'HTTP_USER_AGENT' => 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'),
79
+ Wovnrb.get_settings(settings)
80
+ )
81
+ api_translator = ApiTranslator.new(store, headers, REQUEST_UUID)
82
+ assert_equal(5.0, api_translator.send(:api_timeout))
83
+ end
84
+
85
+ def test_api_timeout_no_user_agent_use_normal_default
86
+ settings = {
87
+ 'project_token' => '123456',
88
+ 'custom_lang_aliases' => { 'ja' => 'Japanese' },
89
+ 'default_lang' => 'en',
90
+ 'url_pattern' => 'subdomain',
91
+ 'url_pattern_reg' => '^(?<lang>[^.]+).',
92
+ 'lang_param_name' => 'lang'
93
+ }
94
+ store = Wovnrb::Store.instance
95
+ store.update_settings(settings)
96
+ env = Wovnrb.get_env('url' => 'http://fr.wovn.io/test')
97
+ env.delete('HTTP_USER_AGENT')
98
+ headers = Wovnrb::Headers.new(
99
+ env,
100
+ Wovnrb.get_settings(settings)
101
+ )
102
+ api_translator = ApiTranslator.new(store, headers, REQUEST_UUID)
103
+ assert_equal(1.0, api_translator.send(:api_timeout))
104
+ end
105
+
61
106
  private
62
107
 
63
- def assert_translation(original_html_fixture, translated_html_fixture, success_expected, response = { encoding: 'gzip', status_code: 200 })
108
+ def assert_translation(original_html_fixture, translated_html_fixture, success_expected, response: { encoding: 'gzip', status_code: 200 }, compress_data: true)
64
109
  original_html = File.read("test/fixtures/html/#{original_html_fixture}")
65
110
  translated_html = File.read("test/fixtures/html/#{translated_html_fixture}")
66
- actual_translated_html = translate(original_html, translated_html, response)
111
+ actual_translated_html = translate(original_html, translated_html, response, compress_data: compress_data)
67
112
 
68
113
  if success_expected
69
114
  assert_equal(actual_translated_html, translated_html)
@@ -72,10 +117,12 @@ module Wovnrb
72
117
  end
73
118
  end
74
119
 
75
- def translate(original_html, translated_html, response)
76
- api_translator, store, headers = create_sut
77
- translation_request_stub = stub_translation_api_request(store, headers, original_html, translated_html, response)
120
+ def translate(original_html, translated_html, response, compress_data: true)
121
+ api_translator, store, _headers = create_sut
122
+ translation_request_stub = stub_translation_api_request(store, original_html, translated_html, response, compress_data: compress_data)
78
123
 
124
+ expected_api_timeout = store.settings['api_timeout_seconds']
125
+ assert_equal(expected_api_timeout, api_translator.send(:api_timeout))
79
126
  actual_translated_html = api_translator.translate(original_html)
80
127
  assert_requested(translation_request_stub, times: 1) if translation_request_stub
81
128
  actual_translated_html
@@ -101,7 +148,7 @@ module Wovnrb
101
148
  [api_translator, store, headers]
102
149
  end
103
150
 
104
- def stub_translation_api_request(store, headers, original_html, translated_html, response)
151
+ def stub_translation_api_request(store, original_html, translated_html, response, compress_data: true)
105
152
  if response
106
153
  cache_key = generate_cache_key(store, original_html)
107
154
  api_host = if store.dev_mode?
@@ -115,14 +162,15 @@ module Wovnrb
115
162
  'Accept' => '*/*',
116
163
  'Accept-Encoding' => 'gzip',
117
164
  'Content-Length' => compressed_data.bytesize,
118
- 'Content-Type' => 'application/octet-stream',
165
+ 'Content-Type' => 'application/json',
166
+ 'Content-Encoding' => 'gzip',
119
167
  'User-Agent' => 'Ruby'
120
168
  }
121
169
  stub_response_json = "{\"body\":\"#{translated_html.gsub("\n", '\n')}\"}"
122
- stub_response = if store.dev_mode?
123
- stub_response_json
124
- else
170
+ stub_response = if compress_data
125
171
  compress(stub_response_json)
172
+ else
173
+ stub_response_json
126
174
  end
127
175
  response_headers = { 'Content-Encoding' => response[:encoding] || 'gzip' }
128
176
  stub_request(:post, api_url)
@@ -147,19 +195,18 @@ module Wovnrb
147
195
  'lang_code' => 'fr',
148
196
  'url_pattern' => 'subdomain',
149
197
  'lang_param_name' => 'lang',
198
+ 'translate_canonical_tag' => true,
150
199
  'product' => 'WOVN.rb',
151
200
  'version' => VERSION,
152
201
  'body' => original_html,
153
202
  'custom_lang_aliases' => '{"ja":"Japanese"}'
154
203
  }
155
204
 
156
- data.map { |key, value| "#{key}=#{CGI.escape(value)}" }.join('&')
205
+ data.to_json
157
206
  end
158
207
 
159
208
  def compress(string)
160
- gzip = Zlib::GzipWriter.new(StringIO.new)
161
- gzip << string
162
- gzip.close.string
209
+ ActiveSupport::Gzip.compress(string)
163
210
  end
164
211
  end
165
212
  end
@@ -2,7 +2,7 @@ require 'test_helper'
2
2
 
3
3
  module Wovnrb
4
4
  class HtmlConverterTest < WovnMiniTest
5
- def test_build_api_compatible_html
5
+ test 'build API compatible html' do
6
6
  converter = prepare_html_converter('<html><body><a class="test">hello</a></body></html>', supported_langs: %w[en vi])
7
7
  converted_html, = converter.build_api_compatible_html
8
8
 
@@ -10,7 +10,7 @@ module Wovnrb
10
10
  assert_equal(expected_html, converted_html)
11
11
  end
12
12
 
13
- def test_build_api_compatible_html_with_custom_lang_param_name
13
+ test 'build API compatible html - with custom lang param name' do
14
14
  settings = {
15
15
  supported_langs: %w[en vi],
16
16
  url_lang_pattern: 'query',
@@ -23,7 +23,7 @@ module Wovnrb
23
23
  assert_equal(expected_html, converted_html)
24
24
  end
25
25
 
26
- def test_build_api_compatible_html_not_fail_for_big_content
26
+ test 'build API compatible html - excessively large HTML' do
27
27
  long_string = 'a' * 60_000
28
28
  converter = prepare_html_converter("<html><body><p>#{long_string}</p></body></html>", supported_langs: %w[en vi])
29
29
  converted_html, = converter.build_api_compatible_html
@@ -32,7 +32,7 @@ module Wovnrb
32
32
  assert_equal(expected_html, converted_html)
33
33
  end
34
34
 
35
- def test_build_api_compatible_html_ignored_content_should_not_be_sent
35
+ test 'build API compatible html - ignored content should not be sent' do
36
36
  html = [
37
37
  '<html><body>',
38
38
  '<p>Hello <span wovn-ignore>WOVN</span><p>',
@@ -45,11 +45,11 @@ module Wovnrb
45
45
  converter = prepare_html_converter(html, ignore_class: ['ignore-me'])
46
46
  converted_html, = converter.build_api_compatible_html
47
47
 
48
- expected_convert_html = "<html lang=\"en\"><head><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"fr\" href=\"http://my-site.com/?wovn=fr\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body><p>Hello <span wovn-ignore=\"\"><!-- __wovn-backend-ignored-key-0 --></span></p><p></p><p>Hello <span data-wovn-ignore=\"\"><!-- __wovn-backend-ignored-key-1 --></span></p><p></p><div><span class=\"ignore-me\"><!-- __wovn-backend-ignored-key-2 --></span></div><span>Have a nice day!</span></body></html>"
48
+ expected_convert_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"fr\" href=\"http://my-site.com/?wovn=fr\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body><p>Hello <span wovn-ignore=\"\"><!-- __wovn-backend-ignored-key-0 --></span></p><p></p><p>Hello <span data-wovn-ignore=\"\"><!-- __wovn-backend-ignored-key-1 --></span></p><p></p><div><span class=\"ignore-me\"><!-- __wovn-backend-ignored-key-2 --></span></div><span>Have a nice day!</span></body></html>"
49
49
  assert_equal(expected_convert_html, converted_html)
50
50
  end
51
51
 
52
- def test_build_api_compatible_html_form_should_not_be_sent
52
+ test 'build API compatible html - do not send html form' do
53
53
  html = [
54
54
  '<html><body>',
55
55
  '<form action="/test" method="POST">',
@@ -62,11 +62,11 @@ module Wovnrb
62
62
  converter = prepare_html_converter(html, ignore_class: [])
63
63
  converted_html, = converter.build_api_compatible_html
64
64
 
65
- expected_convert_html = "<html lang=\"en\"><head><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"fr\" href=\"http://my-site.com/?wovn=fr\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body><form action=\"/test\" method=\"POST\"><!-- __wovn-backend-ignored-key-0 --></form></body></html>"
65
+ expected_convert_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"fr\" href=\"http://my-site.com/?wovn=fr\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body><form action=\"/test\" method=\"POST\"><!-- __wovn-backend-ignored-key-0 --></form></body></html>"
66
66
  assert_equal(expected_convert_html, converted_html)
67
67
  end
68
68
 
69
- def test_build_api_compatible_html_hidden_input_should_not_be_sent
69
+ test 'build API compatible html - do not send hidden form input' do
70
70
  html = [
71
71
  '<html><body>',
72
72
  '<input id="user-id" type="hidden" value="secret-id">',
@@ -91,7 +91,7 @@ module Wovnrb
91
91
  assert_equal(expected_convert_html, converted_html)
92
92
  end
93
93
 
94
- def test_transform_html
94
+ test 'Transform HTML' do
95
95
  converter = prepare_html_converter('<html><body><a>hello</a></body></html>', supported_langs: %w[en vi])
96
96
  translated_html = converter.build
97
97
 
@@ -99,7 +99,7 @@ module Wovnrb
99
99
  assert_equal(expected_html, translated_html)
100
100
  end
101
101
 
102
- def test_transform_html_with_empty_supported_langs
102
+ test 'Transform HTML - with empty supported langs' do
103
103
  converter = prepare_html_converter('<html><body><a>hello</a></body></html>', supported_langs: [])
104
104
  translated_html = converter.build
105
105
 
@@ -107,7 +107,7 @@ module Wovnrb
107
107
  assert_equal(expected_html, translated_html)
108
108
  end
109
109
 
110
- def test_transform_html_with_head_tag
110
+ test 'Transform HTML - with head tag' do
111
111
  converter = prepare_html_converter('<html><head><title>TITLE</title></head><body><a>hello</a></body></html>', supported_langs: %w[en vi])
112
112
  translated_html = converter.build
113
113
 
@@ -115,7 +115,7 @@ module Wovnrb
115
115
  assert_equal(expected_html, translated_html)
116
116
  end
117
117
 
118
- def test_transform_html_without_body
118
+ test 'Transform HTML - without body' do
119
119
  converter = prepare_html_converter('<html>hello<a>world</a></html>', supported_langs: [])
120
120
  translated_html = converter.build
121
121
 
@@ -123,7 +123,7 @@ module Wovnrb
123
123
  assert_equal(expected_html, translated_html)
124
124
  end
125
125
 
126
- def test_transform_html_on_default_lang_with_query_pattern_and_supported_lang
126
+ test 'Transform HTML - default lang - with query pattern and supported langs defined' do
127
127
  dom = get_dom('<html>hello<a>world</a></html>')
128
128
  settings = {
129
129
  'default_lang' => 'en',
@@ -131,14 +131,101 @@ module Wovnrb
131
131
  'url_pattern' => 'query'
132
132
  }
133
133
  store, headers = store_headers_factory(settings)
134
- converter = HtmlConverter.new(dom, store, headers)
134
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
135
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
135
136
  translated_html = converter.build
136
137
 
137
138
  expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body>hello<a>world</a></body></html>"
138
139
  assert_equal(expected_html, translated_html)
139
140
  end
140
141
 
141
- def test_transform_html_on_default_lang_with_path_pattern_and_supported_lang
142
+ test 'Transform HTML - canonical tag - target lang - should translate' do
143
+ dom = get_dom('<html><head><link rel="canonical" href="http://my-site.com/" /></head><body></body></html>')
144
+ settings = {
145
+ 'default_lang' => 'en',
146
+ 'supported_langs' => %w[en ja vi],
147
+ 'url_pattern' => 'path',
148
+ 'translate_canonical_tag' => true
149
+ }
150
+ store, headers = store_headers_factory(settings, 'http://my-site.com/vi/')
151
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
152
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
153
+ translated_html = converter.build
154
+
155
+ expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=vi&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"canonical\" href=\"http://my-site.com/vi/\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/ja/\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/vi/\"></head><body></body></html>"
156
+ assert_equal(expected_html, translated_html)
157
+ end
158
+
159
+ test 'Transform HTML - canonical tag - default lang - path pattern - no need to translate' do
160
+ dom = get_dom('<html><head><link rel="canonical" href="http://my-site.com/" /></head><body></body></html>')
161
+ settings = {
162
+ 'default_lang' => 'en',
163
+ 'supported_langs' => %w[en ja vi],
164
+ 'url_pattern' => 'path',
165
+ 'translate_canonical_tag' => true
166
+ }
167
+ store, headers = store_headers_factory(settings, 'http://my-site.com/')
168
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
169
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
170
+ translated_html = converter.build
171
+
172
+ expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"canonical\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/ja/\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/vi/\"></head><body></body></html>"
173
+ assert_equal(expected_html, translated_html)
174
+ end
175
+
176
+ test 'Transform HTML - canonical tag - default lang - query pattern - no need to translate' do
177
+ dom = get_dom('<html><head><link rel="canonical" href="http://my-site.com/" /></head><body></body></html>')
178
+ settings = {
179
+ 'default_lang' => 'en',
180
+ 'supported_langs' => %w[en ja vi],
181
+ 'url_pattern' => 'query',
182
+ 'translate_canonical_tag' => true
183
+ }
184
+ store, headers = store_headers_factory(settings, 'http://my-site.com/')
185
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
186
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
187
+ translated_html = converter.build
188
+
189
+ expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"canonical\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body></body></html>"
190
+ assert_equal(expected_html, translated_html)
191
+ end
192
+
193
+ test 'Transform HTML - canonical tag - default lang - has default lang alias - should use alias' do
194
+ dom = get_dom('<html><head><link rel="canonical" href="http://my-site.com/" /></head><body></body></html>')
195
+ settings = {
196
+ 'default_lang' => 'en',
197
+ 'supported_langs' => %w[en ja vi],
198
+ 'url_pattern' => 'query',
199
+ 'translate_canonical_tag' => true,
200
+ 'custom_lang_aliases' => { 'en' => 'english' }
201
+ }
202
+ store, headers = store_headers_factory(settings, 'http://my-site.com/')
203
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
204
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
205
+ translated_html = converter.build
206
+
207
+ expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={&quot;en&quot;:&quot;english&quot;}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"canonical\" href=\"http://my-site.com/?wovn=english\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/?wovn=ja\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/?wovn=vi\"></head><body></body></html>"
208
+ assert_equal(expected_html, translated_html)
209
+ end
210
+
211
+ test 'Transform HTML - canonical tag - disabled - do not translate' do
212
+ dom = get_dom('<html><head><link rel="canonical" href="http://my-site.com/" /></head><body></body></html>')
213
+ settings = {
214
+ 'default_lang' => 'en',
215
+ 'supported_langs' => %w[en ja vi],
216
+ 'url_pattern' => 'path',
217
+ 'translate_canonical_tag' => false
218
+ }
219
+ store, headers = store_headers_factory(settings, 'http://my-site.com/vi/')
220
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
221
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
222
+ translated_html = converter.build
223
+
224
+ expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=vi&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"canonical\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/ja/\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/vi/\"></head><body></body></html>"
225
+ assert_equal(expected_html, translated_html)
226
+ end
227
+
228
+ test 'Transform HTML - default lang - with path pattern and supported langs defined' do
142
229
  dom = get_dom('<html>hello<a>world</a></html>')
143
230
  settings = {
144
231
  'default_lang' => 'en',
@@ -146,14 +233,15 @@ module Wovnrb
146
233
  'url_pattern' => 'path'
147
234
  }
148
235
  store, headers = store_headers_factory(settings)
149
- converter = HtmlConverter.new(dom, store, headers)
236
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
237
+ converter = HtmlConverter.new(dom, store, headers, url_lang_switcher)
150
238
  translated_html = converter.build
151
239
 
152
240
  expected_html = "<html lang=\"en\"><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=path&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><link rel=\"alternate\" hreflang=\"en\" href=\"http://my-site.com/\"><link rel=\"alternate\" hreflang=\"ja\" href=\"http://my-site.com/ja/\"><link rel=\"alternate\" hreflang=\"vi\" href=\"http://my-site.com/vi/\"></head><body>hello<a>world</a></body></html>"
153
241
  assert_equal(expected_html, translated_html)
154
242
  end
155
243
 
156
- def test_replace_snippet
244
+ test 'replace_snippet' do
157
245
  converter = prepare_html_converter('<html><head>
158
246
  <script src="/a"></script>
159
247
  <script src="//j.wovn.io/1" async="true">
@@ -161,21 +249,46 @@ module Wovnrb
161
249
  <script src="https//cdn.wovn.io/" data-wovnio="key=2wpv0n async></script>
162
250
  <script src="https://wovn.global.ssl.fastly.net/widget/abcdef></script>
163
251
  </head></html>')
164
- converter.send(:replace_snippet)
165
-
166
- expected_html = "<html><head><meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"><script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script><script src=\"/a\"></script></head><body></body></html>"
167
- assert_equal(expected_html.gsub(/\s+/, ''), converter.send(:html).gsub(/\s+/, ''))
252
+ translated_html = converter.build
253
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
254
+ scripts = dom.css('script')
255
+ assert_equal(2, scripts.length)
256
+ expected_wovn_script = "<script src=\"https://j.wovn.io/1\" async=\"true\" data-wovnio=\"key=123456&amp;backend=true&amp;currentLang=en&amp;defaultLang=en&amp;urlPattern=query&amp;langCodeAliases={}&amp;langParamName=wovn&amp;version=WOVN.rb_#{VERSION}\" data-wovnio-type=\"fallback_snippet\"></script>"
257
+ assert_equal(expected_wovn_script, scripts.first.to_html)
168
258
  end
169
259
 
170
- def test_replace_hreflangs
260
+ test 'replace_hreflangs' do
171
261
  converter = prepare_html_converter('<html><head><link rel="alternate" hreflang="en" href="https://wovn.io/en/"></head></html>')
172
- converter.send(:replace_hreflangs)
173
-
174
- expected_html = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><link rel="alternate" hreflang="en" href="http://my-site.com/"><link rel="alternate" hreflang="fr" href="http://my-site.com/?wovn=fr"><link rel="alternate" hreflang="ja" href="http://my-site.com/?wovn=ja"><link rel="alternate" hreflang="vi" href="http://my-site.com/?wovn=vi"></head><body></body></html>'
175
- assert_equal(expected_html, converter.send(:html))
262
+ translated_html = converter.build
263
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
264
+ href_langs = dom.css('link[rel="alternate"]')
265
+ assert_equal(4, href_langs.length)
266
+ expected_href_langs = {
267
+ 'en' =>
268
+ {
269
+ 'href' => 'http://my-site.com/'
270
+ },
271
+ 'fr' =>
272
+ {
273
+ 'href' => 'http://my-site.com/?wovn=fr'
274
+ },
275
+ 'ja' =>
276
+ {
277
+ 'href' => 'http://my-site.com/?wovn=ja'
278
+ },
279
+ 'vi' =>
280
+ {
281
+ 'href' => 'http://my-site.com/?wovn=vi'
282
+ }
283
+ }
284
+ href_langs.each do |node|
285
+ assertions = expected_href_langs[node['hreflang']]
286
+ assert_not_nil(assertions)
287
+ assert_equal(assertions['href'], node['href'])
288
+ end
176
289
  end
177
290
 
178
- def test_inject_lang_html_tag_with_no_lang_in_html_tag
291
+ test 'inject_lang_html_tag - with no lang in HTML tag - should inject' do
179
292
  settings = default_store_settings
180
293
  store = Wovnrb::Store.instance
181
294
  store.update_settings(settings)
@@ -184,13 +297,14 @@ module Wovnrb
184
297
  Wovnrb.get_env('url' => 'http://my-site.com/'),
185
298
  Wovnrb.get_settings(settings)
186
299
  )
187
- converter = HtmlConverter.new(get_dom('<html><body>hello</body></html>'), store, headers)
188
- converter.send(:inject_lang_html_tag)
189
- expected_html = '<html lang="en"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body>hello</body></html>'
190
- assert_equal(expected_html, converter.send(:html))
300
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
301
+ converter = HtmlConverter.new(get_dom('<html><body>hello</body></html>'), store, headers, url_lang_switcher)
302
+ translated_html = converter.build
303
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
304
+ assert_equal('en', dom.at_css('html')['lang'])
191
305
  end
192
306
 
193
- def test_inject_lang_html_tag_with_lang_in_html_tag
307
+ test 'inject_lang_html_tag - with lang in HTML tag - do not override' do
194
308
  settings = default_store_settings
195
309
  store = Wovnrb::Store.instance
196
310
  store.update_settings(settings)
@@ -199,26 +313,85 @@ module Wovnrb
199
313
  Wovnrb.get_env('url' => 'http://my-site.com/'),
200
314
  Wovnrb.get_settings(settings)
201
315
  )
202
- converter = HtmlConverter.new(get_dom('<html lang="th"><body>hello</body></html>'), store, headers)
203
- converter.send(:inject_lang_html_tag)
204
- expected_html = '<html lang="th"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head><body>hello</body></html>'
205
- assert_equal(expected_html, converter.send(:html))
316
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
317
+ converter = HtmlConverter.new(get_dom('<html lang="th"><body>hello</body></html>'), store, headers, url_lang_switcher)
318
+ translated_html = converter.build
319
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
320
+ assert_equal('th', dom.at_css('html')['lang'])
321
+ end
322
+
323
+ test 'translate_canonical_tag' do
324
+ settings = default_store_settings
325
+ store = Wovnrb::Store.instance
326
+ store.update_settings(settings)
327
+
328
+ headers = Wovnrb::Headers.new(
329
+ Wovnrb.get_env('url' => 'http://my-site.com/?wovn=fr'),
330
+ store.settings
331
+ )
332
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
333
+ converter = HtmlConverter.new(get_dom('<html lang="th"><head><link rel="canonical" href="http://my-site.com" /></head><body>hello</body></html>'), store, headers, url_lang_switcher)
334
+ translated_html = converter.build
335
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
336
+ canonical_tag = dom.at_css('link[rel="canonical"]')
337
+ assert_not_nil(canonical_tag)
338
+ assert_equal('http://my-site.com?wovn=fr', canonical_tag['href'])
339
+ end
340
+
341
+ test 'translate_canonical_tag - path pattern' do
342
+ settings = default_store_settings
343
+ settings['url_pattern'] = 'path'
344
+ store = Wovnrb::Store.instance
345
+ store.update_settings(settings)
346
+
347
+ headers = Wovnrb::Headers.new(
348
+ Wovnrb.get_env('url' => 'http://my-site.com/fr/'),
349
+ store.settings
350
+ )
351
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
352
+ converter = HtmlConverter.new(get_dom('<html lang="th"><head><link rel="canonical" href="http://my-site.com/" /></head><body>hello</body></html>'), store, headers, url_lang_switcher)
353
+ translated_html = converter.build
354
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
355
+ canonical_tag = dom.at_css('link[rel="canonical"]')
356
+ assert_not_nil(canonical_tag)
357
+ assert_equal('http://my-site.com/fr/', canonical_tag['href'])
358
+ end
359
+
360
+ test 'translate_canonical_tag - canonical tag is already translated' do
361
+ # NOTE: this behavior is not correct, but it is the same as html-swapper
362
+ settings = default_store_settings
363
+ settings['url_pattern'] = 'path'
364
+ store = Wovnrb::Store.instance
365
+ store.update_settings(settings)
366
+
367
+ headers = Wovnrb::Headers.new(
368
+ Wovnrb.get_env('url' => 'http://my-site.com/fr/'),
369
+ store.settings
370
+ )
371
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
372
+ converter = HtmlConverter.new(get_dom('<html lang="th"><head><link rel="canonical" href="http://my-site.com/fr/" /></head><body>hello</body></html>'), store, headers, url_lang_switcher)
373
+ translated_html = converter.build
374
+ dom = Helpers::NokogumboHelper.parse_html(translated_html)
375
+ canonical_tag = dom.at_css('link[rel="canonical"]')
376
+ assert_not_nil(canonical_tag)
377
+ assert_equal('http://my-site.com/fr/fr/', canonical_tag['href'])
206
378
  end
207
379
 
208
380
  private
209
381
 
210
382
  def prepare_html_converter(input_html, store_options = {})
211
383
  store, headers = store_headers_factory(store_options)
212
- HtmlConverter.new(get_dom(input_html), store, headers)
384
+ url_lang_switcher = Wovnrb::UrlLanguageSwitcher.new(store)
385
+ HtmlConverter.new(get_dom(input_html), store, headers, url_lang_switcher)
213
386
  end
214
387
 
215
- def store_headers_factory(setting_opts = {})
388
+ def store_headers_factory(setting_opts = {}, url = 'http://my-site.com')
216
389
  settings = default_store_settings.merge(setting_opts)
217
390
  store = Wovnrb::Store.instance
218
391
  store.update_settings(settings)
219
392
 
220
393
  headers = Wovnrb::Headers.new(
221
- Wovnrb.get_env('url' => 'http://my-site.com'),
394
+ Wovnrb.get_env('url' => url),
222
395
  store.settings
223
396
  )
224
397