Class: Hanami::Providers::I18n::Backend

Inherits:
Object
  • Object
show all
Defined in:
lib/hanami/providers/i18n/backend.rb

Overview

A wrapper that provides a full ‘I18n`-like interface for an individual I18n backend. This allows each Hanami slice to have its own isolated I18n instance.

Unlike the global I18n module which uses class variables for configuration, this wrapper maintains per-instance state for true isolation between slices.

Since:

  • x.x.x

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(backend, locale: nil, default_locale: :en, available_locales: [], fallbacks: nil) ⇒ Backend

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Creates a new Backend instance.

Parameters:

  • backend (I18n::Backend::Base)

    the underlying I18n backend

  • locale (Symbol, String, nil) (defaults to: nil)

    initial locale to set in thread-local storage

  • default_locale (Symbol, String) (defaults to: :en)

    the default locale to use when no locale is set

  • available_locales (Array<Symbol, String>) (defaults to: [])

    list of available locales

  • fallbacks (I18n::Locale::Fallbacks, nil) (defaults to: nil)

    fallbacks configuration for missing translations

Since:

  • x.x.x



35
36
37
38
39
40
41
42
43
44
# File 'lib/hanami/providers/i18n/backend.rb', line 35

def initialize(backend, locale: nil, default_locale: :en, available_locales: [], fallbacks: nil)
  @backend = backend
  @default_locale = default_locale.to_sym
  @available_locales = Array(available_locales).map(&:to_sym)
  @fallbacks = fallbacks

  # Set initial locale (if provided) in thread-local storage.
  @storage_key = :"hanami_i18n_#{object_id}"
  self.locale = locale if locale
end

Instance Attribute Details

#backendObject (readonly)

Since:

  • x.x.x



15
16
17
# File 'lib/hanami/providers/i18n/backend.rb', line 15

def backend
  @backend
end

#default_localeSymbol (readonly)

Returns the default locale.

Returns:

  • (Symbol)

    the default locale

Since:

  • x.x.x



23
24
25
# File 'lib/hanami/providers/i18n/backend.rb', line 23

def default_locale
  @default_locale
end

Instance Method Details

#available_localesObject

Returns available locales.

If configured via ‘config.i18n.available_locales`, returns the configured locales. Otherwise, returns all locales detected from loaded translation files.

Since:

  • x.x.x



223
224
225
226
227
228
229
# File 'lib/hanami/providers/i18n/backend.rb', line 223

def available_locales
  if @available_locales.any?
    @available_locales
  else
    @backend.available_locales
  end
end

#eager_load!void

This method returns an undefined value.

Eager loads translations if the backend supports it.

Since:

  • x.x.x



247
248
249
# File 'lib/hanami/providers/i18n/backend.rb', line 247

def eager_load!
  @backend.eager_load! if @backend.respond_to?(:eager_load!)
end

#exists?(key, locale: nil, **options) ⇒ Boolean

Returns true if a translation exists for the given key.

Examples:

exists?("hello") # => true
exists?("missing.key") # => false

Parameters:

  • key (String, Symbol)

    the translation key to check

  • locale (Symbol, String, nil) (defaults to: nil)

    the locale to check (defaults to current locale)

  • options (Hash)

    additional options

Returns:

  • (Boolean)

    true if the translation exists, false otherwise

Since:

  • x.x.x



192
193
194
195
# File 'lib/hanami/providers/i18n/backend.rb', line 192

def exists?(key, locale: nil, **options)
  locale ||= self.locale
  @backend.exists?(locale, key, options)
end

#localeSymbol

Returns the current locale from fiber/thread-local storage, or default_locale.

This is thread-safe and works correctly with concurrent requests. Each backend instance maintains its own locale in thread storage.

Examples:

locale # => :en
self.locale = :fr
locale # => :fr

Returns:

  • (Symbol)

    the current locale or default locale if none is set

Since:

  • x.x.x



265
266
267
# File 'lib/hanami/providers/i18n/backend.rb', line 265

def locale
  Thread.current[@storage_key] || default_locale
end

#locale=(value) ⇒ Symbol?

Sets the current locale in fiber/thread-local storage.

This is thread-safe and works correctly with concurrent requests. Each backend instance maintains its own locale in thread storage.

Examples:

self.locale = :fr
self.locale = "de"
self.locale = nil # resets to default_locale

Parameters:

  • value (Symbol, String, nil)

    the locale to set (converted to symbol)

Returns:

  • (Symbol, nil)

    the locale value that was set

Since:

  • x.x.x



285
286
287
# File 'lib/hanami/providers/i18n/backend.rb', line 285

def locale=(value)
  Thread.current[@storage_key] = value&.to_sym
end

#localize(object, locale: nil, format: :default, **options) ⇒ String Also known as: l

Localizes the given date or time.

Resolves symbol formats through this instance’s translations (e.g. ‘:short` becomes `date.formats.short` or `time.formats.short`). Also resolves locale-dependent strftime codes (e.g. `%a`, `%A`, `%b`, `%B`, `%p`, `%P`).

Examples:

Localize a date

localize(Date.today, format: :long) # => "January 19, 2026"

Localize with specific locale

localize(Date.today, locale: :fr, format: :long) # => "19 janvier 2026"

Parameters:

  • object (Date, Time, DateTime)

    the object to localize

  • locale (Symbol, String, nil) (defaults to: nil)

    the locale to use (defaults to current locale)

  • format (Symbol, String) (defaults to: :default)

    the format to use for localization

  • options (Hash)

    additional localization options

Returns:

  • (String)

    the localized string representation

Since:

  • x.x.x



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/hanami/providers/i18n/backend.rb', line 151

def localize(object, locale: nil, format: :default, **options)
  locale ||= self.locale

  return options[:default] if object.nil? && options.key?(:default)

  unless object.respond_to?(:strftime)
    raise ArgumentError, <<~MSG
      Object must be a Date, DateTime or Time object. #{object.inspect} given.
    MSG
  end

  if format.is_a?(Symbol)
    type = object.respond_to?(:sec) ? "time" : "date"
    format = translate(
      :"#{type}.formats.#{format}",
      **options, locale:, object:, raise: true
    )
  end

  format = expand_localization_format(locale, object, format)
  object.strftime(format)
end

#reload!void

This method returns an undefined value.

Reloads translations from translation files.

Since:

  • x.x.x



237
238
239
# File 'lib/hanami/providers/i18n/backend.rb', line 237

def reload!
  @backend.reload!
end

#t!(key, **options) ⇒ String, Object

Translates the given key, raising an exception if translation is missing.

Examples:

t!("hello") # => "Hello"
t!("missing.key") # raises I18n::MissingTranslationData

Parameters:

  • key (String, Symbol)

    the translation key to look up

  • options (Hash)

    translation options (see #translate)

Returns:

  • (String, Object)

    the translated string

Raises:

  • (I18n::MissingTranslationData)

    if translation is missing

Since:

  • x.x.x



126
127
128
# File 'lib/hanami/providers/i18n/backend.rb', line 126

def t!(key, **options)
  translate(key, **options.merge(raise: true))
end

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

Translates the given key.

Examples:

Basic translation

translate("hello") # => "Hello"

Translation with interpolation

translate("greeting", name: "Alice") # => "Hello, Alice"

With explicit locale

translate("hello", locale: :fr) # => "Bonjour"

Parameters:

  • key (String, Symbol)

    the translation key to look up

  • options (Hash)

    translation options

Options Hash (**options):

  • :locale (Symbol, String)

    the locale to use (defaults to current locale)

  • :default (String, Proc, Array)

    default value if translation is missing

  • :scope (Hash)

    additional scope for the key

  • :count (Integer)

    for pluralization

  • :raise (Boolean)

    whether to raise an exception for missing translations

Returns:

  • (String, Object)

    the translated string or default value

Raises:

  • (I18n::MissingTranslationData)

    if translation is missing and :raise option is true

Since:

  • x.x.x



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/hanami/providers/i18n/backend.rb', line 73

def translate(key, **options)
  locale = options[:locale] || self.locale

  result = catch(:exception) do
    @backend.translate(locale, key, options)
  end

  # If translation is missing and fallbacks are configured, try fallback locales
  if result.is_a?(::I18n::MissingTranslation) && @fallbacks && !options[:fallback]
    fallback_locales = @fallbacks[locale] - [locale]
    fallback_locales.each do |fallback_locale|
      fallback_result = catch(:exception) do
        @backend.translate(fallback_locale, key, options.merge(fallback: true))
      end

      unless fallback_result.is_a?(::I18n::MissingTranslation)
        return fallback_result
      end
    end
  end

  if result.is_a?(::I18n::MissingTranslation)
    if options[:raise]
      raise ::I18n::MissingTranslationData.new(locale, key, options)
    else
      handle_missing_translation(result, options)
    end
  else
    result
  end
end

#transliterate(key, locale: nil, replacement: nil, **options) ⇒ String

Transliterates the given string.

Examples:

transliterate("Ærøskøbing") # => "AEroskobing"

Parameters:

  • key (String)

    the string to transliterate

  • locale (Symbol, String, nil) (defaults to: nil)

    the locale to use (defaults to current locale)

  • replacement (String, nil) (defaults to: nil)

    replacement string for non-transliteratable characters

  • options (Hash)

    additional transliteration options

Returns:

  • (String)

    the transliterated string

Since:

  • x.x.x



211
212
213
214
# File 'lib/hanami/providers/i18n/backend.rb', line 211

def transliterate(key, locale: nil, replacement: nil, **options)
  locale ||= self.locale
  @backend.transliterate(locale, key, replacement)
end

#with_locale(tmp_locale) ⇒ Object

Executes a block with a temporary locale.

This is useful for executing code with a specific locale without affecting other concurrent requests. The previous locale is restored even if the block raises.

Examples:

with_locale(:fr) do
  t("greeting") # Uses French locale
end
# locale is restored to previous value

Nested usage

with_locale(:fr) do
  with_locale(:de) do
    t("hello") # Uses German
  end
  t("hello") # Uses French
end

Parameters:

  • tmp_locale (Symbol, String, nil)

    the temporary locale to use

Yield Returns:

  • (Object)

    the return value of the block

Returns:

  • (Object)

    the return value of the block

Since:

  • x.x.x



316
317
318
319
320
321
322
# File 'lib/hanami/providers/i18n/backend.rb', line 316

def with_locale(tmp_locale)
  previous_locale = Thread.current[@storage_key]
  Thread.current[@storage_key] = tmp_locale&.to_sym
  yield
ensure
  Thread.current[@storage_key] = previous_locale
end