voltron-translate 0.1.6 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|