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 +4 -4
- data/README.md +12 -0
- data/app/assets/javascript/trestle/mobility.js +93 -25
- data/app/assets/stylesheets/trestle/mobility.scss +40 -0
- data/app/controllers/trestle/mobility/translations_controller.rb +16 -0
- data/app/views/trestle/mobility/_check_box.html.erb +3 -3
- data/app/views/trestle/mobility/_deepl_translation_action.html.erb +14 -0
- data/app/views/trestle/mobility/_text_area.html.erb +6 -3
- data/app/views/trestle/mobility/_text_field.html.erb +6 -3
- data/config/routes.rb +7 -0
- data/lib/trestle/mobility/configuration.rb +1 -0
- data/lib/trestle/mobility/translators/deepl_translator.rb +26 -0
- data/lib/trestle/mobility/version.rb +1 -1
- data/lib/trestle/mobility.rb +1 -0
- data/screenshot-deepl.png +0 -0
- metadata +7 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a43a43d7175e12ad8e187b457104e27f4d273a0fb94f8f83f8f6f39fb2e409fa
|
4
|
+
data.tar.gz: f6b84afec6c7eb6f418ae541cc8b907a6043feeec9aebd7788f3807e8871788d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
-
|
16
|
-
|
17
|
-
var field = $(this);
|
18
|
-
var active = field.data('locale') !== activeLocale;
|
19
|
+
Mobility.prototype.chooseLanguage = function (flag) {
|
20
|
+
var self = this;
|
19
21
|
|
20
|
-
|
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
|
-
|
24
|
-
|
25
|
-
|
38
|
+
Mobility.prototype.getActiveField = function () {
|
39
|
+
return this.$element.find('.mobility-field[data-locale="' + this.activeLocale +'"]');
|
40
|
+
}
|
26
41
|
|
27
|
-
|
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
|
-
|
31
|
-
|
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
|
-
|
36
|
-
var item = $(this);
|
37
|
-
activeLocale = item.data('locale');
|
75
|
+
this.$deeplTranslationAction.addClass('mobility__deepl--active');
|
38
76
|
|
39
|
-
|
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
|
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
|
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
|
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,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
|
data/lib/trestle/mobility.rb
CHANGED
@@ -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
|
+
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-
|
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
|