Magnus Remøe
Magnus Remøe

Reputation: 1

Defining translations for nested forms in namespaced resources

I have the below setup

class BudgetLine < ApplicationRecord
  has_many :budget_line_items
  accepts_nested_attributes_for :budget_line_items
end

class BudgetLine::Accommodation < BudgetLine
end

class BudgetLineItem < ApplicationRecord
  belongs_to :budget_line
end

Now I'm trying to specify labels for the nested form of BudgetLineItem inside BudgetLine::Accommodation. According to the i18n documentation, you can normally do something like this:

en:
  activerecord:
    attributes:
      user/role:
        admin: "Admin"
        contributor: "Contributor"

This works if the model in question is not namespaced, as with User above. However, when you want to specify a namespaced model it has the same syntax, so it becomes:

en:
  activerecord:
    attributes:
      budget_line/accommodation/budget_line_items:
        unit: Room

which does not work.

I've tried different variations of this, e.g.

en:
  activerecord:
    attributes:
      budget_line:
        accommodation/budget_line_items:
          price: Price (USD)

which also does not work, because this way of specifying namespaces in locales seems to be deprecated.

As far as I understand, for the label to be translated correctly, the following should return the correct translation: BudgetLine::Accommodation.human_attribute_name("budget_line_items.unit"), but so far I've been unsuccessful in my attempts to target this.

Is there a way to solve for this use case?

Upvotes: 0

Views: 65

Answers (1)

max
max

Reputation: 102016

It's not depreachiated. You just have unrealistic expectations of how it's supposted to work.

Rails looks up translations through the API provived by ActiveModel::Naming which is just based on the class name:

class Foo
  extend ActiveModel::Naming
end

Foo.name                 == "foo"
Foo.model_name.i18n_key  == :foo

# This is the correct way to define nested classes
class Foo
  class Bar
    extend ActiveModel::Naming
  end
end

Foo::Bar.name     == "Foo::Bar"
Foo::Bar.i18n_key == :"foo/bar"

As you can see nested constants use / as the separator for I18n keys as : has special significance in YAML.

I don't know if you're maybe confusing constant nesting which is a language level feature with nested attributes or just somehow thinking that the associations play a role in this (they don't).

BudgetLineItem is a the top level module nesting (main) and it's I18n key is :budget_line_item no matter if it belongs_to a X or Y.

Rails is thus always going to lookup the translation from:

en:
  activerecord:
    attributes:
      budget_line:
        price: Price (USD)

If you wanted the model to be translated differently you would use different classes with different nesting:

class BudgetLine
  class Accommodation < BudgetLine
    class BudgetLineItem < ::BudgetLineItem 
      # ...
    end
  end
end

Upvotes: 0

Related Questions