translation_engine 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.
Files changed (103) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +37 -0
  4. data/app/assets/javascripts/translation_engine/screenshots.js.coffee +225 -0
  5. data/app/assets/stylesheets/translation_engine/screenshots.css +23 -0
  6. data/app/middlewares/translation_engine/catcher_middleware.rb +64 -0
  7. data/app/middlewares/translation_engine/connection_exception_middleware.rb +18 -0
  8. data/app/middlewares/translation_engine/keys_middleware.rb +31 -0
  9. data/app/middlewares/translation_engine/screenshots_middleware.rb +31 -0
  10. data/app/models/translation_engine/backend.rb +79 -0
  11. data/app/models/translation_engine/connection.rb +75 -0
  12. data/app/models/translation_engine/connection_error.rb +2 -0
  13. data/app/models/translation_engine/downloader.rb +72 -0
  14. data/app/models/translation_engine/error.rb +2 -0
  15. data/app/models/translation_engine/release.rb +26 -0
  16. data/app/models/translation_engine/translation.rb +67 -0
  17. data/config/initializers/translation_engine.rb +8 -0
  18. data/lib/tasks/translation_engine_tasks.rake +83 -0
  19. data/lib/translation_engine.rb +10 -0
  20. data/lib/translation_engine/engine.rb +32 -0
  21. data/lib/translation_engine/version.rb +3 -0
  22. data/test/dummy/README.rdoc +28 -0
  23. data/test/dummy/Rakefile +6 -0
  24. data/test/dummy/app/assets/javascripts/application.js +15 -0
  25. data/test/dummy/app/assets/javascripts/root.js +2 -0
  26. data/test/dummy/app/assets/stylesheets/application.css +16 -0
  27. data/test/dummy/app/assets/stylesheets/root.css +4 -0
  28. data/test/dummy/app/controllers/application_controller.rb +5 -0
  29. data/test/dummy/app/controllers/root_controller.rb +4 -0
  30. data/test/dummy/app/helpers/application_helper.rb +2 -0
  31. data/test/dummy/app/helpers/root_helper.rb +2 -0
  32. data/test/dummy/app/views/layouts/application.html.erb +14 -0
  33. data/test/dummy/app/views/root/index.html.erb +8 -0
  34. data/test/dummy/bin/bundle +3 -0
  35. data/test/dummy/bin/rails +4 -0
  36. data/test/dummy/bin/rake +4 -0
  37. data/test/dummy/bin/setup +29 -0
  38. data/test/dummy/config.ru +4 -0
  39. data/test/dummy/config/application.rb +26 -0
  40. data/test/dummy/config/boot.rb +5 -0
  41. data/test/dummy/config/database.yml +25 -0
  42. data/test/dummy/config/environment.rb +5 -0
  43. data/test/dummy/config/environments/development.rb +41 -0
  44. data/test/dummy/config/environments/production.rb +79 -0
  45. data/test/dummy/config/environments/test.rb +42 -0
  46. data/test/dummy/config/initializers/assets.rb +11 -0
  47. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  48. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  49. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  50. data/test/dummy/config/initializers/inflections.rb +16 -0
  51. data/test/dummy/config/initializers/mime_types.rb +4 -0
  52. data/test/dummy/config/initializers/session_store.rb +3 -0
  53. data/test/dummy/config/initializers/translation_engine.rb +7 -0
  54. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  55. data/test/dummy/config/locales/en.yml +23 -0
  56. data/test/dummy/config/routes.rb +58 -0
  57. data/test/dummy/config/secrets.yml +22 -0
  58. data/test/dummy/db/development.sqlite3 +0 -0
  59. data/test/dummy/db/test.sqlite3 +0 -0
  60. data/test/dummy/log/development.log +20917 -0
  61. data/test/dummy/log/test.log +13 -0
  62. data/test/dummy/public/404.html +67 -0
  63. data/test/dummy/public/422.html +67 -0
  64. data/test/dummy/public/500.html +66 -0
  65. data/test/dummy/public/favicon.ico +0 -0
  66. data/test/dummy/test/controllers/root_controller_test.rb +9 -0
  67. data/test/dummy/tmp/cache/assets/development/sprockets/00744134f1b8c820c724a9d6207f3a7a +0 -0
  68. data/test/dummy/tmp/cache/assets/development/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  69. data/test/dummy/tmp/cache/assets/development/sprockets/25e260f6a1dc0c4484c200da624af92e +0 -0
  70. data/test/dummy/tmp/cache/assets/development/sprockets/2c59dca85b9e8c86af73e35e031fbbdc +0 -0
  71. data/test/dummy/tmp/cache/assets/development/sprockets/2f5173deea6c795b8fdde723bb4b63af +0 -0
  72. data/test/dummy/tmp/cache/assets/development/sprockets/3065ce12758c77c2a4921568b7e742a0 +0 -0
  73. data/test/dummy/tmp/cache/assets/development/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  74. data/test/dummy/tmp/cache/assets/development/sprockets/379aa3c595d4aa45885d1db5fbcb6e3a +0 -0
  75. data/test/dummy/tmp/cache/assets/development/sprockets/3824972f4a7973916302b2649b498d5c +0 -0
  76. data/test/dummy/tmp/cache/assets/development/sprockets/3c856723c34a3a47f181661bc3499592 +0 -0
  77. data/test/dummy/tmp/cache/assets/development/sprockets/41448ad2a85326b721f1e060b86dc3dc +0 -0
  78. data/test/dummy/tmp/cache/assets/development/sprockets/4387b22d35f85d5eb8336a8ed1381c5c +0 -0
  79. data/test/dummy/tmp/cache/assets/development/sprockets/48388ecb825f9d2b3ac4af78175993b2 +0 -0
  80. data/test/dummy/tmp/cache/assets/development/sprockets/55588f5ab129d88af0eef8e14f0f57aa +0 -0
  81. data/test/dummy/tmp/cache/assets/development/sprockets/6c9de7f2c8ef919141331199520c6890 +0 -0
  82. data/test/dummy/tmp/cache/assets/development/sprockets/6ef9396e711eaa215cf2fee6f0102551 +0 -0
  83. data/test/dummy/tmp/cache/assets/development/sprockets/7c8b616251089af5cf0b4bddc02c2cf1 +0 -0
  84. data/test/dummy/tmp/cache/assets/development/sprockets/83e8ae6039d56661189e1fb4812c89f0 +0 -0
  85. data/test/dummy/tmp/cache/assets/development/sprockets/91ae3870a5845130aa888fbe093d1554 +0 -0
  86. data/test/dummy/tmp/cache/assets/development/sprockets/9b474687caa91b30ec2214bdd9f54f33 +0 -0
  87. data/test/dummy/tmp/cache/assets/development/sprockets/b6c894a4da0fd8d4cd152a353d826045 +0 -0
  88. data/test/dummy/tmp/cache/assets/development/sprockets/c17e2e13afcf1d3570e8a857ccede2c1 +0 -0
  89. data/test/dummy/tmp/cache/assets/development/sprockets/cffd775d018f68ce5dba1ee0d951a994 +0 -0
  90. data/test/dummy/tmp/cache/assets/development/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  91. data/test/dummy/tmp/cache/assets/development/sprockets/efb95a602af8237a4970b7c683dae187 +0 -0
  92. data/test/dummy/tmp/cache/assets/development/sprockets/f603eeacf1822560ceb9ac4102ff8430 +0 -0
  93. data/test/dummy/tmp/cache/assets/development/sprockets/f7cbd26ba1d28d48de824f0e94586655 +0 -0
  94. data/test/dummy/tmp/cache/assets/test/sprockets/13fe41fee1fe35b49d145bcc06610705 +0 -0
  95. data/test/dummy/tmp/cache/assets/test/sprockets/357970feca3ac29060c1e3861e2c0953 +0 -0
  96. data/test/dummy/tmp/cache/assets/test/sprockets/48388ecb825f9d2b3ac4af78175993b2 +0 -0
  97. data/test/dummy/tmp/cache/assets/test/sprockets/7c8b616251089af5cf0b4bddc02c2cf1 +0 -0
  98. data/test/dummy/tmp/cache/assets/test/sprockets/83e8ae6039d56661189e1fb4812c89f0 +0 -0
  99. data/test/dummy/tmp/cache/assets/test/sprockets/d771ace226fc8215a3572e0aa35bb0d6 +0 -0
  100. data/test/dummy/tmp/cache/assets/test/sprockets/efb95a602af8237a4970b7c683dae187 +0 -0
  101. data/test/test_helper.rb +18 -0
  102. data/test/translation_engine_test.rb +7 -0
  103. metadata +310 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 205d428df157042d2c719d3fc16675987bf5af75
