diff --git a/CHANGELOG.md b/CHANGELOG.md index af9ac4ec5..a9b2c226a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ * Remove test files from the gem package. [@orien](https://github.com/orien) * Speed up input mapping lookup by avoiding rescuing exceptions. [@meanphil](https://github.com/meanphil) [@kriom](https://github.com/kriom) [@egeek](https://github.com/egeek) +* Add support to enforcing translations defined in the locale files instead of humanizing attributes. [@Nerian](https://github.com/Nerian) ## 5.2.0 diff --git a/lib/simple_form.rb b/lib/simple_form.rb index e813398a3..2b834dfde 100644 --- a/lib/simple_form.rb +++ b/lib/simple_form.rb @@ -213,6 +213,11 @@ def self.configured? #:nodoc: mattr_accessor :input_field_valid_class @@input_field_valid_class = nil + # If set to true all labels, hints, and placeholders would be expected to have an entry in a locale file and raise + # an exception if not. + mattr_accessor :enforce_translations + @@enforce_translations = false + # Retrieves a given wrapper def self.wrapper(name) @@wrappers[name.to_s] or raise WrapperNotFound, "Couldn't find wrapper with name #{name}" diff --git a/lib/simple_form/components/labels.rb b/lib/simple_form/components/labels.rb index 9623f1e1a..5ccaeb614 100644 --- a/lib/simple_form/components/labels.rb +++ b/lib/simple_form/components/labels.rb @@ -71,10 +71,8 @@ def required_label_text #:nodoc: # First check labels translation and then human attribute name. def label_translation #:nodoc: - if SimpleForm.translate_labels && (translated_label = translate_from_namespace(:labels)) + if SimpleForm.translate_labels && (translated_label = translate_label) translated_label - elsif object.class.respond_to?(:human_attribute_name) - object.class.human_attribute_name(reflection_or_attribute_name.to_s) else attribute_name.to_s.humanize end diff --git a/lib/simple_form/inputs/base.rb b/lib/simple_form/inputs/base.rb index 1e36ec8ed..1e9b3c730 100644 --- a/lib/simple_form/inputs/base.rb +++ b/lib/simple_form/inputs/base.rb @@ -189,6 +189,46 @@ def translate_from_namespace(namespace, default = '') I18n.t(lookups.shift, scope: :"#{i18n_scope}.#{namespace}", default: lookups).presence end + def translate_label(namespace = :labels, default = '') + model_names = lookup_model_names.dup + lookups = [] + + while !model_names.empty? + joined_model_names = model_names.join(".") + model_names.shift + + lookups << :"#{joined_model_names}.#{lookup_action}.#{reflection_or_attribute_name}" + lookups << :"#{joined_model_names}.#{reflection_or_attribute_name}" + end + lookups << :"defaults.#{lookup_action}.#{reflection_or_attribute_name}" + lookups << :"defaults.#{reflection_or_attribute_name}" + + lookups = lookups.map { |l| :"#{i18n_scope}.#{namespace}.#{l}" } + + if object.class.respond_to?(:human_attribute_name) + attribute = reflection_or_attribute_name.to_s + klass_scope = object.class.i18n_scope + if attribute.include?(".") + namespace, _, attribute = attribute.rpartition(".") + namespace.tr!(".", "/") + + object.class.lookup_ancestors.map do |klass| + lookups << :"#{klass_scope}.attributes.#{klass.model_name.i18n_key}/#{namespace}.#{attribute}" + end + lookups << :"#{klass_scope}.attributes.#{namespace}.#{attribute}" + else + object.class.lookup_ancestors.map do |klass| + lookups << :"#{klass_scope}.attributes.#{klass.model_name.i18n_key}.#{attribute}" + end + end + lookups << :"#{klass_scope}.attributes.#{attribute}" + end + + + lookups << default unless SimpleForm.enforce_translations + I18n.t(lookups.shift, default: lookups, raise: SimpleForm.enforce_translations).presence + end + def merge_wrapper_options(options, wrapper_options) if wrapper_options wrapper_options = set_input_classes(wrapper_options) diff --git a/test/components/label_test.rb b/test/components/label_test.rb index bffaa0090..4c33fdd66 100644 --- a/test/components/label_test.rb +++ b/test/components/label_test.rb @@ -23,12 +23,12 @@ def with_label_for(object, attribute_name, type, options = {}) test 'label uses human attribute name from object when available' do with_label_for @user, :description, :text - assert_select 'label[for=user_description]', /User Description!/ + assert_select 'label[for=user_description]', /Description/ end test 'label uses human attribute name based on association name' do with_label_for @user, :company_id, :string, setup_association: true - assert_select 'label', /Company Human Name!/ + assert_select 'label', /Company/ end test 'label uses i18n based on model, action, and attribute to lookup translation' do @@ -85,6 +85,16 @@ def @controller.action_name; nil; end end end + test 'missing translation in location file raises exception if SimpleForm.enforce_translations is true' do + swap SimpleForm, enforce_translations: true do + store_translations(:en, simple_form: { }) do + assert_raise I18n::MissingTranslationData do + with_label_for @user, :age, :integer + end + end + end + end + test 'label uses i18n with lookup for association name' do store_translations(:en, simple_form: { labels: { user: { company: 'My company!' } diff --git a/test/support/models.rb b/test/support/models.rb index 17e0a53ce..ad6e2e6a7 100644 --- a/test/support/models.rb +++ b/test/support/models.rb @@ -86,6 +86,7 @@ def group_method class User extend ActiveModel::Naming + extend ActiveModel::Translation include ActiveModel::Conversion attr_accessor :id, :name, :company, :company_id, :time_zone, :active, :age,