para-i18n 0.3.2 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (31) hide show
  1. checksums.yaml +5 -5
  2. data/app/helpers/para/i18n/form_helper.rb +13 -0
  3. data/app/views/para/admin/resources/_translations_fields.html.haml +9 -0
  4. data/app/views/para/admin/resources/_translations_form.html.haml +8 -2
  5. data/config/locales/para-i18n.fr.yml +1 -0
  6. data/lib/generators/para/i18n/base_form_generator.rb +28 -0
  7. data/lib/generators/para/i18n/form/form_generator.rb +3 -14
  8. data/lib/generators/para/i18n/form/templates/_translations_form.html.haml +8 -2
  9. data/lib/generators/para/i18n/nested_fields/nested_fields_generator.rb +18 -0
  10. data/lib/generators/para/i18n/nested_fields/templates/_translations_fields.html.haml +11 -0
  11. data/lib/generators/para/i18n/translate/templates/model_migration.rb.erb +1 -1
  12. data/lib/para/i18n.rb +8 -0
  13. data/lib/para/i18n/attribute_translation.rb +26 -0
  14. data/lib/para/i18n/attribute_translation/attachment.rb +58 -0
  15. data/lib/para/i18n/attribute_translation/base.rb +23 -0
  16. data/lib/para/i18n/attribute_translation/simple_attribute.rb +37 -0
  17. data/lib/para/i18n/engine.rb +2 -2
  18. data/lib/para/i18n/fallbacks.rb +11 -2
  19. data/lib/para/i18n/form_builder.rb +10 -0
  20. data/lib/para/i18n/form_builder/nested_form.rb +46 -0
  21. data/lib/para/i18n/form_builder/translations_form.rb +42 -0
  22. data/lib/para/i18n/friendly_id.rb +9 -0
  23. data/lib/para/i18n/helpers/translations_helper.rb +9 -0
  24. data/lib/para/i18n/i18n_input.rb +5 -5
  25. data/lib/para/i18n/inputs.rb +4 -0
  26. data/lib/para/i18n/inputs/nested_many_input.rb +41 -0
  27. data/lib/para/i18n/model.rb +47 -28
  28. data/lib/para/i18n/resources_buttons.rb +1 -1
  29. data/lib/para/i18n/version.rb +1 -1
  30. data/para-i18n.gemspec +1 -1
  31. metadata +27 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 7debf4be928d56fb8b0e9bf814ee6fd09422b036
4
- data.tar.gz: b7b0c7bf833da338a617d40b7ed49e87a3ff995f
2
+ SHA256:
3
+ metadata.gz: 90d12992580fc4a99c6c61436e3fda627f33c8064316d72d9dac154234bf7e58
4
+ data.tar.gz: 4592e7c3895bc9200f212879171f5b039d75884bd0dfa73f576a8624346fbd5d
5
5
  SHA512:
6
- metadata.gz: e40bacf82951a1c80f5f3079fd4d244007a9cf6dbfc9d1dfcc96770011a34564871e687176b31c2704b74c0305dbd52c536210e3d8ba5e81f7db00bef87f04fd
7
- data.tar.gz: 90b24e6e7a78d8622c232796bc93acc6e4a32a1773462ce6dd7023d7173b38241c39721bd42a163b06975351ae37f85588fd30af5f681c3da57b986cbcb7e426
6
+ metadata.gz: 2cf9a1a632377a4d9d4f0780401028e4fd44b6991427a96af28e9ea21414d804a3ad97d0ca552b051fe43848a0c98f5df703a999e104bd0a8eae9309a3b7d69c
7
+ data.tar.gz: f676eac78ac6492fc3a283a162a0e06874d55873ead0e5a0c429ed93cc2445e6dfa2f0491e51e08626eca37dbcc59c08eaba07a083248c843d9d84c67a9bd8af
@@ -0,0 +1,13 @@
1
+ module Para
2
+ module I18n
3
+ module FormHelper
4
+ def para_translations_form_for(resource, options = {}, &block)
5
+ extended_options = options.reverse_merge(
6
+ Para::I18n::FormBuilder::TranslationsForm::TRANSLATIONS_FORM_PARAM_KEY => true
7
+ )
8
+
9
+ para_form_for(resource, extended_options, &block)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ = form.fieldset do
2
+ - I18n.with_locale(@target_locale) do
3
+ = form.input :_disabled_for_locale, as: :boolean, label: t("para.i18n.disabled_for_locale")
4
+
5
+ - translated_model_fields_for(form.object.class).each do |field|
6
+ = form.input field.field_name, as: :i18n
7
+
8
+ - nested_relations_attributes_for(form.object.class).each do |field|
9
+ = form.input field.field_name, as: field.field_type
@@ -1,8 +1,14 @@
1
- = para_form_for(resource, url: @component.relation_path(resource, :translation)) do |form|
1
+ = para_translations_form_for(resource, url: @component.relation_path(resource, :translation), locale: @target_locale) do |form|
2
2
  = target_locale_select
