Class: Zen::Language

Inherits:
Object
  • Object
show all
Includes:
Ramaze::Optioned, Validation
Defined in:
lib/zen/language.rb,
lib/zen/language/translation.rb

Overview

Zen::Language is the heart of the multi language system that comes with Zen. It makes it easy to display localized bits of text as well as adding new collections of translated strings.

Adding Languages

Adding a new language can be done by using Language.add. This method works similar to the ones used by Package and Theme. An example of adding a language (English in this case) looks like the following:

Zen::Language.add do |lang|
  lang.name  = 'en'
  lang.title = 'English'
end

When adding a language you must set the following items:

  • name: the language code as defined in ISO 639. Examples of these codes are "en-GB", "nl", etc. At the moment Zen does not have different language files for British English and American English.
  • title: the name of the language in a human friendly form. This name should be set in the specific language. For example, for Dutch the title would be "Nederlands".

Optionally you can also set the following attributes:

  • rtl: indicates that the language reads from right to left. When set to true the <html> tag will have an extra dir attribute so that browsers can properly display the text from right to left.

Adding Translations

Translations for a certain language are added using Translation. Similar to languages these are added by calling .add(). A simple example of adding a set of translations is the following:

Zen::Language::Translation.add do |trans|
  trans.language = 'en'
  trans.name     = 'foobar'

  trans.translate do |t|

  end
end

This adds a language collection called "foobar" for the English language. Translation strings are added inside the block of the translate() method. Setting these strings works just like setting the keys and values of a hash:

trans.translate do |t|
  t['hello'] = 'Hello World'
end

It is a good idea to group certain language strings together. For example, you might have a few strings related to page titles. The way of doing this is by simply separating groups with a dot in the keys:

trans.translate do |t|
  t['titles.index'] = 'Example'
  t['titles.edit']  = 'Edit Example'
end

The keys specified in []= should match the regular expression as defined in Translation::KEY_REGEX. In plain English, they can only contain lower case letters, underscores and dots.

A full example:

Zen::Language::Translation.add do |trans|
  trans.language = 'en'
  trans.name     = 'foobar'

  trans.translate do |t|
    t['titles.index'] = 'Example'
    t['titles.edit']  = 'Edit Example'
  end
end

Organizing Languages

In order for language files to be loaded by Zen you need to place them in certain directories using a certain file name. Language files should be named after the name setter/getter defined when calling Translation.add (including casing) and should have .rb as extension. These files should be placed in sub directories that match the language name they belong to. These directories in turn should be placed inside a "language" directory.

In other words, our "foobar" example would be stored as following:

 language/
 |
 |__ en/
    |
    |__ foobar.rb

Before you can load files from the language directory you'll need to add it to the list of directories to search each time a language file is loaded. Similar to how you can add view folders or helper folders in Ramaze you can add language folders:

Zen::Language.options.paths << 'path/to/language'

Loading Translations

Once a language file has been added it must be loaded before it can be used. Loading a language file can be done in two ways:

  1. Manually loading it by calling Language.load.
  2. Calling lang or lang() (injected into the global namespace).

In the last case missing language files will be loaded if possible. However, it is recommended that you pre-load your language files before starting the application. By doing this these translations don't have to be loaded during an HTTP request which could potentially slow down the application.

If we wanted to load the "foobar" language file mentioned earlier you can do this as following:

Zen::Language.load('foobar')

Using Translations

Once the entire process of adding and loading a language file has been completed you can use the language strings defined in that file. This can be done by calling the global method lang() which is available in all scopes. If you happen to need it in a scope where it's overwritten you can call lang instead.

A simple example of loading a few language strings of the file defined earlier in this guide looks like this:

lang('foobar.titles.index')

Language keys should always be in the format of A.B where A is the name of the language file ("foobar" in this case) and B a dot separated string that points to the language string to load. This means that the following examples are not valid:

lang('foobar')
lang('foo bar')

Since:

Defined Under Namespace

Modules: SingletonMethods Classes: Translation

Constant Summary

REGISTERED =

Hash containing all the available languages.

Since:

  • 0.2

{}

Instance Attribute Summary (collapse)

Class Method Summary (collapse)

Instance Method Summary (collapse)

Methods included from Validation

#validates_filepath, #validates_format, #validates_length, #validates_presence

Constructor Details

- (Language) initialize

Creates a new instance of the class.

Since:

  • 14-11-2011



335
336
337
338
# File 'lib/zen/language.rb', line 335

def initialize
  @loaded      = []
  @collections = {}
end

Instance Attribute Details

- (Object) collections

A hash of all the language files that have been loaded for a language. The values are the names of these collections and the values the instances of Translation.

Since:

  • 0.2



182
183
184
# File 'lib/zen/language.rb', line 182

def collections
  @collections
end

- (Object) name

The name of the language

Since:

  • 0.2



171
172
173
# File 'lib/zen/language.rb', line 171

def name
  @name
end

- (TrueClass|FalseClass) rtl

Returns a boolean that indicates whether or not the language reads from right to left.

Returns:

  • (TrueClass|FalseClass)

Since:

  • 14-11-2011



357
358
359
# File 'lib/zen/language.rb', line 357

def rtl
  return @rtl.nil? ? false : @rtl
end

- (Object) title

The title of the language (in that specific language).

Since:

  • 0.2



177
178
179
# File 'lib/zen/language.rb', line 177

def title
  @title
end

Class Method Details

+ (Object) add { ... }

Adds a new language.

Examples:

Zen::Language.add do |lang|
  lang.name  = 'nl'
  lang.title = 'Nederlands'
end

Adding an RTL language (such as Japanese)

Zen::Language.add do |lang|
  lang.name  = '...'
  lang.title = '...'
  lang.rtl   = true
end

Yields:

  • Zen::Language

Since:

  • 14-11-2011



204
205
206
207
208
209
210
211
212
# File 'lib/zen/language.rb', line 204

def add
  lang = new

  yield(lang)

  lang.validate

  REGISTERED[lang.name] = lang
end

+ (String) current

Returns an instance of Zen::Language for the current language.

Returns:

  • (String)

Since:

  • 0.3



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
# File 'lib/zen/language.rb', line 258

def current
  if !Ramaze::Current.actions.nil? and !Ramaze::Current.action.nil?
    # The backend
    if Ramaze::Current.action.node.request.env['SCRIPT_NAME'] \
    =~ /^\/admin.*/
      method = :language
    # Probably the frontend
    else
      method = :frontend_language
    end

    # Extract the language from the current User object.
    if Ramaze::Helper.const_defined?(:UserHelper)
      model = Ramaze::Current.action.node.request \
        .env[::Ramaze::Helper::UserHelper::RAMAZE_HELPER_USER]

      if model.respond_to?(method)
        lang = model.send(method)
      end
    end
  end

  # Make sure there always is a language set
  if !lang
    begin
      if method
        lang = get_setting(method).value
      else
        lang = get_setting(:language).value
      end
    rescue
      lang = Zen::Language.options.language
    end
  end

  return REGISTERED[lang]
end

+ (String) html_head

Builds an HTML opening tag with the lang and rtl attributes set for the currently used language.

Returns:

  • (String)

Since:

  • 14-11-2011



318
319
320
321
322
323
324
325
326
327
# File 'lib/zen/language.rb', line 318

def html_head
  curr = Zen::Language.current
  head = "<html lang=\"#{curr.name}\""

  if curr.rtl == true
    header += ' dir="rtl"'
  end

  return head + '>'
end

+ (Object) load(lang_name, lang = nil)

Loads the given language file for the currently used language. If the file has already been loaded this method will not load it again.

Examples:

Zen::Language.load('user')

Parameters:

  • lang_name (String)

    The name of the language file to load.

  • lang (String) (defaults to: nil)

    The name of the language for which to load the collection. Set to the current language by default.

Raises:

Since:

  • 0.1



226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# File 'lib/zen/language.rb', line 226

def load(lang_name, lang = nil)
  lang_name = lang_name.to_s unless lang_name.is_a?(String)
  language  = REGISTERED[lang.to_s] || current

  return if language.collections.keys.include?(lang_name)

  options.paths.each do |path|
    path = File.join(path, language.name, "#{lang_name}.rb")

    # Load the language
    if File.exist?(path)
      require(path)

      unless language.collections[lang_name].nil?
        language.collections[lang_name].load
        return
      end
    end
  end

  raise(
    Zen::LanguageError,
    "No language file could be found for \"#{lang_name}\""
  )
end

+ (Hash) to_hash

Returns a hash where the keys are the language codes and the values the titles.

Returns:

  • (Hash)

Since:

  • 14-11-2011



303
304
305
306
307
308
309
# File 'lib/zen/language.rb', line 303

def to_hash
  hash = {}

  REGISTERED.each { |lang, obj| hash[lang] = obj.title }

  return hash
end

Instance Method Details

- (Object) validate

Validates the current instance using Validation.

Since:

  • 14-11-2011



366
367
368
369
370
371
372
# File 'lib/zen/language.rb', line 366

def validate
  validates_presence([:name, :title])

  if REGISTERED.key?(name)
    raise(Zen::ValidationError, "The language #{name} already exists.")
  end
end