wovnrb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +20 -0
- data/.ruby-version +1 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +28 -0
- data/lib/wovnrb.rb +116 -0
- data/lib/wovnrb/headers.rb +176 -0
- data/lib/wovnrb/lang.rb +70 -0
- data/lib/wovnrb/railtie.rb +15 -0
- data/lib/wovnrb/store.rb +104 -0
- data/lib/wovnrb/version.rb +3 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/wovnrb_spec.rb +7 -0
- data/test/lib/test_headers.rb +96 -0
- data/test/lib/test_lang.rb +45 -0
- data/values/values +1 -0
- data/wovnrb.gemspec +49 -0
- metadata +277 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 61f0246afc971fcc1a0e23f4d52bcc7eb6308047
|
4
|
+
data.tar.gz: 7287c6ccc22deaf0fc375f47b56f1e14a6af8c3e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7b9ae3b2c55af426048647b12897a035cb72b9644d96522dfaddcf8514bf42401e892492684fbda754bcdde6828057576ac858f71e4639015dfbaab5951b827d
|
7
|
+
data.tar.gz: ad3b42dde7eec3635b6560c3d9b4136ba3eda76f146411aa666398adc83f413c1ea04bbb684a1dbd182e566b9ed533be05de251094c929cb7e1d72943e48bbc5
|
data/.gitignore
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
/.bundle/
|
2
|
+
<<<<<<< HEAD
|
3
|
+
/vendor
|
4
|
+
=======
|
5
|
+
/vendor/bundle/
|
6
|
+
>>>>>>> 78ccf8410c19bdee508e96a2386a5273abfad0ba
|
7
|
+
/.yardoc
|
8
|
+
/Gemfile.lock
|
9
|
+
/_yardoc/
|
10
|
+
/coverage/
|
11
|
+
/doc/
|
12
|
+
/pkg/
|
13
|
+
/spec/reports/
|
14
|
+
/tmp/
|
15
|
+
*.bundle
|
16
|
+
*.so
|
17
|
+
*.o
|
18
|
+
*.a
|
19
|
+
*.swp
|
20
|
+
mkmf.log
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
2.0.0-p451
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 TODO: Write your name
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# Wovn
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'wovnrb'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install wovnrb
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
TODO: Write usage instructions here
|
24
|
+
|
25
|
+
## Contributing
|
26
|
+
|
27
|
+
1. Fork it ( https://github.com/[my-github-username]/wovnrb/fork )
|
28
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#require "bundler/gem_tasks"
|
2
|
+
#require 'rake/extensiontask'
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
Rake::TestTask.new do |t|
|
6
|
+
t.libs << 'test'
|
7
|
+
t.test_files = FileList['test/*/*.rb']
|
8
|
+
t.options = '-p'
|
9
|
+
end
|
10
|
+
|
11
|
+
desc 'Run tests'
|
12
|
+
task :default => :test
|
13
|
+
|
14
|
+
#Rake::ExtensionTask.new 'dom' do |ext|
|
15
|
+
# ext.lib_dir = 'lib/wovnrb'
|
16
|
+
#end
|
17
|
+
|
18
|
+
#gemspec = Gem::Specification.load('wovnrb.gemspec')
|
19
|
+
#Rake::ExtensionTask.new do |ext|
|
20
|
+
# ext.name = 'dom'
|
21
|
+
# ext.source_pattern = "*.{cpp,h}"
|
22
|
+
# ext.ext_dir = 'ext/wovnrb'
|
23
|
+
# ext.lib_dir = 'lib/wovnrb'
|
24
|
+
# ext.gem_spec = gemspec
|
25
|
+
#end
|
26
|
+
#
|
27
|
+
#task :default => [:compile]
|
28
|
+
|
data/lib/wovnrb.rb
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'wovnrb/store'
|
2
|
+
require 'wovnrb/headers'
|
3
|
+
require 'wovnrb/lang'
|
4
|
+
#require 'dom'
|
5
|
+
require 'json'
|
6
|
+
|
7
|
+
require 'wovnrb/railtie' if defined?(Rails)
|
8
|
+
|
9
|
+
module Wovnrb
|
10
|
+
|
11
|
+
STORE = Store.new
|
12
|
+
|
13
|
+
class Interceptor
|
14
|
+
def initialize(app)
|
15
|
+
@app = app
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(env)
|
19
|
+
@env = env
|
20
|
+
STORE.refresh_settings
|
21
|
+
headers = Headers.new(env, STORE.settings)
|
22
|
+
if ((headers.path_lang != '' && !STORE.settings['supported_langs'].include?(headers.path_lang)) || headers.path_lang == STORE.settings['default_lang'])
|
23
|
+
redirect_headers = headers.redirect(STORE.settings['default_lang'])
|
24
|
+
redirect_headers['set-cookie'] = "wovn_selected_lang=#{STORE.settings['default_lang']};"
|
25
|
+
return [307, redirect_headers, ['']]
|
26
|
+
elsif headers.path_lang == '' && (headers.browser_lang != STORE.settings['default_lang'] && STORE.settings['supported_langs'].include?(headers.browser_lang))
|
27
|
+
redirect_headers = headers.redirect(headers.browser_lang)
|
28
|
+
return [307, redirect_headers, ['']]
|
29
|
+
end
|
30
|
+
lang = headers.lang
|
31
|
+
|
32
|
+
# pass to application
|
33
|
+
status, res_headers, body = @app.call(headers.request_out)
|
34
|
+
|
35
|
+
if res_headers["Content-Type"] =~ /html/ && !body[0].nil?
|
36
|
+
# Can we make this request beforehand?
|
37
|
+
values = STORE.get_values(headers.redis_url)
|
38
|
+
url = {
|
39
|
+
:protocol => headers.protocol,
|
40
|
+
:host => headers.host,
|
41
|
+
:pathname => headers.pathname
|
42
|
+
}
|
43
|
+
switch_lang(body, values, url, lang) unless status.to_s =~ /^1|302/ || lang === STORE.settings['default_lang']
|
44
|
+
#d = Dom.new(storage.get_values, body, lang)
|
45
|
+
end
|
46
|
+
|
47
|
+
headers.out(res_headers)
|
48
|
+
[status, res_headers, body]
|
49
|
+
#[status, res_headers, d.transform()]
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
def switch_lang(body, values, url, lang=STORE.settings['default_lang'])
|
54
|
+
def_lang = 'en'
|
55
|
+
text_index = values['text_vals'] || {}
|
56
|
+
src_index = values['img_vals'] || {}
|
57
|
+
img_src_prefix = values['img_src_prefix'] || ''
|
58
|
+
string_index = {}
|
59
|
+
body.map! do |b|
|
60
|
+
d = Nokogiri::HTML5(b)
|
61
|
+
d.xpath('//text()').each do |node|
|
62
|
+
node_text = node.content.strip
|
63
|
+
if text_index[node_text] && text_index[node_text][lang]
|
64
|
+
node.content = node.content.gsub(/^(\s*)[\S\s]*(\s*)$/, '\1' + text_index[node_text][lang][0]['data'] + '\2')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
d.xpath('//img').each do |node|
|
68
|
+
# use regular expressions to support case insensitivity (right?)
|
69
|
+
if node.to_html =~ /src=['"][^'"]*['"]/i
|
70
|
+
src = node.to_html.match(/src=['"]([^&'"]*)['"]/i)[1]
|
71
|
+
# THIS SRC CORRECTION DOES NOT HANDLE ONE IMPORTANT CASE
|
72
|
+
# 1) "../path/with/ellipse"
|
73
|
+
# if this is not an absolute src
|
74
|
+
if src !~ /:\/\//
|
75
|
+
# if this is a path with a leading slash
|
76
|
+
if src =~ /^\//
|
77
|
+
src = "#{url[:protocol]}://#{url[:host]}#{src}"
|
78
|
+
else
|
79
|
+
src = "#{url[:protocol]}://#{url[:host]}#{url[:path]}#{src}"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
if src_index[src] && src_index[src][lang]
|
84
|
+
node.attribute('src').value = "#{img_src_prefix}#{src_index[src][lang][0]['data']}"
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
# INSERTS
|
89
|
+
#insert_node = Nokogiri::XML::Node.new('script', d)
|
90
|
+
#insert_node['type'] = 'text/javascript'
|
91
|
+
#insert_node.content = "window.wovn_backend = function() { return {'currentLang': '#{lang}'}; };"
|
92
|
+
#parent_node = d.at_css('head') || d.at_css('body') || d.at_css('html')
|
93
|
+
#parent_node.add_child(insert_node)
|
94
|
+
|
95
|
+
# If dev can't be used on production gem
|
96
|
+
d.xpath('//script').each do |script_node|
|
97
|
+
if script_node['src'] && script_node['src'].include?('//j.wovn.io/')
|
98
|
+
script_node.remove
|
99
|
+
end
|
100
|
+
end
|
101
|
+
insert_node = Nokogiri::XML::Node.new('script', d)
|
102
|
+
insert_node['src'] = '//j.wovn.io/0'
|
103
|
+
insert_node['data-wovnio'] = "key=#{STORE.settings['user_token']}&backend=true¤tLang=#{lang}&urlPattern=#{STORE.settings['url_pattern_name']}"
|
104
|
+
# do this so that there will be a closing tag (better compatibility with browsers)
|
105
|
+
insert_node.content = ' '
|
106
|
+
parent_node = d.at_css('head') || d.at_css('body') || d.at_css('html')
|
107
|
+
parent_node.prepend_child(insert_node)
|
108
|
+
|
109
|
+
d.to_html
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module Wovnrb
|
2
|
+
|
3
|
+
class Headers
|
4
|
+
attr_reader :unmasked_url
|
5
|
+
attr_reader :url
|
6
|
+
attr_reader :protocol
|
7
|
+
attr_reader :unmasked_host
|
8
|
+
attr_reader :host
|
9
|
+
attr_reader :unmasked_pathname
|
10
|
+
attr_reader :pathname
|
11
|
+
attr_reader :redis_url
|
12
|
+
|
13
|
+
def initialize(env, settings)
|
14
|
+
@env = env
|
15
|
+
@protocol = @env['rack.url_scheme']
|
16
|
+
@unmasked_host = @env['HTTP_HOST']
|
17
|
+
@unmasked_pathname = @env['REQUEST_URI'].split('?')[0]
|
18
|
+
@unmasked_pathname += '/' unless @unmasked_pathname =~ /\/$/ || @unmasked_pathname =~ /\/[^\/.]+\.[^\/.]+$/
|
19
|
+
@unmasked_url = "#{@protocol}://#{@unmasked_host}#{@unmasked_pathname}"
|
20
|
+
@host = remove_lang(@env['HTTP_HOST'], self.lang)
|
21
|
+
@pathname, @query = @env['REQUEST_URI'].split('?')
|
22
|
+
@pathname = remove_lang(@pathname, self.lang)
|
23
|
+
@query = @query || ''
|
24
|
+
@url = "#{@host}#{@pathname}#{(@query.length > 0 ? '?' : '') + remove_lang(@query, self.lang)}"
|
25
|
+
if settings['query'].length > 0
|
26
|
+
query_vals = []
|
27
|
+
settings['query'].each do |qv|
|
28
|
+
rx = Regexp.new("(^|&)(?<query_val>#{qv}[^&]+)(&|$)")
|
29
|
+
m = @query.match(rx)
|
30
|
+
if m && m[:query_val]
|
31
|
+
query_vals.push(m[:query_val])
|
32
|
+
end
|
33
|
+
end
|
34
|
+
if query_vals.length > 0
|
35
|
+
@query = "?#{query_vals.sort.join('&')}"
|
36
|
+
end
|
37
|
+
else
|
38
|
+
@query = ''
|
39
|
+
end
|
40
|
+
@query = remove_lang(@query, self.lang)
|
41
|
+
@pathname = @pathname.gsub(/\/$/, '')
|
42
|
+
@redis_url = "#{@host}#{@pathname}#{@query}"
|
43
|
+
end
|
44
|
+
|
45
|
+
def lang
|
46
|
+
(self.path_lang && self.path_lang.length > 0) ? self.path_lang : STORE.settings['default_lang']
|
47
|
+
end
|
48
|
+
|
49
|
+
def path_lang
|
50
|
+
if @path_lang.nil?
|
51
|
+
rp = Regexp.new(STORE.settings['url_pattern_reg'])
|
52
|
+
match = "#{@env['SERVER_NAME']}#{@env['REQUEST_URI']}".match(rp)
|
53
|
+
if match && match[:lang] && Lang::LANG[match[:lang]]
|
54
|
+
@path_lang = match[:lang]
|
55
|
+
else
|
56
|
+
@path_lang = ''
|
57
|
+
end
|
58
|
+
end
|
59
|
+
return @path_lang
|
60
|
+
end
|
61
|
+
|
62
|
+
def browser_lang
|
63
|
+
if @browser_lang.nil?
|
64
|
+
match = (@env['HTTP_COOKIE'] || '').match(/wovn_selected_lang\s*=\s*(?<lang>[^;\s]+)/)
|
65
|
+
if match && match[:lang] && Lang::LANG[match[:lang]]
|
66
|
+
@browser_lang = match[:lang]
|
67
|
+
else
|
68
|
+
# IS THIS RIGHT?
|
69
|
+
@browser_lang = ''
|
70
|
+
accept_langs = (@env['HTTP_ACCEPT_LANGUAGE'] || '').split(/[,;]/)
|
71
|
+
accept_langs.each do |l|
|
72
|
+
if Lang::LANG[l]
|
73
|
+
@browser_lang = l
|
74
|
+
break
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
return @browser_lang
|
80
|
+
end
|
81
|
+
|
82
|
+
def redirect(lang=self.browser_lang)
|
83
|
+
redirect_headers = {}
|
84
|
+
redirect_headers['location'] = self.redirect_location(lang)
|
85
|
+
redirect_headers['content-length'] = '0'
|
86
|
+
return redirect_headers
|
87
|
+
end
|
88
|
+
|
89
|
+
def redirect_location(lang)
|
90
|
+
if lang == STORE.settings['default_lang']
|
91
|
+
# IS THIS RIGHT??
|
92
|
+
return "#{self.protocol}://#{self.url}"
|
93
|
+
#return remove_lang("#{@env['HTTP_HOST']}#{@env['REQUEST_URI']}", lang)
|
94
|
+
else
|
95
|
+
location = self.url
|
96
|
+
case STORE.settings['url_pattern_name']
|
97
|
+
when 'query'
|
98
|
+
if location !~ /\?/
|
99
|
+
location = "#{location}?wovn=#{lang}"
|
100
|
+
else @env['REQUEST_URI'] !~ /(\?|&)wovn=/
|
101
|
+
location = "#{location}&wovn=#{lang}"
|
102
|
+
end
|
103
|
+
when 'subdomain'
|
104
|
+
location = "#{lang}.#{location}"
|
105
|
+
#when 'path'
|
106
|
+
else
|
107
|
+
location = location.sub(/(\/|$)/, "/#{lang}/");
|
108
|
+
end
|
109
|
+
return "#{self.protocol}://#{location}"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def request_out(def_lang=STORE.settings['default_lang'])
|
114
|
+
case STORE.settings['url_pattern_name']
|
115
|
+
when 'query'
|
116
|
+
@env['REQUEST_URI'] = remove_lang(@env['REQUEST_URI'])
|
117
|
+
if @env.has_key?('QUERY_STRING')
|
118
|
+
@env['QUERY_STRING'] = remove_lang(@env['QUERY_STRING'])
|
119
|
+
end
|
120
|
+
if @env.has_key?('ORIGINAL_FULLPATH')
|
121
|
+
@env['ORIGINAL_FULLPATH'] = remove_lang(@env['ORIGINAL_FULLPATH'])
|
122
|
+
end
|
123
|
+
when 'subdomain'
|
124
|
+
@env["HTTP_HOST"] = remove_lang(@env["HTTP_HOST"])
|
125
|
+
@env["SERVER_NAME"] = remove_lang(@env["SERVER_NAME"])
|
126
|
+
if @env.has_key?('HTTP_REFERER')
|
127
|
+
@env["HTTP_REFERER"] = remove_lang(@env["HTTP_REFERER"])
|
128
|
+
end
|
129
|
+
#when 'path'
|
130
|
+
else
|
131
|
+
@env['REQUEST_URI'] = remove_lang(@env['REQUEST_URI'])
|
132
|
+
@env['REQUEST_PATH'] = remove_lang(@env['REQUEST_PATH'])
|
133
|
+
@env['PATH_INFO'] = remove_lang(@env['PATH_INFO'])
|
134
|
+
if @env.has_key?('ORIGINAL_FULLPATH')
|
135
|
+
@env['ORIGINAL_FULLPATH'] = remove_lang(@env['ORIGINAL_FULLPATH'])
|
136
|
+
end
|
137
|
+
end
|
138
|
+
@env
|
139
|
+
end
|
140
|
+
|
141
|
+
def remove_lang(uri, lang=self.path_lang)
|
142
|
+
case STORE.settings['url_pattern_name']
|
143
|
+
when 'query'
|
144
|
+
return uri.sub(/(^|\?|&)wovn=#{lang}(&|$)/, '\1').gsub(/(\?|&)$/, '')
|
145
|
+
when 'subdomain'
|
146
|
+
rp = Regexp.new('(^|(//))' + lang + '\.')
|
147
|
+
return uri.sub(rp, '\1')
|
148
|
+
#when 'path'
|
149
|
+
else
|
150
|
+
return uri.sub(/\/#{lang}(\/|$)/, '/')
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def out(headers)
|
155
|
+
if headers.has_key?("Location")
|
156
|
+
case STORE.settings['url_pattern_name']
|
157
|
+
when 'query'
|
158
|
+
if headers["Location"] =~ /\?/
|
159
|
+
headers["Location"] += "&"
|
160
|
+
else
|
161
|
+
headers["Location"] += "?"
|
162
|
+
end
|
163
|
+
headers['Location'] += "wovn=#{self.lang}"
|
164
|
+
when 'subdomain'
|
165
|
+
headers["Location"] = headers["Location"].sub(/\/\/([^.]+)/, '//' + self.lang + '.\1')
|
166
|
+
#when 'path'
|
167
|
+
else
|
168
|
+
headers["Location"] = headers['Location'].sub(/(\/\/[^\/]+)/, '\1/' + self.lang)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
headers
|
172
|
+
end
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
data/lib/wovnrb/lang.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
# -*- encoding: UTF-8 -*-
|
2
|
+
module Wovnrb
|
3
|
+
class Lang
|
4
|
+
LANG = {
|
5
|
+
#http://msdn.microsoft.com/en-us/library/hh456380.aspx
|
6
|
+
'ar' => {name: 'العربية', code: 'ar', en: 'Arabic'},
|
7
|
+
'zh-CHS' => {name: '简体中文', code: 'zh-CHS', en: 'Simp Chinese'},
|
8
|
+
'zh-CHT' => {name: '繁體中文', code: 'zh-CHT', en: 'Trad Chinese'},
|
9
|
+
'da' => {name: 'Dansk', code: 'da', en: 'Danish'},
|
10
|
+
'nl' => {name: 'Nederlands', code: 'nl', en: 'Dutch'},
|
11
|
+
'en' => {name: 'English', code: 'en', en: 'English'},
|
12
|
+
'fi' => {name: 'Suomi', code: 'fi', en: 'Finnish'},
|
13
|
+
'fr' => {name: 'Français', code: 'fr', en: 'French'},
|
14
|
+
'de' => {name: 'Deutsch', code: 'de', en: 'German'},
|
15
|
+
'el' => {name: 'Ελληνικά', code: 'el', en: 'Greek'},
|
16
|
+
'he' => {name: 'עברית', code: 'he', en: 'Hebrew'},
|
17
|
+
'id' => {name: 'Bahasa Indonesia', code: 'id', en: 'Indonesian'},
|
18
|
+
'it' => {name: 'Italiano', code: 'it', en: 'Italian'},
|
19
|
+
'ja' => {name: '日本語', code: 'ja', en: 'Japanese'},
|
20
|
+
'ko' => {name: '한국어', code: 'ko', en: 'Korean'},
|
21
|
+
'ms' => {name: 'Bahasa Melayu', code: 'ms', en: 'Malay'},
|
22
|
+
'no' => {name: 'Norsk', code: 'no', en: 'Norwegian'},
|
23
|
+
'pl' => {name: 'Polski', code: 'pl', en: 'Polish'},
|
24
|
+
'pt' => {name: 'Português', code: 'pt', en: 'Portuguese'},
|
25
|
+
'ru' => {name: 'Русский', code: 'ru', en: 'Russian'},
|
26
|
+
'es' => {name: 'Español', code: 'es', en: 'Spanish'},
|
27
|
+
'sv' => {name: 'Svensk', code: 'sv', en: 'Swedish'},
|
28
|
+
'th' => {name: 'ภาษาไทย', code: 'th', en: 'Thai'},
|
29
|
+
'hi' => {name: 'हिन्दी', code: 'hi', en: 'Hindi'},
|
30
|
+
'tr' => {name: 'Türkçe', code: 'tr', en: 'Turkish'},
|
31
|
+
'uk' => {name: 'Українська', code: 'uk', en: 'Ukrainian'},
|
32
|
+
'vi' => {name: 'Tiếng Việt', code: 'vi', en: 'Vietnamese'},
|
33
|
+
|
34
|
+
=begin
|
35
|
+
* denotes no Google support
|
36
|
+
*{name: 'Urdu', code: 'ur', en: 'Urdu'},
|
37
|
+
{name: 'Català', code: 'ca'},
|
38
|
+
{name: 'Čeština', code: 'cs'},
|
39
|
+
{name: 'Български', code: 'bg'},
|
40
|
+
{name: 'Estonian', code: 'et'},
|
41
|
+
*{name: 'Haitian Creoloe', code: 'ht'},
|
42
|
+
*{name: 'Hmong Daw', code: 'mww'},
|
43
|
+
{name: 'Hungarian', code: 'hu'},
|
44
|
+
*{name: 'Klingon', code: 'tlh'},
|
45
|
+
*{name: 'Klingon (plqaD)', code: 'tlh-Qaak'},
|
46
|
+
{name: 'Latvian', code: 'lv'},
|
47
|
+
{name: 'Lithuanian', code: 'lt'},
|
48
|
+
{name: 'Maltese', code: 'mt'},
|
49
|
+
{name: 'Persian', code: 'fa'},
|
50
|
+
{name: 'Romanian', code: 'ro'},
|
51
|
+
{name: 'Slovak', code: 'sk'},
|
52
|
+
{name: 'Slovenian', code: 'sl'},
|
53
|
+
{name: 'Ukranian', code: 'uk'},
|
54
|
+
{name: 'Welsh', code: 'cy'},
|
55
|
+
=end
|
56
|
+
}
|
57
|
+
|
58
|
+
def self.get_code(lang_name)
|
59
|
+
return nil if lang_name.nil?
|
60
|
+
return lang_name if LANG[lang_name]
|
61
|
+
LANG.each do |k, l|
|
62
|
+
if lang_name.downcase == l[:name].downcase || lang_name.downcase == l[:en].downcase
|
63
|
+
return l[:code]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
return nil
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Wovnrb
|
2
|
+
|
3
|
+
class Railtie < Rails::Railtie
|
4
|
+
initializer 'wovnrb.configure_rails_initialization' do |app|
|
5
|
+
app.middleware.insert_before(0, Wovnrb::Interceptor)
|
6
|
+
|
7
|
+
#if Rails.env.development? && config.respond_to?(:wovnrb)
|
8
|
+
# config.after_initialize do
|
9
|
+
# config.wovnrb[:user_token] = User.first.short_token
|
10
|
+
# end
|
11
|
+
#end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/wovnrb/store.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'redis'
|
2
|
+
require 'net/http'
|
3
|
+
|
4
|
+
module Wovnrb
|
5
|
+
|
6
|
+
class Store
|
7
|
+
attr_reader :settings
|
8
|
+
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@settings =
|
12
|
+
{
|
13
|
+
'user_token' => '',
|
14
|
+
# 'url_pattern_name' => 'query'
|
15
|
+
# 'url_pattern_reg' => "?.*wovn=(?<lang>[^&]+)(&|$)",
|
16
|
+
'url_pattern_name' => 'path',
|
17
|
+
'url_pattern_reg' => "/(?<lang>[^/.?]+)",
|
18
|
+
#'url_pattern_name' => 'subdomain',
|
19
|
+
#'url_pattern_reg' => "^(?<lang>[^.]+)\.",
|
20
|
+
'query' => [],
|
21
|
+
'backend_host' => 'rs1.wovn.io',
|
22
|
+
'backend_port' => '6379',
|
23
|
+
'default_lang' => 'en',
|
24
|
+
'supported_langs' => ['en'],
|
25
|
+
}
|
26
|
+
# When Store is initialized, the Rails.configuration object is not yet initialized
|
27
|
+
@config_loaded = false
|
28
|
+
end
|
29
|
+
|
30
|
+
def settings
|
31
|
+
if !@config_loaded
|
32
|
+
if Object.const_defined?('Rails') && Rails.configuration.respond_to?(:wovnrb)
|
33
|
+
@settings.merge!(Rails.configuration.wovnrb.stringify_keys)
|
34
|
+
end
|
35
|
+
refresh_settings
|
36
|
+
@config_loaded = true
|
37
|
+
end
|
38
|
+
@settings
|
39
|
+
end
|
40
|
+
|
41
|
+
def refresh_settings
|
42
|
+
# add timer so this only accesses redis once every 5 minutes etc
|
43
|
+
user_token = @settings['user_token']
|
44
|
+
#user_token = 'lYWQ9'
|
45
|
+
redis_key = 'WOVN:BACKEND:SETTING::' + user_token
|
46
|
+
cli = Redis.new(host: @settings['backend_host'], port: @settings['backend_port'])
|
47
|
+
begin
|
48
|
+
vals = cli.hgetall(redis_key) || {}
|
49
|
+
rescue
|
50
|
+
vals = {}
|
51
|
+
end
|
52
|
+
if vals.has_key?('query')
|
53
|
+
vals['query'] = JSON.parse(vals['query'])
|
54
|
+
end
|
55
|
+
if vals.has_key?('supported_langs')
|
56
|
+
vals['supported_langs'] = JSON.parse(vals['supported_langs'])
|
57
|
+
end
|
58
|
+
@settings.merge!(vals)
|
59
|
+
@settings['backend_port'] = @settings['backend_port'].to_s
|
60
|
+
@settings['default_lang'] = Lang.get_code(@settings['default_lang'])
|
61
|
+
if !vals.has_key?('supported_langs')
|
62
|
+
@settings['supported_langs'] = [@settings['default_lang']]
|
63
|
+
end
|
64
|
+
if @settings['url_pattern_name'] == 'path'
|
65
|
+
@settings['url_pattern_reg'] = "/(?<lang>[^/.?]+)"
|
66
|
+
elsif @settings['url_pattern_name'] == 'query'
|
67
|
+
@settings['url_pattern_reg'] = '((\?.*&)|\?)wovn=(?<lang>[^&]+)(&|$)'
|
68
|
+
end
|
69
|
+
@settings
|
70
|
+
end
|
71
|
+
|
72
|
+
def get_values(url)
|
73
|
+
#url = 'http://wovn.io'
|
74
|
+
user_token = @settings['user_token']
|
75
|
+
#user_token = 'lYWQ9'
|
76
|
+
redis_key = 'WOVN:BACKEND:STORAGE:' + url.gsub(/\/$/, '') + ':' + user_token
|
77
|
+
vals = request_values(redis_key)
|
78
|
+
if vals.empty?
|
79
|
+
#uri = URI.parse('http://wovn.io/[USER_ID]/[PAGE_ID]')
|
80
|
+
#Net::HTTP.get(uri)
|
81
|
+
end
|
82
|
+
vals
|
83
|
+
#f = File.open('./values/values', 'r')
|
84
|
+
#return JSON.parse(f.read)
|
85
|
+
#f.close
|
86
|
+
end
|
87
|
+
|
88
|
+
def request_values(key)
|
89
|
+
Rails.logger.info("*******************************************************")
|
90
|
+
Rails.logger.info(key)
|
91
|
+
cli = Redis.new(host: @settings['backend_host'], port: @settings['backend_port'])
|
92
|
+
Rails.logger.info(@settings['backend_host'])
|
93
|
+
Rails.logger.info(@settings['backend_port'])
|
94
|
+
begin
|
95
|
+
vals = cli.get(key) || '{}'
|
96
|
+
vals = JSON.parse(vals)
|
97
|
+
rescue
|
98
|
+
vals = {}
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/spec/wovnrb_spec.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'wovnrb'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'pry'
|
4
|
+
|
5
|
+
class TestHeaders < Minitest::Test
|
6
|
+
|
7
|
+
def test_initialize
|
8
|
+
h = Wovnrb::Headers.new(get_env, get_settings)
|
9
|
+
refute_nil(h)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_initialize_with_simple_url
|
13
|
+
h = Wovnrb::Headers.new(get_env('url' => 'https://wovn.io'), get_settings)
|
14
|
+
#assert_equal(''
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_keys_exist
|
18
|
+
Wovnrb::Lang::LANG.each do |k, l|
|
19
|
+
assert(l.has_key?(:name))
|
20
|
+
assert(l.has_key?(:code))
|
21
|
+
assert(l.has_key?(:en))
|
22
|
+
assert_equal(k, l[:code])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_get_code_with_valid_code
|
27
|
+
assert_equal('ms', Wovnrb::Lang.get_code('ms'))
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_get_code_with_valid_english_name
|
31
|
+
assert_equal('pt', Wovnrb::Lang.get_code('Portuguese'))
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_get_code_with_valid_native_name
|
35
|
+
assert_equal('hi', Wovnrb::Lang.get_code('हिन्दी'))
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_get_code_with_invalid_name
|
39
|
+
assert_equal(nil, Wovnrb::Lang.get_code('WOVN4LYFE'))
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_get_code_with_empty_string
|
43
|
+
assert_equal(nil, Wovnrb::Lang.get_code(''))
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_get_code_with_nil
|
47
|
+
assert_equal(nil, Wovnrb::Lang.get_code(nil))
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_settings(options={})
|
51
|
+
settings = {}
|
52
|
+
settings['user_token'] = 'OHYx9'
|
53
|
+
settings['url_pattern_name'] = 'path'
|
54
|
+
settings['url_pattern_reg'] = "/(?<lang>[^/.?]+)"
|
55
|
+
settings['query'] = []
|
56
|
+
settings['backend_host'] = 'localhost'
|
57
|
+
settings['backend_port'] = '6379'
|
58
|
+
settings['default_lang'] = 'en'
|
59
|
+
settings['supported_langs'] = []
|
60
|
+
settings['secret_key'] = ''
|
61
|
+
|
62
|
+
return settings.merge(options)
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_env(options={})
|
66
|
+
env = {}
|
67
|
+
env['rack.url_scheme'] = 'http'
|
68
|
+
env['HTTP_HOST'] = 'wovn.io'
|
69
|
+
env['REQUEST_URI'] = '/dashboard?param=val&hey=you'
|
70
|
+
env['SERVER_NAME'] = 'wovn.io'
|
71
|
+
env['HTTP_COOKIE'] = "olfsk=olfsk021093478426337242; hblid=KB8AAMzxzu2DSxnB4X7BJ26rBGVeF0yJ; optimizelyEndUserId=oeu1426233718869r0.5398541854228824; __zlcmid=UFeZqrVo6Mv3Yl; wovn_selected_lang=en; optimizelySegments=%7B%7D; optimizelyBuckets=%7B%7D; _equalizer_session=eDFwM3M2QUZJZFhoby9JZlArckcvSUJwNFRINXhUeUxtNnltQXZhV0tqdGhZQjJMZ01URnZTK05ydFVWYmM3U0dtMVN0M0Z0UnNDVG8vdUNDTUtPc21jY0FHREgrZ05CUnBTb0hyUlkvYlBWQVhQR3RZdnhjMWsrRW5rOVp1Z3V3bkgyd3NpSlRZQWU1dlZvNmM1THp6aUZVeE83Y1pWWENRNTBUVFIrV05WeTdDMlFlem1tUzdxaEtndFZBd2dtUjU2ak5EUmJPa3RWWmMyT1pSVWdMTm8zOVZhUWhHdGQ3L1c5bm91RmNSdFRrcC90Tml4N2t3ZWlBaDRya2lLT1I0S0J2TURhUWl6Uk5rOTQ4Y1MwM3VKYnlLMUYraEt5clhRdFd1eGdEWXdZd3pFbWQvdE9vQndhdDVQbXNLcHBURm9CbnZKenU2YnNXRFdqRVl0MVV3bmRyYjhvMDExcGtUVU9tK1lqUGswM3p6M05tbVRnTjE3TUl5cEdpTTZ4a2gray8xK0FvTC9wUDVka1JSeE5GM1prZmRjWDdyVzRhWW5uS2Mxc1BxOEVVTTZFS3N5bTlVN2p5eE5YSjNZWGI2UHd3Vzc0bDM5QjIwL0l5Mm85NmQyWFAwdVQ3ZzJYYk1QOHY2NVJpY2c9LS1KNU96eHVycVJxSDJMbEc4Rm9KVXpBPT0%3D--17e47555d692fb9cde20ef78a09a5eabbf805bb3; mp_a0452663eb7abb7dfa9c94007ebb0090_mixpanel=%7B%22distinct_id%22%3A%20%2253ed9ffa4a65662e37000000%22%2C%22%24initial_referrer%22%3A%20%22http%3A%2F%2Fp.dev-wovn.io%3A8080%2Fhttp%3A%2F%2Fdev-wovn.io%3A3000%22%2C%22%24initial_referring_domain%22%3A%20%22p.dev-wovn.io%3A8080%22%2C%22__mps%22%3A%20%7B%7D%2C%22__mpso%22%3A%20%7B%7D%2C%22__mpa%22%3A%20%7B%7D%2C%22__mpu%22%3A%20%7B%7D%2C%22__mpap%22%3A%20%5B%5D%7D"
|
72
|
+
env['HTTP_ACCEPT_LANGUAGE'] = 'ja,en-US;q=0.8,en;q=0.6'
|
73
|
+
env['QUERY_STRING'] = 'param=val&hey=you'
|
74
|
+
env['ORIGINAL_FULLPATH'] = '/dashboard?param=val&hey=you'
|
75
|
+
#env['HTTP_REFERER'] =
|
76
|
+
env['REQUEST_PATH'] = '/dashboard'
|
77
|
+
env['PATH_INFO'] = '/dashboard'
|
78
|
+
|
79
|
+
if options['url']
|
80
|
+
url = URI.parse(options['url'])
|
81
|
+
env['rack.url_scheme'] = url.scheme
|
82
|
+
env['HTTP_HOST'] = url.host
|
83
|
+
if (url.scheme == 'http' && url.port != 80) || (url.scheme == 'https' && url.port != 443)
|
84
|
+
env['HTTP_HOST'] += ":#{url.port}"
|
85
|
+
end
|
86
|
+
env['SERVER_NAME'] = url.host
|
87
|
+
env['REQUEST_URI'] = url.request_uri
|
88
|
+
env['ORIGINAL_FULLPATH'] = url.request_uri
|
89
|
+
env['QUERY_STRING'] = url.query
|
90
|
+
env['REQUEST_PATH'] = url.path
|
91
|
+
env['PATH_INFO'] = url.path
|
92
|
+
end
|
93
|
+
|
94
|
+
return env.merge(options)
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'wovnrb'
|
2
|
+
#require 'test/unit'
|
3
|
+
#require 'test/unit/notify'
|
4
|
+
require 'minitest/autorun'
|
5
|
+
|
6
|
+
class TestLang < Minitest::Test
|
7
|
+
|
8
|
+
def test_langs_exist
|
9
|
+
refute_nil(Wovnrb::Lang::LANG)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_keys_exist
|
13
|
+
Wovnrb::Lang::LANG.each do |k, l|
|
14
|
+
assert(l.has_key?(:name))
|
15
|
+
assert(l.has_key?(:code))
|
16
|
+
assert(l.has_key?(:en))
|
17
|
+
assert_equal(k, l[:code])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_get_code_with_valid_code
|
22
|
+
assert_equal('ms', Wovnrb::Lang.get_code('ms'))
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_get_code_with_valid_english_name
|
26
|
+
assert_equal('pt', Wovnrb::Lang.get_code('Portuguese'))
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_get_code_with_valid_native_name
|
30
|
+
assert_equal('hi', Wovnrb::Lang.get_code('हिन्दी'))
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_get_code_with_invalid_name
|
34
|
+
assert_equal(nil, Wovnrb::Lang.get_code('WOVN4LYFE'))
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_get_code_with_empty_string
|
38
|
+
assert_equal(nil, Wovnrb::Lang.get_code(''))
|
39
|
+
end
|
40
|
+
|
41
|
+
def test_get_code_with_nil
|
42
|
+
assert_equal(nil, Wovnrb::Lang.get_code(nil))
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
data/values/values
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
[{"_id":{"$oid":"54eab2f84a6566d0ed070000"},"body":"Atteindre le monde","created_at":"2015-02-23T04:56:24.097Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Reach The World","translator_id":null,"updated_at":"2015-02-23T04:56:24.097Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[2]/div[2]/h2/text()"},{"_id":{"$oid":"54eab3054a6566d0ee1b0000"},"body":"価格設定","created_at":"2015-02-23T04:56:37.398Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Pricing","translator_id":null,"updated_at":"2015-02-23T04:56:37.398Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[4]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee190000"},"body":"条件","created_at":"2015-02-23T04:56:37.390Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Terms","translator_id":null,"updated_at":"2015-02-23T04:56:37.390Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[2]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee170000"},"body":"サインアップ","created_at":"2015-02-23T04:56:37.385Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:37.385Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee150000"},"body":"今すぐ開始します","created_at":"2015-02-23T04:56:37.379Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Start Now","translator_id":null,"updated_at":"2015-02-23T04:56:37.379Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/h2/text()"},{"_id":{"$oid":"54eab3054a6566d0ee140000"},"body":"サインアップ","created_at":"2015-02-23T04:56:37.377Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:37.377Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[5]/div[2]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee110000"},"body":"サインアップ","created_at":"2015-02-23T04:56:37.367Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:37.367Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[4]/div[2]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed060000"},"body":"Se connecter","created_at":"2015-02-23T04:56:24.095Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign in","translator_id":null,"updated_at":"2015-02-23T04:56:24.095Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/div[2]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee0b0000"},"body":"サインアップ","created_at":"2015-02-23T04:56:37.196Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:37.196Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[2]/div[2]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee090000"},"body":"世界リーチ","created_at":"2015-02-23T04:56:37.190Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Reach The World","translator_id":null,"updated_at":"2015-02-23T04:56:37.190Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[2]/div[2]/h2/text()"},{"_id":{"$oid":"54eab3054a6566d0ee080000"},"body":"ログイン","created_at":"2015-02-23T04:56:37.187Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign in","translator_id":null,"updated_at":"2015-02-23T04:56:37.187Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/div[2]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee070000"},"body":"サインアップ","created_at":"2015-02-23T04:56:37.184Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:37.184Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/a[1]/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed030000"},"body":"Localisez votre site.","created_at":"2015-02-23T04:56:24.071Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Localize your website.","translator_id":null,"updated_at":"2015-02-23T04:56:24.071Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee130000"},"body":"ワンクリックでは、自動的にページを翻訳したり、プロの翻訳を注文。編集するか、それを自分で書く。あなたはすべての単語、文字、および句読点を制御します。公開した後、変更内容は、サイト上で瞬時に表示されます。","created_at":"2015-02-23T04:56:37.374Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"In one click, automatically translate your page or order a professional translation. Edit or write it yourself. You control every word, letter, and punctuation mark. After publishing, your changes are instantly visible on your site.","translator_id":null,"updated_at":"2015-02-23T04:56:37.374Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[5]/div[2]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee100000"},"body":"あなたのウェブサイトやブログに多言語サポートを追加するのは簡単です。 WOVN.ioが提供するコードの1行は、あなたが始めるために必要なすべてのです。公開された翻訳は、サイト上で瞬時に表示されます。","created_at":"2015-02-23T04:56:37.363Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Adding multilingual support to your website or blog is easy. One line of code, provided by WOVN.io, is all you need to get started. Your published translations will be instantly visible on your site.","translator_id":null,"updated_at":"2015-02-23T04:56:37.363Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[4]/div[2]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee0a0000"},"body":"WOVN.ioは世界にあなたのコンテンツをもたらし、あなたのウェブサイトやブログのための多言語サポートを提供します。サイト訪問者はすぐにWOVN.ioウィジェットを使用して言語を切り替えることができます。あなたの翻訳されたコンテンツのすべての編集および管理は、ブラウザの利便性から行うことができます。","created_at":"2015-02-23T04:56:37.194Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"WOVN.io provides multilingual support for your website or blog, bringing your content to the world. Site visitors can quickly toggle between languages using the WOVN.io widget. All editing and management of your translated content can be done from the convenience of your browser.","translator_id":null,"updated_at":"2015-02-23T04:56:37.194Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[2]/div[2]/p/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed110000"},"body":"En un seul clic, de traduire automatiquement votre page ou commander une traduction professionnelle. Modifier ou écrire vous-même. Vous contrôlez chaque mot, lettre et un signe de ponctuation. Après la publication, vos modifications sont immédiatement visibles sur votre site.","created_at":"2015-02-23T04:56:24.228Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"In one click, automatically translate your page or order a professional translation. Edit or write it yourself. You control every word, letter, and punctuation mark. After publishing, your changes are instantly visible on your site.","translator_id":null,"updated_at":"2015-02-23T04:56:24.228Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[5]/div[2]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee1c0000"},"body":"©2014ミニマル·テクノロジーズ","created_at":"2015-02-23T04:56:37.402Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"©2014 Minimal Technologies","translator_id":null,"updated_at":"2015-02-23T04:56:37.402Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[5]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee1a0000"},"body":"フィードバック&お問い合わせ","created_at":"2015-02-23T04:56:37.392Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Feedback \u0026 Contact","translator_id":null,"updated_at":"2015-02-23T04:56:37.392Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[3]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee180000"},"body":"個人情報保護方針","created_at":"2015-02-23T04:56:37.387Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Privacy Policy","translator_id":null,"updated_at":"2015-02-23T04:56:37.387Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[1]/a/text()"},{"_id":{"$oid":"54eab3054a6566d0ee160000"},"body":"世界とあなたのサイトを共有する。瞬時に。","created_at":"2015-02-23T04:56:37.383Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Share your site with the world. Instantly.","translator_id":null,"updated_at":"2015-02-23T04:56:37.383Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee120000"},"body":"コンテンツあなたがコントロールする","created_at":"2015-02-23T04:56:37.370Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Content You Control","translator_id":null,"updated_at":"2015-02-23T04:56:37.370Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[5]/div[2]/h2/text()"},{"_id":{"$oid":"54eab3054a6566d0ee0f0000"},"body":"一列にはじめよう","created_at":"2015-02-23T04:56:37.206Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Get Started In One Line","translator_id":null,"updated_at":"2015-02-23T04:56:37.206Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[4]/div[2]/h2/text()"},{"_id":{"$oid":"54eab3054a6566d0ee0e0000"},"body":"翻訳して公開","created_at":"2015-02-23T04:56:37.204Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Translate and publish","translator_id":null,"updated_at":"2015-02-23T04:56:37.204Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[3]/div[5]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee0d0000"},"body":"翻訳するためにページを追加します。","created_at":"2015-02-23T04:56:37.201Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Add a page to translate","translator_id":null,"updated_at":"2015-02-23T04:56:37.201Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[3]/div[3]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee0c0000"},"body":"WOVN.ioコードスニペットを挿入します","created_at":"2015-02-23T04:56:37.198Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Insert the WOVN.io code snippet","translator_id":null,"updated_at":"2015-02-23T04:56:37.198Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[3]/div[1]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee050000"},"body":"あなたのウェブサイトをローカライズ。","created_at":"2015-02-23T04:56:37.179Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Localize your website.","translator_id":null,"updated_at":"2015-02-23T04:56:37.179Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee040000"},"body":"コードの1行で世界を歓迎します。","created_at":"2015-02-23T04:56:37.177Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Welcome the world in one line of code.","translator_id":null,"updated_at":"2015-02-23T04:56:37.177Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/h2/text()"},{"_id":{"$oid":"54eab3054a6566d0ee030000"},"body":"Wovn.io |あなたのウェブサイトをローカライズ。","created_at":"2015-02-23T04:56:37.173Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Wovn.io | Localize your website.","translator_id":null,"updated_at":"2015-02-23T04:56:37.173Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/head/title/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed1a0000"},"body":"© 2014 Technologies minimales","created_at":"2015-02-23T04:56:24.255Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"©2014 Minimal Technologies","translator_id":null,"updated_at":"2015-02-23T04:56:24.255Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[5]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed0e0000"},"body":"Ajout d'un support multilingue à votre site ou blog est facile. Une ligne de code, fourni par WOVN.io, est tout ce que vous avez besoin pour commencer. Vos traductions publiées seront instantanément visibles sur votre site.","created_at":"2015-02-23T04:56:24.122Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Adding multilingual support to your website or blog is easy. One line of code, provided by WOVN.io, is all you need to get started. Your published translations will be instantly visible on your site.","translator_id":null,"updated_at":"2015-02-23T04:56:24.122Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[4]/div[2]/p/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed180000"},"body":"Feedback \u0026 Contact","created_at":"2015-02-23T04:56:24.249Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Feedback \u0026 Contact","translator_id":null,"updated_at":"2015-02-23T04:56:24.249Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[3]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed160000"},"body":"Politique de confidentialité","created_at":"2015-02-23T04:56:24.245Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Privacy Policy","translator_id":null,"updated_at":"2015-02-23T04:56:24.245Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[1]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed140000"},"body":"Partager votre site avec le monde. Instantanément.","created_at":"2015-02-23T04:56:24.239Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Share your site with the world. Instantly.","translator_id":null,"updated_at":"2015-02-23T04:56:24.239Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/p/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed100000"},"body":"Contenu You Control","created_at":"2015-02-23T04:56:24.134Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Content You Control","translator_id":null,"updated_at":"2015-02-23T04:56:24.134Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[5]/div[2]/h2/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed0d0000"},"body":"Commencez sur une seule ligne","created_at":"2015-02-23T04:56:24.119Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Get Started In One Line","translator_id":null,"updated_at":"2015-02-23T04:56:24.119Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[4]/div[2]/h2/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed0c0000"},"body":"Traduire et publier","created_at":"2015-02-23T04:56:24.114Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Translate and publish","translator_id":null,"updated_at":"2015-02-23T04:56:24.114Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[3]/div[5]/p/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed020000"},"body":"Bienvenue dans le monde sur une seule ligne de code.","created_at":"2015-02-23T04:56:24.065Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Welcome the world in one line of code.","translator_id":null,"updated_at":"2015-02-23T04:56:24.065Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/h2/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed080000"},"body":"WOVN.io fournit un support multilingue pour votre site ou blog, ce qui porte votre contenu au monde. Les visiteurs du site peuvent rapidement basculer entre les langues utilisant le widget WOVN.io. Tous édition et la gestion de votre contenu traduit peut être fait dans le confort de votre navigateur.","created_at":"2015-02-23T04:56:24.099Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"WOVN.io provides multilingual support for your website or blog, bringing your content to the world. Site visitors can quickly toggle between languages using the WOVN.io widget. All editing and management of your translated content can be done from the convenience of your browser.","translator_id":null,"updated_at":"2015-02-23T04:56:24.099Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[2]/div[2]/p/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed050000"},"body":"Signer","created_at":"2015-02-23T04:56:24.093Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:24.093Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/a[1]/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed040000"},"body":"Gratuit","created_at":"2015-02-23T04:56:24.089Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Free","translator_id":null,"updated_at":"2015-02-23T04:56:24.089Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/div[1]/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed0b0000"},"body":"Ajouter une page à traduire","created_at":"2015-02-23T04:56:24.110Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Add a page to translate","translator_id":null,"updated_at":"2015-02-23T04:56:24.110Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[3]/div[3]/p/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed0a0000"},"body":"Insérez l'extrait de code WOVN.io","created_at":"2015-02-23T04:56:24.106Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Insert the WOVN.io code snippet","translator_id":null,"updated_at":"2015-02-23T04:56:24.106Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[3]/div[1]/p/text()"},{"_id":{"$oid":"54eab3054a6566d0ee060000"},"body":"フリー","created_at":"2015-02-23T04:56:37.182Z","ec":null,"ei":null,"en":null,"et":null,"language":"ja","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Free","translator_id":null,"updated_at":"2015-02-23T04:56:37.182Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[1]/div[1]/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed190000"},"body":"Établissement des prix","created_at":"2015-02-23T04:56:24.251Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Pricing","translator_id":null,"updated_at":"2015-02-23T04:56:24.251Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[4]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed170000"},"body":"Termes","created_at":"2015-02-23T04:56:24.247Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Terms","translator_id":null,"updated_at":"2015-02-23T04:56:24.247Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/div/ul/li[2]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed150000"},"body":"Signer","created_at":"2015-02-23T04:56:24.242Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:24.242Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed130000"},"body":"Démarrer maintenant","created_at":"2015-02-23T04:56:24.236Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Start Now","translator_id":null,"updated_at":"2015-02-23T04:56:24.236Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[6]/h2/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed120000"},"body":"Signer","created_at":"2015-02-23T04:56:24.233Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:24.233Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[5]/div[2]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed0f0000"},"body":"Signer","created_at":"2015-02-23T04:56:24.129Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:24.129Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[4]/div[2]/a/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed010000"},"body":"Wovn.io | Localisez votre site.","created_at":"2015-02-23T04:56:24.047Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Wovn.io | Localize your website.","translator_id":null,"updated_at":"2015-02-23T04:56:24.047Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/head/title/text()"},{"_id":{"$oid":"54eab2f84a6566d0ed090000"},"body":"Signer","created_at":"2015-02-23T04:56:24.102Z","ec":null,"ei":null,"en":null,"et":null,"language":"fr","page_id":{"$oid":"54cb63a64a65667be0000000"},"publish":true,"src_body":"Sign up","translator_id":null,"updated_at":"2015-02-23T04:56:24.102Z","user_id":{"$oid":"53ed9ffa4a65662e37000000"},"xpath":"/html/body/div[2]/div[2]/a/text()"}]
|
data/wovnrb.gemspec
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'wovnrb/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "wovnrb"
|
8
|
+
spec.version = Wovnrb::VERSION
|
9
|
+
spec.authors = ["Jeff Sandford", "Antoine David"]
|
10
|
+
spec.email = ["jeff@wovn.io"]
|
11
|
+
spec.summary = %q{Gem for WOVN.io}
|
12
|
+
spec.description = %q{ALPHA VERSION, not in a useable form.}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
|
17
|
+
files = `git ls-files -z`.split("\x0")
|
18
|
+
files.delete('BEFORE_PUSHING')
|
19
|
+
spec.files = files
|
20
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
21
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
22
|
+
spec.require_paths = ["lib"]
|
23
|
+
#spec.require_paths = ["lib", "ext"]
|
24
|
+
#spec.extensions = spec.files.grep(%r{/extconf\.rb$})
|
25
|
+
#spec.extensions = %w[ext/dom/extconf.rb]
|
26
|
+
#spec.extensions = spec.files.grep(%r{/extconf\.rb$})
|
27
|
+
|
28
|
+
spec.add_dependency "nokogumbo"
|
29
|
+
spec.add_dependency "redis"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
32
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
33
|
+
#spec.add_development_dependency "rspec"
|
34
|
+
#spec.add_development_dependency "rspec-nc"
|
35
|
+
spec.add_development_dependency "test-unit"
|
36
|
+
spec.add_development_dependency "test-unit-notify"
|
37
|
+
spec.add_development_dependency "minitest"
|
38
|
+
spec.add_development_dependency "terminal-notifier"
|
39
|
+
spec.add_development_dependency "guard"
|
40
|
+
spec.add_development_dependency "guard-rspec"
|
41
|
+
spec.add_development_dependency "pry"
|
42
|
+
spec.add_development_dependency "pry-remote"
|
43
|
+
spec.add_development_dependency "pry-nav"
|
44
|
+
#spec.add_development_dependency "rice"
|
45
|
+
spec.add_development_dependency "rake-compiler"
|
46
|
+
spec.add_development_dependency "geminabox"
|
47
|
+
|
48
|
+
end
|
49
|
+
|
metadata
ADDED
@@ -0,0 +1,277 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: wovnrb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jeff Sandford
|
8
|
+
- Antoine David
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-05-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: nokogumbo
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - '>='
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - '>='
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: redis
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - '>='
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :runtime
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: bundler
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ~>
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '1.7'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ~>
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '1.7'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rake
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ~>
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '10.0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '10.0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: test-unit
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - '>='
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: test-unit-notify
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - '>='
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - '>='
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: '0'
|
98
|
+
- !ruby/object:Gem::Dependency
|
99
|
+
name: minitest
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
type: :development
|
106
|
+
prerelease: false
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: terminal-notifier
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - '>='
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - '>='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: guard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - '>='
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - '>='
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: guard-rspec
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - '>='
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - '>='
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
154
|
+
- !ruby/object:Gem::Dependency
|
155
|
+
name: pry
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
157
|
+
requirements:
|
158
|
+
- - '>='
|
159
|
+
- !ruby/object:Gem::Version
|
160
|
+
version: '0'
|
161
|
+
type: :development
|
162
|
+
prerelease: false
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
164
|
+
requirements:
|
165
|
+
- - '>='
|
166
|
+
- !ruby/object:Gem::Version
|
167
|
+
version: '0'
|
168
|
+
- !ruby/object:Gem::Dependency
|
169
|
+
name: pry-remote
|
170
|
+
requirement: !ruby/object:Gem::Requirement
|
171
|
+
requirements:
|
172
|
+
- - '>='
|
173
|
+
- !ruby/object:Gem::Version
|
174
|
+
version: '0'
|
175
|
+
type: :development
|
176
|
+
prerelease: false
|
177
|
+
version_requirements: !ruby/object:Gem::Requirement
|
178
|
+
requirements:
|
179
|
+
- - '>='
|
180
|
+
- !ruby/object:Gem::Version
|
181
|
+
version: '0'
|
182
|
+
- !ruby/object:Gem::Dependency
|
183
|
+
name: pry-nav
|
184
|
+
requirement: !ruby/object:Gem::Requirement
|
185
|
+
requirements:
|
186
|
+
- - '>='
|
187
|
+
- !ruby/object:Gem::Version
|
188
|
+
version: '0'
|
189
|
+
type: :development
|
190
|
+
prerelease: false
|
191
|
+
version_requirements: !ruby/object:Gem::Requirement
|
192
|
+
requirements:
|
193
|
+
- - '>='
|
194
|
+
- !ruby/object:Gem::Version
|
195
|
+
version: '0'
|
196
|
+
- !ruby/object:Gem::Dependency
|
197
|
+
name: rake-compiler
|
198
|
+
requirement: !ruby/object:Gem::Requirement
|
199
|
+
requirements:
|
200
|
+
- - '>='
|
201
|
+
- !ruby/object:Gem::Version
|
202
|
+
version: '0'
|
203
|
+
type: :development
|
204
|
+
prerelease: false
|
205
|
+
version_requirements: !ruby/object:Gem::Requirement
|
206
|
+
requirements:
|
207
|
+
- - '>='
|
208
|
+
- !ruby/object:Gem::Version
|
209
|
+
version: '0'
|
210
|
+
- !ruby/object:Gem::Dependency
|
211
|
+
name: geminabox
|
212
|
+
requirement: !ruby/object:Gem::Requirement
|
213
|
+
requirements:
|
214
|
+
- - '>='
|
215
|
+
- !ruby/object:Gem::Version
|
216
|
+
version: '0'
|
217
|
+
type: :development
|
218
|
+
prerelease: false
|
219
|
+
version_requirements: !ruby/object:Gem::Requirement
|
220
|
+
requirements:
|
221
|
+
- - '>='
|
222
|
+
- !ruby/object:Gem::Version
|
223
|
+
version: '0'
|
224
|
+
description: ALPHA VERSION, not in a useable form.
|
225
|
+
email:
|
226
|
+
- jeff@wovn.io
|
227
|
+
executables: []
|
228
|
+
extensions: []
|
229
|
+
extra_rdoc_files: []
|
230
|
+
files:
|
231
|
+
- .gitignore
|
232
|
+
- .ruby-version
|
233
|
+
- Gemfile
|
234
|
+
- LICENSE.txt
|
235
|
+
- README.md
|
236
|
+
- Rakefile
|
237
|
+
- lib/wovnrb.rb
|
238
|
+
- lib/wovnrb/headers.rb
|
239
|
+
- lib/wovnrb/lang.rb
|
240
|
+
- lib/wovnrb/railtie.rb
|
241
|
+
- lib/wovnrb/store.rb
|
242
|
+
- lib/wovnrb/version.rb
|
243
|
+
- spec/spec_helper.rb
|
244
|
+
- spec/wovnrb_spec.rb
|
245
|
+
- test/lib/test_headers.rb
|
246
|
+
- test/lib/test_lang.rb
|
247
|
+
- values/values
|
248
|
+
- wovnrb.gemspec
|
249
|
+
homepage: ''
|
250
|
+
licenses:
|
251
|
+
- MIT
|
252
|
+
metadata: {}
|
253
|
+
post_install_message:
|
254
|
+
rdoc_options: []
|
255
|
+
require_paths:
|
256
|
+
- lib
|
257
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
258
|
+
requirements:
|
259
|
+
- - '>='
|
260
|
+
- !ruby/object:Gem::Version
|
261
|
+
version: '0'
|
262
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
263
|
+
requirements:
|
264
|
+
- - '>='
|
265
|
+
- !ruby/object:Gem::Version
|
266
|
+
version: '0'
|
267
|
+
requirements: []
|
268
|
+
rubyforge_project:
|
269
|
+
rubygems_version: 2.0.14
|
270
|
+
signing_key:
|
271
|
+
specification_version: 4
|
272
|
+
summary: Gem for WOVN.io
|
273
|
+
test_files:
|
274
|
+
- spec/spec_helper.rb
|
275
|
+
- spec/wovnrb_spec.rb
|
276
|
+
- test/lib/test_headers.rb
|
277
|
+
- test/lib/test_lang.rb
|