Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions lib/russian.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-

$KCODE = 'u' if RUBY_VERSION < "1.9"

Expand All @@ -9,9 +9,10 @@

module Russian
extend self

autoload :Transliteration, 'transliteration'

autoload :Metaphone, 'metaphone'

# Russian locale
LOCALE = :'ru'

Expand All @@ -21,11 +22,11 @@ def locale
end

# Regexp machers for context-based russian month names and day names translation
LOCALIZE_ABBR_MONTH_NAMES_MATCH = /(%d|%e)(.*)(%b)/
LOCALIZE_MONTH_NAMES_MATCH = /(%d|%e)(.*)(%B)/
LOCALIZE_ABBR_MONTH_NAMES_MATCH = /(%[-\d]?d|%e)(.*)(%b)/
LOCALIZE_MONTH_NAMES_MATCH = /(%[-\d]?d|%e)(.*)(%B)/
LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH = /^%a/
LOCALIZE_STANDALONE_DAY_NAMES_MATCH = /^%A/

# Init Russian i18n: load all translations shipped with library.
def init_i18n
I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)
Expand All @@ -39,23 +40,23 @@ def init_i18n
# See I18n::translate
def translate(key, options = {})
I18n.translate(key, options.merge({ :locale => LOCALE }))
end
end
alias :t :translate

# See I18n::localize
def localize(object, options = {})
I18n.localize(object, options.merge({ :locale => LOCALE }))
end
alias :l :localize

# strftime() proxy with Russian localization
def strftime(object, format = :default)
localize(object, { :format => format })
end

# Simple pluralization proxy
#
# Usage:
# Usage:
# Russian.pluralize(1, "вещь", "вещи", "вещей")
# Russian.pluralize(3.14, "вещь", "вещи", "вещей", "вещи")
def pluralize(n, *variants)
Expand All @@ -76,13 +77,47 @@ def transliterate(str)
Russian::Transliteration.transliterate(str)
end
alias :translit :transliterate


# De-transliteration for russian language
#
# Usage:
# Russian.detranslit("rubin")
# Russian.detransliterate("rubin")
def detransliterate(str)
Russian::Transliteration.detransliterate(str)
end
alias :detranslit :detransliterate

# Metaphone code for russian language
#
# Usage:
# Russian.metaphone("рубин")
def metaphone(str)
Russian::Metaphone.generate(str)
end

# Change the input string as it would be typed in the standard russian keyboard layout
#
# Usage:
# Russian.layout_rus("hemby") # рубин
def layout_rus(str)
Russian::Transliteration.layout_rus(str)
end

# Change the input string as it would be typed in the standard english keyboard layout
#
# Usage:
# Russian.layout_eng("дум") # lev
def layout_eng(str)
Russian::Transliteration.layout_eng(str)
end

protected
# Returns all locale files shipped with library
def locale_files
Dir[File.join(File.dirname(__FILE__), "russian", "locale", "**/*")]
end

# Converts an array of pluralization variants to a Hash that can be used
# with I18n pluralization.
def pluralization_variants_to_hash(*variants)
Expand Down
20 changes: 10 additions & 10 deletions lib/russian/action_view_ext/helpers/date_helper.rb
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-

# Заменяет хелпер Rails <tt>select_month</tt> и метод <tt>translated_month_names</tt>
# Заменяет хелпер Rails <tt>select_month</tt> и метод <tt>translated_month_names</tt>
# для поддержки функционала "отдельностоящих имен месяцев".
#
# Теперь можно использовать и полные, и сокращенные название месяцев в двух вариантах -- контекстном
# (по умолчанию) и отдельностоящем (если в текущем языке есть соответствующие переводы).
# Теперь хелперы поддерживают ключ <tt>:use_standalone_month_names</tt>, хелпер <tt>select_month</tt>
# Теперь хелперы поддерживают ключ <tt>:use_standalone_month_names</tt>, хелпер <tt>select_month</tt>
# устанавливает его по умолчанию.
# Отдельностоящие имена месяцев также используютс когда указан ключ <tt>:discard_day</tt>.
#
#
# Replaces Rails <tt>select_month</tt> helper and <tt>translated_month_names</tt> private method to provide
# "standalone month names" feature.
# "standalone month names" feature.
#
# It is now possible to use both abbreviated and full month names in two variants (if current locale provides them).
# All date helpers support <tt>:use_standalone_month_names</tt> key now, <tt>select_month</tt> helper sets
# All date helpers support <tt>:use_standalone_month_names</tt> key now, <tt>select_month</tt> helper sets
# it to true by default.
# Standalone month names are also used when <tt>:discard_day</tt> key is provided.
if defined?(ActionView::Helpers::DateTimeSelector)
Expand All @@ -27,7 +27,7 @@ module DateHelper
# instead of names -- set the <tt>:use_month_numbers</tt> key in +options+ to true for this to happen. If you
# want both numbers and names, set the <tt>:add_month_numbers</tt> key in +options+ to true. If you would prefer
# to show month names as abbreviations, set the <tt>:use_short_month</tt> key in +options+ to true. If you want
# to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
# to use your own month names, set the <tt>:use_month_names</tt> key in +options+ to an array of 12 month names.
# You can also choose if you want to use i18n standalone month names or default month names -- you can
# force standalone month names usage by using <tt>:use_standalone_month_names</tt> key.
# Override the field name using the <tt>:field_name</tt> option, 'month' by default.
Expand Down Expand Up @@ -66,7 +66,7 @@ def select_month(date, options = {}, html_options = {})
DateTimeSelector.new(date, options.merge(:use_standalone_month_names => true), html_options).select_month
end
end

