Module: I18n::JS

Defined in:
lib/i18n/js.rb,
lib/i18n/js/utils.rb,
lib/i18n/js/engine.rb,
lib/i18n/js/segment.rb,
lib/i18n/js/version.rb,
lib/i18n/js/middleware.rb,
lib/i18n/js/dependencies.rb,
lib/i18n/js/fallback_locales.rb,
lib/i18n/js/private/hash_with_symbol_keys.rb

Defined Under Namespace

Modules: Dependencies, Private, Utils Classes: Engine, FallbackLocales, Middleware, Segment, SprocketsExtension

Constant Summary collapse

DEFAULT_CONFIG_PATH =
"config/i18n-js.yml"
DEFAULT_EXPORT_DIR_PATH =
"public/javascripts"
VERSION =
"3.0.9"

Class Method Summary collapse

Class Method Details

.configObject

Load configuration file for partial exporting and custom output directory



101
102
103
104
105
106
107
108
109
110
# File 'lib/i18n/js.rb', line 101

def self.config
  if config_file_exists?
    erb_result_from_yaml_file = ERB.new(File.read(config_file_path)).result
    Private::HashWithSymbolKeys.new(
      (::YAML.load(erb_result_from_yaml_file) || {})
    )
  else
    Private::HashWithSymbolKeys.new({})
  end.freeze
end

.config_file_exists?Boolean

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.

Check if configuration file exist

Returns:

  • (Boolean)


114
115
116
# File 'lib/i18n/js.rb', line 114

def self.config_file_exists?
  File.file? config_file_path
end

.config_file_pathObject

The configuration file. This defaults to the ‘config/i18n-js.yml` file.



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

def self.config_file_path
  @config_file_path ||= DEFAULT_CONFIG_PATH
end

.config_file_path=(new_path) ⇒ Object



27
28
29
# File 'lib/i18n/js.rb', line 27

def self.config_file_path=(new_path)
  @config_file_path = new_path
end

.configured_segmentsObject



47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/i18n/js.rb', line 47

def self.configured_segments
  config[:translations].inject([]) do |segments, options_hash|
    options_hash_with_symbol_keys = Private::HashWithSymbolKeys.new(options_hash)
    file = options_hash_with_symbol_keys[:file]
    only = options_hash_with_symbol_keys[:only] || '*'
    exceptions = [options_hash_with_symbol_keys[:except] || []].flatten

    result = segment_for_scope(only, exceptions)

    merge_with_fallbacks!(result) if fallbacks

    unless result.empty?
      segments << Segment.new(
        file,
        result,
        extract_segment_options(options_hash_with_symbol_keys),
      )
    end

    segments
  end
end

.exclude(translations, exceptions) ⇒ Object

Exclude keys from translations listed in the ‘except:` section in the config file



132
133
134
135
136
137
138
139
140
141
# File 'lib/i18n/js.rb', line 132

def self.exclude(translations, exceptions)
  return translations if exceptions.empty?

  exceptions.inject(translations) do |memo, exception|
    exception_scopes = exception.to_s.split(".")
    Utils.deep_reject(memo) do |key, value, scopes|
      Utils.scopes_match?(scopes, exception_scopes)
    end
  end
end

.exportObject

Export translations to JavaScript, considering settings from configuration file



33
34
35
36
37
# File 'lib/i18n/js.rb', line 33

def self.export
  export_i18n_js

  translation_segments.each(&:save!)
end

.extract_segment_options(options) ⇒ Object



205
206
207
208
209
210
211
# File 'lib/i18n/js.rb', line 205

def self.extract_segment_options(options)
  segment_options = Private::HashWithSymbolKeys.new({
    js_extend: js_extend,
    sort_translation_keys: sort_translation_keys?,
  }).freeze
  segment_options.merge(options.slice(*Segment::OPTIONS))
end

.fallbacksObject



181
182
183
184
185
186
# File 'lib/i18n/js.rb', line 181

def self.fallbacks
  config.fetch(:fallbacks) do
    # default value
    true
  end
end

.filter(translations, scopes) ⇒ Object

Filter translations according to the specified scope.



144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/i18n/js.rb', line 144

