Skip to content

Fall back to global translations in Component.translate - #2727

Merged
joelhawksley merged 3 commits into
ViewComponent:mainfrom
afurm:class-translate-missing-keys
Oct 19, 2026
Merged

joelhawksley merged 3 commits into
ViewComponent:mainfrom
afurm:class-translate-missing-keys

Conversation

@afurm

@afurm afurm commented Oct 17, 2026

Copy link
Copy Markdown
Contributor

What are you trying to accomplish?

Component.translate (added in #1656) blows up for any key that isn't in the component's sidecar file:

TranslatableComponent.t(".missing")   # => UncaughtThrowError: uncaught throw :exception
TranslatableComponent.t("from.rails") # => UncaughtThrowError, even though the key is in config/locales
MyComponent.t(".message")             # no sidecar file => NoMethodError: undefined method 'translate' for nil

The I18n backend throws :exception for a missing key and expects I18n.translate to catch it. The class method calls the backend directly, so nothing catches it. For components without sidecar translations, __vc_i18n_backend is nil.

What approach did you choose and why?

Do what the instance method already does: try the sidecar backend first, catch the missing translation, and fall back to the global translations, here through I18n.translate, since there's no view context on the class. A missing key now returns the usual "Translation missing" string, and default: and raise: true behave like they do with I18n.t. When there are no sidecar translations, it goes straight to I18n.translate.

Anything you want to highlight for special attention from reviewers?

The class method still doesn't do the HTML-safe handling for _html keys. #1656 left that out on purpose, so I didn't touch it.

afurm and others added 3 commits October 17, 2026 10:50
Calling translate on the component class with a key that isn't in the
sidecar translations raised UncaughtThrowError, because the I18n backend
throws :exception for a missing key and nothing caught it. Components
without sidecar translations raised NoMethodError on the nil backend.

Fall back to I18n.translate in both cases, like the instance method falls
back to the view context's translate.
Use I18nBackend#exists? to decide between sidecar and global
translations in both the class and instance translate methods, rather
than catching I18n's internal :exception throw. This also fixes
`default:` shadowing existing global translations, since the sidecar
backend applied the default before the fallback could run.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: ba89fbcb-d0e9-4f12-8673-169fbe391979
@joelhawksley
joelhawksley merged commit 5713b34 into ViewComponent:main Oct 19, 2026
19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants