x-govuk/govuk-form-builder

Possible improvement: localisation of nested attributes

Closed this issue ยท 6 comments

Hello,

Not a high priority as there is a work around which is to specify the legend text, label text, etc. via options or proc.
However I've noticed nested attributes are not automatically translated (via locales) like the rest of attributes.

For nested attributes, the #schema_path method in the Localisation trait will produce the following i18n lookup key:

helpers.label.steps_case_codefendants_form[codefendants_attributes][0].first_name

Although this is technically correct, it makes for complicated, or impractical locales as you need to define locales for each of the indexes. This is produced usually by using f.fields_for :collection and nest inside attributes for elements of that collection.

It seems like the @object_name used in the #schema_path method is the culprit. In my example that would be steps_case_codefendants_form[codefendants_attributes][0]. Usually, not nested attributes would produce just steps_case_codefendants_form.

I wonder if it is worth exploring the possibility of "un-nesting" these objects safely without impacting any other translations? It may seem obvious to just remove anything in brackets so these objects become un-nested and their locales are predictable, however I'm not sure if there are other implications here.

I've hacked together a local modification to the #schema_path method that removes anything in brackets with gsub and it works just fine, for input labels, radios, and other elements as expected, but unsure this is something worth dealing with at the gem level or leave this kind of translations passed as options to the helpers?

Perhaps instead of removing everything in brackets it might be interesting to keep the nested relationship (but not the indexing) as a means of "namespace" in the locales. It could also avoid potential clashing with attributes of the same name in the parent (probably an edge case but still).
So the above @object_name might produce this other i18n key instead: helpers.label.steps_case_codefendants_form.codefendants_attributes.first_name

Anyways, just an idea ๐Ÿ’ก
Let me know if you need more examples!

Thanks @zheileman.

I'd be more than happy for something like this to go in. We might need to mark it as experimental and enable it via a config flag, it's a really far reaching bit of the code.

I took your initial code and wrote a really basic spec, also I think we can simplify the regexp and make it work for multiple levels of nesting via

base_object_name = @object_name.to_s.scan(%r{\w+}).join(".")

That's great @peteryates, and I totally agree with you this may be an experimental feature that has to be enabled conciously via config. I feel more comfortable that way, just in case ๐Ÿ‘

I noticed your regex might not give us the result we want, because it will preserve the indexes? Unless I'm missing something here.

Given the following @object_name I get these results:

'steps_case_codefendants_form[codefendants_attributes][0]'.scan(%r{(\w+)}).join(".")
=> "steps_case_codefendants_form.codefendants_attributes.0"

'steps_case_codefendants_form[codefendants_attributes][0][foobar_attributes][1]'.scan(%r{(\w+)}).join(".")
=> "steps_case_codefendants_form.codefendants_attributes.0.foobar_attributes.1"

It keeps the indexes which makes in effect the translation through locales difficult or not possible. I think it would be better to remove the indexes, by probably tweaking a bit the regex.

Ah yeah - my test case didn't have indices ๐Ÿ™ˆ

It would be super helpful if you could add a test case with them and we can take a look at improving the regexp (or breaking out some StringScanner.

@peteryates Yep no worries! I will give it a go maybe later today ๐Ÿ‘

Great, thanks. I created #386, let's continue this there.

#386 is merged and will be in the next release ๐Ÿš€