3
3
 
4
4
  = form.fieldset do
5
+ - I18n.with_locale(@target_locale) do
6
+ = form.input :_disabled_for_locale, as: :boolean, label: t("para.i18n.disabled_for_locale")
7
+
5
8
  - translated_model_fields_for(resource.class).each do |field|
6
- = form.input field.field_name, as: :i18n, locale: @target_locale
9
+ = form.input field.field_name, as: :i18n
10
+
11
+ - nested_relations_attributes_for(resource.class).each do |field|
12
+ = form.input field.field_name, as: field.field_type
7
13
 
8
14
  = form.actions(except: :submit_and_add_another)
@@ -4,3 +4,4 @@ fr:
4
4
  translate: "Traduire"
5
5
  translation: "Traduction"
6
6
  choose_locale: "Traduire en :"
7
+ disabled_for_locale: "Masquer pour la langue en cours"
@@ -0,0 +1,28 @@
1
+ module Para
2
+ module I18n
3
+ module FormGeneratorConcern
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ include Para::Admin::BaseHelper
8
+ include Para::Generators::FieldHelpers
9
+ include Para::ModelHelper
10
+ include Para::I18n::Helpers::TranslationsHelper
11
+ end
12
+
13
+ private
14
+
15
+ def translated_attributes
16
+ translated_model_fields_for(model)
17
+ end
18
+
19
+ def nested_relations_attributes
20
+ nested_relations_attributes_for(model)
21
+ end
22
+
23
+ def model
24
+ @model ||= class_name.constantize
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,10 +1,9 @@
1
+ require "generators/para/i18n/base_form_generator"
2
+
1
3
  module Para
2
4
  module I18n
3
5
  class FormGenerator < Para::Generators::NamedBase
4
- include Para::Admin::BaseHelper
5
- include Para::Generators::FieldHelpers
6
- include Para::ModelHelper
7
- include Para::I18n::Helpers::TranslationsHelper
6
+ include Para::I18n::FormGeneratorConcern
8
7
 
9
8
  source_root File.expand_path("../templates", __FILE__)
10
9
 
@@ -14,16 +13,6 @@ module Para
14
13
  "app/views/admin/#{ plural_namespaced_path }/_translations_form.html.haml"
15
14
  )
16
15
  end
17
-
18
- private
19
-
20
- def translated_attributes
21
- translated_model_fields_for(model)
22
- end
23
-
24
- def model
25
- @model ||= class_name.constantize
26
- end
27
16
  end
28
17
  end
29
18
  end
@@ -1,9 +1,15 @@
1
- = para_form_for(resource, url: @component.relation_path(resource, :translation)) do |form|
1
+ = para_translations_form_for(resource, url: @component.relation_path(resource, :translation), locale: @target_locale) do |form|
2
2
  = target_locale_select
3
3
 
4
4
  = form.fieldset do
5
+ - I18n.with_locale(@target_locale) do
6
+ = form.input :_disabled_for_locale, as: :boolean, label: t("para.i18n.disabled_for_locale")
7
+
5
8
  <%- translated_attributes.each do |field| -%>
6
- = form.input :<%= field.field_name %>, as: :i18n, locale: @target_locale
9
+ = form.input :<%= field.field_name %>, as: :i18n
10
+ <%- end -%>
11
+ <%- nested_relations_attributes.each do |field| -%>
12
+ = form.input :<%= field.field_name %>, as: :<%= field.field_type %>
7
13
  <%- end -%>
