Module: RailsErrorDashboard::I18nHelper
- Includes:
- ActionView::Helpers::JavaScriptHelper
- Included in:
- BacktraceHelper, MailerI18nHelper, OverviewHelper, UserAgentHelper
- Defined in:
- app/helpers/rails_error_dashboard/i18n_helper.rb
Overview
View-layer entry point for RED's translations.
The helper is deliberately named red_t, not t. Two reasons:
1. Overriding `t` in an engine helper risks colliding with the host app's
own helpers and with Rails' built-in translate, which has lazy-lookup
behaviour ("t('.title')") that RED's private backend does not provide.
2. An explicit name makes every translated site greppable — worth a lot
when the remaining ~1,600 strings get extracted a page at a time.
Instance Method Summary collapse
-
#red_chart_date(time, pattern) ⇒ String
A finished, localized date string for somewhere the browser will not re-render it.
-
#red_js_t(key, **options) ⇒ String
Translate for interpolation into a JavaScript string literal.
-
#red_js_tp(key, count:, **options) ⇒ Object
Pluralized variant of red_js_t, for counts written by JS.
-
#red_js_translations ⇒ Hash
The translation payload handed to the browser as window.RED_I18N.
-
#red_locale ⇒ String
The locale this render should use.
-
#red_t(key, **options) ⇒ String
Translate a key in the current request's locale.
-
#red_time_format(preset) ⇒ String
A strftime pattern for one of ApplicationHelper#local_time's presets, localized.
-
#red_tp(key, count:, **options) ⇒ Object
Pluralized translation.
Instance Method Details
#red_chart_date(time, pattern) ⇒ String
A finished, localized date string for somewhere the browser will not re-render it.
Almost every timestamp on the dashboard goes out as a that formatDateTime() localizes client-side. Chart labels cannot: they are serialized into a JS array and handed to Chart.js as plain strings, so whatever the server writes is what the axis shows. Calling strftime directly there is what put English month names on every locale's charts (#178) — Ruby's strftime is not locale-aware.
Same formatter the mailers and the Slack/Discord payloads use, so a chart axis and an email agree about what a date looks like.
170 171 172 173 174 175 176 177 178 |
# File 'app/helpers/rails_error_dashboard/i18n_helper.rb', line 170 def red_chart_date(time, pattern) return "" if time.nil? time = time.to_time if time.respond_to?(:to_time) && !time.is_a?(Time) Services::LocalizedTimeFormatter.call(time, pattern: pattern, locale: red_locale) rescue StandardError # A chart with an English axis beats a chart that fails to render. time.respond_to?(:strftime) ? time.strftime(pattern) : time.to_s end |
#red_js_t(key, **options) ⇒ String
Translate for interpolation into a JavaScript string literal.
red_t html-escapes, which is right for page text and wrong here. The two sinks in the layout's script blocks disagree about entities: showToast and innerHTML decode ' back to an apostrophe, but textContent renders it literally, so a French string would display "d'accéder" on screen.
escape_javascript is what the surrounding code already uses for flash
messages (<%= j flash[:notice] %>), and it is the correct escaping for
this position: it neutralizes quotes, backslashes and line terminators
that would break out of or truncate the literal, without touching
characters the sink will render.
Values still pass through the same total lookup, so a missing key is readable text rather than a raise inside a breakout — and then consumed as JS strings, so ERB escaping here would render literal & in the browser.
116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'app/helpers/rails_error_dashboard/i18n_helper.rb', line 116 def red_js_translations locale = red_locale { "locale" => locale, "js" => I18nStore.subtree("red.js", locale: locale), "formats" => I18nStore.subtree("red.time.formats", locale: locale), # Not under red.js because the server renders it too — local_time_ago # wraps the same key. Sharing one key is the point: both sides then # put "ago" wherever the language wants it, rather than each guessing. "ago" => I18nStore.translate("red.time.ago", locale: locale) } rescue StandardError {} end |
#red_locale ⇒ String
The locale this render should use.
An explicit @red_locale wins over Current. Mailer and notification templates render outside the dashboard's around_action: there is no request, so Current.locale is nil at best and — on a reused Puma or job-runner thread — another request's leftover value at worst. That is the #143/#148 bug class. Those templates are handed a locale resolved at enqueue time (Concerns::LocalizedJob) and assigned to @red_locale, so reading it here is what makes the async path independent of thread state.
Views rendered in a real dashboard request set no @red_locale and fall through to Current, which is correct there.
64 65 66 67 68 69 70 71 |
# File 'app/helpers/rails_error_dashboard/i18n_helper.rb', line 64 def red_locale explicit = defined?(@red_locale) ? @red_locale : nil return I18nStore.resolve(explicit) if explicit.present? Current.locale_or_default rescue StandardError I18nStore::DEFAULT_LOCALE end |
#red_t(key, **options) ⇒ String
Translate a key in the current request's locale.
Output is HTML-escaped unless the key ends in _html, matching Rails' convention. Escaping happens here rather than in I18nStore because it is a view concern — mailers' text parts and JS payloads must not be escaped.
26 27 28 29 30 31 32 33 34 35 36 |
# File 'app/helpers/rails_error_dashboard/i18n_helper.rb', line 26 def red_t(key, **) value = I18nStore.translate(key, locale: red_locale, **) if key.to_s.end_with?("_html") value.html_safe else ERB::Util.html_escape(value) end rescue StandardError "" end |
#red_time_format(preset) ⇒ String
A strftime pattern for one of ApplicationHelper#local_time's presets, localized. Falls back to the English pattern for an unknown preset.
Kept here rather than inline in the view so the Ruby fallback rendering and the browser's data-format re-render always agree on the pattern.
141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'app/helpers/rails_error_dashboard/i18n_helper.rb', line 141 def red_time_format(preset) key = "red.time.formats.#{preset}" pattern = I18nStore.translate(key, locale: red_locale) # A miss returns humanized key text, which would be a nonsense strftime # pattern. Detect it by the absence of any % directive and fall back. return pattern if pattern.include?("%") I18nStore.translate("red.time.formats.full", locale: I18nStore::DEFAULT_LOCALE) rescue StandardError "%B %d, %Y %I:%M:%S %p" end |
#red_tp(key, count:, **options) ⇒ Object
Pluralized translation. Selects the plural form from count using the
locale's CLDR rules, so it handles languages with more than English's
two forms.
Always use this rather than a ternary on "s" — an English binary plural is wrong in most languages, and several have no plural distinction at all.
46 47 48 |
# File 'app/helpers/rails_error_dashboard/i18n_helper.rb', line 46 def red_tp(key, count:, **) red_t(key, count: count, **) end |