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.
Files changed (45) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -0
  3. data/Gemfile +19 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +144 -0
  6. data/Rakefile +12 -0
  7. data/app/controllers/translations_controller.rb +42 -0
  8. data/config/initializers/babbel.rb +2 -0
  9. data/config/routes.rb +3 -0
  10. data/inline_translation.gemspec +28 -0
  11. data/lib/generators/inline_translation/install/install_generator.rb +24 -0
  12. data/lib/generators/inline_translation/install/templates/add_inline_translations.rb +16 -0
  13. data/lib/generators/inline_translation/install/templates/create.js.erb +4 -0
  14. data/lib/generators/inline_translation/install/templates/inline_translation.rb +1 -0
  15. data/lib/inline_translation.rb +42 -0
  16. data/lib/inline_translation/concerns/acts_as_translatable.rb +17 -0
  17. data/lib/inline_translation/concerns/translatable.rb +17 -0
  18. data/lib/inline_translation/config/routes.rb +3 -0
  19. data/lib/inline_translation/engine.rb +4 -0
  20. data/lib/inline_translation/helpers/translations_helper.rb +26 -0
  21. data/lib/inline_translation/models/translation.rb +9 -0
  22. data/lib/inline_translation/services/translation_service.rb +36 -0
  23. data/lib/inline_translation/translators/base.rb +25 -0
  24. data/lib/inline_translation/translators/bing.rb +21 -0
  25. data/lib/inline_translation/translators/null.rb +18 -0
  26. data/lib/inline_translation/version.rb +3 -0
  27. metadata +50 -48
  28. data/test/babbel_integration_test.rb +0 -34
  29. data/test/fixtures/application_controller.rb +0 -3
  30. data/test/fixtures/rails.rb +0 -36
  31. data/test/lib/babbel_test.rb +0 -9
  32. data/test/lib/concerns/acts_as_translatable_test.rb +0 -62
  33. data/test/lib/concerns/translatable_test.rb +0 -31
  34. data/test/lib/controllers/translations_controller_test.rb +0 -62
  35. data/test/lib/generators/babbel_generator_install_test.rb +0 -22
  36. data/test/lib/helpers/translations_helper_test.rb +0 -61
  37. data/test/lib/models/translation_test.rb +0 -55
  38. data/test/lib/services/translation_service_test.rb +0 -69
  39. data/test/lib/translators/base_test.rb +0 -65
  40. data/test/lib/translators/bing_test.rb +0 -39
  41. data/test/lib/translators/null_test.rb +0 -20
  42. data/test/test_helper.rb +0 -74
  43. data/test/test_types/controller_test.rb +0 -6
  44. data/test/test_types/integration_test.rb +0 -2
  45. data/test/test_types/unit_test.rb +0 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1712a04eec4217093462a4e8ce98265646adf6d5
4
- data.tar.gz: 03182eb9ece86002f1334fdd89c4cba98e4f760b
3
+ metadata.gz: 4c43a8db80105aeb7be961e297ca2f9a3aabe463
4
+ data.tar.gz: 59d7a9fe4cfcfd4e6aa5ab7a4a1083c381d7b6f3
5
5
  SHA512:
6
- metadata.gz: 6d18f77ae8291f105db60da48524990b5566c7038bb92402a16d166e0618618dc97fcc054d41fceffe6de15dbfc26362354c1a9e0f31d973205b1f53e873180b
7
- data.tar.gz: df2bcc2e4a0f4e8d399598d9ce316d31ecab1ab519a14a0a7dd7c9ac36a3c231b6816c6d8d0b8584a886505fc7a7398b8b776d03a6ab4a04c95e7bcd2d665057
6
+ metadata.gz: 4c52ef16c8ccb78f6ebece9e129f89e25cb2bd904d52f36053f99d6dc69fbb235d1594600981f158afa8ecd5beffc67745e3814fe74ba73b64dc1ec8c3a5ff5d
7
+ data.tar.gz: 5e1905f57907db594ca8eb80e59da5e49dd2b3a730b06ed459d484a6bce5dbb200ec6108823fa9115fb2afcaba02af0c080fd9cd11322bd4a96fc10a54c62b14
@@ -0,0 +1,15 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ *.gem
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
@@ -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.
@@ -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
@@ -0,0 +1,12 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ task default: :test
5
+
6
+ Rake::TestTask.new :test do |t|
7
+ t.libs << 'lib'
8
+ t.libs << 'test'
9
+ t.pattern = 'test/**/*_test.rb'
10
+ t.verbose = true
11
+ t.warning = false
12
+ end
@@ -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
@@ -0,0 +1,2 @@
1
+ ActiveSupport.on_load(:active_record) { include InlineTranslation::Concerns::ActsAsTranslatable }
2
+ ActiveSupport.on_load(:action_view) { include InlineTranslation::Helpers::TranslationsHelper }
@@ -0,0 +1,3 @@
1
+ Rails.application.routes.draw do
2
+ resources :translations, only: :create, module: 'inline_translation/controllers', as: :translations
3
+ end
@@ -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,4 @@
1
+ target = $('#<%= @translatable.class.to_s.downcase %>-<%= @translatable.id %>')
2
+ <% @translations.each do |translation| %>
3
+ target.find('.inline-translation-translated.<%= translation.field %>-translated').html("<%= j translation.translation %>")
4
+ <% 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