russian 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +20 -0
- data/README.textile +44 -0
- data/Rakefile +55 -0
- data/TODO +11 -0
- data/init.rb +3 -0
- data/lib/russian.rb +91 -0
- data/lib/russian/action_view_ext/helpers/date_helper.rb +90 -0
- data/lib/russian/active_record_ext/custom_error_message.rb +33 -0
- data/lib/russian/backend/advanced.rb +104 -0
- data/lib/russian/locale/actionview.yml +113 -0
- data/lib/russian/locale/activerecord.yml +48 -0
- data/lib/russian/locale/activesupport.yml +5 -0
- data/lib/russian/locale/datetime.yml +29 -0
- data/lib/russian/locale/pluralize.rb +22 -0
- data/lib/vendor/i18n/MIT-LICENSE +20 -0
- data/lib/vendor/i18n/README.textile +18 -0
- data/lib/vendor/i18n/i18n.gemspec +24 -0
- data/lib/vendor/i18n/lib/i18n.rb +180 -0
- data/lib/vendor/i18n/lib/i18n/backend/simple.rb +192 -0
- data/lib/vendor/i18n/lib/i18n/exceptions.rb +53 -0
- data/lib/vendor/i18n/test/all.rb +5 -0
- data/lib/vendor/i18n/test/i18n_exceptions_test.rb +100 -0
- data/lib/vendor/i18n/test/i18n_test.rb +125 -0
- data/lib/vendor/i18n/test/locale/en-US.rb +1 -0
- data/lib/vendor/i18n/test/locale/en-US.yml +3 -0
- data/lib/vendor/i18n/test/simple_backend_test.rb +473 -0
- data/spec/i18n/locale/datetime_spec.rb +91 -0
- data/spec/i18n/locale/pluralization_spec.rb +20 -0
- data/spec/russian_spec.rb +141 -0
- data/spec/spec_helper.rb +5 -0
- metadata +100 -0
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Yaroslav Markin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
h1. Russian
|
2
|
+
|
3
|
+
Russian language support for Ruby and Rails, using I18n library (also shipped in Rails 2.2+).
|
4
|
+
|
5
|
+
Поддержка русского языка для Ruby и Rails при помощи библиотеки I18n (также входит в состав Rails 2.2+)
|
6
|
+
|
7
|
+
h3. If you don't speak Russian
|
8
|
+
|
9
|
+
This code may still be useful for you. You can learn how to create custom backends for I18n and how to
|
10
|
+
provide support of "standalone" (as defined in "Unicode CLDR":http://unicode.org/cldr/) month names with I18n and Rails, and also how to add dead simple pluralization rules into your translation tables.
|
11
|
+
|
12
|
+
h1. Что это
|
13
|
+
|
14
|
+
Russian -- это библиотека для полноценной поддержки русского языка (форматирование даты и времени, плюрализация, локализация в целом) для Ruby и Ruby on Rails.
|
15
|
+
|
16
|
+
Для этого используется библиотека I18n, несколько хаков поверх нее и файлы переводов.
|
17
|
+
|
18
|
+
I18n входит в состав Ruby on Rails начиная с версии 2.2, но на момент публикации нормальная поддержка русского языка отсутствовала.
|
19
|
+
|
20
|
+
h1. Установка
|
21
|
+
|
22
|
+
TODO: пути на GitHub, публикация на RubyForge
|
23
|
+
|
24
|
+
* gem rubyforge
|
25
|
+
* gem github
|
26
|
+
|
27
|
+
h2. Ruby on Rails
|
28
|
+
|
29
|
+
* gem
|
30
|
+
* plugin github
|
31
|
+
|
32
|
+
h1. Использование
|
33
|
+
|
34
|
+
* Прозрачное: локаль по умолчанию, свой бекенд (недеструктивный)
|
35
|
+
* Хелперы Russian.*
|
36
|
+
|
37
|
+
h2. Ruby on Rails
|
38
|
+
|
39
|
+
* Стандартный язык для I18n
|
40
|
+
* Перегрузка хелперов
|
41
|
+
|
42
|
+
h1. Автор
|
43
|
+
|
44
|
+
Ярослав Маркин ("yaroslav@markin.net":mailto:yaroslav@markin.net)
|
data/Rakefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake/gempackagetask'
|
3
|
+
require 'spec/rake/spectask'
|
4
|
+
require 'rubygems/specification'
|
5
|
+
require 'date'
|
6
|
+
|
7
|
+
GEM = "russian"
|
8
|
+
GEM_VERSION = "0.0.1"
|
9
|
+
AUTHOR = "Yaroslav Markin"
|
10
|
+
EMAIL = "yaroslav@markin.net"
|
11
|
+
HOMEPAGE = "http://github.com/yaroslav/russian/"
|
12
|
+
SUMMARY = "Russian language support for Ruby and Rails"
|
13
|
+
|
14
|
+
spec = Gem::Specification.new do |s|
|
15
|
+
s.name = GEM
|
16
|
+
s.version = GEM_VERSION
|
17
|
+
s.platform = Gem::Platform::RUBY
|
18
|
+
s.has_rdoc = true
|
19
|
+
s.extra_rdoc_files = ["README.textile", "LICENSE", 'TODO']
|
20
|
+
s.summary = SUMMARY
|
21
|
+
s.description = s.summary
|
22
|
+
s.author = AUTHOR
|
23
|
+
s.email = EMAIL
|
24
|
+
s.homepage = HOMEPAGE
|
25
|
+
|
26
|
+
# Uncomment this to add a dependency
|
27
|
+
# s.add_dependency "foo"
|
28
|
+
|
29
|
+
s.require_path = 'lib'
|
30
|
+
s.autorequire = GEM
|
31
|
+
s.files = %w(LICENSE README.textile Rakefile TODO init.rb) + Dir.glob("{lib,spec}/**/*")
|
32
|
+
end
|
33
|
+
|
34
|
+
Rake::GemPackageTask.new(spec) do |pkg|
|
35
|
+
pkg.gem_spec = spec
|
36
|
+
end
|
37
|
+
|
38
|
+
task :default => :spec
|
39
|
+
desc "Run specs"
|
40
|
+
Spec::Rake::SpecTask.new do |t|
|
41
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
42
|
+
t.spec_opts = %w(-fs --color)
|
43
|
+
end
|
44
|
+
|
45
|
+
desc "install the gem locally"
|
46
|
+
task :install => [:package] do
|
47
|
+
sh %{sudo gem install pkg/#{GEM}-#{GEM_VERSION}}
|
48
|
+
end
|
49
|
+
|
50
|
+
desc "create a gemspec file"
|
51
|
+
task :make_spec do
|
52
|
+
File.open("#{GEM}.gemspec", "w") do |file|
|
53
|
+
file.puts spec.to_ruby
|
54
|
+
end
|
55
|
+
end
|
data/TODO
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
TODO
|
2
|
+
====
|
3
|
+
* docs and README (english - brief, full russian doc)
|
4
|
+
* check Unicode CLDR to ensure all datetime formats are correct
|
5
|
+
* refactor Advanced backend localize method (looks ugly)
|
6
|
+
|
7
|
+
Questionable
|
8
|
+
============
|
9
|
+
* integration spec coverage for actionview locale
|
10
|
+
* integration spec coverage for activerecord locale
|
11
|
+
* integration spec coverage for activesupport locale
|
data/init.rb
ADDED
data/lib/russian.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
$KCODE='u'
|
2
|
+
|
3
|
+
$:.push File.join(File.dirname(__FILE__), 'russian')
|
4
|
+
$:.push File.join(File.dirname(__FILE__), 'vendor', 'i18n', 'lib')
|
5
|
+
|
6
|
+
require 'i18n' unless defined?(I18n)
|
7
|
+
|
8
|
+
require 'backend/advanced'
|
9
|
+
require 'action_view_ext/helpers/date_helper'
|
10
|
+
require 'active_record_ext/custom_error_message'
|
11
|
+
|
12
|
+
module Russian
|
13
|
+
module VERSION
|
14
|
+
MAJOR = 0
|
15
|
+
MINOR = 0
|
16
|
+
TINY = 1
|
17
|
+
|
18
|
+
STRING = [MAJOR, MINOR, TINY].join('.')
|
19
|
+
end
|
20
|
+
|
21
|
+
# Russian locale
|
22
|
+
LOCALE = :'ru-RU'
|
23
|
+
|
24
|
+
class << self
|
25
|
+
# Russian locale
|
26
|
+
def locale
|
27
|
+
LOCALE
|
28
|
+
end
|
29
|
+
|
30
|
+
# Returns custom backend class for usage with Russian library
|
31
|
+
#
|
32
|
+
# See I18n::Backend
|
33
|
+
def i18n_backend_class
|
34
|
+
I18n::Backend::Advanced
|
35
|
+
end
|
36
|
+
|
37
|
+
# Init Russian i18n: set custom backend, set default locale to Russian locale, load all translations
|
38
|
+
# shipped with library.
|
39
|
+
def init_i18n
|
40
|
+
I18n.backend = Russian.i18n_backend_class.new
|
41
|
+
I18n.default_locale = LOCALE
|
42
|
+
locale_files.each { |file| I18n.backend.load_translations(file) }
|
43
|
+
end
|
44
|
+
|
45
|
+
# See I18n::translate
|
46
|
+
def translate(key, options = {})
|
47
|
+
I18n.translate(key, options.merge({ :locale => LOCALE }))
|
48
|
+
end
|
49
|
+
alias :t :translate
|
50
|
+
|
51
|
+
# See I18n::localize
|
52
|
+
def localize(object, options = {})
|
53
|
+
I18n.localize(object, options.merge({ :locale => LOCALE }))
|
54
|
+
end
|
55
|
+
alias :l :localize
|
56
|
+
|
57
|
+
# strftime() proxy with Russian localization
|
58
|
+
def strftime(object, format = :default)
|
59
|
+
localize(object, { :format => format })
|
60
|
+
end
|
61
|
+
|
62
|
+
# Simple pluralization proxy
|
63
|
+
#
|
64
|
+
# Usage:
|
65
|
+
# Russian.pluralize(1, "вещь", "вещи", "вещей")
|
66
|
+
def pluralize(n, *variants)
|
67
|
+
variants_hash = pluralization_variants_to_hash(*variants)
|
68
|
+
I18n.backend.send(:pluralize, LOCALE, variants_hash, n)
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
# Returns all locale files shipped with library
|
73
|
+
def locale_files
|
74
|
+
Dir[File.join(File.dirname(__FILE__), "russian", "locale", "**/*")]
|
75
|
+
end
|
76
|
+
|
77
|
+
# Converts an array of pluralization variants (3 entries) to a Hash that can be used
|
78
|
+
# with I18n pluralization.
|
79
|
+
def pluralization_variants_to_hash(*variants)
|
80
|
+
raise ArgumentError, "Must have at least 3 variants for pluralization" if variants.size < 3
|
81
|
+
{
|
82
|
+
:one => variants[0],
|
83
|
+
:few => variants[1],
|
84
|
+
:many => variants[2],
|
85
|
+
:other => variants[1]
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
Russian.init_i18n
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# Replaces Rails select_month helper and translated_month_names private method to provide
|
2
|
+
# "standalone month names" feature.
|
3
|
+
#
|
4
|
+
# It is now possible to use both abbreviated and full month names in two variants (if current locale provides them).
|
5
|
+
# All date helpers support <tt>:use_standalone_month_names</tt> key now, <tt>select_month</tt> helper sets
|
6
|
+
# it to true by default.
|
7
|
+
# Standalone month names are also used when <tt>:discard_day</tt> key is provided.
|
8
|
+
if defined?(ActionView::Helpers::DateTimeSelector) && ActionView::Helpers::DateTimeSelector.private_instance_methods.include?("translated_month_names")
|
9
|
+
module ActionView
|
10
|
+
module Helpers
|
11
|
+
module DateHelper
|
12
|
+
# Returns a select tag with options for each of the months January through December with the current month
|
13
|
+
# selected. The month names are presented as keys (what's shown to the user) and the month numbers (1-12) are
|
14
|
+
# used as values (what's submitted to the server). It's also possible to use month numbers for the presentation
|
15
|
+
# instead of names -- set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you
|
16
|
+
# want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer
|
17
|
+
# to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want
|
18
|
+
# to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
|
19
|
+
# You can also choose if you want to use i18n standalone month names or default month names -- you can
|
20
|
+
# force standalone month names usage by using <tt>:use_standalone_month_names</tt> key.
|
21
|
+
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
|
22
|
+
#
|
23
|
+
# ==== Examples
|
24
|
+
# # Generates a select field for months that defaults to the current month that
|
25
|
+
# # will use keys like "January", "March".
|
26
|
+
# select_month(Date.today)
|
27
|
+
#
|
28
|
+
# # Generates a select field for months that defaults to the current month that
|
29
|
+
# # is named "start" rather than "month"
|
30
|
+
# select_month(Date.today, :field_name => 'start')
|
31
|
+
#
|
32
|
+
# # Generates a select field for months that defaults to the current month that
|
33
|
+
# # will use keys like "1", "3".
|
34
|
+
# select_month(Date.today, :use_month_numbers => true)
|
35
|
+
#
|
36
|
+
# # Generates a select field for months that defaults to the current month that
|
37
|
+
# # will use keys like "1 - January", "3 - March".
|
38
|
+
# select_month(Date.today, :add_month_numbers => true)
|
39
|
+
#
|
40
|
+
# # Generates a select field for months that defaults to the current month that
|
41
|
+
# # will use keys like "Jan", "Mar".
|
42
|
+
# select_month(Date.today, :use_short_month => true)
|
43
|
+
#
|
44
|
+
# # Generates a select field for months that defaults to the current month that
|
45
|
+
# # will use keys like "Januar", "Marts."
|
46
|
+
# select_month(Date.today, :use_month_names => %w(Januar Februar Marts ...))
|
47
|
+
#
|
48
|
+
def select_month(date, options = {}, html_options = {})
|
49
|
+
DateTimeSelector.new(date, options.merge(:use_standalone_month_names => true), html_options).select_month
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class DateTimeSelector #:nodoc:
|
54
|
+
private
|
55
|
+
# Returns translated month names
|
56
|
+
# => [nil, "January", "February", "March",
|
57
|
+
# "April", "May", "June", "July",
|
58
|
+
# "August", "September", "October",
|
59
|
+
# "November", "December"]
|
60
|
+
#
|
61
|
+
# If :use_short_month option is set
|
62
|
+
# => [nil, "Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
63
|
+
# "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
|
64
|
+
#
|
65
|
+
# Also looks up if <tt>:discard_day</tt> or <tt>:use_standalone_month_names</tt> option is set
|
66
|
+
# and uses i18n standalone month names if so.
|
67
|
+
def translated_month_names
|
68
|
+
begin
|
69
|
+
if @options[:use_short_month]
|
70
|
+
if (@options[:discard_day] || @options[:use_standalone_month_names]) && I18n.translate(:'date.standalone_abbr_month_names')
|
71
|
+
key = :'date.standalone_abbr_month_names'
|
72
|
+
else
|
73
|
+
key = :'date.abbr_month_names'
|
74
|
+
end
|
75
|
+
else
|
76
|
+
if (@options[:discard_day] || @options[:use_standalone_month_names]) && I18n.translate(:'date.standalone_month_names')
|
77
|
+
key = :'date.standalone_month_names'
|
78
|
+
else
|
79
|
+
key = :'date.month_names'
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
I18n.translate(key, :locale => @options[:locale])
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end # if defined?
|
@@ -0,0 +1,33 @@
|
|
1
|
+
if defined?(ActiveRecord::Errors)
|
2
|
+
# The following is taken from custom_error_message plugin by David Easley
|
3
|
+
# (http://rubyforge.org/projects/custom-err-msg/)
|
4
|
+
module ActiveRecord
|
5
|
+
class Errors
|
6
|
+
|
7
|
+
# Redefine the ActiveRecord::Errors::full_messages method:
|
8
|
+
# Returns all the full error messages in an array. 'Base' messages are handled as usual.
|
9
|
+
# Non-base messages are prefixed with the attribute name as usual UNLESS they begin with '^'
|
10
|
+
# in which case the attribute name is omitted.
|
11
|
+
# E.g. validates_acceptance_of :accepted_terms, :message => '^Please accept the terms of service'
|
12
|
+
def full_messages
|
13
|
+
full_messages = []
|
14
|
+
|
15
|
+
@errors.each_key do |attr|
|
16
|
+
@errors[attr].each do |msg|
|
17
|
+
next if msg.nil?
|
18
|
+
|
19
|
+
if attr == "base"
|
20
|
+
full_messages << msg
|
21
|
+
elsif msg =~ /^\^/
|
22
|
+
full_messages << msg[1..-1]
|
23
|
+
else
|
24
|
+
full_messages << @base.class.human_attribute_name(attr) + " " + msg
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
return full_messages
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module I18n
|
2
|
+
module Backend
|
3
|
+
# Advanced I18n backend.
|
4
|
+
#
|
5
|
+
# Extends <tt>Simple</tt> backend. Allows usage of <tt>standalone_*</tt> keys
|
6
|
+
# for DateTime localization and usage of user-defined <tt>Proc</tt> (lambda) pluralization
|
7
|
+
# methods in translation tables.
|
8
|
+
class Advanced < Simple
|
9
|
+
LOCALIZE_ABBR_MONTH_NAMES_MATCH = /(%d|%e)?(\s*)(%b)/
|
10
|
+
LOCALIZE_MONTH_NAMES_MATCH = /(%d|%e)?(\s*)(%B)/
|
11
|
+
LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH = /^%a/
|
12
|
+
LOCALIZE_STANDALONE_DAY_NAMES_MATCH = /^%A/
|
13
|
+
|
14
|
+
# Acts the same as +strftime+, but returns a localized version of the
|
15
|
+
# formatted date string. Takes a key from the date/time formats
|
16
|
+
# translations as a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
|
17
|
+
#
|
18
|
+
# Note that it differs from <tt>localize</tt> in <tt>Simple</tt> backend by checking for
|
19
|
+
# <tt>standalone_*</tt> month name/day name keys in translation and using them if available.
|
20
|
+
def localize(locale, object, format = :default)
|
21
|
+
raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
|
22
|
+
|
23
|
+
type = object.respond_to?(:sec) ? 'time' : 'date'
|
24
|
+
# TODO only translate these if format is a String?
|
25
|
+
formats = translate(locale, :"#{type}.formats")
|
26
|
+
format = formats[format.to_sym] if formats && formats[format.to_sym]
|
27
|
+
# TODO raise exception unless format found?
|
28
|
+
format = format.to_s.dup
|
29
|
+
|
30
|
+
# TODO only translate these if the format string is actually present
|
31
|
+
# TODO check which format strings are present, then bulk translate then, then replace them
|
32
|
+
|
33
|
+
if lookup(locale, :"date.standalone_abbr_day_names")
|
34
|
+
format.gsub!(LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH,
|
35
|
+
translate(locale, :"date.standalone_abbr_day_names")[object.wday])
|
36
|
+
end
|
37
|
+
format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
|
38
|
+
|
39
|
+
if lookup(locale, :"date.standalone_day_names")
|
40
|
+
format.gsub!(LOCALIZE_STANDALONE_DAY_NAMES_MATCH,
|
41
|
+
translate(locale, :"date.standalone_day_names")[object.wday])
|
42
|
+
end
|
43
|
+
format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
|
44
|
+
|
45
|
+
if lookup(locale, :"date.standalone_abbr_month_names")
|
46
|
+
format.gsub!(LOCALIZE_ABBR_MONTH_NAMES_MATCH) do
|
47
|
+
$1 ? $1 + $2 + translate(locale, :"date.abbr_month_names")[object.mon] :
|
48
|
+
$2 + translate(locale, :"date.standalone_abbr_month_names")[object.mon]
|
49
|
+
end
|
50
|
+
else
|
51
|
+
format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
|
52
|
+
end
|
53
|
+
|
54
|
+
if lookup(locale, :"date.standalone_month_names")
|
55
|
+
format.gsub!(LOCALIZE_MONTH_NAMES_MATCH) do
|
56
|
+
$1 ? $1 + $2 + translate(locale, :"date.month_names")[object.mon] :
|
57
|
+
$2 + translate(locale, :"date.standalone_month_names")[object.mon]
|
58
|
+
end
|
59
|
+
else
|
60
|
+
format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
|
61
|
+
end
|
62
|
+
|
63
|
+
format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
|
64
|
+
object.strftime(format)
|
65
|
+
end
|
66
|
+
|
67
|
+
protected
|
68
|
+
# Picks a pluralization rule specified in translation tables for a language or
|
69
|
+
# uses default pluralization rules.
|
70
|
+
#
|
71
|
+
# This is how pluralization rules are defined in translation tables, English
|
72
|
+
# language for example:
|
73
|
+
#
|
74
|
+
# store_translations :'en-US', {
|
75
|
+
# :pluralize => lambda { |n| n == 1 ? :one : :other }
|
76
|
+
# }
|
77
|
+
#
|
78
|
+
# Rule must return a symbol to use with pluralization, it must be one of:
|
79
|
+
# :zero, :one, :two, :few, :many, :other
|
80
|
+
def pluralize(locale, entry, count)
|
81
|
+
return entry unless entry.is_a?(Hash) and count
|
82
|
+
|
83
|
+
key = :zero if count == 0 && entry.has_key?(:zero)
|
84
|
+
locale_pluralize = lookup(locale, :pluralize)
|
85
|
+
if locale_pluralize && locale_pluralize.respond_to?(:call)
|
86
|
+
key ||= locale_pluralize.call(count)
|
87
|
+
else
|
88
|
+
key ||= default_pluralizer(count)
|
89
|
+
end
|
90
|
+
raise InvalidPluralizationData.new(entry, count) unless entry.has_key?(key)
|
91
|
+
|
92
|
+
entry[key]
|
93
|
+
end
|
94
|
+
|
95
|
+
# Default pluralizer, used if pluralization rule is not defined in translations.
|
96
|
+
#
|
97
|
+
# Uses English pluralization rules -- it will pick the first translation if count is not equal to 1
|
98
|
+
# and the second translation if it is equal to 1.
|
99
|
+
def default_pluralizer(count)
|
100
|
+
count == 1 ? :one : :other
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|