attr_translate 1.0.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 +7 -0
- data/CHANGELOG.md +4 -0
- data/README.md +83 -0
- data/lib/attr_translate.rb +2 -0
- data/lib/attr_translate/active_record.rb +1 -0
- data/lib/attr_translate/attr_translate.rb +145 -0
- data/lib/attr_translate/translation_attribute.rb +18 -0
- data/lib/attr_translate/version.rb +16 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7d9a44a5c74b80f11fc6c36cc4153bec6f019bb3
|
4
|
+
data.tar.gz: 4716ef9f800a4786ed938a84432ad1c729aba82e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c3a9a0bb4c6b23f8e8571de91eeeb416f5df2b059b5147f617d94f8d0a07cb113b007d78853fbd0a268d51f1ca1a34b4e74e9d82974df639a6b9b3352c1c9d19
|
7
|
+
data.tar.gz: daf05ddcc2a0d73f6e7161b851b9e071a2f88a982cffeb3e5cd81dc9ce401401dd4c4f9be13468763bcde5cbaab12f3b686fbb31be35d62c2011b73ecb491d24
|
data/CHANGELOG.md
ADDED
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
# AttrTranslate
|
2
|
+
|
3
|
+
Rails concern for ActiveRecord attribute translation using PostgreSQL's JSONB datatype.
|
4
|
+
|
5
|
+
AttrTranslate is extracted from the Brightcommerce platform and is used in a number of other software projects.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
To install add the line to your Gemfile:
|
10
|
+
|
11
|
+
``` ruby
|
12
|
+
gem 'attr_translate'
|
13
|
+
```
|
14
|
+
|
15
|
+
And `bundle install`.
|
16
|
+
|
17
|
+
## How To Use
|
18
|
+
|
19
|
+
To add AttrTranslate to a model, include the concern and class method:
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
class Post < ActiveRecord::Base
|
23
|
+
include AttrTranslate
|
24
|
+
|
25
|
+
attr_translate :title, :body
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
For convenience the `attr_translate` class method is aliased internally as `attr_translates`.
|
30
|
+
|
31
|
+
To autoload AttrTranslate for all models, add the following to an initializer:
|
32
|
+
|
33
|
+
``` ruby
|
34
|
+
require 'attr_translate/active_record'
|
35
|
+
```
|
36
|
+
|
37
|
+
You then don't need to `include AttrTranslate` in any model, but you still need to add the `attr_translate` class method.
|
38
|
+
|
39
|
+
### Setup
|
40
|
+
|
41
|
+
Each attribute that will have translations will need to be setup appropriately in your model's migration. Append `_translations` to the column name, and set the column type to `:jsonb`. To aid in search, setup an index using the `gin` index type. Each translation will be stored using the locale as a key in a hash and converted to JSON.
|
42
|
+
|
43
|
+
``` ruby
|
44
|
+
class CreatePosts < ActiveRecord::Migration[5.2]
|
45
|
+
def change
|
46
|
+
create_table :posts do |table|
|
47
|
+
table.column :title_translations, :jsonb, default: {}, index: {using: 'gin'}
|
48
|
+
table.column :body_translations, :jsonb, default: {}, index: {using: 'gin'}
|
49
|
+
table.timestamps
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
54
|
+
|
55
|
+
## Dependencies
|
56
|
+
|
57
|
+
AttrTranslate gem has the following runtime dependencies:
|
58
|
+
- activerecord >= 5.1.4
|
59
|
+
- activesupport >= 5.1.4
|
60
|
+
|
61
|
+
## Compatibility
|
62
|
+
|
63
|
+
Tested with MRI 2.4.2 against Rails 5.2.2.
|
64
|
+
|
65
|
+
## Contributing
|
66
|
+
|
67
|
+
1. Fork it
|
68
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
69
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
70
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
71
|
+
5. Create new Pull Request
|
72
|
+
|
73
|
+
## Credit
|
74
|
+
|
75
|
+
This gem was written and is maintained by [Jurgen Jocubeit](https://github.com/JurgenJocubeit), CEO and President Brightcommerce, Inc.
|
76
|
+
|
77
|
+
## License
|
78
|
+
|
79
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
80
|
+
|
81
|
+
## Copyright
|
82
|
+
|
83
|
+
Copyright 2018 Brightcommerce, Inc.
|
@@ -0,0 +1 @@
|
|
1
|
+
ActiveRecord::Base.send :include, AttrTranslate
|
@@ -0,0 +1,145 @@
|
|
1
|
+
require 'active_support/concern'
|
2
|
+
require_relative './translation_attribute'
|
3
|
+
|
4
|
+
module AttrTranslate
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
class_methods do
|
8
|
+
def attr_translate(*attrs)
|
9
|
+
class_attribute :translated_attribute_names, :permitted_translated_attributes
|
10
|
+
|
11
|
+
self.translated_attribute_names = attrs
|
12
|
+
self.permitted_translated_attributes = [
|
13
|
+
*self.ancestors
|
14
|
+
.select { |klass| klass.respond_to?(:permitted_translated_attributes) }
|
15
|
+
.map(&:permitted_translated_attributes),
|
16
|
+
*attrs.product(I18n.available_locales)
|
17
|
+
.map { |attribute, locale| :"#{attribute}_#{locale}" }
|
18
|
+
].flatten.compact
|
19
|
+
|
20
|
+
attrs.each do |attr_name|
|
21
|
+
define_method attr_name do |**params|
|
22
|
+
read_json_translation(attr_name, params)
|
23
|
+
end
|
24
|
+
|
25
|
+
define_method "#{attr_name}=" do |value|
|
26
|
+
write_json_translation(attr_name, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
define_singleton_method "with_#{attr_name}_translation" do |value, locale = I18n.locale|
|
30
|
+
quoted_translation_store = connection.quote_column_name("#{attr_name}_translations")
|
31
|
+
translation_hash = { "#{locale}" => value }
|
32
|
+
where("#{quoted_translation_store} @> :translation::jsonb", translation: translation_hash.to_json)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
send(:prepend, TranslationAttribute)
|
37
|
+
end
|
38
|
+
alias_method :attr_translates, :attr_translate
|
39
|
+
|
40
|
+
def translates?
|
41
|
+
true
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
def disable_fallback
|
47
|
+
toggle_fallback(false)
|
48
|
+
end
|
49
|
+
|
50
|
+
def enable_fallback
|
51
|
+
toggle_fallback(true)
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
attr_reader :enabled_fallback
|
57
|
+
|
58
|
+
def json_translate_fallback_locales(locale)
|
59
|
+
return locale if enabled_fallback == false || !::I18n.respond_to?(:fallbacks)
|
60
|
+
::I18n.fallbacks[locale]
|
61
|
+
end
|
62
|
+
|
63
|
+
def read_json_translation(attr_name, locale = I18n.locale, **params)
|
64
|
+
translations = public_send("#{attr_name}_translations") || {}
|
65
|
+
|
66
|
+
available = Array(json_translate_fallback_locales(locale)).detect do |available_locale|
|
67
|
+
translations[available_locale.to_s].present?
|
68
|
+
end
|
69
|
+
|
70
|
+
translation = translations[available.to_s]
|
71
|
+
# Rescue from MissingInterpolationArgument
|
72
|
+
# so the default behaviour doesn't change.
|
73
|
+
begin
|
74
|
+
::I18n.interpolate(translation, params) if translation
|
75
|
+
rescue ::I18n::MissingInterpolationArgument
|
76
|
+
translation
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def write_json_translation(attr_name, value, locale = I18n.locale)
|
81
|
+
translation_store = "#{attr_name}_translations"
|
82
|
+
translations = public_send(translation_store) || {}
|
83
|
+
public_send("#{translation_store}_will_change!") unless translations[locale.to_s] == value
|
84
|
+
translations[locale.to_s] = value
|
85
|
+
public_send("#{translation_store}=", translations)
|
86
|
+
value
|
87
|
+
end
|
88
|
+
|
89
|
+
def respond_to_with_translates?(symbol, include_all = false)
|
90
|
+
return true if parse_translated_attribute_accessor(symbol)
|
91
|
+
respond_to_without_translates?(symbol, include_all)
|
92
|
+
end
|
93
|
+
|
94
|
+
def method_missing_with_translates(method_name, *args)
|
95
|
+
translated_attr_name, locale, assigning = parse_translated_attribute_accessor(method_name)
|
96
|
+
|
97
|
+
return method_missing_without_translates(method_name, *args) unless translated_attr_name
|
98
|
+
|
99
|
+
if assigning
|
100
|
+
write_json_translation(translated_attr_name, args.first, locale)
|
101
|
+
else
|
102
|
+
read_json_translation(translated_attr_name, locale)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# Internal: Parse a translated convenience accessor name.
|
107
|
+
#
|
108
|
+
# method_name - The accessor name.
|
109
|
+
#
|
110
|
+
# Examples
|
111
|
+
#
|
112
|
+
# parse_translated_attribute_accessor("title_en=")
|
113
|
+
# # => [:title, :en, true]
|
114
|
+
#
|
115
|
+
# parse_translated_attribute_accessor("title_fr")
|
116
|
+
# # => [:title, :fr, false]
|
117
|
+
#
|
118
|
+
# Returns the attribute name Symbol, locale Symbol, and a Boolean
|
119
|
+
# indicating whether or not the caller is attempting to assign a value.
|
120
|
+
def parse_translated_attribute_accessor(method_name)
|
121
|
+
return unless /\A(?<attribute>[a-z0-9_]+)_(?<locale>[a-z]{2})(?<assignment>=?)\z/ =~ method_name
|
122
|
+
|
123
|
+
translated_attr_name = attribute.to_sym
|
124
|
+
return unless translated_attribute_names.include?(translated_attr_name)
|
125
|
+
|
126
|
+
locale = locale.to_sym
|
127
|
+
assigning = assignment.present?
|
128
|
+
|
129
|
+
[translated_attr_name, locale, assigning]
|
130
|
+
end
|
131
|
+
|
132
|
+
def toggle_fallback(enabled)
|
133
|
+
if block_given?
|
134
|
+
old_value = @enabled_fallback
|
135
|
+
begin
|
136
|
+
@enabled_fallback = enabled
|
137
|
+
yield
|
138
|
+
ensure
|
139
|
+
@enabled_fallback = old_value
|
140
|
+
end
|
141
|
+
else
|
142
|
+
@enabled_fallback = enabled
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module TranslationAttribute
|
2
|
+
def respond_to?(symbol, include_all = false)
|
3
|
+
return true if parse_translated_attribute_accessor(symbol)
|
4
|
+
super(symbol, include_all)
|
5
|
+
end
|
6
|
+
|
7
|
+
def method_missing(method_name, *args, **params)
|
8
|
+
translated_attr_name, locale, assigning = parse_translated_attribute_accessor(method_name)
|
9
|
+
|
10
|
+
return super(method_name, *args, **params) unless translated_attr_name
|
11
|
+
|
12
|
+
if assigning
|
13
|
+
write_json_translation(translated_attr_name, args.first, locale)
|
14
|
+
else
|
15
|
+
read_json_translation(translated_attr_name, locale, **params)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module AttrTranslate
|
2
|
+
module Version
|
3
|
+
Major = 1
|
4
|
+
Minor = 0
|
5
|
+
Revision = 0
|
6
|
+
Prerelease = nil
|
7
|
+
Compact = [Major, Minor, Revision, Prerelease].compact.join('.')
|
8
|
+
Summary = "AttrTranslate v#{Compact}"
|
9
|
+
Description = "Provides scopes for finding published, unpublished and returning recent or upcoming items."
|
10
|
+
Author = "Jurgen Jocubeit"
|
11
|
+
Email = "support@brightcommerce.com"
|
12
|
+
Homepage = "https://github.com/brightcommerce/attr_translate"
|
13
|
+
Metadata = {'copyright' => 'Copyright 2018 Brightcommerce, Inc. All Rights Reserved.'}
|
14
|
+
License = "MIT"
|
15
|
+
end
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: attr_translate
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jurgen Jocubeit
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-12-24 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activerecord
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 5.1.4
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 5.1.4
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 5.1.4
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 5.1.4
|
41
|
+
description: Provides scopes for finding published, unpublished and returning recent
|
42
|
+
or upcoming items.
|
43
|
+
email: support@brightcommerce.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- CHANGELOG.md
|
49
|
+
- README.md
|
50
|
+
- lib/attr_translate.rb
|
51
|
+
- lib/attr_translate/active_record.rb
|
52
|
+
- lib/attr_translate/attr_translate.rb
|
53
|
+
- lib/attr_translate/translation_attribute.rb
|
54
|
+
- lib/attr_translate/version.rb
|
55
|
+
homepage: https://github.com/brightcommerce/attr_translate
|
56
|
+
licenses:
|
57
|
+
- MIT
|
58
|
+
metadata:
|
59
|
+
copyright: Copyright 2018 Brightcommerce, Inc. All Rights Reserved.
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
require_paths:
|
63
|
+
- lib
|
64
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.3'
|
69
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: '0'
|
74
|
+
requirements: []
|
75
|
+
rubyforge_project:
|
76
|
+
rubygems_version: 2.6.13
|
77
|
+
signing_key:
|
78
|
+
specification_version: 4
|
79
|
+
summary: AttrTranslate v1.0.0
|
80
|
+
test_files: []
|