Class: Esp::Mw::I18n

Inherits:
Object
  • Object
show all
Defined in:
lib/esp/mw/i18n.rb

Overview

Locale-aware string lookup. Two interfaces:

  • ‘t(key)` returns the resolved string (with default-locale fallback) and tracks misses. Used directly from the Ruby DSL.

  • ‘resolve!(value)` walks any data structure and replaces `“@t:<key>”` sentinel strings via `t`. Used post-load for JSON or subprocess-loader output (Python/JS/TS) where in-process helpers can’t reach.

Catalogues are nested-hash YAML files at ‘mods/<Mod>/i18n/<locale>.yaml`. Lookup is dot-pathed: `t(“activator.stump”)` reads `{stump: “…”}`.

Defined Under Namespace

Classes: Miss

Constant Summary collapse

DEFAULT_LOCALE =
'en'.freeze
SENTINEL_PREFIX =
'@t:'.freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(catalogues, locale: DEFAULT_LOCALE, default_locale: DEFAULT_LOCALE) ⇒ I18n

Returns a new instance of I18n.



25
26
27
28
29
30
# File 'lib/esp/mw/i18n.rb', line 25

def initialize(catalogues, locale: DEFAULT_LOCALE, default_locale: DEFAULT_LOCALE)
  @catalogues = catalogues
  @locale = locale
  @default_locale = default_locale
  @misses = []
end

Instance Attribute Details

#default_localeObject (readonly)

Returns the value of attribute default_locale.



23
24
25
# File 'lib/esp/mw/i18n.rb', line 23

def default_locale
  @default_locale
end

#localeObject (readonly)

Returns the value of attribute locale.



23
24
25
# File 'lib/esp/mw/i18n.rb', line 23

def locale
  @locale
end

Class Method Details

.check(source_dir) ⇒ Object

Compares each non-default locale catalogue against the default locale’s key set, reporting keys missing from / orphaned in each. Returns { locale => { missing: […], orphan: […] } }; shared by the ‘i18n check` CLI command and the Operations surface.



79
80
81
82
83
84
85
86
87
88
# File 'lib/esp/mw/i18n.rb', line 79

def self.check(source_dir)
  catalogues = load_catalogues(source_dir)
  default_keys = flatten(catalogues[DEFAULT_LOCALE] || {}).keys
  catalogues.each_with_object({}) do |(locale, cat), out|
    next if locale == DEFAULT_LOCALE

    keys = flatten(cat).keys
    out[locale] = { missing: default_keys - keys, orphan: keys - default_keys }
  end
end

.flatten(hash, prefix = '') ⇒ Object

Flattens nested catalogue hash to dot-pathed keys: ‘{b: “x”}` -> `=> “x”`.



92
93
94
95
96
97
98
99
100
101
# File 'lib/esp/mw/i18n.rb', line 92

def self.flatten(hash, prefix = '')
  hash.each_with_object({}) do |(k, v), out|
    key = prefix.empty? ? k.to_s : "#{prefix}.#{k}"
    if v.is_a?(Hash)
      out.merge!(flatten(v, key))
    else
      out[key] = v
    end
  end
end

.load_catalogues(source_dir) ⇒ Object



65
66
67
68
69
70
71
72
73
# File 'lib/esp/mw/i18n.rb', line 65

def self.load_catalogues(source_dir)
  i18n_dir = File.join(source_dir, 'i18n')
  return {} unless File.directory?(i18n_dir)

  Dir.glob(File.join(i18n_dir, '*.yaml')).each_with_object({}) do |path, out|
    locale = File.basename(path, '.yaml')
    out[locale] = YAML.safe_load_file(path) || {}
  end
end

Instance Method Details

#missesObject



61
62
63
# File 'lib/esp/mw/i18n.rb', line 61

def misses
  @misses.uniq
end

#resolve!(value) ⇒ Object

Recursively replaces ‘“@t:<key>”` strings in any structure. Mutates Hash values and Array elements in place; returns the result for convenience.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'lib/esp/mw/i18n.rb', line 46

def resolve!(value)
  case value
  when String
    value.start_with?(SENTINEL_PREFIX) ? t(value.delete_prefix(SENTINEL_PREFIX)) : value
  when Array
    value.map! { |v| resolve!(v) }
    value
  when Hash
    value.each { |k, v| value[k] = resolve!(v) }
    value
  else
    value
  end
end

#t(key) ⇒ Object

Returns the value at ‘key` in the active locale, falling back to the default locale, then to the literal key. Records misses for later reporting.



35
36
37
38
39
40
41
# File 'lib/esp/mw/i18n.rb', line 35

def t(key)
  value = lookup(@locale, key)
  return value if value

  @misses << Miss.new(key: key, locale: @locale)
  lookup(@default_locale, key) || key
end