trestle-mobility 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 321983d8b2ced10b0bfcf36a909b5503b3bd35dac0bb1bd7ba72ef1eea860645
4
- data.tar.gz: 5be8fc9e56a4a004549e2ee14a907e170d323daab6909afee3496a7cd8e7015d
3
+ metadata.gz: a43a43d7175e12ad8e187b457104e27f4d273a0fb94f8f83f8f6f39fb2e409fa
4
+ data.tar.gz: f6b84afec6c7eb6f418ae541cc8b907a6043feeec9aebd7788f3807e8871788d
5
5
  SHA512:
6
- metadata.gz: 5f57c749ce315c62befd711d087c24c220057b2c96f75489965ec16f5e7096a9792fcf2e32bb21029e3e6617b45cbb302bf869c4ee27fee5c007962c9313f28b
7
- data.tar.gz: bb2974fe1ec3be058228357629021e5ceae82a65d20f8ab42749ea3f666012b44d27bd56a9aa3fb065217d44ea6a302070558142cdcfa75dc0cbc39afa32f0ba
6
+ metadata.gz: 72d5f7c872fc6aa8b0700458cbce9de3f96ea49b658a74b4921d3a6e1948a77507dac6993de77c371433808f7c30bf95444fc09be4faaf8ef32bfdd9d16e3b7d
7
+ data.tar.gz: 956dd0052b15112ed083ece196ab65642fd5f0ad01eda5f8ea2d9a1863a8718af92df66ee502c94f6099feab3da3522e8c24c668a7d5890982ed875a290bab79
data/README.md CHANGED
@@ -7,6 +7,8 @@
7
7
  ## Features / problems
8
8
 
9
9
  - Manage Mobility translations with a space-efficient dropdown interface in Trestle