8
14
 
9
15
  = form.actions(except: :submit_and_add_another)
@@ -0,0 +1,18 @@
1
+ require "generators/para/i18n/base_form_generator"
2
+
3
+ module Para
4
+ module I18n
5
+ class NestedFieldsGenerator < Para::Generators::NamedBase
6
+ include Para::I18n::FormGeneratorConcern
7
+
8
+ source_root File.expand_path("../templates", __FILE__)
9
+
10
+ def generate_nested_fields
11
+ template(
12
+ "_translations_fields.html.haml",
13
+ "app/views/admin/#{ plural_namespaced_path }/_translations_fields.html.haml"
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ = form.fieldset do
2
+ - I18n.with_locale(@target_locale) do
3
+ = form.input :_disabled_for_locale, as: :boolean, label: t("para.i18n.disabled_for_locale")
4
+
5
+ <%- translated_attributes.each do |field| -%>
6
+ = form.input :<%= field.field_name %>, as: :i18n
7
+ <%- end -%>
8
+ <%- nested_relations_attributes.each do |field| -%>
9
+ = form.input :<%= field.field_name %>, as: :<%= field.field_type %>
10
+ <%- end -%>
11
+
@@ -1,4 +1,4 @@
1
- class Translate<%= table_name.camelize %> < ActiveRecord::Migration
1
+ class Translate<%= table_name.camelize %> < ActiveRecord::Migration<%= "[#{Rails.version.to_f}]" if Rails.version.to_i >= 5 %>
2
2
  def change
3
3
  add_column :<%= table_name %>, :_translations, :jsonb
4
4
  end
data/lib/para/i18n.rb CHANGED
@@ -8,6 +8,14 @@ require 'para/i18n/model'
8
8
  require 'para/i18n/resources_table'
9
9
  require 'para/i18n/resources_buttons'
10
10
 
11
+ require 'para/i18n/attribute_translation'
12
+ require 'para/i18n/attribute_translation/base'
13
+ require 'para/i18n/attribute_translation/simple_attribute'
14
+ require 'para/i18n/attribute_translation/attachment'
15
+
16
+ require 'para/i18n/form_builder'
17
+ require 'para/i18n/inputs'
18
+
11
19
  require 'para/i18n/friendly_id'
12
20
 
13
21
  require 'para/i18n/i18n_input'
@@ -0,0 +1,26 @@
1
+ module Para
2
+ module I18n
3
+ # This module redirects the reading and writing of the translated attributes to the
4
+ # right attribute translation class
5
+ #
6
+ module AttributeTranslation
7
+ def self.read(locale, resource, attribute)
8
+ attribute_translation_class(locale, resource.class, attribute).read(resource)
9
+ end
10
+
11
+ def self.write(locale, resource, attribute, value)
12
+ attribute_translation_class(locale, resource.class, attribute).write(resource, value)
13
+ end
14
+
15
+ def self.attribute_translation_class(locale, model, attribute)
16
+ attribute_translation_class = if AttributeTranslation::Attachment.matches?(model, attribute)
17
+ AttributeTranslation::Attachment.new(locale, model, attribute)
18
+ else
19
+ AttributeTranslation::SimpleAttribute.new(locale, model, attribute)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+
@@ -0,0 +1,58 @@
1
+ module Para
2
+ module I18n
3
+ module AttributeTranslation
4
+ class Attachment < Para::I18n::AttributeTranslation::Base
5
+ def read(resource)
6
+ attachment = resource.public_send(reflection_name)
7
+
8
+ if default_locale? || attachment.attached? || !fallback_locale
9
+ attachment
10
+ elsif fallback_locale
11
+ self.class.new(fallback_locale, model, attribute).read(resource)
12
+ end
13
+ end
14
+
15
+ def write(resource, value)
16
+ resource.public_send(:"#{reflection_name}=", value)
17
+ end
18
+
19
+ def self.matches?(model, attribute)
20
+ model.reflections.key?("#{attribute}_attachment") &&
21
+ model.reflections.key?("#{attribute}_blob")
22
+ end
23
+
24
+ def self.prepare(model, attribute)
25
+ return unless matches?(model, attribute)
26
+
27
+ (I18n.available_locales - [I18n.default_locale]).each do |locale|
28
+ new(locale, model, attribute).prepare_translated_attachment
29
+ end
30
+ end
31
+
32
+ def prepare_translated_attachment
33
+ model.alias_method(untranslated_getter_name, attribute)
34
+ model.alias_method(untranslated_setter_name, :"#{attribute}=")
35
+ model.has_one_attached(reflection_name)
36
+ end
37
+
38
+ private
39
+
40
+ def reflection_name
41
+ @reflection_name ||= if default_locale?
42
+ untranslated_getter_name
43
+ else
44
+ [attribute, locale, "translation"].join("_")
45
+ end
46
+ end
47
+
48
+ def untranslated_getter_name
49
+ @untranslated_getter_name ||= :"untranslated_#{attribute}"
50
+ end
51
+
52
+ def untranslated_setter_name
53
+ @untranslated_setter_name ||= :"untranslated_#{attribute}="
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,23 @@
1
+ module Para
2
+ module I18n
3
+ module AttributeTranslation
4
+ class Base
5
+ attr_reader :locale, :model, :attribute
6
+
7
+ def initialize(locale, model, attribute)
8
+ @locale = locale.to_s
9
+ @model = model
10
+ @attribute = attribute.to_s
11
+ end
12
+
13
+ def default_locale?
14
+ @default_locale ||= locale == I18n.default_locale.to_s
15
+ end
16
+
17
+ def fallback_locale
18
+ @fallback_locale ||= Para::I18n::Fallbacks.i18n_fallback_for(locale.to_sym)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,37 @@
1
+ module Para
2
+ module I18n
3
+ module AttributeTranslation
4
+ class SimpleAttribute < Para::I18n::AttributeTranslation::Base
5
+ def read(resource)
6
+ # Directly read the plain column / store accessor if the current locale is the
7
+ # default one..
8
+ if default_locale? && attribute != "_disabled_for_locale"
9
+ return resource.read_plain_or_store_attribute(attribute)
10
+ end
11
+
12
+ translations = resource.model_translations[locale]
13
+
14
+ if translations && (translation = translations[attribute])
15
+ translation
16
+ elsif fallback_locale
17
+ # If no translation was returned, try to fallback to the next locale
18
+ self.class.new(fallback_locale, model, attribute).read(resource)
19
+ end
20
+ end
21
+
22
+ def write(resource, value)
23
+ if default_locale? && attribute != "_disabled_for_locale"
24
+ return resource.write_plain_or_store_attribute(attribute, value)
25
+ end
26
+
27
+ # did not us ||= here to fix first assignation.
28
+ # Did not investigate on why ||= does not work
29
+ resource.model_translations[locale] = {} unless resource.model_translations[locale]
30
+ resource.model_translations[locale][attribute] = value
31
+ resource._translations_will_change!
32
+ value
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
@@ -11,7 +11,7 @@ module Para
11
11
  ::Para.config.routes.extend_routes_for(:component) do
12
12
  resource :translation, only: [:edit, :update], controller: '/para/admin/translations'
13
13
  end
14
-
14
+
15
15
  ::Para.config.routes.extend_routes_for(:crud_component) do
16
16
  resource :translation, only: [:edit, :update], controller: '/para/admin/translations'
17
17
  end
@@ -41,7 +41,7 @@ module Para
41
41
  icon: 'globe',
42
42
  label: ::I18n.t('para.i18n.translate'),
43
43
  url: @component.relation_path(resource, :translation, action: :edit)
44
- } if resource.class.translates?
44
+ } if resource.class.translates? && can?(:translate, resource)
45
45
  end