def self.filter(translations, scopes)
  scopes = scopes.split(".") if scopes.is_a?(String)
  scopes = scopes.clone
  scope = scopes.shift

  if scope == "*"
    results = {}
    translations.each do |scope, translations|
      tmp = scopes.empty? ? translations : filter(translations, scopes)
      results[scope.to_sym] = tmp unless tmp.nil?
    end
    return results
  elsif translations.respond_to?(:key?) && translations.key?(scope.to_sym)
    return {scope.to_sym => scopes.empty? ? translations[scope.to_sym] : filter(translations[scope.to_sym], scopes)}
  end
  nil
end

.filtered_translationsObject



81
82
83
84
85
86
87
88
89
# File 'lib/i18n/js.rb', line 81

def self.filtered_translations
  translations = {}.tap do |result|
    translation_segments.each do |segment|
      Utils.deep_merge!(result, segment.translations)
    end
  end
  return Utils.deep_key_sort(translations) if I18n::JS.sort_translation_keys?
  translations
end

.js_extendObject



188
189
190
191
192
193
# File 'lib/i18n/js.rb', line 188

def self.js_extend
  config.fetch(:js_extend) do
    # default value
    true
  end
end

.merge_with_fallbacks!(result) ⇒ Object

deep_merge! given result with result for fallback locale



71
72
73
74
75
76
77
78
79
# File 'lib/i18n/js.rb', line 71

def self.merge_with_fallbacks!(result)
  I18n.available_locales.each do |locale|
    fallback_locales = FallbackLocales.new(fallbacks, locale)
    fallback_locales.each do |fallback_locale|
      # `result[fallback_locale]` could be missing
      result[locale] = Utils.deep_merge(result[fallback_locale] || {}, result[locale] || {})
    end
  end
end

.scoped_translations(scopes, exceptions = []) ⇒ Object

:nodoc:



118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/i18n/js.rb', line 118

def self.scoped_translations(scopes, exceptions = []) # :nodoc:
  result = {}

  [scopes].flatten.each do |scope|
    translations_without_exceptions = exclude(translations, exceptions)
    filtered_translations = filter(translations_without_exceptions, scope) || {}

    Utils.deep_merge!(result, filtered_translations)
  end

  result
end

.segment_for_scope(scope, exceptions) ⇒ Object



39
40
41
42
43
44
45
# File 'lib/i18n/js.rb', line 39

def self.segment_for_scope(scope, exceptions)
  if scope == "*"
    exclude(translations, exceptions)
  else
    scoped_translations(scope, exceptions)
  end
end

.sort_translation_keys=(value) ⇒ Object



201
202
203
# File 'lib/i18n/js.rb', line 201

def self.sort_translation_keys=(value)
  @sort_translation_keys = !!value
end

.sort_translation_keys?Boolean

Returns:

  • (Boolean)


195
196
197
198
199
# File 'lib/i18n/js.rb', line 195

def self.sort_translation_keys?
  @sort_translation_keys ||= (config[:sort_translation_keys]) if config.key?(:sort_translation_keys)
  @sort_translation_keys = true if @sort_translation_keys.nil?
  @sort_translation_keys
end

.translation_segmentsObject



91
92
93
94
95
96
97
# File 'lib/i18n/js.rb', line 91

def self.translation_segments
  if config_file_exists? && config[:translations]
    configured_segments
  else
    [Segment.new("#{DEFAULT_EXPORT_DIR_PATH}/translations.js", translations)]
  end
end

.translationsObject

Initialize and return translations



163
164
165
166
167
168
169
170
171
172
173
174
175
# File 'lib/i18n/js.rb', line 163

def self.translations
  ::I18n.backend.instance_eval do
    init_translations unless initialized?
    # When activesupport is absent,
    # the core extension (`#slice`) from `i18n` gem will be used instead
    # And it's causing errors (at least in test)
    #
    # So the input is wrapped by our class for better `#slice`
    Private::HashWithSymbolKeys.new(translations).
      slice(*::I18n.available_locales).
      to_h
  end
end

.use_fallbacks?Boolean

Returns:

  • (Boolean)


177
178
179
# File 'lib/i18n/js.rb', line 177

def self.use_fallbacks?
  fallbacks != false
end