Class: R18n::I18n

Inherits:
Object
  • Object
show all
Defined in:
lib/r18n-core/i18n.rb

Overview

General class to i18n support in your application. It load Translation and Locale classes and create pretty way to use it.

To get translation you can use same with Translation way – use method with translation's name or [name] method. Translations will be also loaded for default locale, sublocales from first in locales and general languages for dialects (it will load fr for fr_CA too).

Translations will loaded by loader object, which must have 2 methods:

  • available – return array of locales of available translations;

  • load(locale) – return Hash of translation. If you will use default loader (R18n.default_loader) you can pass to I18n only constructor argument for loader:

    R18n::I18n.new('en', R18n::Loader::YAML.new('dir/with/translations'))

is a same as:

R18n::I18n.new('en', 'dir/with/translations')

In translation file you can use strings, numbers, floats (any YAML types) and pluralizable values (!!pl). You can use params in string values, which you can replace in program. Just write %1, %2, etc and set it values as method arguments, when you will be get value.

You can use filters for some YAML type or for all strings. See R18n::Filters for details.

R18n contain translations for common words (such as "OK", "Cancel", etc) for most supported locales. See base/ dir.

Usage

translations/ru.yml

one: Один

translations/en.yml

one: One
two: Two

example.rb

i18n = R18n::I18n.new(['ru', 'en'], 'translations/')

i18n.one   #=> "Один"
i18n.two   #=> "Two"

i18n.locale.title        #=> "Русский"
i18n.locale.code         #=> "ru"
i18n.locale.ltr?         #=> true

i18n.l -11000.5          #=> "−11 000,5"
i18n.l Time.now          #=> "Вск, 21 сен 2008, 22:10:10 MSD"
i18n.l Time.now, :date   #=> "21.09.2008"
i18n.l Time.now, :time   #=> "22:10"
i18n.l Time.now, '%A'    #=> "Воскресенье"

i18n.yes    #=> "Yes"
i18n.ok     #=> "OK"
i18n.cancel #=> "Cancel"

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(locales, translation_places = nil, opts = {}) ⇒ I18n

Create i18n for locales with translations from translation_places and locales data. Translations will be also loaded for default locale, sublocales from first in locales and general languages for dialects (it will load fr for fr_CA too).

locales must be a locale code (RFC 3066) or array, ordered by priority. translation_places must be a string with path or array.



137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/r18n-core/i18n.rb', line 137

def initialize(locales, translation_places = nil, opts = {})
  locales = Array(locales)

  locales.each_with_index do |locale, i|
    locales.insert(i + 1, locale.match(/([^_-]+)[_-]/)[1]) if locale.match?(/[^_-]+[_-]/)
    locales.insert(i + 1, *(Locale.load(locale).sublocales - locales)) if Locale.exists?(locale)
  end
  locales << self.class.default
  locales.map! { |i| i.to_s.downcase }.uniq!
  @locales_codes = locales
  @locales = locales.each_with_object([]) do |locale, result|
    locale = Locale.load(locale)
    next unless locale

    result << locale
  end

  if translation_places
    @original_places = translation_places
  else
    @original_places = R18n.extension_places
    @locale = @locales.first
  end

  @translation_places = self.class.convert_places(@original_places)

  @filters =
    if opts[:on_filters] || opts[:off_filters]
      CustomFilterList.new(opts[:on_filters], opts[:off_filters])
    else
      GlobalFilterList.instance
    end

  key = translation_cache_key
  if R18n.cache.key? key
    @locale, @translation = *R18n.cache[key]
  else
    reload!
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing ⇒ Object

Return translation with special name.

Translation can contain variable part. Just set is as %1, %2, etc in translations file and set values in next params.



282
283
284
# File 'lib/r18n-core/i18n.rb', line 282

def [](name, *params)
  @translation[name, *params]
end

Class Attribute Details

.default ⇒ Object

Returns the value of attribute default.



89
90
91
# File 'lib/r18n-core/i18n.rb', line 89

def default
  @default
end

Instance Attribute Details

#locale ⇒ Object (readonly)

First locale with locale file



128
129
130
# File 'lib/r18n-core/i18n.rb', line 128

def locale
  @locale
end

#locales ⇒ Object (readonly)

User locales, ordered by priority



122
123
124
# File 'lib/r18n-core/i18n.rb', line 122

def locales
  @locales
end

#translation_places ⇒ Object (readonly)

Loaders with translations files



125
126
127
# File 'lib/r18n-core/i18n.rb', line 125

def translation_places
  @translation_places