46
46
  end
47
47
  end
@@ -1,12 +1,21 @@
1
1
  module Para
2
2
  module I18n
3
3
  module Fallbacks
4
+ mattr_accessor :_disable_fallbacks
5
+
6
+ def self.without_i18n_fallbacks(&block)
7
+ self._disable_fallbacks = true
8
+ block.call
9
+ ensure
10
+ self._disable_fallbacks = false
11
+ end
12
+
4
13
  def self.i18n_fallback_for(locale)
5
- return unless ::I18n.respond_to?(:fallbacks)
14
+ return if _disable_fallbacks || !::I18n.respond_to?(:fallbacks)
6
15
 
7
16
  if (fallbacks = ::I18n.fallbacks[locale]) && fallbacks.length > 1
8
17
  fallbacks[1]
9
- else
18
+ elsif locale != ::I18n.default_locale
10
19
  ::I18n.default_locale
11
20
  end
12
21
  end
@@ -0,0 +1,10 @@
1
+ require 'para/form_builder'
2
+
3
+ require 'para/i18n/form_builder/nested_form'
4
+ require 'para/i18n/form_builder/translations_form'
5
+
6
+ # Extend the para extended simple_form form builder to included translations related
7
+ # methods.
8
+ #
9
+ SimpleForm::FormBuilder.prepend(Para::I18n::FormBuilder::NestedForm)
10
+ SimpleForm::FormBuilder.prepend(Para::I18n::FormBuilder::TranslationsForm)
@@ -0,0 +1,46 @@
1
+ # frozen_string_literals: true
2
+
3
+ module Para
4
+ module I18n
5
+ module FormBuilder
6
+ # Thid module provides methods to extend the para's nested form functionality by
7
+ # extending the SimpleForm::FormBuilder.
8
+ #
9
+ module NestedForm
10
+ # Traverses the parent_builder chain until the top of the builder chain returning
11
+ # the top-most form builder which represents the one created through the
12
+ # `form_for` like helper.
13
+ #
14
+ # Note that this could go into the Para::FormBuilder::NestedForm module, but it's
15
+ # not used inside Para, so we keep it here for now.
16
+ #
17
+ def top_level_form_builder
18
+ parent_builder = options[:parent_builder]
19
+
20
+ while parent_builder && parent_builder.options[:parent_builder]
21
+ parent_builder = parent_builder.options[:parent_builder]
22
+ end
23
+
24
+ parent_builder || self
25
+ end
26
+
27
+ # Don't allow nested fields destruction if we're in a translations form as this is
28
+ # the method used by the FormBuilder#remove_association_button method to check
29
+ # whether it's allowed to render the remove button or not.
30
+ #
31
+ def allow_destroy?
32
+ return false if translations_form?
33
+
34
+ super
35
+ end
36
+
37
+ # Overrides the Para::FormBuilder::NestedForm#fields_partial_name method to render
38
+ # a different nested fields partial when the builder is a translations form
39
+ #
40
+ def nested_fields_partial_name
41
+ translations_form? ? :translations_fields : :fields
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literals: true
2
+
3
+ module Para
4
+ module I18n
5
+ module FormBuilder
6
+ # Thid module extends the Para overriden SimpleForm::FormBuilder to include some
7
+ # trnaslations form related methods and overrides, allowing a simple use of
8
+ # translations forms with the para-i18n gem.
9
+ #
10
+ module TranslationsForm
11
+ TRANSLATIONS_FORM_PARAM_KEY = :_translations_form
12
+
13
+ # Allows storing a gobal reference to the target locale of the translations form,
14
+ # which allows input objects to fetch it directly, without having to provide
15
+ # manually the :locale parameter for each input
16
+ #
17
+ # Example :
18
+ #
19
+ # = para_translations_form_for(resource, locale: @target_Locale) do |form|
20
+ # = form.input :title, as: :i18n # No need to pass `:locale` option here.
21
+ #
22
+ def target_locale
23
+ top_level_form_builder.options.with_indifferent_access[:locale]
24
+ end
25
+
26
+ # Allows checking if the current form builder is a translations form, depending
27
+ # on the passed TRANSLATIONS_FORM_PARAM_KEY option. This is automatically passed
28
+ # to the form builder when using the `para_translations_form_for` helper.
29
+ #
30
+ # Example :
31
+ #
32
+ # para_translations_form_for(resource)
33
+ # # OR
34
+ # para_form_for(resource, _translations_form: true)
35
+ #
36
+ def translations_form?
37
+ !!top_level_form_builder.options.with_indifferent_access[TRANSLATIONS_FORM_PARAM_KEY]
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -10,6 +10,15 @@ module FriendlyId
10
10
  def included(model_class)