class DateTimeSelector #:nodoc:
private
# Returns translated month names
Expand Down Expand Up @@ -108,11 +108,11 @@ def translated_month_names
key = :'date.month_names'
end
end

I18n.translate(key, :locale => @options[:locale])
end

end
end
end
end # if defined?
end # if defined?
16 changes: 8 additions & 8 deletions lib/russian/active_model_ext/custom_error_message.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-

if defined?(ActiveModel::Errors)
module ActiveModel
Expand All @@ -13,19 +13,19 @@ class Errors
# теперь не имеют префикса с названием атрибута если в сообщении об ошибке первым символом указан "^".
#
# Так, например,
#
#
# validates_acceptance_of :accepted_terms, :message => 'нужно принять соглашение'
#
#
# даст сообщение
#
#
# Accepted terms нужно принять соглашение
#
#
# однако,
#
#
# validates_acceptance_of :accepted_terms, :message => '^Нужно принять соглашение'
#
#
# даст сообщение
#
#
# Нужно принять соглашение
#
#
Expand Down
2 changes: 1 addition & 1 deletion lib/russian/locale/actionview.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ ru:
# These are also the defaults for 'currency', 'percentage', 'precision', and 'human'
format:
# Sets the separator between the units, for more precision (e.g. 1.0 / 2.0 == 0.5)
separator: "."
separator: ","
# Delimets thousands (e.g. 1,000,000 is a million) (always in groups of three)
delimiter: " "
# Number of decimals, behind the separator (the number 1 with a precision of 2 gives: 1.00)
Expand Down
2 changes: 1 addition & 1 deletion lib/russian/locale/activemodel.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ ru:
inclusion: "имеет непредусмотренное значение"
exclusion: "имеет зарезервированное значение"
invalid: "имеет неверное значение"
confirmation: "не совпадает с подтверждением"
confirmation: "не совпадает с подтверждаемым значением"
accepted: "нужно подтвердить"
empty: "не может быть пустым"
blank: "не может быть пустым"
Expand Down
2 changes: 1 addition & 1 deletion lib/russian/locale/activerecord.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ ru:
inclusion: "имеет непредусмотренное значение"
exclusion: "имеет зарезервированное значение"
invalid: "имеет неверное значение"
confirmation: "не совпадает с подтверждением"
confirmation: "не совпадает с подтверждаемым значением"
accepted: "нужно подтвердить"
empty: "не может быть пустым"
blank: "не может быть пустым"
Expand Down
2 changes: 1 addition & 1 deletion lib/russian/locale/datetime.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-

# Context-based month name and day name switching for Russian
#
Expand Down
8 changes: 4 additions & 4 deletions lib/russian/locale/pluralization.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-