10
+ - Supports text fields, text area's and check boxes
11
+ - Integrates with [DeepL Pro](https://www.deepl.com/pro.html) to automatically translate fields
10
12
  - Developed for usage with Mobility's Postgres container back-end
11
13
  - Probably works with other back-ends but has not been tested
12
14
 
@@ -57,6 +59,16 @@ Or specify it per field:
57
59
  mobility_text_field :subtitle, selected: "nl"
58
60
  ```
59
61
 
62
+ ### DeepL translation
63
+
64
+ <img src="/screenshot-deepl.png?raw=true" width="410" height="241" alt="Trestle Mobility DeepL integration screenshot" />
65
+
66
+ Trestle Mobility can automatically populate empty field values with translations from other languages. This functionality is powered by the excellent [deepl-rb](https://github.com/wikiti/deepl-rb) gem. To make use of this, add `deepl-rb` to your Gemfile and specify your DeepL Pro API key in your Trestle initializer:
67
+
68
+ ```ruby
69
+ config.mobility.deepl_api_key = "YOUR-API-KEY"
70
+ ```
71
+
60
72
  ## Installation
61
73
 
62
74
  These instructions assume you have a working Trestle application. To integrate trestle-mobility, first add it to your application's Gemfile:
@@ -1,46 +1,114 @@
1
1
  Trestle.init(function(e, root) {
2
2
  function init() {
3
3
  $(root).find('.mobility').each(function() {
4
- new Mobility(this);
4
+ var instance = new Mobility(this);
5
+ instance.initEvents();
6
+ instance.chooseLanguage();
5
7
  })
6
8
  }
7
9
 
8
- function Mobility (element) {
9
- var element = $(element);
10
- var activeLocale = element.data('active');
11
- var button = element.find('.mobility-active');
12
- var inputFields = element.find('.mobility-field');
13
- var dropdownItems = element.find('.dropdown-item');
10
+ var Mobility = function (element) {
11
+ this.$element = $(element);
12
+ this.$inputFields = this.$element.find('.mobility-field');
13
+ this.$dropdownItems = this.$element.find('.dropdown-item');
14
+ this.$button = this.$element.find('.mobility-active');
15
+ this.$deeplTranslationAction = this.$element.find('.mobility__deepl');
16
+ this.activeLocale = this.$element.data('active');
17
+ };
14
18
 
15
- function toggle (flag) {
16
- $(inputFields).each(function() {
17
- var field = $(this);
18
- var active = field.data('locale') !== activeLocale;
19
+ Mobility.prototype.chooseLanguage = function (flag) {
20
+ var self = this;
19
21
 
20
- field.toggleClass('hidden', active)
21
- })
22
+ this.$inputFields.each(function() {
23
+ var field = $(this);
24
+ var active = field.data('locale') !== self.activeLocale;
25
+ field.toggleClass('hidden', active)
26
+ })
27
+
28
+ this.$dropdownItems.each(function() {
29
+ var item = $(this);
30
+ var active = item.data('locale') === self.activeLocale;
31
+ item.toggleClass('active', active)
32
+ })
33
+
34
+ if (flag) this.$button.text(flag);
35
+ if (this.$deeplTranslationAction) this.presentDeepl();
36
+ }
22
37
 
23
- $(dropdownItems).each(function() {
24
- var field = $(this);
25
- var active = field.data('locale') === activeLocale;
38
+ Mobility.prototype.getActiveField = function () {
39
+ return this.$element.find('.mobility-field[data-locale="' + this.activeLocale +'"]');
40
+ }
26
41
 
27
- field.toggleClass('active', active)
42
+ Mobility.prototype.getFieldByLocale = function (locale) {
43
+ return this.$element.find('.mobility-field[data-locale="' + locale +'"]');
44
+ }
45
+
46
+ Mobility.prototype.presentDeepl = function () {
47
+ var self = this;
48
+ var actionable = !this.getActiveField().val();
49
+
50
+ this.$deeplTranslationAction.toggleClass('mobility__deepl--actionable', actionable)
51
+
52
+ if (actionable) {
53
+ this.$deeplTranslationAction.find('.dropdown-item').each(function() {
54
+ var item = $(this);
55
+ item.toggleClass('disabled', item.data('locale') === self.activeLocale)
28
56
  })
57
+ }
58
+ }
29
59
 
30
- if (flag) {
31
- button.text(flag);
60
+ Mobility.prototype.dismissDeepl = function () {
61
+ this.$deeplTranslationAction.removeClass('mobility__deepl--actionable')
62
+ }
63
+
64
+ Mobility.prototype.deeplTranslate = function (fromLocale) {
65
+ var self = this;
66
+ var path = this.$deeplTranslationAction.data('remote-path');
67
+ var data = {
68
+ translation: {
69
+ text: this.getFieldByLocale(fromLocale).val(),
70
+ from_locale: fromLocale,
71
+ to_locale: this.activeLocale
32
72
  }
33
73
  }
34
74
 
35
- element.find('.dropdown-item').on('click', function () {
36
- var item = $(this);
37
- activeLocale = item.data('locale');
75
+ this.$deeplTranslationAction.addClass('mobility__deepl--active');
38
76
 
39
- toggle(item.text());
77
+ $.post(path, data, function() {
78
+ self.$deeplTranslationAction.removeClass('mobility__deepl--active');
79
+ }).done(function(text) {
80
+ self.getActiveField().val(text);
81
+ self.dismissDeepl();
40
82
  });
41
-
42
- toggle()
43
83
  }
44
84
 
85
+ Mobility.prototype.initEvents = function () {
86
+ var self = this;
87
+
88
+ this.$element.find('.mobility__languages .dropdown-item').on('click', function () {
89
+ var $item = $(this);
90
+ self.activeLocale = $item.data('locale');
91
+ self.chooseLanguage($item.text());
92
+ });
93
+
94
+ this.$element.find('.mobility__deepl-languages .dropdown-item').on('click', function (e) {
95
+ var $item = $(this);
96
+
97
+ if ($item.hasClass('disabled')) {
98
+ e.preventDefault();
99
+ e.stopPropagation();
100
+ return;
101
+ }
102
+
103
+ self.deeplTranslate($item.data('locale'));
104
+ });
105
+
106
+ if (this.$deeplTranslationAction) {
107
+ this.$inputFields.on('change', function() {
108
+ self.presentDeepl()
109
+ })
110
+ }
111
+ };
112
+
45
113
  init();
46
114
  });
@@ -1,3 +1,15 @@
1
+ .mobility {
2
+ .dropdown-item.disabled,
3
+ .dropdown-item.disabled:visited,
4
+ .dropdown-item.disabled:active,
5
+ .dropdown-item.disabled:hover {
6
+ background-color:#d9d9d9 !important;
7
+ color:#aaa !important;
8
+ opacity: 0.7;
9
+ cursor: default;
10
+ }
11
+ }
12
+
1
13
  .mobility-checkbox {
2
14
  display: flex;
3
15
  align-items:center;
@@ -6,3 +18,31 @@
6
18
  .mobility-checkbox__label {
7
19
  margin-left: 8px;
8
20
  }
21
+
22
+
23
+ .mobility__deepl-progress {
24
+ display: none;
25
+ margin-right: 4px;
26
+ }
27
+
28
+ .mobility__deepl {
29
+ display: none;
30
+ margin-top: 4px;
31
+ text-align: right;
32
+
33
+ .progress {
34
+ display: inline-block;
35
+ width: 97px;
36
+ margin-right: 4px;
37
+ }
38
+
39
+ &--actionable {
40
+ display: block;
41
+ }
42
+
43
+ &--active {
44
+ .mobility__deepl-progress {
45
+ display: inline-block;
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,16 @@
1
+ class Trestle::Mobility::TranslationsController < Trestle::ApplicationController
2
+ def translate
3
+ translation = Trestle::Mobility::Translators::DeeplTranslator.new.translate(
4
+ translation_params[:text],
5
+ translation_params[:from_locale],
6
+ translation_params[:to_locale]
7
+ )
8
+
9
+ render plain: translation
10
+ end
11
+
12
+ private
13
+ def translation_params
14
+ params.require(:translation).permit(:text, :from_locale, :to_locale)
15
+ end
16
+ end
@@ -1,10 +1,10 @@
1
- <div class="form-group">
2
- <div class="input-group mobility" data-active="<%= selected %>">
1
+ <div class="form-group mobility" data-active="<%= selected %>">
2
+ <div class="input-group">
3
3
  <div class="input-group-btn">
4
4
  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
5
5
  <span class="mobility-active"><%= "#{EmojiFlag.new(selected)} #{selected.upcase}" %></span> <span class="caret"></span>
6
6
  </button>
7
- <ul class="dropdown-menu">
7
+ <ul class="dropdown-menu mobility__languages">
8
8
  <% locales.each do |locale| %>
9
9
  <li><a href="#<%= "#{field_name}_#{locale}" %>" class="dropdown-item" data-locale="<%= locale %>"><%= "#{EmojiFlag.new(locale)} #{locale.upcase}" %></a></li>
10
10
  <% end %>
@@ -0,0 +1,14 @@
1
+ <div class="mobility__deepl" data-remote-path="<%= trestle.translate_path %>">
2
+ <small class="mobility__deepl-progress">Translating…</small>
3
+
4
+ <div class="btn-group">
5
+ <button class="btn btn-default btn-xs dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
6
+ Translate from <span class="caret"></span>
7
+ </button>
8
+ <ul class="dropdown-menu mobility__deepl-languages">
9
+ <% locales.each do |locale| %>
10
+ <li><a href="javascript:void(0)" class="dropdown-item" data-locale="<%= locale %>"><%= "#{EmojiFlag.new(locale)} #{locale.upcase}" %></a></li>
11
+ <% end %>
12
+ </ul>
13
+ </div>
14
+ </div>
@@ -1,9 +1,9 @@
1
- <div class="form-group">
2
- <div class="input-group mobility" data-active="<%= selected %>">
1
+ <div class="form-group mobility" data-active="<%= selected %>">
2
+ <div class="input-group">
3
3
  <button type="button" class="btn btn-default dropdown-toggle input-group-addon" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
4
4
  <span class="mobility-active"><%= "#{EmojiFlag.new(selected)} #{selected.upcase}" %></span> <span class="caret"></span>
5
5
  </button>
6
- <ul class="dropdown-menu">
6
+ <ul class="dropdown-menu mobility__languages">
7
7
  <% locales.each do |locale| %>
8
8
  <li><a href="#<%= "#{field_name}_#{locale}" %>" class="dropdown-item" data-locale="<%= locale %>"><%= "#{EmojiFlag.new(locale)} #{locale.upcase}" %></a></li>
9
9
  <% end %>
@@ -12,4 +12,7 @@
12
12
  <%= form.raw_text_area "#{field_name}_#{locale}", class: "form-control mobility-field#{locale == selected ? '' : ' hidden'}", placeholder: "#{label} (#{locale.upcase})", rows: rows, data: { locale: locale } %>
13
13
  <% end %>
14
14
  </div>
15
+
16
+ <%= render(partial: "trestle/mobility/deepl_translation_action",
17
+ locals: { locales: locales }) if Trestle.config.mobility.deepl_api_key %>
15
18
  </div>
@@ -1,10 +1,10 @@
1
- <div class="form-group">
2
- <div class="input-group mobility" data-active="<%= selected %>">
1
+ <div class="form-group mobility" data-active="<%= selected %>">
2
+ <div class="input-group">
3
3
  <div class="input-group-btn">
4
4
  <button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
5
5
  <span class="mobility-active"><%= "#{EmojiFlag.new(selected)} #{selected.upcase}" %></span> <span class="caret"></span>
6
6
  </button>
7
- <ul class="dropdown-menu">
7
+ <ul class="dropdown-menu mobility__languages">
8
8
  <% locales.each do |locale| %>
9
9
  <li><a href="#<%= "#{field_name}_#{locale}" %>" class="dropdown-item" data-locale="<%= locale %>"><%= "#{EmojiFlag.new(locale)} #{locale.upcase}" %></a></li>
10
10
  <% end %>
@@ -14,4 +14,7 @@
14
14
  <%= form.raw_text_field "#{field_name}_#{locale}", class: "form-control mobility-field#{locale == selected ? '' : ' hidden'}", placeholder: "#{label} (#{locale.upcase})", data: { locale: locale } %>
15
15
  <% end %>
16
16
  </div>
17
+
18
+ <%= render(partial: "trestle/mobility/deepl_translation_action",
19
+ locals: { locales: locales }) if Trestle.config.mobility.deepl_api_key %>
17
20
  </div>
data/config/routes.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Trestle::Engine.routes.draw do
4
+ controller "trestle/mobility/translations" do
5
+ post "translate"
6
+ end
7
+ end
@@ -4,6 +4,7 @@ module Trestle
4
4
  include Configurable
5
5
 
6
6
  option :selected
7
+ option :deepl_api_key
7
8
  end
8
9
  end
9
10
  end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Trestle::Mobility::Translators
4
+ class DeeplTranslator
5
+ def initialize(*)
6
+ begin
7
+ require "deepl"
8
+ rescue LoadError
9
+ raise StandardError, "Add the 'deepl-rb' gem to your Gemfile"
10
+ end
11
+
12
+ configure_api_key!
13
+ end
14
+
15
+ def translate(text, from, to)
16
+ DeepL.translate(text, from, to)
17
+ end
18
+
19
+ private
20
+ def configure_api_key!
21
+ DeepL.configure do |config|
22
+ config.auth_key = Trestle.config.mobility.deepl_api_key
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,5 +1,5 @@
1
1
  module Trestle
2
2
  module Mobility
3
- VERSION = "0.4.0"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
@@ -3,6 +3,7 @@ require "emoji_flag"
3
3
  require "trestle"
4
4
  require "trestle/mobility/version"
5
5
  require "trestle/mobility/configuration"
6
+ require "trestle/mobility/translators/deepl_translator"
6
7
  require "trestle/mobility/engine" if defined?(Rails)
7
8
 
8
9
  Trestle::Configuration.option :mobility, Trestle::Mobility::Configuration.new
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trestle-mobility
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Venneman
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-05-15 00:00:00.000000000 Z
11
+ date: 2019-05-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: emoji_flag
@@ -95,19 +95,24 @@ files:
95
95
  - Rakefile
96
96
  - app/assets/javascript/trestle/mobility.js
97
97
  - app/assets/stylesheets/trestle/mobility.scss
98
+ - app/controllers/trestle/mobility/translations_controller.rb
98
99
  - app/views/trestle/mobility/_check_box.html.erb
100
+ - app/views/trestle/mobility/_deepl_translation_action.html.erb
99
101
  - app/views/trestle/mobility/_text_area.html.erb
100
102
  - app/views/trestle/mobility/_text_field.html.erb
101
103
  - bin/console
102
104
  - bin/setup
103
105
  - config/initializers/trestle.rb
106
+ - config/routes.rb
104
107
  - lib/trestle/mobility.rb
105
108
  - lib/trestle/mobility/configuration.rb
106
109
  - lib/trestle/mobility/engine.rb
107
110
  - lib/trestle/mobility/fields/check_box.rb
108
111
  - lib/trestle/mobility/fields/text_area.rb
109
112
  - lib/trestle/mobility/fields/text_field.rb
113
+ - lib/trestle/mobility/translators/deepl_translator.rb
110
114
  - lib/trestle/mobility/version.rb
115
+ - screenshot-deepl.png
111
116
  - screenshot.png
112
117
  - trestle-mobility.gemspec
113
118
  homepage: https://github.com/richardvenneman/trestle-mobility