11
11
  model_class.extend(ClassMethods)
12
12
 
13
+ # Support for I18n finder methods on ActiveRecord::Relation of the including
14
+ # model. Example :
15
+ model_class.instance_eval do
16
+ relation.class.send(:include, ClassMethods)
17
+ if (ActiveRecord::VERSION::MAJOR == 4 && ActiveRecord::VERSION::MINOR == 2) || ActiveRecord::VERSION::MAJOR >= 5
18
+ model_class.send(:extend, ClassMethods)
19
+ end
20
+ end
21
+
13
22
  # Support for friendly finds on associations for Rails 4.0.1 and above.
14
23
  #
15
24
  # Borrowed from FriendlyId::Finders module
@@ -9,6 +9,15 @@ module Para
9
9
  model.translated_attribute_names.include?(field.name.to_sym)
10
10
  end
11
11
  end
12
+
13
+ def nested_relations_attributes_for(model)
14
+ model_field_mappings(model).fields.select do |field|
15
+ next unless field.field_type.in?(["nested_one", "nested_many"])
16
+
17
+ # This returns nil if the target model is not translated
18
+ model.reflect_on_association(field.name).klass.translatable?
19
+ end
20
+ end
12
21
  end
13
22
  end
14
23
  end
@@ -26,11 +26,11 @@ module Para
26
26
  private
