inline_translation 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +15 -0
- data/Gemfile +19 -0
- data/LICENSE.txt +22 -0
- data/README.md +144 -0
- data/Rakefile +12 -0
- data/app/controllers/translations_controller.rb +42 -0
- data/config/initializers/babbel.rb +2 -0
- data/config/routes.rb +3 -0
- data/inline_translation.gemspec +28 -0
- data/lib/generators/inline_translation/install/install_generator.rb +24 -0
- data/lib/generators/inline_translation/install/templates/add_inline_translations.rb +16 -0
- data/lib/generators/inline_translation/install/templates/create.js.erb +4 -0
- data/lib/generators/inline_translation/install/templates/inline_translation.rb +1 -0
- data/lib/inline_translation.rb +42 -0
- data/lib/inline_translation/concerns/acts_as_translatable.rb +17 -0
- data/lib/inline_translation/concerns/translatable.rb +17 -0
- data/lib/inline_translation/config/routes.rb +3 -0
- data/lib/inline_translation/engine.rb +4 -0
- data/lib/inline_translation/helpers/translations_helper.rb +26 -0
- data/lib/inline_translation/models/translation.rb +9 -0
- data/lib/inline_translation/services/translation_service.rb +36 -0
- data/lib/inline_translation/translators/base.rb +25 -0
- data/lib/inline_translation/translators/bing.rb +21 -0
- data/lib/inline_translation/translators/null.rb +18 -0
- data/lib/inline_translation/version.rb +3 -0
- metadata +50 -48
- data/test/babbel_integration_test.rb +0 -34
- data/test/fixtures/application_controller.rb +0 -3
- data/test/fixtures/rails.rb +0 -36
- data/test/lib/babbel_test.rb +0 -9
- data/test/lib/concerns/acts_as_translatable_test.rb +0 -62
- data/test/lib/concerns/translatable_test.rb +0 -31
- data/test/lib/controllers/translations_controller_test.rb +0 -62
- data/test/lib/generators/babbel_generator_install_test.rb +0 -22
- data/test/lib/helpers/translations_helper_test.rb +0 -61
- data/test/lib/models/translation_test.rb +0 -55
- data/test/lib/services/translation_service_test.rb +0 -69
- data/test/lib/translators/base_test.rb +0 -65
- data/test/lib/translators/bing_test.rb +0 -39
- data/test/lib/translators/null_test.rb +0 -20
- data/test/test_helper.rb +0 -74
- data/test/test_types/controller_test.rb +0 -6
- data/test/test_types/integration_test.rb +0 -2
- data/test/test_types/unit_test.rb +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c43a8db80105aeb7be961e297ca2f9a3aabe463
|
4
|
+
data.tar.gz: 59d7a9fe4cfcfd4e6aa5ab7a4a1083c381d7b6f3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4c52ef16c8ccb78f6ebece9e129f89e25cb2bd904d52f36053f99d6dc69fbb235d1594600981f158afa8ecd5beffc67745e3814fe74ba73b64dc1ec8c3a5ff5d
|
7
|
+
data.tar.gz: 5e1905f57907db594ca8eb80e59da5e49dd2b3a730b06ed459d484a6bce5dbb200ec6108823fa9115fb2afcaba02af0c080fd9cd11322bd4a96fc10a54c62b14
|
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in InlineTranslation.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'rails', '~> 4.1.0'
|
7
|
+
gem 'bing_translator', '~> 4.4.0'
|
8
|
+
|
9
|
+
group :development, :test do
|
10
|
+
gem 'byebug', require: nil
|
11
|
+
gem 'temping'
|
12
|
+
gem 'mocha'
|
13
|
+
gem 'sqlite3'
|
14
|
+
gem 'byebug'
|
15
|
+
end
|
16
|
+
|
17
|
+
group :test do
|
18
|
+
gem 'codeclimate-test-reporter', require: nil
|
19
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 James Kiesel
|
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,144 @@
|
|
1
|
+
# Inline Translation
|
2
|
+
|
3
|
+
`inline_translation` is a gem which provides your application with a simple, easy-to-use way to perform inline translations of content, into a variety of languages.
|
4
|
+
|
5
|
+
It's written as a wrapper for the fine [bing_translator gem](https://github.com/relrod/bing_translator-gem), but can be easily extended to using other translation services.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'inline_translation'
|
13
|
+
```
|
14
|
+
|
15
|
+
And then execute:
|
16
|
+
|
17
|
+
$ bundle
|
18
|
+
|
19
|
+
Then, execute the install generator
|
20
|
+
|
21
|
+
$ rails g inline_translation:install
|
22
|
+
|
23
|
+
And migrate
|
24
|
+
|
25
|
+
$ rake db:migrate
|
26
|
+
|
27
|
+
Now you're all set up!
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Inline Translation supplies several helper methods to make your translating life easier.
|
32
|
+
|
33
|
+
To mark a field on an object as translatable, simply add
|
34
|
+
|
35
|
+
`acts_as_translatable, on: :field_name`
|
36
|
+
|
37
|
+
to your model.
|
38
|
+
|
39
|
+
#### Additional options
|
40
|
+
|
41
|
+
- **load_via** - the class method used to find a record for your model. Defaults to `:find`
|
42
|
+
- **id_field** - field name for the unique identifier for your model. Defaults to `:id`
|
43
|
+
- **language_field** - field name for the method / column name on your model to retrieve the language. Defaults to `language`
|
44
|
+
|
45
|
+
NB: Oftentimes, you may wish to delegate this method to a user or other object, instead of storing the language on every model.
|
46
|
+
|
47
|
+
For example:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
# model.rb
|
51
|
+
class Model < ActiveRecord::Base
|
52
|
+
belongs_to :author, class_name: 'User'
|
53
|
+
acts_as_translatable on: :column
|
54
|
+
|
55
|
+
def language
|
56
|
+
author.locale
|
57
|
+
end
|
58
|
+
end
|
59
|
+
```
|
60
|
+
|
61
|
+
## On the frontend
|
62
|
+
|
63
|
+
#### The translation link
|
64
|
+
|
65
|
+
InlineTranslation provides a simple helper method for translation links in the view.
|
66
|
+
|
67
|
+
For example, adding
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
translate_link_for(@model, to: :fr)
|
71
|
+
```
|
72
|
+
|
73
|
+
Will add an ajax link to create and store a French translation. The `to` field will default to I18n.locale.
|
74
|
+
|
75
|
+
###### Additional options
|
76
|
+
|
77
|
+
- **text** - The text of the anchor generated. Defaults to 'Translate'
|
78
|
+
- **to** - The language to translate to with this link. Defaults to I18n.locale
|
79
|
+
|
80
|
+
(NB: This link will not appear if `@model.language` is equal to the 'to' parameter, since we cannot perform translations to the same language.)
|
81
|
+
|
82
|
+
#### Populating the translation (via UJS)
|
83
|
+
|
84
|
+
The simplest possible markup for including translations on callback:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
# /app/views/models/show.html.erb
|
88
|
+
<div id="model-1">
|
89
|
+
<%= translated_element_for @model, :field_a %>
|
90
|
+
<%= translated_element_for @model, :field_b %>
|
91
|
+
</div>
|
92
|
+
```
|
93
|
+
|
94
|
+
(Note that this markup can occur anywhere, as long as the `translated_element_for` elements are within a div of the format 'className-id')
|
95
|
+
|
96
|
+
If this particular markup structure doesn't work for you for whatever reason, feel free to edit the `app/views/translations/create.js.erb` with javascript to your liking.
|
97
|
+
|
98
|
+
###### Additional options
|
99
|
+
|
100
|
+
- **element** - The type of element generated. Defaults to 'span'
|
101
|
+
|
102
|
+
#### Populating the translation (via JSON)
|
103
|
+
|
104
|
+
The `translations#create` action can also accept a `:json` format, which will return a list of serialized translations. These can be consumed by your javascript frontend framework as you see fit.
|
105
|
+
(TODO: provide more robust support for custom serialization, such as through ActiveModel::Serializers PRs welcome!)
|
106
|
+
|
107
|
+
ie, a simplistic implementation in angular:
|
108
|
+
|
109
|
+
```html
|
110
|
+
<!--in the view -->
|
111
|
+
<a href='' ng-click='translateToFrench()'>Translate</a>
|
112
|
+
```
|
113
|
+
|
114
|
+
```javascript
|
115
|
+
// in the controller
|
116
|
+
$scope.translateToFrench = function() {
|
117
|
+
$http.post('/translations', { translatable_id: 1, translatable_type: 'Model', to: 'fr', format: 'json'}).then(function(data) {
|
118
|
+
$scope.frenchTranslation = data
|
119
|
+
})
|
120
|
+
}
|
121
|
+
```
|
122
|
+
|
123
|
+
|
124
|
+
## On the backend
|
125
|
+
|
126
|
+
InlineTranslation uses the Bing Translator API as a default. For instructions on setting up the Bing Translator API, [go here](https://github.com/relrod/bing_translator-gem#getting-a-client-id-and-secret).
|
127
|
+
|
128
|
+
## Different Translators
|
129
|
+
|
130
|
+
Simply change the line in `config/initializers/inline_translation.rb` to use whatever translator you desire.
|
131
|
+
|
132
|
+
Note that a custom translator must implement the following methods:
|
133
|
+
|
134
|
+
- `self.ready?`: Returns true if the translator can translate anything
|
135
|
+
- `can_translate?`: Returns true the translator can translate the given translatable
|
136
|
+
- `translate`: Returns a translation for all `acts_as_translatable` fields on the translatable
|
137
|
+
|
138
|
+
## Contributing
|
139
|
+
|
140
|
+
1. Fork it ( https://github.com/[my-github-username]/inline_translation/fork )
|
141
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
142
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
143
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
144
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
module InlineTranslation
|
2
|
+
module Controllers
|
3
|
+
class TranslationsController < ::ApplicationController
|
4
|
+
respond_to :js, :json
|
5
|
+
|
6
|
+
def create
|
7
|
+
if service.translate(translatable, to: to_language)
|
8
|
+
@translations = translatable.translations.where(language: to_language)
|
9
|
+
respond_to do |format|
|
10
|
+
format.js { render :create }
|
11
|
+
format.json { render json: @translations } # TODO: support for AMS / custom serialization
|
12
|
+
end
|
13
|
+
else
|
14
|
+
failure_response
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def failure_response
|
21
|
+
head :unprocessable_entity
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.controller_path
|
25
|
+
:translations
|
26
|
+
end
|
27
|
+
|
28
|
+
def service
|
29
|
+
@service ||= InlineTranslation::Services::TranslationService.new
|
30
|
+
end
|
31
|
+
|
32
|
+
def translatable
|
33
|
+
@translatable ||= params[:translatable_type].classify.constantize.get_instance params[:translatable_id] rescue nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def to_language
|
37
|
+
params[:to] || I18n.locale
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/config/routes.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'inline_translation/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "inline_translation"
|
8
|
+
spec.version = InlineTranslation::VERSION
|
9
|
+
spec.authors = ["James Kiesel (gdpelican)"]
|
10
|
+
spec.email = ["james@loomio.org"]
|
11
|
+
|
12
|
+
spec.summary = "Store on-the-fly translations using Bing (or others!)"
|
13
|
+
spec.description = "Sets up a framework for allowing inline translation of database content"
|
14
|
+
spec.homepage = "http://www.github.com/gdpelican/inline_translation"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["app", "lib"]
|
21
|
+
|
22
|
+
spec.add_runtime_dependency "rails", "~> 4.1"
|
23
|
+
spec.add_runtime_dependency "bing_translator", "~> 4.4"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
26
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
27
|
+
spec.add_development_dependency "minitest", "~> 5.7"
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module InlineTranslation
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
include Rails::Generators::Migration
|
4
|
+
desc "Adds InlineTranslation translations table & initializer"
|
5
|
+
source_root File.expand_path '../templates', __FILE__
|
6
|
+
|
7
|
+
def copy_migration
|
8
|
+
migration_template "add_inline_translations.rb", "db/migrate/add_inline_translations.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
def copy_initializer
|
12
|
+
copy_file "inline_translation.rb", "config/initializers/inline_translation.rb"
|
13
|
+
end
|
14
|
+
|
15
|
+
def copy_js_view
|
16
|
+
copy_file "create.js.erb", "app/views/translations/create.js.erb"
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.next_migration_number(path)
|
20
|
+
@previous_migration_nr ||= Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
21
|
+
@previous_migration_nr += 1
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class AddInlineTranslations < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :translations do |t|
|
4
|
+
t.integer :translatable_id
|
5
|
+
t.string :translatable_type
|
6
|
+
t.string :field
|
7
|
+
t.string :language
|
8
|
+
t.text :translation
|
9
|
+
t.timestamps
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.down
|
14
|
+
drop_table :translations
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
InlineTranslation.translator = InlineTranslation::Translators::Bing
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_support'
|
2
|
+
require 'inline_translation/engine'
|
3
|
+
|
4
|
+
module InlineTranslation
|
5
|
+
extend ActiveSupport::Autoload
|
6
|
+
|
7
|
+
cattr_accessor :translator
|
8
|
+
|
9
|
+
module Concerns
|
10
|
+
autoload :ActsAsTranslatable, 'inline_translation/concerns/acts_as_translatable'
|
11
|
+
autoload :Translatable, 'inline_translation/concerns/translatable'
|
12
|
+
end
|
13
|
+
|
14
|
+
module Controllers
|
15
|
+
autoload :TranslationsController, 'controllers/translations_controller'
|
16
|
+
end
|
17
|
+
|
18
|
+
module Generators
|
19
|
+
autoload :InstallGenerator, 'generators/install/install_generator'
|
20
|
+
end
|
21
|
+
|
22
|
+
module Helpers
|
23
|
+
autoload :TranslationsHelper, 'inline_translation/helpers/translations_helper'
|
24
|
+
end
|
25
|
+
|
26
|
+
module Models
|
27
|
+
autoload :Translation, 'inline_translation/models/translation'
|
28
|
+
end
|
29
|
+
|
30
|
+
module Services
|
31
|
+
autoload :TranslationService, 'inline_translation/services/translation_service'
|
32
|
+
end
|
33
|
+
|
34
|
+
module Translators
|
35
|
+
autoload :Base, 'inline_translation/translators/base'
|
36
|
+
autoload :Bing, 'inline_translation/translators/bing'
|
37
|
+
autoload :Null, 'inline_translation/translators/null'
|
38
|
+
end
|
39
|
+
|
40
|
+
self.translator ||= Translators::Null
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module InlineTranslation
|
2
|
+
module Concerns
|
3
|
+
module ActsAsTranslatable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
module ClassMethods
|
7
|
+
def acts_as_translatable(on: [], load_via: :find, id_field: :id, language_field: :language)
|
8
|
+
include InlineTranslation::Concerns::Translatable
|
9
|
+
define_singleton_method :translatable_fields, -> { Array on }
|
10
|
+
define_singleton_method :get_instance, ->(id) { send load_via, id }
|
11
|
+
define_method :id_field, -> { send id_field }
|
12
|
+
define_method :language_field, -> { send language_field }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module InlineTranslation
|
2
|
+
module Concerns
|
3
|
+
module Translatable
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
included do
|
6
|
+
has_many :translations, as: :translatable, class_name: 'InlineTranslation::Models::Translation'
|
7
|
+
before_update :destroy_modified_translations
|
8
|
+
|
9
|
+
private
|
10
|
+
|
11
|
+
def destroy_modified_translations
|
12
|
+
translations.each { |t| t.destroy if changed.include? t.field }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|