end

Class Method Details

.convert_places(places) ⇒ Object

Load default loader for elements in places with only constructor argument.



110
111
112
113
114
115
116
117
118
# File 'lib/r18n-core/i18n.rb', line 110

def convert_places(places)
  Array(places).map! do |loader|
    if loader.respond_to?(:available) && loader.respond_to?(:load)
      loader
    else
      R18n.default_loader.new(loader)
    end
  end
end

.parse_http(str) ⇒ Object

Parse HTTP_ACCEPT_LANGUAGE and return array of user locales



92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
# File 'lib/r18n-core/i18n.rb', line 92

def parse_http(str)
  return [] if str.nil?

  locales = str.split(',')
  locales.map! do |locale|
    locale = locale.split ';q='
    if locale.size == 1
      [locale[0], 1.0]
    else
      [locale[0], locale[1].to_f]
    end
  end
  locales.sort! { |a, b| b[1] <=> a[1] }
  locales.map! { |i| i[0] }
end

Instance Method Details

#[](name, *params) ⇒ Object Also known as: method_missing

Return translation with special name.

Translation can contain variable part. Just set is as %1, %2, etc in translations file and set values in next params.



279
280
281
# File 'lib/r18n-core/i18n.rb', line 279

def [](name, *params)
  @translation[name, *params]
end

#available_locales ⇒ Object

Return Array of locales with available translations.



248
249
250
# File 'lib/r18n-core/i18n.rb', line 248

def available_locales
  @available_locales ||= R18n.available_locales(@translation_places)
end

#filter_list ⇒ Object

Return custom filters list



179
180
181
# File 'lib/r18n-core/i18n.rb', line 179

def filter_list
  @filters
end

#localize(object, format = nil) ⇒ Object Also known as: l

Convert object to String, according to the rules of the current locale. It support Integer, Float, Time, Date and DateTime.

For time classes you can set format in standard strftime form, :full ("01 Jule, 2009"), :human ("yesterday"), :standard ("07/01/09") or :month for standalone month name. Default format is :standard.

i18n.l -12000.5         #=> "−12,000.5"
i18n.l Time.now         #=> "07/01/09 12:59"
i18n.l Time.now.to_date #=> "07/01/09"
i18n.l Time.now, :human #=> "now"
i18n.l Time.now, :full  #=> "Jule 1st, 2009 12:59"


265
266
267
# File 'lib/r18n-core/i18n.rb', line 265

def localize(object, format = nil, **)
  locale.localize(object, format, i18n: self, **)
end

#reload! ⇒ Object

Reload translations.



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/r18n-core/i18n.rb', line 194

def reload!
  @available_locales = @available_codes = nil
  @translation_places = self.class.convert_places(@original_places)

  available_in_places = @translation_places.to_h { |i| [i, i.available] }
  available_in_extensions = R18n.extension_places.to_h { |i| [i, i.available] }

  unless defined? @locale
    available_in_places.each_value do |available|
      @locales.each do |locale|
        if available.include? locale
          @locale = locale
          break
        end
      end
      break if defined? @locale
    end
  end
  @locale ||= @locales.first
  unless @locale.supported?
    @locales.each do |locale|
      if locale.supported?
        @locale.base = locale
        break
      end
    end
  end

  @translation = Translation.new(@locale, '', filters: @filters)
  @locales.each do |locale|
    loaded = false

    available_in_places.each do |place, available|
      if available.include? locale
        @translation.merge! place.load(locale), locale
        loaded = true
      end
    end

    next unless loaded

    available_in_extensions.each do |extension, available|
      @translation.merge! extension.load(locale), locale if available.include? locale

      if available.include? locale.parent
        @translation.merge! extension.load(locale.parent), locale.parent
      end
    end
  end

  R18n.cache[translation_cache_key] = [@locale, @translation]
end

#t ⇒ Object

Return translations.



271
272
273
# File 'lib/r18n-core/i18n.rb', line 271

def t
  @translation
end

#translation_cache_key ⇒ Object

Return unique key for current locales in translation and places.



184
185
186
187
188
189
190
191
# File 'lib/r18n-core/i18n.rb', line 184

def translation_cache_key
  @available_codes ||= @translation_places
    .inject([]) { |all, i| all + i.available }
    .uniq.map { |i| i.code.downcase }
  "#{(@locales_codes & @available_codes).join(',')}@" \
    "#{@filters.hash}_#{R18n.default_loader.hash}_#{@translation_places.hash}_" +
    R18n.extension_places.hash.to_s
end