27
27
 
28
28
  def locale
29
- if (locale = options[:locale])
30
- locale
31
- else
32
- raise 'Missing `:locale` option passed to :i18n input.'
33
- end
29
+ locale = options.fetch(:locale, @builder.target_locale)
30
+ return locale if locale.present?
31
+
32
+ raise 'No target locale for the current i18n input. Please provide a `:locale`' \
33
+ 'option to the :i18n input or the `para_translations_form_for` method'
34
34
  end
35
35
 
36
36
  def original_content
@@ -0,0 +1,4 @@
1
+ require "para/inputs/nested_many_input"
2
+ require 'para/i18n/inputs/nested_many_input'
3
+
4
+ Para::Inputs::NestedManyInput.prepend(Para::I18n::Inputs::NestedManyInput)
@@ -0,0 +1,41 @@
1
+ module Para
2
+ module I18n
3
+ module Inputs
4
+ module NestedManyInput
5
+ def input(_wrapper_options = nil)
6
+ # Disable the add button and orderable features of the input.
7
+ # Note : The remove button disabling is done by the
8
+ # Para::I18n::FormBuilder::TranslationsForm extension
9
+ if within_translations_form?
10
+ options[:add_button] = false
11
+ options[:orderable] = false
12
+ end
13
+
14
+ super
15
+ end
16
+ private
17
+
18
+ def within_translations_form?
19
+ @builder.translations_form?
20
+ end
21
+
22
+ # Extend remote partial params with the :_translations_form key if we're in the
23
+ # context of a translations form builder.
24
+ #
25
+ def remote_partial_params
26
+ super.tap do |remote_partial_params|
27
+ if within_translations_form?
28
+ remote_partial_params.deep_merge!(
29
+ builder_options: {
30
+ Para::I18n::FormBuilder::TranslationsForm::TRANSLATIONS_FORM_PARAM_KEY => true,
31
+ locale: @builder.target_locale
32
+ }
33
+ )
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
41
+
@@ -9,33 +9,17 @@ module Para
9
9
  end
10
10
 
11
11
  def read_translated_attribute(field, locale = ::I18n.locale)
12
- return read_plain_or_store_attribute(field) if locale == ::I18n.default_locale
13
-
14
- if model_translations[locale.to_s]
15
- if (translation = model_translations[locale.to_s][field.to_s])
16
- return translation
17
- end
18
- end
19
-
20
- # If no translation was returned, try to fallback to the next locale
21
- if (fallback_locale = Fallbacks.i18n_fallback_for(locale))
22
- read_translated_attribute(field, fallback_locale)
23
- end
12
+ Para::I18n::AttributeTranslation.read(locale, self, field)
24
13
  end
25
14
 
