Module: RailsI18nOnair::LiveUi::ControllerHelper

Defined in:
lib/rails_i18n_onair/live_ui/controller_helper.rb

Overview

Prepended to AbstractController::Translation so that controller-level t() calls (used for flash messages, mailers, etc.) embed invisible markers around the translated text.

The LiveUi::Middleware later replaces these markers with editable wrappers — the same ones TranslationHelper uses in views.

Markers use Unicode mathematical brackets (⟦ ⟧) which:

• survive ERB HTML-escaping (only & < > " ' are escaped)
• survive flash session serialization (just string bytes)
• are extremely unlikely in real translation text

When Live UI is OFF or no translator is signed in, the call falls straight through — zero overhead.

Constant Summary collapse

I18N_MARKER_OPEN =

"\u27E6".freeze
I18N_MARKER_CLOSE =

"\u27E7".freeze

Instance Method Summary collapse

Instance Method Details

#translate(key, **options) ⇒ Object Also known as: t



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/rails_i18n_onair/live_ui/controller_helper.rb', line 23

def translate(key, **options)
  wrapping = RailsI18nOnair.configuration.live_ui? && _i18n_onair_translator_signed_in?

  # Interpolation values may themselves carry markers from a nested
  # t() call — strip them so the outer text stays clean.
  Unwrapper.unwrap_options!(options) if wrapping

  result = super(key, **options)

  return result unless wrapping
  # Only plain text can carry markers (t() may return a Hash subtree)
  return result unless result.is_a?(String)

  # Resolve lazy keys (.title → controller.action.title)
  resolved_key = if key.to_s.start_with?(".")
                   "#{controller_path.tr('/', '.')}.#{action_name}#{key}"
                 else
                   key.to_s
                 end
  # Include :scope so the editor saves to the correct full key path
  if options[:scope]
    resolved_key = (Array(options[:scope]).map(&:to_s) + [resolved_key]).join(".")
  end

  # Strip region from locale: "en_FRA" → "en"
  locale = (options[:locale] || I18n.locale).to_s.split(/[-_]/).first

  # ⟦i18n:key:locale⟧translated text⟦/i18n⟧
  "#{I18N_MARKER_OPEN}i18n:#{resolved_key}:#{locale}#{I18N_MARKER_CLOSE}" \
  "#{result}" \
  "#{I18N_MARKER_OPEN}/i18n#{I18N_MARKER_CLOSE}"
end