# Правило плюрализации для русского языка, взято из CLDR, http://unicode.org/cldr/
#
Expand All @@ -19,10 +19,10 @@
:ru => {
:'i18n' => {
:plural => {
:rule => lambda { |n|
n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other
:rule => lambda { |n|
n % 10 == 1 && n % 100 != 11 ? :one : [2, 3, 4].include?(n % 10) && ![12, 13, 14].include?(n % 100) ? :few : n % 10 == 0 || [5, 6, 7, 8, 9].include?(n % 10) || [11, 12, 13, 14].include?(n % 100) ? :many : :other
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion lib/russian/locale/transliterator.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- encoding: utf-8 -*-

# I18n transliteration delegates to Russian::Transliteration (we're unable
# to use common I18n transliteration tables with Russian)
Expand Down
86 changes: 86 additions & 0 deletions lib/russian/metaphone.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# -*- encoding: utf-8 -*-

module Russian
# Metaphone code generation for english words and metaphon-like code for russian titles
#
# Генерация метафон-кодов для английский слов и русских названий
# (русская версия заточена и будет дальше дорабатываться именно
# в эту сторону - названия и заголовки)
module Metaphone
extend self

require "active_support/core_ext/string"

TRANSFORMATIONS_EN = [
[/\A[gkp]n/ , 'n'], # gn, kn, or pn at the start turns into 'n'
[/\Ax/ , 's'], # x at the start turns into 's'
[/\Awh/ , 'w'], # wh at the start turns into 'w'
[/mb\z/ , 'm'], # mb at the end turns into 'm'
[/sch/ , 'sk'], # sch sounds like 'sk'
[/x/ , 'ks'],
[/cia/ , 'xia'], # the 'c' -cia- and -ch- sounds like 'x'
[/ch/ , 'xh'],
[/c([iey])/ , 's\1'], # the 'c' -ce-, -ci-, or -cy- sounds like 's'
[/ck/ , 'k'],
[/c/ , 'k'],
[/dg([eiy])/ , 'j\1'], # the 'dg' in -dge-, -dgi-, or -dgy- sounds like 'j'
[/d/ , 't'],
[/gh/ , ''],
[/gned/ , 'ned'],
[/gn((?![aeiou])|(\z))/ , 'n'],
[/g[eiy]/ , 'j'],
[/ph/ , 'f'],
[/[aeiou]h(?!(?:[aeoiu]|$))/ , '\1'], # 'h' is silent after a vowel unless it's between vowels
[/q/ , 'k'],
[/s(h|(ia)|(io))/ , 'x\1'],
[/t((ia)|(io))/ , 'x\1'],
[/v/ , 'f'],
[/w(?![aeiou])/ , ''],
[/y(?![aeiou])/ , ''],
[/z/ , 's'],
# [/th/ , '0'], # <-- zero ?!?
[/th/ , 'z'], # need only latin letters, no digits or smth else
]

# english metaphone code was inspired by
# author: AndyV http://snippets.dzone.com/user/AndyV
# source: http://snippets.dzone.com/posts/show/4112
def generate_en(aWord)
word = aWord.downcase
TRANSFORMATIONS_EN.each { |transform| word.gsub!(transform[0], transform[1]) }
word.squeeze
return word.present? ? (word[0] + word[1..-1].gsub(/[aeiou]/, '')).upcase : ""
end

TRANSFORMATIONS_RU = [
[ /[дт]ь?с/,'ц' ], # seems this improves matching
[ /зз/, 'цц' ], # for metaphone(detranslit(pizza)) == metaphone(пицца)
[ /[аяоёуюыиэеї]/, '' ],# remove vowels
[ /[йъь]/, '' ], # these also ; this also removes all adjactive endings (-ый, -ая, -ое, ...)
[ /сч/,'ш' ], # seems this improves matching
# [ /ч/, 'ц' ],
[ /[ґгк]/, 'х' ],
[ /б/, 'п' ], # map pair letters
[ /в/, 'ф' ],
[ /д/, 'т' ],
[ /[жщ]/, 'ш' ],
[ /з/, 'с' ],
]

def generate_ru(aWord)
word = aWord.mb_chars.downcase
TRANSFORMATIONS_RU.each { |transform| word.gsub!(transform[0], transform[1]) }
word.squeeze
end

# Generates a metaphone code for the given string
#
# Генерирует метафон-код заданной строки (в т.ч. русской, в т.ч. рус+eng)
def generate(str)
str.split(/\s+/).map do |s|
s =~ /[A-Za-z]/ ? generate_en(s =~ /[^A-Za-z]/ ? Russian.translit(s) : s) : generate_ru(s)
end .join(' ').mb_chars.upcase.gsub(/[^A-ZА-Я]+/, ' ').gsub(/\s+/, ' ').strip
end

end
end
2 changes: 1 addition & 1 deletion lib/russian/russian_rails.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
end

if defined?(ActionView::Helpers)
require 'action_view_ext/helpers/date_helper'
require 'action_view_ext/helpers/date_helper'
end
Loading