26
- def write_translated_attribute field, value, locale = ::I18n.locale
27
- return write_plain_or_store_attribute(field, value) if locale == ::I18n.default_locale
28
-
29
- # did not us ||= here to fix first assignation.
30
- # Did not investigate on why ||= does not work
31
- model_translations[locale.to_s] = {} unless model_translations[locale.to_s]
32
- model_translations[locale.to_s][field.to_s] = value
15
+ def write_translated_attribute(field, value, locale = ::I18n.locale)
16
+ Para::I18n::AttributeTranslation.write(locale, self, field, value)
33
17
  end
34
18
 
35
19
  def model_translations
36
20
  unless respond_to?(:_translations)
37
21
  raise "The model #{ self.class.name } is not translatable. " +
38
- "Please run `rails g i18n_admin:translate #{ self.model_name.element }` " +
22
+ "Please run `rails g para:i18n:translate #{ self.model_name.element }` " +
39
23
  "generator to create the model's migration."
40
24
  end
41
25
 
@@ -43,11 +27,20 @@ module Para
43
27
  end
44
28
 
45
29
  def translation_for(locale)
46
- model_translations[locale.to_s] || {}
30
+ case locale.to_sym
31
+ when I18n.default_locale then default_locale_translations
32
+ else model_translations[locale.to_s] || {}
33
+ end.with_indifferent_access
47
34
  end
48
35
 
49
- private
36
+ def disabled_for_locale?
37
+ self.class.translates? && _disabled_for_locale
38
+ end
50
39
 
40
+ # This method allows reading an attribute from the ActiveRecord table, whether it's
41
+ # a plain column of the table, or a field of a store (hash, json etc.) of the table,
42
+ # accessed through the ActiveRecord.store_accessor interface.
43
+ #
51
44
  def read_plain_or_store_attribute(field)
52
45
  if plain_column?(field)
53
46
  read_attribute(field)
@@ -68,6 +61,8 @@ module Para
68
61
  end
69
62
  end
70
63
 
64
+ private
65
+
71
66
  def plain_column?(field)
72
67
  self.class.columns_hash.key?(field.to_s)
73
68
  end
@@ -80,25 +75,49 @@ module Para
80
75
  store.first if store
81
76
  end
82
77
 
78
+ def default_locale_translations
79
+ translated_attribute_names.each_with_object({}) do |attribute_name, hash|
80
+ hash[attribute_name] = read_plain_or_store_attribute(attribute_name)
81
+ end
82
+ end
83
+
83
84
  module ClassMethods
84
85
  def translates(*fields)
85
86
  self.translated_attribute_names = fields.map(&:to_sym)
86
87
  self.translatable = true
87
88
 
88
89
  fields.each do |field|
89
- define_method field do
90
- read_translated_attribute(field)
91
- end
90
+ prepare_attribute_translation(field)
91
+ end
92
+
93
+ define_method(:_disabled_for_locale) do
94
+ read_translated_attribute(:_disabled_for_locale) == "1"
95
+ end
92
96
 
93
- define_method :"#{ field }=" do |value|
94
- write_translated_attribute(field, value)
95
- end
97
+ define_method(:_disabled_for_locale=) do |value|
98
+ write_translated_attribute(:_disabled_for_locale, value)
96
99
  end
97
100
  end
98
101
 
99
102
  def translates?
100
103
  translatable
101
104
  end
105
+
106
+ private
107
+
108
+ def prepare_attribute_translation(attribute)
109
+ # Let the Para::I18n::AttributeTranslation::Attachment module handle
110
+ # ActiveStorage attachment fields translation preparation.
111
+ Para::I18n::AttributeTranslation::Attachment.prepare(self, attribute)
112
+
113
+ define_method(attribute) do
114
+ read_translated_attribute(attribute)
115
+ end
116
+
117
+ define_method(:"#{attribute}=") do |value|
118
+ write_translated_attribute(attribute, value)
119
+ end
120
+ end
102
121
  end
103
122
  end
104
123
  end
@@ -2,7 +2,7 @@ module Para
2
2
  module I18n
3
3
  module ResourcesButtons
4
4
  def translate_button(resource)
5
- return unless resource.class.translates?
5
+ return unless resource.class.translates? && view.can?(:translate, resource)
6
6
 
7
7
  path = component.relation_path(resource, :translation, action: :edit)
8
8
  options = { class: 'btn btn-default' }
@@ -1,5 +1,5 @@
1
1
  module Para
