para-i18n 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +77 -1
- data/app/controllers/para/admin/translations_controller.rb +13 -5
- data/lib/generators/para/i18n/translate/templates/model_migration.rb.erb +1 -1
- data/lib/generators/para/i18n/translate/translate_generator.rb +1 -5
- data/lib/para/i18n/engine.rb +7 -3
- data/lib/para/i18n/friendly_id.rb +22 -9
- data/lib/para/i18n/i18n_input.rb +34 -9
- data/lib/para/i18n/model.rb +41 -7
- data/lib/para/i18n/resources_table.rb +1 -1
- data/lib/para/i18n/translations_helper.rb +2 -1
- data/lib/para/i18n/version.rb +1 -1
- data/lib/para/i18n.rb +3 -0
- metadata +2 -3
- data/app/views/para/inputs/_i18n.html.haml +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7ca0ae98159f636ad5cf97f4481d066819e4daf2
|
4
|
+
data.tar.gz: e2bd232647bd4edee8c06fc82a931fad40ef7211
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79e0910d8bf7ec05871b8721f547ee29b4fd4e5192f2aaf1d8ae7bd1f825dd8a79040d144c538e3c2b1677d1cd8f420d2137d6db0d9ba37ffa6e907bdf876330
|
7
|
+
data.tar.gz: b19299a63bb9eff4690854f285eda67dab0c5df3bbd1cbbd703ab5139b71fede3425b49d97abc1bb048390b4b8c6b4372be2cb23cb3937db61de40cab638ad62
|
data/README.md
CHANGED
@@ -57,7 +57,7 @@ end
|
|
57
57
|
Now, any `crud` component managing the `Page` model will show a button to access
|
58
58
|
the translation interface for existing entries.
|
59
59
|
|
60
|
-
|
60
|
+
### Overriding the translations form
|
61
61
|
|
62
62
|
The translation form can be overriden by generating it with the `para:i18n:form`
|
63
63
|
generator. This is useful to delete or add fields to translate that are not
|
@@ -73,6 +73,82 @@ rails g para:i18n:form page
|
|
73
73
|
This will create a partial at `app/views/admin/pages/_translations_form.html.haml`
|
74
74
|
that you can override.
|
75
75
|
|
76
|
+
### Translation fields customization
|
77
|
+
|
78
|
+
This gem uses a special [Simple Form](https://github.com/plataformatec/simple_form)
|
79
|
+
input to manage translations.
|
80
|
+
|
81
|
+
Example :
|
82
|
+
|
83
|
+
```ruby
|
84
|
+
= form.input :title, as: :i18n, locale: @target_locale
|
85
|
+
```
|
86
|
+
|
87
|
+
When generating the translations form, you can edit those inputs, remove or add
|
88
|
+
some inputs.
|
89
|
+
|
90
|
+
#### Managing nested resources
|
91
|
+
|
92
|
+
You can simply manage nested resources by using the `simple_fields_for` form
|
93
|
+
helper :
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
= form.simple_fields_for :nested_resources do |fields|
|
97
|
+
= fields.input :nested_title, as: :i18n, locale: @target_locale
|
98
|
+
```
|
99
|
+
|
100
|
+
#### Passing options to the translation field
|
101
|
+
|
102
|
+
The I18n field generates a plain HTML section with the original contents of the
|
103
|
+
field (in the `I18n.default_locale` locale), and a sub-input, which uses the
|
104
|
+
default type that Para infers from the attribute.
|
105
|
+
|
106
|
+
You can override the generated field type or pass other options by using the
|
107
|
+
`:input_html` option :
|
108
|
+
|
109
|
+
```ruby
|
110
|
+
= form.input :value, as: :i18n, locale: @target_locale, input_html: { as: :numeric, spinner: false }
|
111
|
+
```
|
112
|
+
|
113
|
+
Also, if your original content contains useful HTML, you can use the `:html_safe`
|
114
|
+
to be applied to the original content by using the `:original_html` option :
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
= form.input :value, as: :i18n, locale: @target_locale, original_html: { html_safe: true }
|
118
|
+
```
|
119
|
+
|
120
|
+
### Locales fallbacks support
|
121
|
+
|
122
|
+
The gem fully supports Rails' I18n fallbacks and will try to fallback to any
|
123
|
+
available translation using the `I18n.fallbacks` hash if you enable them.
|
124
|
+
|
125
|
+
If not enabled, any untranslated content will be empty.
|
126
|
+
|
127
|
+
### Friendly id support
|
128
|
+
|
129
|
+
The gem comes with friendly_id i18n support, with a dedicated `:i18n` module to
|
130
|
+
include instead of the `:slugged` module into your models friendly_id options.
|
131
|
+
|
132
|
+
For example, for the page :
|
133
|
+
|
134
|
+
```ruby
|
135
|
+
class Page < ActiveRecord::Base
|
136
|
+
translates :title, :slug
|
137
|
+
|
138
|
+
friendly_id :title, use: [:finders, :i18n]
|
139
|
+
end
|
140
|
+
```
|
141
|
+
|
142
|
+
> **Warning** : You always need to put the `:i18n` fiendly_id module after all
|
143
|
+
other modules, so the finder methods included in this module take the current
|
144
|
+
locale into account.
|
145
|
+
|
146
|
+
This will automatically build localized slugs when updating the `title` in any
|
147
|
+
locale, and will allow you to find the resources with the translated slugs.
|
148
|
+
|
149
|
+
Note that if I18n fallbacks are enabled, it will try to fall back to the next
|
150
|
+
locale if no resource was found for the given slug and locale.
|
151
|
+
|
76
152
|
## Contributing
|
77
153
|
|
78
154
|
Bug reports and pull requests are welcome on GitHub at https://github.com/para-cms/para-i18n.
|
@@ -1,7 +1,11 @@
|
|
1
1
|
module Para
|
2
2
|
module Admin
|
3
|
-
class TranslationsController < ::Para::Admin::
|
3
|
+
class TranslationsController < ::Para::Admin::ResourcesController
|
4
|
+
include Para::Admin::ResourceControllerConcerns
|
5
|
+
|
6
|
+
before_action :load_and_authorize_crud_resource
|
4
7
|
before_action :load_locales
|
8
|
+
before_action :add_breadcrumbs
|
5
9
|
|
6
10
|
def edit
|
7
11
|
end
|
@@ -19,10 +23,14 @@ module Para
|
|
19
23
|
private
|
20
24
|
|
21
25
|
def load_and_authorize_crud_resource
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
options = { class: resource_model }
|
27
|
+
|
28
|
+
options.merge!(
|
29
|
+
singleton: true,
|
30
|
+
through: :component
|
31
|
+
) unless params.key?(:resource_id)
|
25
32
|
|
33
|
+
loader = self.class.cancan_resource_class.new(self, :resource, options)
|
26
34
|
loader.load_and_authorize_resource
|
27
35
|
end
|
28
36
|
|
@@ -36,7 +44,7 @@ module Para
|
|
36
44
|
end
|
37
45
|
|
38
46
|
def add_breadcrumbs
|
39
|
-
|
47
|
+
add_breadcrumb(resource_title_for(resource), @component.relation_path(resource, action: :show)) if resource
|
40
48
|
add_breadcrumb(t('para.i18n.translation'))
|
41
49
|
end
|
42
50
|
end
|
@@ -15,7 +15,7 @@ module Para
|
|
15
15
|
desc "I18nAdmin translation generator"
|
16
16
|
|
17
17
|
def generate_migration
|
18
|
-
migration_template 'model_migration.rb.erb', "db/migrate/translate_#{
|
18
|
+
migration_template 'model_migration.rb.erb', "db/migrate/translate_#{ table_name }.rb"
|
19
19
|
end
|
20
20
|
|
21
21
|
def migrate
|
@@ -31,10 +31,6 @@ module Para
|
|
31
31
|
def plural_class_name
|
32
32
|
@plural_class_name ||= class_name.pluralize
|
33
33
|
end
|
34
|
-
|
35
|
-
def table_name
|
36
|
-
@table_name ||= plural_class_name.underscore
|
37
|
-
end
|
38
34
|
end
|
39
35
|
end
|
40
36
|
end
|
data/lib/para/i18n/engine.rb
CHANGED
@@ -9,7 +9,11 @@ module Para
|
|
9
9
|
|
10
10
|
initializer 'para.i18n.extend_para_routes' do
|
11
11
|
::Para.config.routes.extend_routes_for(:crud_component) do
|
12
|
-
resource :translation, only: [:edit, :update]
|
12
|
+
resource :translation, only: [:edit, :update], controller: '/para/admin/translations'
|
13
|
+
end
|
14
|
+
|
15
|
+
::Para.config.routes.extend_routes_for(:form_component) do
|
16
|
+
resource :translation, only: [:edit, :update], controller: '/para/admin/translations'
|
13
17
|
end
|
14
18
|
end
|
15
19
|
|
@@ -26,12 +30,12 @@ module Para
|
|
26
30
|
end
|
27
31
|
|
28
32
|
initializer 'para.i18n.add_translate_actions' do
|
29
|
-
Para.config.add_actions_for('crud/edit') do
|
33
|
+
Para.config.add_actions_for('crud/edit', 'form/show') do
|
30
34
|
{
|
31
35
|
icon: 'globe',
|
32
36
|
label: ::I18n.t('para.i18n.translate'),
|
33
37
|
url: @component.relation_path(resource, :translation, action: :edit)
|
34
|
-
}
|
38
|
+
} if resource.class.translates?
|
35
39
|
end
|
36
40
|
end
|
37
41
|
end
|
@@ -9,6 +9,15 @@ module FriendlyId
|
|
9
9
|
|
10
10
|
def included(model_class)
|
11
11
|
model_class.extend(ClassMethods)
|
12
|
+
|
13
|
+
# Support for friendly finds on associations for Rails 4.0.1 and above.
|
14
|
+
#
|
15
|
+
# Borrowed from FriendlyId::Finders module
|
16
|
+
#
|
17
|
+
if ::ActiveRecord.const_defined?('AssociationRelation')
|
18
|
+
association_relation_delegate_class = model_class.relation_delegate_class(::ActiveRecord::AssociationRelation)
|
19
|
+
association_relation_delegate_class.send(:include, ClassMethods)
|
20
|
+
end
|
12
21
|
end
|
13
22
|
end
|
14
23
|
|
@@ -31,21 +40,25 @@ module FriendlyId
|
|
31
40
|
end
|
32
41
|
|
33
42
|
module ClassMethods
|
34
|
-
def exists_by_friendly_id?(id)
|
35
|
-
if (exists = by_friendly_id(id).exists?)
|
43
|
+
def exists_by_friendly_id?(id, locale = ::I18n.locale)
|
44
|
+
if (exists = by_friendly_id(id, locale).exists?)
|
36
45
|
exists
|
37
|
-
elsif (fallback_locale = Para::I18n::Fallbacks.i18n_fallback_for(
|
38
|
-
|
46
|
+
elsif (fallback_locale = Para::I18n::Fallbacks.i18n_fallback_for(locale)) &&
|
47
|
+
fallback_locale != locale
|
48
|
+
then
|
49
|
+
exists_by_friendly_id?(id, fallback_locale)
|
39
50
|
end
|
40
51
|
end
|
41
52
|
|
42
53
|
private
|
43
54
|
|
44
|
-
def first_by_friendly_id(id)
|
45
|
-
if (first = by_friendly_id(id).first)
|
55
|
+
def first_by_friendly_id(id, locale = ::I18n.locale)
|
56
|
+
if (first = by_friendly_id(id, locale).first)
|
46
57
|
first
|
47
|
-
elsif (fallback_locale = Para::I18n::Fallbacks.i18n_fallback_for(
|
48
|
-
|
58
|
+
elsif (fallback_locale = Para::I18n::Fallbacks.i18n_fallback_for(locale)) &&
|
59
|
+
fallback_locale != locale
|
60
|
+
then
|
61
|
+
first_by_friendly_id(id, fallback_locale)
|
49
62
|
end
|
50
63
|
end
|
51
64
|
|
@@ -53,7 +66,7 @@ module FriendlyId
|
|
53
66
|
if locale == ::I18n.default_locale
|
54
67
|
where(friendly_id_config.query_field => id)
|
55
68
|
else
|
56
|
-
json_path = "{#{
|
69
|
+
json_path = "{#{ locale },#{ friendly_id_config.query_field }}"
|
57
70
|
where("_translations#>>'#{ json_path }' = ?", id)
|
58
71
|
end
|
59
72
|
end
|
data/lib/para/i18n/i18n_input.rb
CHANGED
@@ -1,18 +1,26 @@
|
|
1
1
|
module Para
|
2
2
|
module Inputs
|
3
3
|
class I18nInput < SimpleForm::Inputs::Base
|
4
|
+
delegate :content_tag, to: :template
|
5
|
+
|
4
6
|
def input(wrapper_options = nil)
|
5
7
|
model = object.class
|
8
|
+
render
|
9
|
+
end
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
11
|
+
def render
|
12
|
+
content_tag(:div, class: 'row') do
|
13
|
+
content_tag(:div, class: 'col-md-6') do
|
14
|
+
::I18n.with_locale(::I18n.default_locale) do
|
15
|
+
original_content
|
16
|
+
end
|
17
|
+
end +
|
18
|
+
content_tag(:div, class: 'col-md-6') do
|
19
|
+
::I18n.with_locale(locale) do
|
20
|
+
@builder.input_field(attribute_name, input_options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
16
24
|
end
|
17
25
|
|
18
26
|
private
|
@@ -24,6 +32,23 @@ module Para
|
|
24
32
|
raise 'Missing `:locale` option passed to :i18n input.'
|
25
33
|
end
|
26
34
|
end
|
35
|
+
|
36
|
+
def original_content
|
37
|
+
value = template.value_for(object, attribute_name)
|
38
|
+
value = value.html_safe if original_options[:html_safe]
|
39
|
+
value
|
40
|
+
end
|
41
|
+
|
42
|
+
def original_options
|
43
|
+
@original_options ||= options[:original_html] || {}
|
44
|
+
end
|
45
|
+
|
46
|
+
def input_options
|
47
|
+
@input_options ||= (options[:input_html] || {}).tap do |hash|
|
48
|
+
hash[:class] ||= ''
|
49
|
+
hash[:class] += ' form-control'
|
50
|
+
end
|
51
|
+
end
|
27
52
|
end
|
28
53
|
end
|
29
54
|
end
|
data/lib/para/i18n/model.rb
CHANGED
@@ -4,11 +4,11 @@ module Para
|
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
6
|
included do
|
7
|
-
class_attribute :
|
7
|
+
class_attribute :translated_attribute_names
|
8
8
|
end
|
9
9
|
|
10
10
|
def read_translated_attribute(field, locale = ::I18n.locale)
|
11
|
-
return
|
11
|
+
return read_plain_or_store_attribute(field) if locale == ::I18n.default_locale
|
12
12
|
|
13
13
|
if model_translations[locale.to_s]
|
14
14
|
if (translation = model_translations[locale.to_s][field.to_s])
|
@@ -23,7 +23,7 @@ module Para
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def write_translated_attribute field, value, locale = ::I18n.locale
|
26
|
-
return
|
26
|
+
return write_plain_or_store_attribute(field, value) if locale == ::I18n.default_locale
|
27
27
|
|
28
28
|
model_translations[locale.to_s] ||= {}
|
29
29
|
model_translations[locale.to_s][field.to_s] = value
|
@@ -40,12 +40,46 @@ module Para
|
|
40
40
|
end
|
41
41
|
|
42
42
|
def translation_for(locale)
|
43
|
-
model_translations[locale] || {}
|
43
|
+
model_translations[locale.to_s] || {}
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def read_plain_or_store_attribute(field)
|
49
|
+
if plain_column?(field)
|
50
|
+
read_attribute(field)
|
51
|
+
elsif (store_name = find_stored_column(field))
|
52
|
+
read_store_attribute(store_name, field)
|
53
|
+
else
|
54
|
+
raise ActiveRecord::UnknownAttributeError.new(self, field)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def write_plain_or_store_attribute(field, value)
|
59
|
+
if plain_column?(field)
|
60
|
+
write_attribute(field, value)
|
61
|
+
elsif (store_name = find_stored_column(field))
|
62
|
+
write_store_attribute(store_name, field, value)
|
63
|
+
else
|
64
|
+
raise ActiveRecord::UnknownAttributeError.new(self, field)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def plain_column?(field)
|
69
|
+
self.class.columns_hash.key?(field.to_s)
|
70
|
+
end
|
71
|
+
|
72
|
+
def find_stored_column(field)
|
73
|
+
store = self.class.stored_attributes.find do |name, attributes|
|
74
|
+
attributes.include?(field.to_sym)
|
75
|
+
end
|
76
|
+
|
77
|
+
store.first if store
|
44
78
|
end
|
45
79
|
|
46
80
|
module ClassMethods
|
47
81
|
def translates(*fields)
|
48
|
-
self.
|
82
|
+
self.translated_attribute_names = fields.map(&:to_sym)
|
49
83
|
|
50
84
|
fields.each do |field|
|
51
85
|
define_method field do
|
@@ -58,8 +92,8 @@ module Para
|
|
58
92
|
end
|
59
93
|
end
|
60
94
|
|
61
|
-
def
|
62
|
-
|
95
|
+
def translates?
|
96
|
+
translated_attribute_names && translated_attribute_names.length > 0
|
63
97
|
end
|
64
98
|
end
|
65
99
|
end
|
@@ -10,7 +10,7 @@ module Para
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def translate_button(resource)
|
13
|
-
return unless resource.class.
|
13
|
+
return unless resource.class.translates?
|
14
14
|
|
15
15
|
path = component.relation_path(resource, :translation, action: :edit)
|
16
16
|
options = { class: 'btn btn-info' }
|
@@ -4,7 +4,8 @@ module Para
|
|
4
4
|
# TODO : Support images & co
|
5
5
|
def translated_model_fields_for(model)
|
6
6
|
model_field_mappings(model).fields.select do |field|
|
7
|
-
model.
|
7
|
+
model.translated_attribute_names &&
|
8
|
+
model.translated_attribute_names.include?(field.name.to_sym)
|
8
9
|
end
|
9
10
|
end
|
10
11
|
end
|
data/lib/para/i18n/version.rb
CHANGED
data/lib/para/i18n.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: para-i18n
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Valentin Ballestrino
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -71,7 +71,6 @@ files:
|
|
71
71
|
- app/controllers/para/admin/translations_controller.rb
|
72
72
|
- app/views/para/admin/resources/_translations_form.html.haml
|
73
73
|
- app/views/para/admin/translations/edit.html.haml
|
74
|
-
- app/views/para/inputs/_i18n.html.haml
|
75
74
|
- bin/console
|
76
75
|
- bin/setup
|
77
76
|
- config/locales/para-i18n.fr.yml
|