4
+ data.tar.gz: 4ed393be15ecd6795e97f49e8157b7e22f105306
5
+ SHA512:
6
+ metadata.gz: 5f71b85e162c5826caebe3a66a005ded7b60d072c545f5dcbe4363a1257be7ecea1d01ce7282e1599bd15ce488c8a9a75deb9172262447707b66438bccf39221
7
+ data.tar.gz: 8f44020c85bcf9bce0d212beeb3682ea4d3f5c9d5f5651086ef4e4191eac3c7872eca778a287d233d4b3b97e8199cab55c86d6c0a4f1a5ba769c3e3a3ec63091
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2015 Ondrej Bartas
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'TranslationEngine'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,225 @@
1
+ #= require html2canvas
2
+
3
+ class TranslationEngine
4
+
5
+ baseUrl: '/translation_engine/keys'
6
+ submitButton: ''
7
+ highlightButton: ''
8
+ translationsQueue: []
9
+ screenshots: []
10
+ screenshotsCaptured: {}
11
+ translationIndex: 0
12
+ keysVisible: false
13
+ keysInfoGenerated: false
14
+ highlights: []
15
+ variant: 'desktop'
16
+
17
+ constructor: (startButton, highlightButton) ->
18
+ @startButton = $(startButton)
19
+ @highlightButton = $(highlightButton)
20
+ @lookupDom()
21
+ @bindStartButton()
22
+ @bindHighlightButton()
23
+ @variant = 'mobile' if $('body').hasClass('mobile')
24
+
25
+ start: ->
26
+ setTimeout @nextTranslationScreeshot, 100
27
+
28
+ highlight: ->
29
+ baseUrl = @baseUrl
30
+ keysVisible = @keysVisible
31
+ @translationsQueue.map((translation) ->
32
+ # generate url
33
+ if !keysVisible
34
+ [ country, rest... ] = translation.key.split('.')
35
+ url = "#{baseUrl}/#{country}/translates/browse/all/#{rest.join('/')}"
36
+ translation['url'] = url
37
+ translation.backup = translation.element.html()
38
+ translation.element.html("<a href='#{url}' style='color: #444; background: #ddd'>#{translation.key}</a>")
39
+ else
40
+ translation.element.html(translation.backup)
41
+ )
42
+
43
+
44
+ @keysVisible = !@keysVisible
45
+
46
+ appendScreenshotsOverlay: ->
47
+ if $('body').find('.screenshots-overlay').length == 0
48
+ $('body').append('<div class="screenshots-overlay" data-html2canvas-ignore="true"></div>')
49
+ $('body').append('<div class="screenshots-status" data-html2canvas-ignore="true"></div>')
50
+
51
+ dismissScreenshotsOverlay: ->
52
+ setTimeout ->
53
+ $('body').find('.screenshots-overlay').detach()
54
+ $('body').find('.screenshots-status').detach()
55
+ , 1000
56
+
57
+ bindStartButton: ->
58
+ @startButton.click =>
59
+ if @translationsQueue.length > @translationIndex
60
+ setTimeout @nextTranslationScreeshot, 100
61
+ else
62
+ @appendScreenshotsOverlay()
63
+ @setStatusText('Screenshots already send')
64
+ @dismissScreenshotsOverlay()
65
+
66
+ bindHighlightButton: ->
67
+ @highlightButton.click =>
68
+ @highlight()
69
+
70
+ nextTranslationScreeshot: =>
71
+ if @translationsQueue.length > @translationIndex
72
+ @renderHighlight()
73
+ else
74
+ @sendTranslations()
75
+
76
+ lookupDom: ->
77
+ @lookupTextDom()
78
+ @lookupAttributesDom()
79
+ @lookupMissingTranslationDom()
80
+
81
+ lookupTextDom: ->
82
+ while $(':contains("--TRANSLATION--")').length > 0
83
+ $(':contains("--TRANSLATION--")').each (i, element) =>
84
+ element = $(element)
85
+ if element.find(':contains("--TRANSLATION--")').length == 0
86
+ text = element.html()
87
+ matched = @findTranslationFromText(text)
88
+ element.html(text.replace(matched[0], ''))
89
+
90
+ @translationsQueue.push
91
+ key: matched[1],
92
+ element: element
93
+
94
+ lookupAttributesDom: ->
95
+ $('*').each (i, element) =>
96
+ $.each element.attributes, (i, attribute) =>
97
+ if attribute.value.match('--TRANSLATION--')
98
+ element = $(element)
99
+ text = attribute.value
100
+ matched = @findTranslationFromText(text)
101
+ element.attr(attribute.name, text.replace(matched[0], ''))
102
+
103
+ @translationsQueue.push
104
+ key: matched[1],
105
+ element: element
106
+
107
+ lookupMissingTranslationDom: ->
108
+ $('[class^="translation"]').each (i, element) =>
109
+ element = $(element)
110
+ if element.attr('title') != undefined && element.attr('title').match('translation')
111
+ @translationsQueue.push
112
+ element: element,
113
+ key: element.attr('title').replace('translation missing: ', '')
114
+
115
+ findTranslationFromText: (text) ->
116
+ translations_regexp = /--TRANSLATION--(.*?)--/g
117
+ translations_regexp.exec(text)
118
+
119
+ setStatusText: (text) ->
120
+ $('body').find('.screenshots-status').text(text)
121
+
122
+ windowLocation: ->
123
+ window.location.pathname.replace(/\?.*/, '').replace(/\d+/, ':id')
124
+
125
+ sendTranslations: ->
126
+ data = {
127
+ location: @windowLocation(),
128
+ images: @screenshots,
129
+ highlights: @highlights
130
+ }
131
+ @setStatusText('Sending translations')
132
+
133
+ $.ajax(
134
+ url: '/translation_engine/screenshots',
135
+ type: 'POST',
136
+ data: JSON.stringify(data),
137
+ contentType: 'json'
138
+ ).done (response) =>
139
+ @setStatusText(response.message)
140
+ @dismissScreenshotsOverlay()
141
+
142
+ renderHighlight: ->
143
+ @appendScreenshotsOverlay()
144
+
145
+ translation = @translationsQueue[@translationIndex]
146
+
147
+ @setStatusText("Capturing #{translation.key} (#{@translationIndex}/#{@translationsQueue.length})")
148
+
149
+ image_name = @windowLocation()
150
+
151
+ type = 'span'
152
+
153
+ if translation.element.parent('select').length > 0
154
+ main_element = translation.element.parent('select')
155
+ type = 'select'
156
+ original_selected_value = main_element.val()
157
+ new_value = translation.element.val()
158
+ image_name += "#select_#{main_element.attr('id')}_#{new_value}"
159
+ main_element.val(new_value)
160
+
161
+ else if translation.element.closest('.dropdown').length > 0
162
+ main_element = translation.element
163
+ dropdown = main_element.closest('.dropdown')
164
+ dropdown.addClass('open')
165
+ image_name += "#dropdown_#{dropdown.attr('id')}"
166
+ type = 'dropdown'
167
+
168
+ else if translation.element.closest('.modal').length > 0
169
+ main_element = translation.element
170
+ modal = main_element.closest('.modal')
171
+ modal.css(height: $(document).height()).removeClass('fade in').modal('show')
172
+ $('.modal-backdrop').css(height: $(document).height())
173
+ image_name += "#modal_#{modal.attr('id')}"
174
+ type = 'modal'
175
+
176
+ else
177
+ main_element = translation.element
178
+
179
+ offset = main_element.offset()
180
+ width = main_element.outerWidth()
181
+ height = main_element.outerHeight()
182
+
183
+ @highlights.push
184
+ key: translation.key,
185
+ image_name: image_name,
186
+ x: offset.left,
187
+ y: offset.top,
188
+ width: width,
189
+ height: height
190
+
191
+ setTimeout =>
192
+ if @screenshotsCaptured[image_name] == true
193
+ if type == 'select'
194
+ main_element.val(original_selected_value)
195
+ else if type == 'dropdown'
196
+ main_element.closest('.dropdown').removeClass('open')
197
+ else if type == 'modal'
198
+ main_element.closest('.modal').modal('hide')
199
+ @translationIndex += 1
200
+ @nextTranslationScreeshot()
201
+ else
202
+ html2canvas([ document.body ], {
203
+ onrendered: (canvas) =>
204
+ @screenshots.push {
205
+ location: document.URL,
206
+ name: image_name,
207
+ variant: @variant,
208
+ image: canvas.toDataURL()
209
+ }
210
+ @screenshotsCaptured[image_name] = true
211
+ @translationIndex += 1
212
+ @nextTranslationScreeshot()
213
+ })
214
+ , 1
215
+
216
+ $(document).ready ->
217
+ window.TranslationEngine = new TranslationEngine(
218
+ '.translation_engine_start',
219
+ '.translation_highlight_start'
220
+ )
221
+
222
+ $(window).bind 'ajaxComplete', ->
223
+ window.TranslationEngine.lookupDom()
224
+
225
+ $(document).trigger 'translation_engine:ready'
@@ -0,0 +1,23 @@
1
+ .screenshots-overlay {
2
+ background: rgba(0, 0, 0, 0.3);
3
+ bottom: 0;
4
+ left: 0;
5
+ position: absolute;
6
+ right: 0;
7
+ top: 0;
8
+ z-index: 10000;
9
+ }
10
+
11
+ .screenshots-status {
12
+ background: rgba(0, 0, 0, 0.5);
13
+ color: white;
14
+ font-family: sans-serif;
15
+ font-size: 20px;
16
+ left: 0;
17
+ padding: 10px;
18
+ position: fixed;
19
+ right: 0;
20
+ text-align: center;
21
+ top: 20%;
22
+ z-index: 10001;
23
+ }
@@ -0,0 +1,64 @@
1
+ class TranslationEngine::CatcherMiddleware
2
+ REMOVE_QUERY = /\?.*/
3
+ REPLACE_IDS = /\d+/
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if TranslationEngine.use_catcher
11
+ call_catcher(env)
12
+ else
13
+ @app.call(env)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def call_catcher(env)
20
+ TranslationEngine::Translation.clear_catched
21
+
22
+ if env['QUERY_STRING'].include?('translation_release')
23
+ I18n.backend.release = params(env)['translation_release']
24
+ end
25
+
26
+ update_translations unless assets_request?(env)
27
+
28
+ response = @app.call(env)
29
+
30
+ send_translations(env)
31
+
32
+ response
33
+ end
34
+
35
+ def assets_request?(env)
36
+ env['PATH_INFO'] =~ /\/assets/
37
+ end
38
+
39
+ def params(env)
40
+ Rack::Utils.parse_query(env['QUERY_STRING'], '&')
41
+ end
42
+
43
+ def update_translations
44
+ translation_downloader.update
45
+ end
46
+
47
+ def send_translations(env)
48
+ return if TranslationEngine::Translation.catched.empty?
49
+
50
+ location = env['PATH_INFO'].gsub(REMOVE_QUERY, '').gsub(REPLACE_IDS, ':id')
51
+
52
+ data = {
53
+ location: location,
54
+ locale: I18n.locale,
55
+ translations: TranslationEngine::Translation.catched.uniq
56
+ }
57
+
58
+ Thread.new { TranslationEngine::Connection.new.send_translations(data) }
59
+ end
60
+
61
+ def translation_downloader
62
+ @translation_downloader ||= TranslationEngine::Downloader.new
63
+ end
64
+ end
@@ -0,0 +1,18 @@
1
+ require 'faraday'
2
+
3
+ class TranslationEngine::ConnectionExceptionMiddleware < Faraday::Middleware
4
+ def call(env)
5
+ begin
6
+ @app.call(env)
7
+ rescue Faraday::Error => e
8
+ message = "Connecting to TranslationServer got #{e.class}: #{e.message}"
9
+
10
+ if TranslationEngine.raise_exceptions
11
+ raise ConnectionError, message
12
+ else
13
+ Rails.logger.error { message }
14
+ {}
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,31 @@
1
+ class TranslationEngine::KeysMiddleware
2
+
3
+ URL_PATH = /\A\/translation_engine\/keys/
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if env['PATH_INFO'] =~ URL_PATH
11
+ handle_redirect_request(env)
12
+ else
13
+ @app.call(env)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def handle_redirect_request(env)
20
+ key_path = env['PATH_INFO'].gsub(URL_PATH, '')
21
+
22
+ [
23
+ 302,
24
+ {
25
+ 'Location' => "#{TranslationEngine.api_host}/#{key_path}",
26
+ 'Content-Type' => 'text/html'
27
+ },
28
+ ['Moved Temporarily']
29
+ ]
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ class TranslationEngine::ScreenshotsMiddleware
2
+
3
+ URL_PATH = /\A\/translation_engine\/screenshots/
4
+
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ def call(env)
10
+ if TranslationEngine.use_screenshots && env['PATH_INFO'] =~ URL_PATH
11
+ handle_translation_request(env)
12
+ else
13
+ @app.call(env)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def handle_translation_request(env)
20
+ data = JSON.parse(env["rack.input"].read)
21
+
22
+ TranslationEngine::Connection.new
23
+ .send_images(data.merge(locale: I18n.locale))
24
+
25
+ [
26
+ 200,
27
+ { 'Content-Type' => 'application/json' },
28
+ [{ message: 'translations saved' }.to_json]
29
+ ]
30
+ end
31
+ end