2
2
  module I18n
3
- VERSION = "0.3.2"
3
+ VERSION = "0.5.0"
4
4
  end
5
5
  end
data/para-i18n.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
20
  spec.require_paths = ["lib"]
21
21
 
22
- spec.add_dependency "para", "~> 0.8"
22
+ spec.add_dependency "para", ">= 0.9.2", "<= 1.0"
23
23
 
24
24
  spec.add_development_dependency "bundler", "~> 1.11"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
metadata CHANGED
@@ -1,29 +1,35 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: para-i18n
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Valentin Ballestrino
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-04-16 00:00:00.000000000 Z
11
+ date: 2021-02-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: para
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: 0.9.2
20
+ - - "<="
18
21
  - !ruby/object:Gem::Version
19
- version: '0.8'
22
+ version: '1.0'
20
23
  type: :runtime
21
24
  prerelease: false
22
25
  version_requirements: !ruby/object:Gem::Requirement
23
26
  requirements:
24
- - - "~>"
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ version: 0.9.2
30
+ - - "<="
25
31
  - !ruby/object:Gem::Version
26
- version: '0.8'
32
+ version: '1.0'
27
33
  - !ruby/object:Gem::Dependency
28
34
  name: bundler
29
35
  requirement: !ruby/object:Gem::Requirement
@@ -83,24 +89,38 @@ files:
83
89
  - app/assets/javascripts/para/admin/translation.coffee
84
90
  - app/assets/javascripts/para/i18n.coffee
85
91
  - app/controllers/para/admin/translations_controller.rb
92
+ - app/helpers/para/i18n/form_helper.rb
93
+ - app/views/para/admin/resources/_translations_fields.html.haml
86
94
  - app/views/para/admin/resources/_translations_form.html.haml
87
95
  - app/views/para/admin/translations/_target_locale_select.html.haml
88
96
  - app/views/para/admin/translations/edit.html.haml
89
97
  - bin/console
90
98
  - bin/setup
91
99
  - config/locales/para-i18n.fr.yml
100
+ - lib/generators/para/i18n/base_form_generator.rb
92
101
  - lib/generators/para/i18n/form/form_generator.rb
93
102
  - lib/generators/para/i18n/form/templates/_translations_form.html.haml
103
+ - lib/generators/para/i18n/nested_fields/nested_fields_generator.rb
104
+ - lib/generators/para/i18n/nested_fields/templates/_translations_fields.html.haml
94
105
  - lib/generators/para/i18n/translate/templates/model_migration.rb.erb
95
106
  - lib/generators/para/i18n/translate/translate_generator.rb
96
107
  - lib/para/i18n.rb
108
+ - lib/para/i18n/attribute_translation.rb
109
+ - lib/para/i18n/attribute_translation/attachment.rb
110
+ - lib/para/i18n/attribute_translation/base.rb
111
+ - lib/para/i18n/attribute_translation/simple_attribute.rb
97
112
  - lib/para/i18n/engine.rb
98
113
  - lib/para/i18n/fallbacks.rb
114
+ - lib/para/i18n/form_builder.rb
115
+ - lib/para/i18n/form_builder/nested_form.rb
116
+ - lib/para/i18n/form_builder/translations_form.rb
99
117
  - lib/para/i18n/friendly_id.rb
100
118
  - lib/para/i18n/helpers.rb
101
119
  - lib/para/i18n/helpers/translations_form_helper.rb
102
120
  - lib/para/i18n/helpers/translations_helper.rb
103
121
  - lib/para/i18n/i18n_input.rb
122
+ - lib/para/i18n/inputs.rb
123
+ - lib/para/i18n/inputs/nested_many_input.rb
104
124
  - lib/para/i18n/model.rb
105
125
  - lib/para/i18n/resources_buttons.rb
106
126
  - lib/para/i18n/resources_table.rb
@@ -125,8 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
125
145
  - !ruby/object:Gem::Version
126
146
  version: '0'
127
147
  requirements: []
128
- rubyforge_project:
129
- rubygems_version: 2.6.11
148
+ rubygems_version: 3.1.4
130
149
  signing_key:
131
150
  specification_version: 4
132
151
  summary: Para CMS I18n admin module for models