mobility 0.2.3 → 0.3.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
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +16 -0
- data/Gemfile +6 -1
- data/Gemfile.lock +59 -57
- data/README.md +63 -18
- data/lib/mobility.rb +0 -1
- data/lib/mobility/active_record.rb +0 -1
- data/lib/mobility/active_record/translation.rb +1 -1
- data/lib/mobility/attributes.rb +22 -11
- data/lib/mobility/backends/active_record/table.rb +13 -1
- data/lib/mobility/configuration.rb +24 -3
- data/lib/mobility/plugins/active_model/dirty.rb +19 -1
- data/lib/mobility/plugins/active_record/attribute_methods.rb +39 -0
- data/lib/mobility/plugins/active_record/dirty.rb +77 -12
- data/lib/mobility/plugins/attribute_methods.rb +41 -0
- data/lib/mobility/plugins/dirty.rb +1 -5
- data/lib/mobility/plugins/fallbacks.rb +44 -19
- data/lib/mobility/plugins/fallthrough_accessors.rb +2 -2
- data/lib/mobility/plugins/locale_accessors.rb +6 -6
- data/lib/mobility/version.rb +1 -1
- metadata +14 -7
- metadata.gz.sig +0 -0
- data/lib/mobility/active_record/attribute_methods.rb +0 -36
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c134f78117865e131baf9ceecb0c902cb63abb08
|
|
4
|
+
data.tar.gz: 2076ecc0e3164b962d1f5147e0af81d2ba9baac3
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6ec9f5003e16ace7ea7a77136266af20f5c86beb1ebea6ae4e83598d20bdf4d14971d6f029c2b1bd74763c599287e362b7b3204c51660606ab2b371a4620842
|
|
7
|
+
data.tar.gz: 8eae38b70cb15cb0eeec7dfb51f72e4076268312bdd73d63a9fda7611414d116e5bd95771a3042ca080ea4495c335e50a66f5c92a1beb6994e2d1d8d4c9d3bb9
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data.tar.gz.sig
CHANGED
|
Binary file
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Mobility Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3
|
|
4
|
+
|
|
5
|
+
### 0.3.0 (November 30, 2017)
|
|
6
|
+
* `dup` support for table backend ([#84](https://github.com/shioyama/mobility/pull/84)). Thanks [@pwim](https://github.com/pwim)!
|
|
7
|
+
* Disable fallbacks when using locale/fallthrough accessors
|
|
8
|
+
([#86](https://github.com/shioyama/mobility/pull/86), [#87](https://github.com/shioyama/mobility/pull/87),
|
|
9
|
+
[#88](https://github.com/shioyama/mobility/pull/88), [#89](https://github.com/shioyama/mobility/pull/89))
|
|
10
|
+
* Convert AttributeMethods to plugin
|
|
11
|
+
([#102](https://github.com/shioyama/mobility/pull/102))
|
|
12
|
+
* Ensure `cache_key` is invalidated when updating translations
|
|
13
|
+
([#104](https://github.com/shioyama/mobility/pull/102)) Thanks
|
|
14
|
+
[@pwim](https://github.com/pwim)!
|
|
15
|
+
* Update dependency versions ([#107](https://github.com/shioyama/mobility/pull/107))
|
|
16
|
+
* Support new AR::Dirty methods ([#111](https://github.com/shioyama/mobility/pull/111))
|
|
17
|
+
* Use `public_send` in LocaleAccessors plugin ([#117](https://github.com/shioyama/mobility/pull/117))
|
|
18
|
+
|
|
3
19
|
## 0.2
|
|
4
20
|
|
|
5
21
|
### 0.2.3 (September 14, 2017)
|
data/Gemfile
CHANGED
|
@@ -9,6 +9,9 @@ group :development, :test do
|
|
|
9
9
|
gem 'activerecord', '>= 5.0', '< 5.1'
|
|
10
10
|
elsif ENV['RAILS_VERSION'] == '4.2'
|
|
11
11
|
gem 'activerecord', '>= 4.2.6', '< 5.0'
|
|
12
|
+
elsif ENV['RAILS_VERSION'] == '5.2'
|
|
13
|
+
gem 'activerecord', '>= 5.2.0.beta1'
|
|
14
|
+
gem 'railties', '>= 5.2.0.beta1'
|
|
12
15
|
else
|
|
13
16
|
gem 'activerecord', '>= 5.1', '< 5.2'
|
|
14
17
|
end
|
|
@@ -16,6 +19,8 @@ group :development, :test do
|
|
|
16
19
|
elsif ENV['ORM'] == 'sequel'
|
|
17
20
|
if ENV['SEQUEL_VERSION'] == '4.41'
|
|
18
21
|
gem 'sequel', '>= 4.41.0', '< 4.46.0'
|
|
22
|
+
elsif ENV['SEQUEL_VERSION'] == 'latest'
|
|
23
|
+
gem 'sequel', '>= 5.0.0'
|
|
19
24
|
else
|
|
20
25
|
gem 'sequel', '>= 4.46.0', '< 5.0'
|
|
21
26
|
end
|
|
@@ -27,7 +32,7 @@ group :development, :test do
|
|
|
27
32
|
gem 'guard-rspec'
|
|
28
33
|
gem 'pry-byebug'
|
|
29
34
|
gem 'sqlite3'
|
|
30
|
-
gem 'mysql2', '~> 0.
|
|
35
|
+
gem 'mysql2', '~> 0.4.9'
|
|
31
36
|
gem 'pg'
|
|
32
37
|
end
|
|
33
38
|
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,45 +1,46 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
mobility (0.
|
|
5
|
-
i18n (>= 0.6.10, < 0.
|
|
4
|
+
mobility (0.3.0.pre.alpha)
|
|
5
|
+
i18n (>= 0.6.10, < 0.10)
|
|
6
6
|
request_store (~> 1.0)
|
|
7
7
|
|
|
8
8
|
GEM
|
|
9
9
|
remote: https://rubygems.org/
|
|
10
10
|
specs:
|
|
11
|
-
actionpack (5.
|
|
12
|
-
actionview (= 5.
|
|
13
|
-
activesupport (= 5.
|
|
11
|
+
actionpack (5.2.0.beta2)
|
|
12
|
+
actionview (= 5.2.0.beta2)
|
|
13
|
+
activesupport (= 5.2.0.beta2)
|
|
14
14
|
rack (~> 2.0)
|
|
15
|
-
rack-test (
|
|
15
|
+
rack-test (>= 0.6.3)
|
|
16
16
|
rails-dom-testing (~> 2.0)
|
|
17
17
|
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
18
|
-
actionview (5.
|
|
19
|
-
activesupport (= 5.
|
|
18
|
+
actionview (5.2.0.beta2)
|
|
19
|
+
activesupport (= 5.2.0.beta2)
|
|
20
20
|
builder (~> 3.1)
|
|
21
21
|
erubi (~> 1.4)
|
|
22
22
|
rails-dom-testing (~> 2.0)
|
|
23
23
|
rails-html-sanitizer (~> 1.0, >= 1.0.3)
|
|
24
|
-
activemodel (5.
|
|
25
|
-
activesupport (= 5.
|
|
26
|
-
activerecord (5.
|
|
27
|
-
activemodel (= 5.
|
|
28
|
-
activesupport (= 5.
|
|
29
|
-
arel (
|
|
30
|
-
activesupport (5.
|
|
24
|
+
activemodel (5.2.0.beta2)
|
|
25
|
+
activesupport (= 5.2.0.beta2)
|
|
26
|
+
activerecord (5.2.0.beta2)
|
|
27
|
+
activemodel (= 5.2.0.beta2)
|
|
28
|
+
activesupport (= 5.2.0.beta2)
|
|
29
|
+
arel (>= 9.0)
|
|
30
|
+
activesupport (5.2.0.beta2)
|
|
31
31
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
|
32
32
|
i18n (~> 0.7)
|
|
33
33
|
minitest (~> 5.1)
|
|
34
34
|
tzinfo (~> 1.1)
|
|
35
|
-
arel (
|
|
35
|
+
arel (9.0.0)
|
|
36
36
|
builder (3.2.3)
|
|
37
|
-
byebug (9.0
|
|
38
|
-
coderay (1.1.
|
|
37
|
+
byebug (9.1.0)
|
|
38
|
+
coderay (1.1.2)
|
|
39
39
|
concurrent-ruby (1.0.5)
|
|
40
|
-
|
|
40
|
+
crass (1.0.3)
|
|
41
|
+
database_cleaner (1.6.2)
|
|
41
42
|
diff-lcs (1.3)
|
|
42
|
-
erubi (1.
|
|
43
|
+
erubi (1.7.0)
|
|
43
44
|
ffi (1.9.18)
|
|
44
45
|
formatador (0.2.5)
|
|
45
46
|
generator_spec (0.9.4)
|
|
@@ -59,91 +60,92 @@ GEM
|
|
|
59
60
|
guard (~> 2.1)
|
|
60
61
|
guard-compat (~> 1.1)
|
|
61
62
|
rspec (>= 2.99.0, < 4.0)
|
|
62
|
-
i18n (0.
|
|
63
|
+
i18n (0.9.1)
|
|
64
|
+
concurrent-ruby (~> 1.0)
|
|
63
65
|
listen (3.1.5)
|
|
64
66
|
rb-fsevent (~> 0.9, >= 0.9.4)
|
|
65
67
|
rb-inotify (~> 0.9, >= 0.9.7)
|
|
66
68
|
ruby_dep (~> 1.2)
|
|
67
|
-
loofah (2.
|
|
69
|
+
loofah (2.1.1)
|
|
70
|
+
crass (~> 1.0.2)
|
|
68
71
|
nokogiri (>= 1.5.9)
|
|
69
72
|
lumberjack (1.0.12)
|
|
70
|
-
method_source (0.
|
|
71
|
-
mini_portile2 (2.
|
|
73
|
+
method_source (0.9.0)
|
|
74
|
+
mini_portile2 (2.3.0)
|
|
72
75
|
minitest (5.10.3)
|
|
73
|
-
mysql2 (0.
|
|
76
|
+
mysql2 (0.4.10)
|
|
74
77
|
nenv (0.3.0)
|
|
75
|
-
nokogiri (1.8.
|
|
76
|
-
mini_portile2 (~> 2.
|
|
78
|
+
nokogiri (1.8.1)
|
|
79
|
+
mini_portile2 (~> 2.3.0)
|
|
77
80
|
notiffany (0.1.1)
|
|
78
81
|
nenv (~> 0.1)
|
|
79
82
|
shellany (~> 0.0)
|
|
80
83
|
pg (0.21.0)
|
|
81
|
-
pry (0.
|
|
84
|
+
pry (0.11.3)
|
|
82
85
|
coderay (~> 1.1.0)
|
|
83
|
-
method_source (~> 0.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
byebug (~> 9.0)
|
|
86
|
+
method_source (~> 0.9.0)
|
|
87
|
+
pry-byebug (3.5.1)
|
|
88
|
+
byebug (~> 9.1)
|
|
87
89
|
pry (~> 0.10)
|
|
88
90
|
rack (2.0.3)
|
|
89
|
-
rack-test (0.
|
|
90
|
-
rack (>= 1.0)
|
|
91
|
+
rack-test (0.8.2)
|
|
92
|
+
rack (>= 1.0, < 3)
|
|
91
93
|
rails-dom-testing (2.0.3)
|
|
92
94
|
activesupport (>= 4.2.0)
|
|
93
95
|
nokogiri (>= 1.6)
|
|
94
96
|
rails-html-sanitizer (1.0.3)
|
|
95
97
|
loofah (~> 2.0)
|
|
96
|
-
railties (5.
|
|
97
|
-
actionpack (= 5.
|
|
98
|
-
activesupport (= 5.
|
|
98
|
+
railties (5.2.0.beta2)
|
|
99
|
+
actionpack (= 5.2.0.beta2)
|
|
100
|
+
activesupport (= 5.2.0.beta2)
|
|
99
101
|
method_source
|
|
100
102
|
rake (>= 0.8.7)
|
|
101
103
|
thor (>= 0.18.1, < 2.0)
|
|
102
|
-
rake (
|
|
104
|
+
rake (12.3.0)
|
|
103
105
|
rb-fsevent (0.10.2)
|
|
104
106
|
rb-inotify (0.9.10)
|
|
105
107
|
ffi (>= 0.5.0, < 2)
|
|
106
108
|
request_store (1.3.2)
|
|
107
|
-
rspec (3.
|
|
108
|
-
rspec-core (~> 3.
|
|
109
|
-
rspec-expectations (~> 3.
|
|
110
|
-
rspec-mocks (~> 3.
|
|
111
|
-
rspec-core (3.
|
|
112
|
-
rspec-support (~> 3.
|
|
113
|
-
rspec-expectations (3.
|
|
109
|
+
rspec (3.7.0)
|
|
110
|
+
rspec-core (~> 3.7.0)
|
|
111
|
+
rspec-expectations (~> 3.7.0)
|
|
112
|
+
rspec-mocks (~> 3.7.0)
|
|
113
|
+
rspec-core (3.7.0)
|
|
114
|
+
rspec-support (~> 3.7.0)
|
|
115
|
+
rspec-expectations (3.7.0)
|
|
114
116
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
115
|
-
rspec-support (~> 3.
|
|
116
|
-
rspec-mocks (3.
|
|
117
|
+
rspec-support (~> 3.7.0)
|
|
118
|
+
rspec-mocks (3.7.0)
|
|
117
119
|
diff-lcs (>= 1.2.0, < 2.0)
|
|
118
|
-
rspec-support (~> 3.
|
|
119
|
-
rspec-support (3.
|
|
120
|
+
rspec-support (~> 3.7.0)
|
|
121
|
+
rspec-support (3.7.0)
|
|
120
122
|
ruby_dep (1.5.0)
|
|
121
123
|
shellany (0.0.1)
|
|
122
|
-
slop (3.6.0)
|
|
123
124
|
sqlite3 (1.3.13)
|
|
124
|
-
thor (0.
|
|
125
|
+
thor (0.20.0)
|
|
125
126
|
thread_safe (0.3.6)
|
|
126
|
-
tzinfo (1.2.
|
|
127
|
+
tzinfo (1.2.4)
|
|
127
128
|
thread_safe (~> 0.1)
|
|
128
|
-
yard (0.9.
|
|
129
|
+
yard (0.9.12)
|
|
129
130
|
|
|
130
131
|
PLATFORMS
|
|
131
132
|
ruby
|
|
132
133
|
|
|
133
134
|
DEPENDENCIES
|
|
134
|
-
activerecord (>= 5.
|
|
135
|
+
activerecord (>= 5.2.0.beta1)
|
|
135
136
|
bundler (~> 1.12)
|
|
136
137
|
database_cleaner (~> 1.5, >= 1.5.3)
|
|
137
138
|
generator_spec (~> 0.9.4)
|
|
138
139
|
guard-rspec
|
|
139
140
|
mobility!
|
|
140
|
-
mysql2 (~> 0.
|
|
141
|
+
mysql2 (~> 0.4.9)
|
|
141
142
|
pg
|
|
142
143
|
pry-byebug
|
|
143
|
-
|
|
144
|
+
railties (>= 5.2.0.beta1)
|
|
145
|
+
rake (~> 12, >= 12.2.1)
|
|
144
146
|
rspec (~> 3.0)
|
|
145
147
|
sqlite3
|
|
146
148
|
yard (~> 0.9.0)
|
|
147
149
|
|
|
148
150
|
BUNDLED WITH
|
|
149
|
-
1.
|
|
151
|
+
1.16.0.pre.2
|
data/README.md
CHANGED
|
@@ -16,7 +16,8 @@ Mobility
|
|
|
16
16
|
Mobility is a gem for storing and retrieving translations as attributes on a
|
|
17
17
|
class. These translations could be the content of blog posts, captions on
|
|
18
18
|
images, tags on bookmarks, or anything else you might want to store in
|
|
19
|
-
different languages.
|
|
19
|
+
different languages. For examples of what Mobility can do, see the
|
|
20
|
+
<a href="#companies-using-mobility">Companies using Mobility</a> section below.
|
|
20
21
|
|
|
21
22
|
Storage of translations is handled by customizable "backends" which encapsulate
|
|
22
23
|
different storage strategies. The default, preferred way to store translations
|
|
@@ -41,13 +42,17 @@ Mobility](http://dejimata.com/2017/3/3/translating-with-mobility). See also the
|
|
|
41
42
|
works for future releases, and other pages of the [wiki][wiki] for more detail
|
|
42
43
|
on usage.
|
|
43
44
|
|
|
45
|
+
If you're coming from Globalize, be sure to also read the [Migrating from
|
|
46
|
+
Globalize](https://github.com/shioyama/mobility/wiki/Migrating-from-Globalize)
|
|
47
|
+
section of the wiki.
|
|
48
|
+
|
|
44
49
|
Installation
|
|
45
50
|
------------
|
|
46
51
|
|
|
47
52
|
Add this line to your application's Gemfile:
|
|
48
53
|
|
|
49
54
|
```ruby
|
|
50
|
-
gem 'mobility', '~> 0.
|
|
55
|
+
gem 'mobility', '~> 0.3.0'
|
|
51
56
|
```
|
|
52
57
|
|
|
53
58
|
Mobility is cryptographically signed. To be sure the gem you install hasn't
|
|
@@ -104,7 +109,7 @@ See [Getting Started](#quickstart) to get started translating your models.
|
|
|
104
109
|
### Sequel
|
|
105
110
|
|
|
106
111
|
Requirements:
|
|
107
|
-
- Sequel >= 4.0
|
|
112
|
+
- Sequel >= 4.0, < 5.0 (5.0 support is in the works)
|
|
108
113
|
|
|
109
114
|
You can extend `Mobility` just like in ActiveRecord, or you can use the
|
|
110
115
|
`mobility` plugin, which does the same thing:
|
|
@@ -222,7 +227,7 @@ locations, usually database columns. By default these values are stored as keys
|
|
|
222
227
|
tables, one for strings and one for text columns, but this can be easily
|
|
223
228
|
changed and/or customized (see the [Backends](#backends) section below).
|
|
224
229
|
|
|
225
|
-
### Getting and Setting Translations
|
|
230
|
+
### <a name="getset"></a> Getting and Setting Translations
|
|
226
231
|
|
|
227
232
|
The easiest way to get or set a translation is to use the getter and setter
|
|
228
233
|
methods described above (`word.name` and `word.name=`), but you may want to
|
|
@@ -309,6 +314,11 @@ word.name(locale: :fr)
|
|
|
309
314
|
#=> "mobilité"
|
|
310
315
|
```
|
|
311
316
|
|
|
317
|
+
Note that setting the locale this way will pass an option `locale: true` to the
|
|
318
|
+
backend and all plugins. Plugins may use this option to change their behavior
|
|
319
|
+
(passing the locale explicitly this way, for example, disables
|
|
320
|
+
[fallbacks](#fallbacks), see below for details).
|
|
321
|
+
|
|
312
322
|
You can also *set* the value of an attribute this way; however, since the
|
|
313
323
|
`word.name = <value>` syntax does not accept any options, the only way to do this is to
|
|
314
324
|
use `send` (this is included mostly for consistency):
|
|
@@ -387,8 +397,8 @@ translated attributes on a class:
|
|
|
387
397
|
```ruby
|
|
388
398
|
class Word < ApplicationRecord
|
|
389
399
|
extend Mobility
|
|
390
|
-
translates :name, type: :string, fallbacks: { de: :ja, fr: :ja }
|
|
391
|
-
translates :meaning, type: :text, fallbacks: { de: :ja, fr: :ja }
|
|
400
|
+
translates :name, type: :string, fallbacks: { de: :ja, fr: :ja }, locale_accessors: true
|
|
401
|
+
translates :meaning, type: :text, fallbacks: { de: :ja, fr: :ja }, locale_accessors: true
|
|
392
402
|
end
|
|
393
403
|
```
|
|
394
404
|
|
|
@@ -404,17 +414,20 @@ but not for other locales:
|
|
|
404
414
|
```ruby
|
|
405
415
|
Mobility.locale = :ja
|
|
406
416
|
word = Word.create(name: "モビリティ", meaning: "(名詞):動きやすさ、可動性")
|
|
407
|
-
|
|
417
|
+
Mobility.locale = :de
|
|
418
|
+
word.name
|
|
408
419
|
#=> "モビリティ"
|
|
409
|
-
word.meaning
|
|
420
|
+
word.meaning
|
|
410
421
|
#=> "(名詞):動きやすさ、可動性"
|
|
411
|
-
|
|
422
|
+
Mobility.locale = :fr
|
|
423
|
+
word.name
|
|
412
424
|
#=> "モビリティ"
|
|
413
|
-
word.meaning
|
|
425
|
+
word.meaning
|
|
414
426
|
#=> "(名詞):動きやすさ、可動性"
|
|
415
|
-
|
|
427
|
+
Mobility.locale = :ru
|
|
428
|
+
word.name
|
|
416
429
|
#=> nil
|
|
417
|
-
word.meaning
|
|
430
|
+
word.meaning
|
|
418
431
|
#=> nil
|
|
419
432
|
```
|
|
420
433
|
|
|
@@ -423,11 +436,14 @@ You can optionally disable fallbacks to get the real value for a given locale
|
|
|
423
436
|
passing `fallback: false` (*singular*, not plural) to the getter method:
|
|
424
437
|
|
|
425
438
|
```ruby
|
|
426
|
-
|
|
439
|
+
Mobility.locale = :de
|
|
440
|
+
word.meaning(fallback: false)
|
|
427
441
|
#=> nil
|
|
428
|
-
|
|
442
|
+
Mobility.locale = :fr
|
|
443
|
+
word.meaning(fallback: false)
|
|
429
444
|
#=> nil
|
|
430
|
-
|
|
445
|
+
Mobility.locale = :ja
|
|
446
|
+
word.meaning(fallback: false)
|
|
431
447
|
#=> "(名詞):動きやすさ、可動性"
|
|
432
448
|
```
|
|
433
449
|
|
|
@@ -439,11 +455,28 @@ Mobility.with_locale(:fr) do
|
|
|
439
455
|
word.meaning = "(nf): aptitude à bouger, à se déplacer, à changer, à évoluer"
|
|
440
456
|
end
|
|
441
457
|
word.save
|
|
442
|
-
|
|
458
|
+
Mobility.locale = :de
|
|
459
|
+
word.meaning(fallback: false)
|
|
443
460
|
#=> nil
|
|
444
|
-
word.meaning(
|
|
461
|
+
word.meaning(fallback: :fr)
|
|
445
462
|
#=> "(nf): aptitude à bouger, à se déplacer, à changer, à évoluer"
|
|
446
|
-
word.meaning(
|
|
463
|
+
word.meaning(fallback: [:ja, :fr])
|
|
464
|
+
#=> "(名詞):動きやすさ、可動性"
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
Also note that passing a `locale` option into an attribute reader or writer, or
|
|
468
|
+
using [locale accessors or fallthrough accessors](#getset) to get or set
|
|
469
|
+
any attribute value, will disable fallbacks (just like `fallback: false`).
|
|
470
|
+
(This will take precedence over any value of the `fallback` option.)
|
|
471
|
+
|
|
472
|
+
Continuing from the last example:
|
|
473
|
+
|
|
474
|
+
```ruby
|
|
475
|
+
word.meaning(locale: :de)
|
|
476
|
+
#=> nil
|
|
477
|
+
word.meaning_de
|
|
478
|
+
#=> nil
|
|
479
|
+
Mobility.with_locale(:de) { word.meaning }
|
|
447
480
|
#=> "(名詞):動きやすさ、可動性"
|
|
448
481
|
```
|
|
449
482
|
|
|
@@ -830,6 +863,18 @@ More Information
|
|
|
830
863
|
- [API documentation][docs]
|
|
831
864
|
- [Wiki][wiki]
|
|
832
865
|
|
|
866
|
+
<a name="#companies-using-mobility"></a>Companies using Mobility
|
|
867
|
+
------------------------
|
|
868
|
+
|
|
869
|
+
<img alt="Logos of companies using Mobility" src="./img/companies-using-mobility.png" style="width: 100%" />
|
|
870
|
+
|
|
871
|
+
- [Doorkeeper](https://www.doorkeeper.jp/)
|
|
872
|
+
- [Oreegano](https://www.oreegano.com/)
|
|
873
|
+
- [Venuu](https://venuu.fi)
|
|
874
|
+
- ... <sup>✱</sup>
|
|
875
|
+
|
|
876
|
+
<sup>✱</sup> <small>Post an issue or email me to add your company's name to this list.</small>
|
|
877
|
+
|
|
833
878
|
License
|
|
834
879
|
-------
|
|
835
880
|
|
data/lib/mobility.rb
CHANGED
|
@@ -89,7 +89,6 @@ module Mobility
|
|
|
89
89
|
|
|
90
90
|
if Loaded::ActiveRecord
|
|
91
91
|
model_class.include(ActiveRecord) if model_class < ::ActiveRecord::Base
|
|
92
|
-
model_class.include(ActiveRecord::AttributeMethods) if model_class.ancestors.include?(::ActiveRecord::AttributeMethods)
|
|
93
92
|
end
|
|
94
93
|
|
|
95
94
|
if Loaded::Sequel
|
|
@@ -4,7 +4,7 @@ module Mobility
|
|
|
4
4
|
class Translation < ::ActiveRecord::Base
|
|
5
5
|
self.abstract_class = true
|
|
6
6
|
|
|
7
|
-
belongs_to :translatable, polymorphic: true
|
|
7
|
+
belongs_to :translatable, polymorphic: true, touch: true
|
|
8
8
|
|
|
9
9
|
validates :key, presence: true, uniqueness: { scope: [:translatable_id, :translatable_type, :locale] }
|
|
10
10
|
validates :translatable, presence: true
|
data/lib/mobility/attributes.rb
CHANGED
|
@@ -19,7 +19,7 @@ like including a module. Creating an instance like this:
|
|
|
19
19
|
|
|
20
20
|
Attributes.new("title", backend: :my_backend, locale_accessors: [:en, :ja], cache: true, fallbacks: true)
|
|
21
21
|
|
|
22
|
-
will generate an anonymous module that behaves like this:
|
|
22
|
+
will generate an anonymous module that behaves (approximately) like this:
|
|
23
23
|
|
|
24
24
|
Module.new do
|
|
25
25
|
def title_backend
|
|
@@ -131,7 +131,7 @@ with other backends.
|
|
|
131
131
|
def initialize(*attribute_names, method: :accessor, backend: Mobility.default_backend, **backend_options)
|
|
132
132
|
raise ArgumentError, "method must be one of: reader, writer, accessor" unless %i[reader writer accessor].include?(method)
|
|
133
133
|
@method = method
|
|
134
|
-
@options = Mobility.default_options.merge(backend_options)
|
|
134
|
+
@options = Mobility.default_options.to_h.merge(backend_options)
|
|
135
135
|
@names = attribute_names.map(&:to_s)
|
|
136
136
|
raise Mobility::BackendRequired, "Backend option required if Mobility.config.default_backend is not set." if backend.nil?
|
|
137
137
|
@backend_name = backend
|
|
@@ -168,6 +168,17 @@ with other backends.
|
|
|
168
168
|
names.each(&block)
|
|
169
169
|
end
|
|
170
170
|
|
|
171
|
+
# Process options passed into accessor method before calling backend, and
|
|
172
|
+
# return locale
|
|
173
|
+
# @param [Hash] options Options hash passed to accessor method
|
|
174
|
+
# @return [Symbol] locale
|
|
175
|
+
def self.process_options!(options)
|
|
176
|
+
(options[:locale] || Mobility.locale).tap { |locale|
|
|
177
|
+
Mobility.enforce_available_locales!(locale)
|
|
178
|
+
options[:locale] &&= !!locale
|
|
179
|
+
}.to_sym
|
|
180
|
+
end
|
|
181
|
+
|
|
171
182
|
private
|
|
172
183
|
|
|
173
184
|
def define_backend(attribute)
|
|
@@ -179,24 +190,24 @@ with other backends.
|
|
|
179
190
|
end
|
|
180
191
|
|
|
181
192
|
def define_reader(attribute)
|
|
182
|
-
define_method attribute do
|
|
193
|
+
define_method attribute do |**options|
|
|
183
194
|
return super() if options.delete(:super)
|
|
184
|
-
Mobility.
|
|
185
|
-
mobility_backend_for(attribute).read(locale
|
|
195
|
+
locale = Mobility::Attributes.process_options!(options)
|
|
196
|
+
mobility_backend_for(attribute).read(locale, options)
|
|
186
197
|
end
|
|
187
198
|
|
|
188
|
-
define_method "#{attribute}?" do
|
|
199
|
+
define_method "#{attribute}?" do |**options|
|
|
189
200
|
return super() if options.delete(:super)
|
|
190
|
-
Mobility.
|
|
191
|
-
mobility_backend_for(attribute).present?(locale
|
|
201
|
+
locale = Mobility::Attributes.process_options!(options)
|
|
202
|
+
mobility_backend_for(attribute).present?(locale, options)
|
|
192
203
|
end
|
|
193
204
|
end
|
|
194
205
|
|
|
195
206
|
def define_writer(attribute)
|
|
196
|
-
define_method "#{attribute}=" do |value,
|
|
207
|
+
define_method "#{attribute}=" do |value, **options|
|
|
197
208
|
return super(value) if options.delete(:super)
|
|
198
|
-
Mobility.
|
|
199
|
-
mobility_backend_for(attribute).write(locale
|
|
209
|
+
locale = Mobility::Attributes.process_options!(options)
|
|
210
|
+
mobility_backend_for(attribute).write(locale, value, options)
|
|
200
211
|
end
|
|
201
212
|
end
|
|
202
213
|
|
|
@@ -136,7 +136,19 @@ columns to that table.
|
|
|
136
136
|
translation_class.belongs_to :translated_model,
|
|
137
137
|
class_name: name,
|
|
138
138
|
foreign_key: options[:foreign_key],
|
|
139
|
-
inverse_of: association_name
|
|
139
|
+
inverse_of: association_name,
|
|
140
|
+
touch: true
|
|
141
|
+
|
|
142
|
+
module_name = "MobilityArTable#{association_name.to_s.camelcase}"
|
|
143
|
+
unless const_defined?(module_name)
|
|
144
|
+
callback_methods = Module.new do
|
|
145
|
+
define_method :initialize_dup do |source|
|
|
146
|
+
super(source)
|
|
147
|
+
self.send("#{association_name}=", source.send(association_name).map(&:dup))
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
include const_set(module_name, callback_methods)
|
|
151
|
+
end
|
|
140
152
|
end
|
|
141
153
|
|
|
142
154
|
setup_query_methods(QueryMethods)
|
|
@@ -20,7 +20,17 @@ Stores shared Mobility configuration referenced by all backends.
|
|
|
20
20
|
# may not include the keys 'backend' or 'model_class'.
|
|
21
21
|
# @return [Hash]
|
|
22
22
|
attr_reader :default_options
|
|
23
|
+
|
|
24
|
+
# @deprecated The default_options= setter has been deprecated. Set each
|
|
25
|
+
# option on the default_options hash instead.
|
|
23
26
|
def default_options=(options)
|
|
27
|
+
warn %{
|
|
28
|
+
WARNING: The default_options= setter has been deprecated.
|
|
29
|
+
Set each option on the default_options hash instead, like this:
|
|
30
|
+
|
|
31
|
+
config.default_options[:fallbacks] = { ... }
|
|
32
|
+
config.default_options[:dirty] = true
|
|
33
|
+
}
|
|
24
34
|
if (keys = options.keys & RESERVED_OPTION_KEYS).present?
|
|
25
35
|
raise ReservedOptionKey,
|
|
26
36
|
"Default options may not contain the following reserved keys: #{keys.join(', ')}"
|
|
@@ -63,24 +73,35 @@ Stores shared Mobility configuration referenced by all backends.
|
|
|
63
73
|
@query_method = :i18n
|
|
64
74
|
@default_fallbacks = lambda { |fallbacks| I18n::Locale::Fallbacks.new(fallbacks) }
|
|
65
75
|
@default_accessor_locales = lambda { I18n.available_locales }
|
|
66
|
-
@default_options = {
|
|
76
|
+
@default_options = Options[{
|
|
67
77
|
cache: true,
|
|
68
78
|
dirty: false,
|
|
69
79
|
fallbacks: nil,
|
|
70
80
|
presence: true,
|
|
71
|
-
default: nil
|
|
72
|
-
|
|
81
|
+
default: nil,
|
|
82
|
+
attribute_methods: false
|
|
83
|
+
}]
|
|
73
84
|
@plugins = %i[
|
|
74
85
|
cache
|
|
75
86
|
dirty
|
|
76
87
|
fallbacks
|
|
77
88
|
presence
|
|
78
89
|
default
|
|
90
|
+
attribute_methods
|
|
79
91
|
fallthrough_accessors
|
|
80
92
|
locale_accessors
|
|
81
93
|
]
|
|
82
94
|
end
|
|
83
95
|
|
|
84
96
|
class ReservedOptionKey < Exception; end
|
|
97
|
+
|
|
98
|
+
class Options < Hash
|
|
99
|
+
def []=(key, _)
|
|
100
|
+
if RESERVED_OPTION_KEYS.include?(key)
|
|
101
|
+
raise Configuration::ReservedOptionKey, "Default options may not contain the following reserved key: #{key}"
|
|
102
|
+
end
|
|
103
|
+
super
|
|
104
|
+
end
|
|
105
|
+
end
|
|
85
106
|
end
|
|
86
107
|
end
|
|
@@ -30,8 +30,9 @@ value of the translated attribute if passed to it.
|
|
|
30
30
|
def write(locale, value, options = {})
|
|
31
31
|
locale_accessor = Mobility.normalize_locale_accessor(attribute, locale)
|
|
32
32
|
if model.changed_attributes.has_key?(locale_accessor) && model.changed_attributes[locale_accessor] == value
|
|
33
|
-
model.attributes_changed_by_setter.except!(locale_accessor)
|
|
33
|
+
model.send(:attributes_changed_by_setter).except!(locale_accessor)
|
|
34
34
|
elsif read(locale, options.merge(fallback: false)) != value
|
|
35
|
+
model.send(:mobility_changed_attributes) << locale_accessor
|
|
35
36
|
model.send(:attribute_will_change!, locale_accessor)
|
|
36
37
|
end
|
|
37
38
|
super
|
|
@@ -63,6 +64,10 @@ value of the translated attribute if passed to it.
|
|
|
63
64
|
private :restore_attribute!
|
|
64
65
|
end
|
|
65
66
|
|
|
67
|
+
def included(model_class)
|
|
68
|
+
model_class.include ChangedAttributes
|
|
69
|
+
end
|
|
70
|
+
|
|
66
71
|
private
|
|
67
72
|
|
|
68
73
|
# Get method suffixes. Creating an object just to get the list of
|
|
@@ -74,6 +79,19 @@ value of the translated attribute if passed to it.
|
|
|
74
79
|
include ::ActiveModel::Dirty
|
|
75
80
|
end.attribute_method_matchers.map(&:suffix).select { |m| m =~ /\A_/ }
|
|
76
81
|
end
|
|
82
|
+
|
|
83
|
+
# Tracks which translated attributes have been changed, separate from
|
|
84
|
+
# the default tracking of changes in ActiveModel/ActiveRecord Dirty.
|
|
85
|
+
# This is required in order for the Mobility ActiveRecord Dirty
|
|
86
|
+
# plugin to correctly read the value of locale accessors like
|
|
87
|
+
# +title_en+ in dirty tracking.
|
|
88
|
+
module ChangedAttributes
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
def mobility_changed_attributes
|
|
92
|
+
@mobility_changed_attributes ||= Set.new
|
|
93
|
+
end
|
|
94
|
+
end
|
|
77
95
|
end
|
|
78
96
|
end
|
|
79
97
|
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
module Mobility
|
|
2
|
+
module Plugins
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
Module builder adding translated attributes to #attributes hash on model
|
|
6
|
+
instance. See {Mobility::Plugins::AttributeMethods} for further details.
|
|
7
|
+
|
|
8
|
+
=end
|
|
9
|
+
module ActiveRecord
|
|
10
|
+
module TranslatedAttributes
|
|
11
|
+
def translated_attributes
|
|
12
|
+
{}
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def attributes
|
|
16
|
+
super.merge(translated_attributes)
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
class AttributeMethods < Module
|
|
21
|
+
def initialize(*attribute_names)
|
|
22
|
+
include TranslatedAttributes
|
|
23
|
+
define_method :translated_attributes do
|
|
24
|
+
super().merge(attribute_names.inject({}) do |attributes, name|
|
|
25
|
+
attributes.merge(name.to_s => send(name))
|
|
26
|
+
end)
|
|
27
|
+
end
|
|
28
|
+
delegate :translated_attribute_names, to: :class
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def included(model_class)
|
|
32
|
+
model_class.class_eval do
|
|
33
|
+
define_method :untranslated_attributes, ::ActiveRecord::Base.instance_method(:attributes)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -8,6 +8,17 @@ module Mobility
|
|
|
8
8
|
Dirty tracking for AR models. See {Mobility::Plugins::ActiveModel::Dirty} for
|
|
9
9
|
details on usage.
|
|
10
10
|
|
|
11
|
+
In addition to methods added by {Mobility::Plugins::ActiveModel::Diryt}, the
|
|
12
|
+
AR::Dirty plugin adds support for the following persistence-specific methods
|
|
13
|
+
(for a model with a translated attribute +title+):
|
|
14
|
+
- +saved_changes+
|
|
15
|
+
- +saved_change_to_title?+
|
|
16
|
+
- +saved_change_to_title+
|
|
17
|
+
- +title_before_last_save+
|
|
18
|
+
- +will_save_change_to_title?+
|
|
19
|
+
- +title_change_to_be_saved+
|
|
20
|
+
- +title_in_database+
|
|
21
|
+
|
|
11
22
|
=end
|
|
12
23
|
module ActiveRecord
|
|
13
24
|
module Dirty
|
|
@@ -19,7 +30,33 @@ details on usage.
|
|
|
19
30
|
def initialize(*attribute_names)
|
|
20
31
|
super
|
|
21
32
|
@attribute_names = attribute_names
|
|
33
|
+
define_method_overrides
|
|
34
|
+
define_attribute_methods if ::ActiveRecord::VERSION::STRING >= '5.1'
|
|
35
|
+
end
|
|
22
36
|
|
|
37
|
+
# Overrides +ActiveRecord::AttributeMethods::ClassMethods#has_attribute+ and
|
|
38
|
+
# +ActiveModel::AttributeMethods#_read_attribute+ to treat
|
|
39
|
+
# fallthrough attribute methods just like "real" attribute methods.
|
|
40
|
+
#
|
|
41
|
+
# @note Patching +has_attribute?+ is necessary as of AR 5.1 due to this commit[https://github.com/rails/rails/commit/4fed08fa787a316fa51f14baca9eae11913f5050].
|
|
42
|
+
# (I have voiced my opposition to this change here[https://github.com/rails/rails/pull/27963#issuecomment-310092787]).
|
|
43
|
+
# @param [Attributes] attributes
|
|
44
|
+
def included(model_class)
|
|
45
|
+
super
|
|
46
|
+
names = @attribute_names
|
|
47
|
+
method_name_regex = /\A(#{names.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
|
48
|
+
has_attribute = Module.new do
|
|
49
|
+
define_method :has_attribute? do |attr_name|
|
|
50
|
+
super(attr_name) || !!method_name_regex.match(attr_name)
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
model_class.extend has_attribute
|
|
54
|
+
model_class.include ReadAttribute if ::ActiveRecord::VERSION::STRING >= '5.2'
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
private
|
|
58
|
+
|
|
59
|
+
def define_method_overrides
|
|
23
60
|
changes_applied_method = ::ActiveRecord::VERSION::STRING < '5.1' ? :changes_applied : :changes_internally_applied
|
|
24
61
|
define_method changes_applied_method do
|
|
25
62
|
@previously_changed = changes
|
|
@@ -36,21 +73,49 @@ details on usage.
|
|
|
36
73
|
end
|
|
37
74
|
end
|
|
38
75
|
|
|
39
|
-
#
|
|
40
|
-
|
|
76
|
+
# For AR >= 5.1 only
|
|
77
|
+
def define_attribute_methods
|
|
78
|
+
define_method :saved_changes do
|
|
79
|
+
(@previously_changed ||= ActiveSupport::HashWithIndifferentAccess.new).merge(super())
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
@attribute_names.each do |name|
|
|
83
|
+
define_method :"saved_change_to_#{name}?" do
|
|
84
|
+
previous_changes.include?(Mobility.normalize_locale_accessor(name))
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
define_method :"saved_change_to_#{name}" do
|
|
88
|
+
previous_changes[Mobility.normalize_locale_accessor(name)]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
define_method :"#{name}_before_last_save" do
|
|
92
|
+
previous_changes[Mobility.normalize_locale_accessor(name)].first
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
alias_method :"will_save_change_to_#{name}?", :"#{name}_changed?"
|
|
96
|
+
alias_method :"#{name}_change_to_be_saved", :"#{name}_change"
|
|
97
|
+
alias_method :"#{name}_in_database", :"#{name}_was"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Overrides _read_attribute to correctly dispatch reads on translated
|
|
102
|
+
# attributes to their respective setters, rather than to
|
|
103
|
+
# +@attributes+, which would otherwise return +nil+.
|
|
41
104
|
#
|
|
42
|
-
#
|
|
43
|
-
#
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
super
|
|
105
|
+
# For background on why this is necessary, see:
|
|
106
|
+
# https://github.com/shioyama/mobility/issues/115
|
|
107
|
+
module ReadAttribute
|
|
108
|
+
# @note We first check if attributes has the key +attr+ to avoid
|
|
109
|
+
# doing any extra work in case this is a "normal"
|
|
110
|
+
# (non-translated) attribute.
|
|
111
|
+
def _read_attribute(attr, *args)
|
|
112
|
+
if @attributes.key?(attr)
|
|
113
|
+
super
|
|
114
|
+
else
|
|
115
|
+
mobility_changed_attributes.include?(attr) ? __send__(attr) : super
|
|
51
116
|
end
|
|
52
117
|
end
|
|
53
|
-
|
|
118
|
+
private :_read_attribute
|
|
54
119
|
end
|
|
55
120
|
end
|
|
56
121
|
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
module Mobility
|
|
2
|
+
module Plugins
|
|
3
|
+
=begin
|
|
4
|
+
|
|
5
|
+
Adds translated attribute names and values to the hash returned by #attributes.
|
|
6
|
+
Also adds a method #translated_attributes with names and values of translated
|
|
7
|
+
attributes only.
|
|
8
|
+
|
|
9
|
+
@note Adding translated attributes to +attributes+ can have unexpected
|
|
10
|
+
consequences, since these attributes do not have corresponding columns in the
|
|
11
|
+
model table. Using this plugin may lead to conflicts with other gems.
|
|
12
|
+
|
|
13
|
+
=end
|
|
14
|
+
module AttributeMethods
|
|
15
|
+
class << self
|
|
16
|
+
# Applies attribute_methods plugin for a given option value.
|
|
17
|
+
# @param [Attributes] attributes
|
|
18
|
+
# @param [Boolean] option Value of option
|
|
19
|
+
# @raise [ArgumentError] if model class does not support dirty tracking
|
|
20
|
+
def apply(attributes, option)
|
|
21
|
+
if option
|
|
22
|
+
include_attribute_methods_module(attributes.model_class, *attributes.names)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
private
|
|
27
|
+
|
|
28
|
+
def include_attribute_methods_module(model_class, *attribute_names)
|
|
29
|
+
module_builder =
|
|
30
|
+
if Loaded::ActiveRecord && model_class.ancestors.include?(::ActiveRecord::AttributeMethods)
|
|
31
|
+
require "mobility/plugins/active_record/attribute_methods"
|
|
32
|
+
Plugins::ActiveRecord::AttributeMethods
|
|
33
|
+
else
|
|
34
|
+
raise ArgumentError, "#{model_class} does not support AttributeMethods plugin."
|
|
35
|
+
end
|
|
36
|
+
model_class.include module_builder.new(*attribute_names)
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -14,11 +14,7 @@ details.
|
|
|
14
14
|
@note Dirty tracking can have unexpected results when combined with fallbacks.
|
|
15
15
|
A change in the fallback locale value will not mark an attribute falling
|
|
16
16
|
through to that locale as changed, even though it may look like it has
|
|
17
|
-
changed.
|
|
18
|
-
or blank to a new value, the change will be recorded as a change from that
|
|
19
|
-
fallback value, rather than from the nil or blank value. The specs are the
|
|
20
|
-
most reliable source of information on the interaction between dirty tracking
|
|
21
|
-
and fallbacks.
|
|
17
|
+
changed. See the specs for details on expected behavior.
|
|
22
18
|
|
|
23
19
|
=end
|
|
24
20
|
module Dirty
|
|
@@ -15,14 +15,20 @@ defaults to an instance of +I18n::Locale::Fallbacks+, but can be configured
|
|
|
15
15
|
If a hash is passed to the +fallbacks+ option, a new fallbacks instance will be
|
|
16
16
|
created for the model with the hash defining additional fallbacks.
|
|
17
17
|
|
|
18
|
-
In addition, fallbacks
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
locale
|
|
18
|
+
In addition, fallbacks are disabled in certain situation. To explicitly disable
|
|
19
|
+
fallbacks when reading and writing, you can pass the <tt>fallback: false</tt>
|
|
20
|
+
option to the reader method. This can be useful to determine the actual
|
|
21
|
+
value of the translated attribute, including a possible +nil+ value.
|
|
22
|
+
|
|
23
|
+
The other situation where fallbacks are disabled is when the locale is
|
|
24
|
+
specified explicitly, either by passing a `locale` option to the accessor or by
|
|
25
|
+
using locale or fallthrough accessors. (See example below.)
|
|
26
|
+
|
|
27
|
+
You can also pass a locale or array of locales to the +fallback+ option to use
|
|
28
|
+
that locale or locales that read, e.g. <tt>fallback: :fr</tt> would fetch the
|
|
29
|
+
French translation if the value in the current locale was +nil+, whereas
|
|
30
|
+
<tt>fallback: [:fr, :es]</tt> would try French, then Spanish if the value in
|
|
31
|
+
the current locale was +nil+.
|
|
26
32
|
|
|
27
33
|
@see https://github.com/svenfuchs/i18n/wiki/Fallbacks I18n Fallbacks
|
|
28
34
|
|
|
@@ -76,6 +82,26 @@ locale was +nil+.
|
|
|
76
82
|
#=> nil
|
|
77
83
|
post.title(fallback: :fr)
|
|
78
84
|
#=> "Mobilité"
|
|
85
|
+
|
|
86
|
+
@example Fallbacks disabled
|
|
87
|
+
class Post
|
|
88
|
+
translates :title, fallbacks: { :'fr' => 'en' }, locale_accessors: true
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
I18n.default_locale = :en
|
|
92
|
+
Mobility.locale = :en
|
|
93
|
+
post = Post.new(title: "Mobility")
|
|
94
|
+
|
|
95
|
+
Mobility.locale = :fr
|
|
96
|
+
post.title
|
|
97
|
+
#=> "Mobility"
|
|
98
|
+
post.title(fallback: false)
|
|
99
|
+
#=> nil
|
|
100
|
+
post.title(locale: :fr)
|
|
101
|
+
#=> nil
|
|
102
|
+
post.title_fr
|
|
103
|
+
#=> nil
|
|
104
|
+
|
|
79
105
|
=end
|
|
80
106
|
class Fallbacks < Module
|
|
81
107
|
# Applies fallbacks plugin to attributes.
|
|
@@ -92,17 +118,16 @@ locale was +nil+.
|
|
|
92
118
|
private
|
|
93
119
|
|
|
94
120
|
def define_read(fallbacks)
|
|
95
|
-
define_method :read do |locale, **options|
|
|
96
|
-
fallback
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
value = super(fallback_locale, options)
|
|
103
|
-
break value if Util.present?(value)
|
|
104
|
-
end
|
|
121
|
+
define_method :read do |locale, fallback: true, **options|
|
|
122
|
+
return super(locale, options) if !fallback || options[:locale]
|
|
123
|
+
|
|
124
|
+
locales = fallback == true ? fallbacks[locale] : [locale, *fallback]
|
|
125
|
+
locales.each do |fallback_locale|
|
|
126
|
+
value = super(fallback_locale, options)
|
|
127
|
+
return value if Util.present?(value)
|
|
105
128
|
end
|
|
129
|
+
|
|
130
|
+
super(locale, options)
|
|
106
131
|
end
|
|
107
132
|
end
|
|
108
133
|
|
|
@@ -112,7 +137,7 @@ locale was +nil+.
|
|
|
112
137
|
elsif option == true
|
|
113
138
|
Mobility.default_fallbacks
|
|
114
139
|
else
|
|
115
|
-
|
|
140
|
+
Hash.new { [] }
|
|
116
141
|
end
|
|
117
142
|
end
|
|
118
143
|
end
|
|
@@ -46,12 +46,12 @@ model class is generated.
|
|
|
46
46
|
def initialize(*attributes)
|
|
47
47
|
method_name_regex = /\A(#{attributes.join('|'.freeze)})_([a-z]{2}(_[a-z]{2})?)(=?|\??)\z/.freeze
|
|
48
48
|
|
|
49
|
-
define_method :method_missing do |method_name, *arguments, &block|
|
|
49
|
+
define_method :method_missing do |method_name, *arguments, **options, &block|
|
|
50
50
|
if method_name =~ method_name_regex
|
|
51
51
|
attribute = $1.to_sym
|
|
52
52
|
locale, suffix = $2.split('_'.freeze)
|
|
53
53
|
locale = "#{locale}-#{suffix.upcase}".freeze if suffix
|
|
54
|
-
|
|
54
|
+
public_send("#{attribute}#{$4}".freeze, *arguments, **options, locale: locale.to_sym)
|
|
55
55
|
else
|
|
56
56
|
super(method_name, *arguments, &block)
|
|
57
57
|
end
|
|
@@ -58,14 +58,14 @@ If no locales are passed as an option to the initializer,
|
|
|
58
58
|
|
|
59
59
|
define_method "#{name}_#{normalized_locale}" do |**options|
|
|
60
60
|
return super() if options.delete(:super)
|
|
61
|
-
warn warning_message if options
|
|
62
|
-
|
|
61
|
+
warn warning_message if options[:locale]
|
|
62
|
+
public_send(name, **options, locale: locale)
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
define_method "#{name}_#{normalized_locale}?" do |**options|
|
|
66
66
|
return super() if options.delete(:super)
|
|
67
|
-
warn warning_message if options
|
|
68
|
-
|
|
67
|
+
warn warning_message if options[:locale]
|
|
68
|
+
public_send("#{name}?", **options, locale: locale)
|
|
69
69
|
end
|
|
70
70
|
end
|
|
71
71
|
|
|
@@ -75,8 +75,8 @@ If no locales are passed as an option to the initializer,
|
|
|
75
75
|
|
|
76
76
|
define_method "#{name}_#{normalized_locale}=" do |value, **options|
|
|
77
77
|
return super(value) if options.delete(:super)
|
|
78
|
-
warn warning_message if options
|
|
79
|
-
|
|
78
|
+
warn warning_message if options[:locale]
|
|
79
|
+
public_send("#{name}=", value, **options, locale: locale)
|
|
80
80
|
end
|
|
81
81
|
end
|
|
82
82
|
end
|
data/lib/mobility/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mobility
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chris Salzberg
|
|
@@ -30,7 +30,7 @@ cert_chain:
|
|
|
30
30
|
eGDROPZoL5RXwiOnRbexxa7dcAxMrDfGB/hpiunIPWPsi4n5P7K/6OO/sGVMl9xv
|
|
31
31
|
SZBPXjzrHdyOFLBYXB+PG7s3F/4=
|
|
32
32
|
-----END CERTIFICATE-----
|
|
33
|
-
date: 2017-
|
|
33
|
+
date: 2017-11-30 00:00:00.000000000 Z
|
|
34
34
|
dependencies:
|
|
35
35
|
- !ruby/object:Gem::Dependency
|
|
36
36
|
name: request_store
|
|
@@ -55,7 +55,7 @@ dependencies:
|
|
|
55
55
|
version: 0.6.10
|
|
56
56
|
- - "<"
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
|
-
version: '0.
|
|
58
|
+
version: '0.10'
|
|
59
59
|
type: :runtime
|
|
60
60
|
prerelease: false
|
|
61
61
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -65,7 +65,7 @@ dependencies:
|
|
|
65
65
|
version: 0.6.10
|
|
66
66
|
- - "<"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0.
|
|
68
|
+
version: '0.10'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: bundler
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -106,14 +106,20 @@ dependencies:
|
|
|
106
106
|
requirements:
|
|
107
107
|
- - "~>"
|
|
108
108
|
- !ruby/object:Gem::Version
|
|
109
|
-
version: '
|
|
109
|
+
version: '12'
|
|
110
|
+
- - ">="
|
|
111
|
+
- !ruby/object:Gem::Version
|
|
112
|
+
version: 12.2.1
|
|
110
113
|
type: :development
|
|
111
114
|
prerelease: false
|
|
112
115
|
version_requirements: !ruby/object:Gem::Requirement
|
|
113
116
|
requirements:
|
|
114
117
|
- - "~>"
|
|
115
118
|
- !ruby/object:Gem::Version
|
|
116
|
-
version: '
|
|
119
|
+
version: '12'
|
|
120
|
+
- - ">="
|
|
121
|
+
- !ruby/object:Gem::Version
|
|
122
|
+
version: 12.2.1
|
|
117
123
|
- !ruby/object:Gem::Dependency
|
|
118
124
|
name: rspec
|
|
119
125
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -163,7 +169,6 @@ files:
|
|
|
163
169
|
- lib/mobility/active_model.rb
|
|
164
170
|
- lib/mobility/active_model/backend_resetter.rb
|
|
165
171
|
- lib/mobility/active_record.rb
|
|
166
|
-
- lib/mobility/active_record/attribute_methods.rb
|
|
167
172
|
- lib/mobility/active_record/backend_resetter.rb
|
|
168
173
|
- lib/mobility/active_record/model_translation.rb
|
|
169
174
|
- lib/mobility/active_record/string_translation.rb
|
|
@@ -221,7 +226,9 @@ files:
|
|
|
221
226
|
- lib/mobility/plugins/active_model.rb
|
|
222
227
|
- lib/mobility/plugins/active_model/dirty.rb
|
|
223
228
|
- lib/mobility/plugins/active_record.rb
|
|
229
|
+
- lib/mobility/plugins/active_record/attribute_methods.rb
|
|
224
230
|
- lib/mobility/plugins/active_record/dirty.rb
|
|
231
|
+
- lib/mobility/plugins/attribute_methods.rb
|
|
225
232
|
- lib/mobility/plugins/cache.rb
|
|
226
233
|
- lib/mobility/plugins/cache/translation_cacher.rb
|
|
227
234
|
- lib/mobility/plugins/default.rb
|
metadata.gz.sig
CHANGED
|
Binary file
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
module Mobility
|
|
2
|
-
module ActiveRecord
|
|
3
|
-
=begin
|
|
4
|
-
|
|
5
|
-
Included into model if model has +ActiveRecord::AttributeMethods+ among its
|
|
6
|
-
ancestors.
|
|
7
|
-
|
|
8
|
-
=end
|
|
9
|
-
module AttributeMethods
|
|
10
|
-
delegate :translated_attribute_names, to: :class
|
|
11
|
-
|
|
12
|
-
# Adds translated attributes to +attributes+.
|
|
13
|
-
# @return [Array<String>] Model attributes
|
|
14
|
-
# @!method attributes
|
|
15
|
-
def self.included(model)
|
|
16
|
-
attributes_method = Module.new do
|
|
17
|
-
def attributes
|
|
18
|
-
super.merge(translated_attributes)
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
model.class_eval do
|
|
22
|
-
alias_method :untranslated_attributes, :attributes
|
|
23
|
-
include attributes_method
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
# Translated attributes defined on model.
|
|
28
|
-
# @return [Array<String>] Translated attributes
|
|
29
|
-
def translated_attributes
|
|
30
|
-
translated_attribute_names.inject({}) do |attributes, name|
|
|
31
|
-
attributes.merge(name.to_s => send(name))
|
|
32
|
-
end
|
|
33
|
-
end
|
|
34
|
-
end
|
|
35
|
-
end
|
|
36
|
-
end
|