voltron-translate 0.1.6 → 0.2.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 +93 -0
- data/app/models/voltron/translation.rb +7 -0
- data/lib/generators/templates/db/migrate/create_voltron_translations.rb +11 -0
- data/lib/generators/voltron/translate/install_generator.rb +39 -2
- data/lib/voltron/config/translate.rb +2 -2
- data/lib/voltron/translatable.rb +121 -0
- data/lib/voltron/translate/{railtie.rb → engine.rb} +5 -3
- data/lib/voltron/translate/version.rb +1 -1
- data/lib/voltron/translate.rb +4 -1
- data/voltron-translate.gemspec +3 -1
- metadata +38 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 496b01a5fc6aef8382150266d811b2b0feddbd4e
|
4
|
+
data.tar.gz: 6db2b1e2291a17e376c74cee8744a674632c17d7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eef4569dd7db4562ceed56dce7154fe081708b4f975b0b5b600a973bf68b30caf347cd8799a8a1253b87c22542ed69668da41e1501027ed9c04200b52313bd99
|
7
|
+
data.tar.gz: e27b55db4f9163ec69576d22a89845dff355f01a52d55dffa16705311cb5ed41d296924b8e878f7984cb8310e64901aedfd291d3542d769b25b187eec08130f4
|
data/README.md
CHANGED
@@ -26,6 +26,8 @@ Then run the following to create the voltron.rb initializer (if not exists alrea
|
|
26
26
|
|
27
27
|
## Usage
|
28
28
|
|
29
|
+
### The Double Underscore Method
|
30
|
+
|
29
31
|
Voltron Translate extends ActiveRecord::Base, ActionController::Base, ActionMailer::Base, and ActionView::Base with a __ (double underscore) method that makes internationalization and/or translating static phrases easier.
|
30
32
|
|
31
33
|
Once installed, from any class that extends from any of the three rails classes you can use the double underscore method to allow for real time text translation. For example:
|
@@ -102,12 +104,103 @@ __("User with name %{person_name} has been saved successfully.", :de, person_nam
|
|
102
104
|
|
103
105
|
Will always look for the above translation within de.csv
|
104
106
|
|
107
|
+
### Backend Translations
|
108
|
+
|
109
|
+
To add support for translations of dynamic text, i.e. - Text entered into a form, Voltron Translate adds a `translates` class method to models.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class Company < ActiveRecord::Base
|
113
|
+
|
114
|
+
# translates :attribute_name1, :attribute_name2, :attribute_name3, ..., options={}
|
115
|
+
translates :name, :greeting, { locales: [:en, :es, :de, :"en-GB"], default: :en }
|
116
|
+
|
117
|
+
end
|
118
|
+
```
|
119
|
+
|
120
|
+
Options to the `translates` method are optional, and, if any/all or omitted, the defaults are as follows:
|
121
|
+
|
122
|
+
locales -> Defaults to Voltron.config.translates.locales, which itself defaults to Rails.application.config.i18n.available_locales
|
123
|
+
default -> nil, will just return the value of the original attribute, i.e. - "name" or "greeting"
|
124
|
+
|
125
|
+
The `translates` method adds locale specific version of the attribute(s) to the model with the following methods:
|
126
|
+
|
127
|
+
`<attribute>_<locale>`
|
128
|
+
|
129
|
+
`<attribute>_<locale>=`
|
130
|
+
|
131
|
+
`<attribute>_<locale>?`
|
132
|
+
|
133
|
+
`<attribute>_<locale>_will_change!`
|
134
|
+
|
135
|
+
`<attribute>_<locale>_changed?`
|
136
|
+
|
137
|
+
`<attribute>_<locale>_was`
|
138
|
+
|
139
|
+
In addition, it will override the `<attribute>` method with one that takes a single, optional argument: the locale you want to return the text for. Consider the following:
|
140
|
+
|
141
|
+
```ruby
|
142
|
+
# Voltron.config.translate.locales = [:en, :es, :"en-GB"]
|
143
|
+
class Company < ActiveRecord::Base
|
144
|
+
|
145
|
+
translates :name
|
146
|
+
|
147
|
+
end
|
148
|
+
```
|
149
|
+
|
150
|
+
```ruby
|
151
|
+
@company = Company.create(name: 'Company Name', name_es: 'Spanish Company Name', name_en_gb: 'British Company Name')
|
152
|
+
|
153
|
+
@company.name # Returns 'Company Name'
|
154
|
+
@company.name(:es) # Returns 'Spanish Company Name'
|
155
|
+
@company.name(:invalid_locale) # Returns 'Company Name', since it ultimately will fall back to the original attribute
|
156
|
+
|
157
|
+
# OR, access the locale directly:
|
158
|
+
|
159
|
+
@company.name_es # Returns 'Spanish Company Name'
|
160
|
+
@company.name_en_gb # Returns 'British Company Name'
|
161
|
+
|
162
|
+
# Without specifying a specific locale in either the method call or +translates+ option, it will try and base it's lookup by the value of I18n.locale
|
163
|
+
|
164
|
+
I18n.locale = :en
|
165
|
+
@company.name # Returns 'Company Name'
|
166
|
+
|
167
|
+
I18n.locale = :es
|
168
|
+
@company.name # Returns 'Spanish Company Name', since our global locale is set to :es
|
169
|
+
```
|
170
|
+
|
171
|
+
Should go without saying, but to set the translation text on the frontend, you'd just create a separate form field for each locales text:
|
172
|
+
|
173
|
+
```erb
|
174
|
+
<%= form_for @company do |f| %>
|
175
|
+
|
176
|
+
<div>
|
177
|
+
<%= f.label :name %>
|
178
|
+
<%= f.text_field :name %>
|
179
|
+
</div>
|
180
|
+
|
181
|
+
<div>
|
182
|
+
<%= f.label :name_es %>
|
183
|
+
<%= f.text_field :name_es %>
|
184
|
+
</div>
|
185
|
+
|
186
|
+
<div>
|
187
|
+
<%= f.label :name_en_gb %>
|
188
|
+
<%= f.text_field :name_en_gb %>
|
189
|
+
</div>
|
190
|
+
|
191
|
+
<% end %>
|
192
|
+
```
|
193
|
+
|
194
|
+
Add the appropriate attributes to your strong params, so on, so on...
|
195
|
+
|
105
196
|
## Things to Note
|
106
197
|
|
107
198
|
Setting `Voltron.config.translate.enabled` to `false` will never break any __() call, it simply causes it to ignore the locale argument (if specified) and return the interpolated string using the latter arguments (again, if any)
|
108
199
|
|
109
200
|
Disabling translations simply disables any IO related actions that would occur normally, like building or looking up translations when __() methods are called.
|
110
201
|
|
202
|
+
It also disables the locale specific text translation on any method call that was targeted with `translates`, meaning `@company.name(:es)` would be the equivalent of calling `@company.name`. Note that `@company.name_es` would still work as it normally would.
|
203
|
+
|
111
204
|
## Development
|
112
205
|
|
113
206
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
@@ -3,6 +3,8 @@ module Voltron
|
|
3
3
|
module Generators
|
4
4
|
class InstallGenerator < Rails::Generators::Base
|
5
5
|
|
6
|
+
source_root File.expand_path("../../../templates", __FILE__)
|
7
|
+
|
6
8
|
desc 'Add Voltron Translate initializer'
|
7
9
|
|
8
10
|
def inject_initializer
|
@@ -27,8 +29,11 @@ module Voltron
|
|
27
29
|
# Whether or not translation is enabled
|
28
30
|
# config.translate.enabled = true
|
29
31
|
|
30
|
-
# Which locales to build translation files for
|
31
|
-
#
|
32
|
+
# Which locales to build translation files for. This setting also
|
33
|
+
# determines the global default locales used with the `translates` class method
|
34
|
+
# For example, if this is [:en, :es, :de], calling `translates :attribute` in a model
|
35
|
+
# Will expose the methods `attribute_en`, `attribute_es`, and `attribute_de`
|
36
|
+
# config.translate.locales = Rails.application.config.i18n.available_locales
|
32
37
|
|
33
38
|
# In what environments can translation generation occur. Recommended to keep this as development (default)
|
34
39
|
# config.translate.build_environment << :development
|
@@ -36,6 +41,38 @@ CONTENT
|
|
36
41
|
end
|
37
42
|
end
|
38
43
|
end
|
44
|
+
|
45
|
+
def copy_migrations
|
46
|
+
copy_migration 'create_voltron_translations'
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def copy_migration(filename)
|
52
|
+
if migration_exists?(Rails.root.join('db', 'migrate'), filename)
|
53
|
+
say_status('skipped', "Migration #{filename}.rb already exists")
|
54
|
+
else
|
55
|
+
copy_file "db/migrate/#{filename}.rb", Rails.root.join('db', 'migrate', "#{migration_number}_#{filename}.rb")
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def migration_exists?(dirname, filename)
|
60
|
+
Dir.glob("#{dirname}/[0-9]*_*.rb").grep(/\d+_#{filename}.rb$/).first
|
61
|
+
end
|
62
|
+
|
63
|
+
def migration_id_exists?(dirname, id)
|
64
|
+
Dir.glob("#{dirname}/#{id}*").length > 0
|
65
|
+
end
|
66
|
+
|
67
|
+
def migration_number
|
68
|
+
@migration_number ||= Time.now.strftime('%Y%m%d%H%M%S').to_i
|
69
|
+
|
70
|
+
while migration_id_exists?(Rails.root.join('db', 'migrate'), @migration_number) do
|
71
|
+
@migration_number += 1
|
72
|
+
end
|
73
|
+
|
74
|
+
@migration_number
|
75
|
+
end
|
39
76
|
end
|
40
77
|
end
|
41
78
|
end
|
@@ -12,7 +12,7 @@ module Voltron
|
|
12
12
|
def initialize
|
13
13
|
@build_environment ||= [:development]
|
14
14
|
@enabled ||= true
|
15
|
-
@locales ||=
|
15
|
+
@locales ||= I18n.available_locales
|
16
16
|
end
|
17
17
|
|
18
18
|
def enabled?
|
@@ -20,7 +20,7 @@ module Voltron
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def buildable?
|
23
|
-
|
23
|
+
Array.wrap(build_environment).map(&:to_s).include?(Rails.env.to_s)
|
24
24
|
end
|
25
25
|
end
|
26
26
|
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module Voltron
|
2
|
+
module Translatable
|
3
|
+
|
4
|
+
def translates(*attributes)
|
5
|
+
include InstanceMethods
|
6
|
+
|
7
|
+
options = (attributes.extract_options!).with_indifferent_access
|
8
|
+
locales = Array.wrap(options[:locales] || Voltron.config.translate.locales).map(&:to_s).map(&:underscore)
|
9
|
+
|
10
|
+
attributes.each do |attribute|
|
11
|
+
|
12
|
+
column = self.columns_hash[attribute.to_s]
|
13
|
+
|
14
|
+
raise ::ActiveRecord::UnknownAttributeError.new(self.new, attribute) if column.nil?
|
15
|
+
|
16
|
+
raise ::Voltron::Translate::InvalidColumnTypeError.new("Invalid type '#{column.type}' for attribute: #{attribute}. Translations only work on string and text attribute types.") unless [:string, :text].include?(column.type)
|
17
|
+
|
18
|
+
# Override the attribute with a method that accepts a specific locale as an argument
|
19
|
+
# If specified, will attempt to fetch that locale's translation, otherwise the default
|
20
|
+
# locale specified for the attribute, and ultimately the current locale translation
|
21
|
+
# If still nil, returns the value from super
|
22
|
+
define_method :"#{attribute}" do |locale=nil|
|
23
|
+
# +action_view/helpers/targs+ exist when this method is called from within
|
24
|
+
# ActionView::Helpers. In other words, form helper tags. In that
|
25
|
+
# case we want the actual value of the attribute, not whatever the locale is
|
26
|
+
return super() if caller.any? { |l| /action_view\/helpers\/tags/.match(l) } || !Voltron.config.translate.enabled?
|
27
|
+
try(:"#{attribute}_#{locale.to_s.underscore}") || try(:"#{attribute}_#{options[:default].to_s.underscore}") || try(:"#{attribute}_#{I18n.locale.to_s.underscore}") || super()
|
28
|
+
end
|
29
|
+
|
30
|
+
locales.each do |locale|
|
31
|
+
|
32
|
+
# Define setter, i.e. - +attribute_es=+
|
33
|
+
define_method :"#{attribute}_#{locale}=" do |val|
|
34
|
+
attribute_will_change! "#{attribute}_#{locale}"
|
35
|
+
instance_variable_set("@#{attribute}_#{locale}", val)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Define getter, i.e - +attribute_es+
|
39
|
+
# If nil, calling this method will attempt to fetch the value
|
40
|
+
# We do this to avoid preloading the translations association records
|
41
|
+
define_method :"#{attribute}_#{locale}" do
|
42
|
+
if instance_variable_get("@#{attribute}_#{locale}").nil?
|
43
|
+
instance_variable_set("@#{attribute}_#{locale}", send(:"#{attribute}_#{locale}_was"))
|
44
|
+
end
|
45
|
+
instance_variable_get("@#{attribute}_#{locale}")
|
46
|
+
end
|
47
|
+
|
48
|
+
# Define the changed? method, i.e. - +attribute_es_changed?+
|
49
|
+
define_method :"#{attribute}_#{locale}_changed?" do
|
50
|
+
changed.include?("#{attribute}_#{locale}")
|
51
|
+
end
|
52
|
+
|
53
|
+
# Define the was method, i.e. - +attribute_es_was+
|
54
|
+
define_method :"#{attribute}_#{locale}_was" do
|
55
|
+
translations.find_by(attribute_name: attribute, locale: locale).try(:translation)
|
56
|
+
end
|
57
|
+
|
58
|
+
define_method :"#{attribute}_#{locale}_will_change!" do
|
59
|
+
attribute_will_change! "#{attribute}_#{locale}"
|
60
|
+
end
|
61
|
+
|
62
|
+
define_method :"#{attribute}_#{locale}?" do
|
63
|
+
instance_variable_get("@#{attribute}_#{locale}").present?
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# In case +translates+ was called multiple times, merge in the new attributes/locales
|
70
|
+
# with the pre-existing ones
|
71
|
+
all_attributes = @_translations.try(:keys) || []
|
72
|
+
all_attributes += attributes
|
73
|
+
all_attributes.uniq!
|
74
|
+
|
75
|
+
all_locales = @_translations.try(:values) || []
|
76
|
+
all_locales += locales
|
77
|
+
all_locales.flatten!
|
78
|
+
all_locales.uniq!
|
79
|
+
|
80
|
+
has_many :translations, as: :resource, class_name: 'Voltron::Translation', dependent: :destroy
|
81
|
+
|
82
|
+
before_save :build_translations
|
83
|
+
|
84
|
+
accepts_nested_attributes_for :translations, reject_if: :all_blank, allow_destroy: true
|
85
|
+
|
86
|
+
@_translations = all_attributes.map { |a| { a.to_s => all_locales } }.reduce(Hash.new, :merge)
|
87
|
+
end
|
88
|
+
|
89
|
+
module InstanceMethods
|
90
|
+
|
91
|
+
# Before validation, iterate over all possible translation methods
|
92
|
+
# and either update the corresponding translation record or build it,
|
93
|
+
# so it can be saved when the parent record is saved
|
94
|
+
def build_translations
|
95
|
+
self.translations_attributes = translation_methods.map do |m, t|
|
96
|
+
if send(:"#{m}_changed?")
|
97
|
+
# Find the translation if it previously existed, or create new one
|
98
|
+
translation = translations.where(attribute_name: t[:attribute], locale: t[:locale]).first || Voltron::Translation.new(attribute_name: t[:attribute], locale: t[:locale])
|
99
|
+
# Set the translation text on our returned translation object
|
100
|
+
translation.translation = instance_variable_get("@#{m}")
|
101
|
+
# Return the attributes of our translation that will be assigned to self.translations_attributes
|
102
|
+
translation.attributes
|
103
|
+
end
|
104
|
+
end.compact
|
105
|
+
end
|
106
|
+
|
107
|
+
private
|
108
|
+
|
109
|
+
def translate_translations
|
110
|
+
self.class.instance_variable_get('@_translations')
|
111
|
+
end
|
112
|
+
|
113
|
+
def translation_methods
|
114
|
+
translate_translations.map do |attribute, locales|
|
115
|
+
locales.map { |locale| { :"#{attribute}_#{locale}" => { attribute: attribute, locale: locale } } }
|
116
|
+
end.flatten.reduce(Hash.new, :merge)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
@@ -1,12 +1,14 @@
|
|
1
|
-
require 'voltron'
|
2
|
-
|
3
1
|
module Voltron
|
4
2
|
module Translate
|
5
|
-
class
|
3
|
+
class Engine < Rails::Engine
|
4
|
+
|
5
|
+
isolate_namespace Voltron
|
6
|
+
|
6
7
|
initializer 'voltron.translate.initialize' do
|
7
8
|
::ActionController::Base.send :include, ::Voltron::Translate
|
8
9
|
::ActiveRecord::Base.send :include, ::Voltron::Translate
|
9
10
|
::ActiveRecord::Base.send :extend, ::Voltron::Translate
|
11
|
+
::ActiveRecord::Base.send :extend, ::Voltron::Translatable
|
10
12
|
::ActionView::Base.send :include, ::Voltron::Translate
|
11
13
|
::ActionMailer::Base.send :include, ::Voltron::Translate
|
12
14
|
end
|
data/lib/voltron/translate.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'voltron'
|
2
2
|
require 'voltron/translate/version'
|
3
3
|
require 'voltron/config/translate'
|
4
|
+
require 'voltron/translatable'
|
4
5
|
require 'digest'
|
5
6
|
require 'csv'
|
6
7
|
require 'google_hash'
|
@@ -8,6 +9,8 @@ require 'google_hash'
|
|
8
9
|
module Voltron
|
9
10
|
module Translate
|
10
11
|
|
12
|
+
class InvalidColumnTypeError < StandardError; end
|
13
|
+
|
11
14
|
def __(text, locale = I18n.locale, **args)
|
12
15
|
return (text % args) unless Voltron.config.translate.enabled?
|
13
16
|
|
@@ -143,4 +146,4 @@ module Voltron
|
|
143
146
|
end
|
144
147
|
end
|
145
148
|
|
146
|
-
require 'voltron/translate/
|
149
|
+
require 'voltron/translate/engine' if defined?(Rails)
|
data/voltron-translate.gemspec
CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
21
|
spec.add_dependency 'rails', '>= 4.2'
|
22
|
-
spec.add_dependency 'voltron', '
|
22
|
+
spec.add_dependency 'voltron', '~> 0.2.4'
|
23
23
|
spec.add_dependency 'google_hash', '>= 0.9.0'
|
24
24
|
|
25
25
|
spec.add_development_dependency 'bundler', '>= 1.12'
|
@@ -28,4 +28,6 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency 'rspec-rails', '>= 3.4'
|
29
29
|
spec.add_development_dependency 'sqlite3', '>= 1.2'
|
30
30
|
spec.add_development_dependency 'simplecov', '0.11.0'
|
31
|
+
spec.add_development_dependency 'factory_girl_rails', '>= 4.7'
|
32
|
+
spec.add_development_dependency 'byebug'
|
31
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: voltron-translate
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Eric Hainer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: voltron
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.2.
|
33
|
+
version: 0.2.4
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.2.
|
40
|
+
version: 0.2.4
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: google_hash
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -136,6 +136,34 @@ dependencies:
|
|
136
136
|
- - '='
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.11.0
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: factory_girl_rails
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '4.7'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - ">="
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '4.7'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: byebug
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
139
167
|
description:
|
140
168
|
email:
|
141
169
|
- eric@commercekitchen.com
|
@@ -151,12 +179,15 @@ files:
|
|
151
179
|
- LICENSE.txt
|
152
180
|
- README.md
|
153
181
|
- Rakefile
|
182
|
+
- app/models/voltron/translation.rb
|
154
183
|
- bin/console
|
155
184
|
- bin/setup
|
185
|
+
- lib/generators/templates/db/migrate/create_voltron_translations.rb
|
156
186
|
- lib/generators/voltron/translate/install_generator.rb
|
157
187
|
- lib/voltron/config/translate.rb
|
188
|
+
- lib/voltron/translatable.rb
|
158
189
|
- lib/voltron/translate.rb
|
159
|
-
- lib/voltron/translate/
|
190
|
+
- lib/voltron/translate/engine.rb
|
160
191
|
- lib/voltron/translate/version.rb
|
161
192
|
- voltron-translate.gemspec
|
162
193
|
homepage: https://github.com/ehainer/voltron-translate
|