tranzu-rack-tranzu 0.0.1
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.
- data/README +0 -0
- data/lib/rack/tranzu.rb +107 -0
- data/spec/tranzu_spec.rb +99 -0
- metadata +65 -0
data/README
ADDED
|
File without changes
|
data/lib/rack/tranzu.rb
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
require 'nokogiri'
|
|
2
|
+
require 'lib/text_block'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
module Rack
|
|
6
|
+
class Tranzu
|
|
7
|
+
|
|
8
|
+
def initialize(app, site_key)
|
|
9
|
+
@app, @site_key = app, site_key
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def call(env)
|
|
13
|
+
status, headers, response = @app.call(env)
|
|
14
|
+
|
|
15
|
+
if headers["Content-Type"].include? "text/html"
|
|
16
|
+
translate_page(status, headers, response)
|
|
17
|
+
else
|
|
18
|
+
[status, headers, response]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def translate_page(status, headers, response)
|
|
25
|
+
doc = parse_web_page(response)
|
|
26
|
+
|
|
27
|
+
doc.traverse do |dom_element|
|
|
28
|
+
if dom_element.text? && !dom_element.inner_text.blank?
|
|
29
|
+
record_text_block_if_new(dom_element.inner_text.strip)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
doc.traverse do |dom_element|
|
|
34
|
+
if dom_element.text? && !dom_element.inner_text.blank?
|
|
35
|
+
replace_text_with_applicable_translations(dom_element)
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
html = serialized_html(doc)
|
|
40
|
+
|
|
41
|
+
[status, headers, [html]]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def serialized_html(doc)
|
|
45
|
+
html = doc.search("html").to_html
|
|
46
|
+
html.gsub(/\>\n\</,"><")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def replace_text_with_applicable_translations(text_element)
|
|
51
|
+
new_text = text_element.inner_text
|
|
52
|
+
all_stored_text_blocks.each do |key, value|
|
|
53
|
+
new_text.gsub!(/#{key}/, value) if value # TODO: escape key for Regexp
|
|
54
|
+
end
|
|
55
|
+
text_element.parent.content = new_text
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def parse_web_page(response)
|
|
59
|
+
all_content = ""
|
|
60
|
+
response.each do |content|
|
|
61
|
+
all_content << content
|
|
62
|
+
end
|
|
63
|
+
doc = Nokogiri::HTML(all_content)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def all_stored_text_blocks
|
|
67
|
+
unless @mapping
|
|
68
|
+
@mapping = {}
|
|
69
|
+
text_blocks = TextBlock.find(:all, :params => {:site_key => @site_key})
|
|
70
|
+
|
|
71
|
+
text_blocks.each do |text_block|
|
|
72
|
+
@mapping[text_block.source_text] = text_block.target_text
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
@mapping
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def text_blocks_with_translations
|
|
79
|
+
all_stored_text_blocks.delete_if{|key, value| value.nil?}
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def untranslated_text_blocks
|
|
83
|
+
all_stored_text_blocks.select{|key, value| value.nil?}.map{|pair| pair.first}
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def record_text_block_if_new(source_text)
|
|
87
|
+
text_block = TextBlock.find(:one, :params => {:site_key => @site_key, :source_text => source_text})
|
|
88
|
+
unless text_block
|
|
89
|
+
text_block = TextBlock.create(:site_key => @site_key, :source_text => source_text)
|
|
90
|
+
unless text_block
|
|
91
|
+
raise Exception.new("unable to create text block")
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def record_text_block_with_translation(source_text, target_text)
|
|
97
|
+
text_block = TextBlock.find(:one, :params => {:site_key => @site_key, :source_text => source_text})
|
|
98
|
+
text_block ||= TextBlock.new(:site_key => @site_key, :source_text => source_text)
|
|
99
|
+
text_block.target_text = target_text
|
|
100
|
+
unless text_block.save
|
|
101
|
+
raise Exception.new("unable to save text block")
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|
data/spec/tranzu_spec.rb
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
require 'rack'
|
|
2
|
+
require 'lib/text_block'
|
|
3
|
+
require 'lib/rack/tranzu'
|
|
4
|
+
|
|
5
|
+
describe Rack::Tranzu do
|
|
6
|
+
def delete_all_text_blocks
|
|
7
|
+
text_blocks = TextBlock.find(:all)
|
|
8
|
+
text_blocks.each do |text_block|
|
|
9
|
+
text_block.destroy
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
before (:each) do
|
|
14
|
+
delete_all_text_blocks
|
|
15
|
+
@response_strings = []
|
|
16
|
+
@client_app = lambda {|env| [200, {'Content-Type' => 'text/html'}, @response_strings] }
|
|
17
|
+
@app = Rack::Tranzu.new(@client_app, "1234ABCD")
|
|
18
|
+
@app.send(:record_text_block_with_translation, "This is an example of already translated text.", "Se ejemplifica texto ya traducido.")
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
it "should store all text blocks returned by the web site" do
|
|
22
|
+
delete_all_text_blocks # re-delete items for this test case only
|
|
23
|
+
@response_strings << "<html><body><p>This is an example of already translated text.</p><p>This is an example of untranslated text.</p><p>This is another example of untranslated text.</p></body></html>"
|
|
24
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
source_text_items = TextBlock.find(:all).map {|text_block_translations| text_block_translations.source_text}
|
|
28
|
+
source_text_items.sort.should == ["This is an example of already translated text.", "This is an example of untranslated text.", "This is another example of untranslated text."].sort
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should identify stored text blocks with no corresponding translations" do
|
|
32
|
+
@response_strings << "<html><body><p>This is an example of already translated text.</p><p>This is an example of untranslated text.</p><p>This is another example of untranslated text.</p></body></html>"
|
|
33
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
34
|
+
untranslated_text_blocks = @app.send(:untranslated_text_blocks)
|
|
35
|
+
untranslated_text_blocks.sort.should == ["This is an example of untranslated text.", "This is another example of untranslated text."].sort
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should identify stored text blocks with corresponding translations" do
|
|
39
|
+
@response_strings << "<html><body><p>This is an example of already translated text.</p><p>This is an example of untranslated text.</p><p>This is another example of untranslated text.</p></body></html>"
|
|
40
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
41
|
+
text_blocks_with_translations = @app.send(:text_blocks_with_translations)
|
|
42
|
+
text_blocks_with_translations.should == {"This is an example of already translated text." => "Se ejemplifica texto ya traducido."}
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should pass-through stored text blocks that lack translated equivalents" do
|
|
46
|
+
@response_strings << "<html><body><p>This is an example of untranslated text.</p></body></html>"
|
|
47
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
48
|
+
response.body.should == @response_strings[0]
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should replace stored text blocks with translated equivalents" do
|
|
52
|
+
@response_strings << "<html><body><p>This is an example of already translated text.</p></body></html>"
|
|
53
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
54
|
+
response.body.should == "<html><body><p>Se ejemplifica texto ya traducido.</p></body></html>"
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
it "should replace text blocks with translated equivalents and leave those that lack translated equivalents untranslated" do
|
|
58
|
+
@response_strings << "<html><body><p>This is an example of already translated text.</p><p>This is an example of untranslated text.</p></body></html>"
|
|
59
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
60
|
+
response.body.should == "<html><body><p>Se ejemplifica texto ya traducido.</p><p>This is an example of untranslated text.</p></body></html>"
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should not translate any text blocks if the site id is not valid" do
|
|
64
|
+
@app = Rack::Tranzu.new(@client_app, "X1234ABCD")
|
|
65
|
+
source_text = "<html><body><p>This is an example of already translated text.</p><p>This is an example of untranslated text.</p></body></html>"
|
|
66
|
+
@response_strings << source_text
|
|
67
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
68
|
+
response.body.should == source_text
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
describe "translating is partial to html" do
|
|
72
|
+
it "should attempt to translate html requests" do
|
|
73
|
+
@response_strings << "<html><body><p>This is an example of already translated text.</p></body></html>"
|
|
74
|
+
@app.should_receive(:translate_page).and_return([200, {'Content-Type' => 'text/html'}, @response_strings])
|
|
75
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/html')
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should not attempt to translate non-html requests" do
|
|
79
|
+
@response_strings << "<adam>adam is studly</adam>"
|
|
80
|
+
@client_app = lambda {|env| [201, {'Content-Type' => 'text/xml', 'Content-Encoding' => 'gzip'}, @response_strings] }
|
|
81
|
+
@app = Rack::Tranzu.new(@client_app, "1234ABCD")
|
|
82
|
+
@app.should_not_receive(:translate_page)
|
|
83
|
+
response = Rack::MockRequest.new(@app).get('/', 'HTTP_ACCEPT' => 'text/xml')
|
|
84
|
+
response.body.should == @response_strings[0]
|
|
85
|
+
response.status.should == 201
|
|
86
|
+
response.headers.should == {'Content-Type' => 'text/xml', 'Content-Encoding' => 'gzip'}
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should not strip out linefeeds from html"
|
|
91
|
+
|
|
92
|
+
it "should not strip out leading or trailing whitespace from text nodes"
|
|
93
|
+
|
|
94
|
+
it "should not change DOCTYPE if it exists in the application response'"
|
|
95
|
+
|
|
96
|
+
it "should not add DOCTYPE if it is not in the application response"
|
|
97
|
+
|
|
98
|
+
end
|
|
99
|
+
|
metadata
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: tranzu-rack-tranzu
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- John Reitano
|
|
8
|
+
- Adam King
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2009-09-01 00:00:00 -07:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: rack
|
|
18
|
+
type: :runtime
|
|
19
|
+
version_requirement:
|
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ~>
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: "0.4"
|
|
25
|
+
version:
|
|
26
|
+
description: Website translation middleware.
|
|
27
|
+
email: tranzuapp@gmail.com
|
|
28
|
+
executables: []
|
|
29
|
+
|
|
30
|
+
extensions: []
|
|
31
|
+
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
|
|
34
|
+
files:
|
|
35
|
+
- README
|
|
36
|
+
- lib/rack/tranzu.rb
|
|
37
|
+
has_rdoc: false
|
|
38
|
+
homepage: http://github.com/tranzu/rack-tranzu
|
|
39
|
+
licenses:
|
|
40
|
+
post_install_message:
|
|
41
|
+
rdoc_options: []
|
|
42
|
+
|
|
43
|
+
require_paths:
|
|
44
|
+
- lib
|
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
46
|
+
requirements:
|
|
47
|
+
- - ">="
|
|
48
|
+
- !ruby/object:Gem::Version
|
|
49
|
+
version: "0"
|
|
50
|
+
version:
|
|
51
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: "0"
|
|
56
|
+
version:
|
|
57
|
+
requirements: []
|
|
58
|
+
|
|
59
|
+
rubyforge_project:
|
|
60
|
+
rubygems_version: 1.3.5
|
|
61
|
+
signing_key:
|
|
62
|
+
specification_version: 2
|
|
63
|
+
summary: Website translation middleware.
|
|
64
|
+
test_files:
|
|
65
|
+
- spec/tranzu_spec.rb
|