Module: Tina4::Localization

Defined in:
lib/tina4/localization.rb

Constant Summary collapse

LOCALE_DIRS =
%w[locales translations i18n src/locales].freeze

Class Method Summary collapse

Class Method Details

.add(locale, key, value) ⇒ Object



114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
# File 'lib/tina4/localization.rb', line 114

def add(locale, key, value)
  translations[locale.to_s] ||= {}
  keys = key.to_s.split(".")
  hash = translations[locale.to_s]
  keys[0..-2].each do |k|
    hash[k] ||= {}
    hash = hash[k]
  end
  hash[keys.last] = value

  # Register leaf-key alias (first-wins)
  leaf = keys.last
  if value.is_a?(String)
    flat_aliases[locale.to_s] ||= {}
    flat_aliases[locale.to_s][leaf] ||= value
  end
end

.add_translation(locale, key, value) ⇒ Object



110
111
112
# File 'lib/tina4/localization.rb', line 110

def add_translation(locale, key, value)
  add(locale, key, value)
end

.available_locales(root_dir = Dir.pwd) ⇒ Object

List available locale codes by scanning the configured locale dir(s) for *.json / *.yml / *.yaml file stems, sorted. When no dir exists/has files, returns a [default_locale] floor (parity with Python/PHP/Node — never an empty list when a default locale is known).



136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/tina4/localization.rb', line 136

def available_locales(root_dir = Dir.pwd)
  stems = []
  locale_search_dirs(root_dir).each do |locale_dir|
    %w[*.json *.yml *.yaml].each do |pattern|
      Dir.glob(File.join(locale_dir, pattern)).each do |file|
        stems << File.basename(file, File.extname(file))
      end
    end
  end
  stems.uniq!
  stems.empty? ? [default_locale] : stems.sort
end

.current_localeObject



19
20
21
# File 'lib/tina4/localization.rb', line 19

def current_locale
  @current_locale || ENV["TINA4_LOCALE"] || "en"
end

.current_locale=(locale) ⇒ Object



23
24
25
# File 'lib/tina4/localization.rb', line 23

def current_locale=(locale)
  @current_locale = locale.to_s
end

.default_localeObject

The fallback locale used when a key is missing in the current locale. Mirrors the Python master (TINA4_LOCALE, else "en").



29
30
31
# File 'lib/tina4/localization.rb', line 29

def default_locale
  ENV["TINA4_LOCALE"] || "en"
end

.flat_aliasesObject

Flat alias map: { locale => { leaf_key => value } } First-wins on conflict — later duplicates are ignored.



15
16
17
# File 'lib/tina4/localization.rb', line 15

def flat_aliases
  @flat_aliases ||= {}
end

.get_localeObject



97
98
99
# File 'lib/tina4/localization.rb', line 97

def get_locale
  current_locale
end

.load(root_dir = Dir.pwd) ⇒ Object



33
34
35
36
37
38
39
40
41
42
# File 'lib/tina4/localization.rb', line 33

def load(root_dir = Dir.pwd)
  locale_search_dirs(root_dir).each do |locale_dir|
    Dir.glob(File.join(locale_dir, "*.json")).each do |file|
      ingest_json_file(File.basename(file, ".json"), file)
    end
    Dir.glob(File.join(locale_dir, "*.{yml,yaml}")).each do |file|
      ingest_yaml_file(File.basename(file, File.extname(file)), file)
    end
  end
end

.load_locale(locale, root_dir = Dir.pwd) ⇒ Object

Load a SINGLE locale's file (JSON, then YAML) from the configured search dirs if it is not already loaded. Boot-safe (a malformed file is skipped, never raised) — mirrors Python's _load_locale.



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/tina4/localization.rb', line 75

def load_locale(locale, root_dir = Dir.pwd)
  locale = locale.to_s
  return if translations.key?(locale)

  locale_search_dirs(root_dir).each do |locale_dir|
    json = File.join(locale_dir, "#{locale}.json")
    if File.file?(json)
      ingest_json_file(locale, json)
      return
    end
    %w[yml yaml].each do |ext|
      yaml = File.join(locale_dir, "#{locale}.#{ext}")
      if File.file?(yaml)
        ingest_yaml_file(locale, yaml)
        return
      end
    end
  end
  # No file found — cache an empty table so lookups fall back to the key.
  translations[locale] ||= {}
end

.load_translations(locale) ⇒ Object



105
106
107
108
# File 'lib/tina4/localization.rb', line 105

def load_translations(locale)
  load(Dir.pwd) if translations.empty?
  translations[locale.to_s] || {}
end

.set_locale(locale) ⇒ Object



63
64
65
66
67
68
69
70
# File 'lib/tina4/localization.rb', line 63

def set_locale(locale)
  self.current_locale = locale.to_s
  # Lazily load the new locale's file if it hasn't been loaded yet, so a
  # switch to an unloaded locale resolves its keys (parity with Python/PHP/
  # Node, where setting the locale triggers a per-locale load).
  load_locale(locale.to_s) unless translations.key?(locale.to_s)
  current_locale
end

.t(key, locale: nil, default: nil, **interpolations) ⇒ Object



44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/tina4/localization.rb', line 44

def t(key, locale: nil, default: nil, **interpolations)
  lang = locale || current_locale
  value = lookup(lang, key)

  # Fallback: current locale -> default/fallback locale -> the key itself.
  if value.nil? && lang != default_locale
    value = lookup(default_locale, key)
  end

  value = default || key if value.nil?

  # Interpolation: "Hello {name}" => "Hello World". PARTIAL — each {name}
  # token present in interpolations is replaced; a missing param's
  # placeholder is left literal, and a malformed placeholder ({x.y} with a
  # dot, {n:d} with a spec, a lone unmatched brace) is left literal too.
  # Never raises — a bad template must not crash t().
  interpolate(value, interpolations)
end

.translate(key, params: nil, locale: nil) ⇒ Object



101
102
103
# File 'lib/tina4/localization.rb', line 101

def translate(key, params: nil, locale: nil)
  t(key, locale: locale, **(params || {}))
end

.translationsObject



9
10
11
# File 'lib/tina4/localization.rb', line 9

def translations
  @translations ||= {}
end