diff --git a/lib/russian.rb b/lib/russian.rb
index a3d70b4..7b1631b 100644
--- a/lib/russian.rb
+++ b/lib/russian.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
$KCODE = 'u' if RUBY_VERSION < "1.9"
@@ -9,9 +9,10 @@
module Russian
extend self
-
+
autoload :Transliteration, 'transliteration'
-
+ autoload :Metaphone, 'metaphone'
+
# Russian locale
LOCALE = :'ru'
@@ -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)
@@ -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)
@@ -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)
diff --git a/lib/russian/action_view_ext/helpers/date_helper.rb b/lib/russian/action_view_ext/helpers/date_helper.rb
index 9a1b598..4ff05a8 100644
--- a/lib/russian/action_view_ext/helpers/date_helper.rb
+++ b/lib/russian/action_view_ext/helpers/date_helper.rb
@@ -1,20 +1,20 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
-# Заменяет хелпер Rails select_month и метод translated_month_names
+# Заменяет хелпер Rails select_month и метод translated_month_names
# для поддержки функционала "отдельностоящих имен месяцев".
#
# Теперь можно использовать и полные, и сокращенные название месяцев в двух вариантах -- контекстном
# (по умолчанию) и отдельностоящем (если в текущем языке есть соответствующие переводы).
-# Теперь хелперы поддерживают ключ :use_standalone_month_names, хелпер select_month
+# Теперь хелперы поддерживают ключ :use_standalone_month_names, хелпер select_month
# устанавливает его по умолчанию.
# Отдельностоящие имена месяцев также используютс когда указан ключ :discard_day.
#
#
# Replaces Rails select_month helper and translated_month_names 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 :use_standalone_month_names key now, select_month helper sets
+# All date helpers support :use_standalone_month_names key now, select_month helper sets
# it to true by default.
# Standalone month names are also used when :discard_day key is provided.
if defined?(ActionView::Helpers::DateTimeSelector)
@@ -27,7 +27,7 @@ module DateHelper
# instead of names -- set the :use_month_numbers key in +options+ to true for this to happen. If you
# want both numbers and names, set the :add_month_numbers key in +options+ to true. If you would prefer
# to show month names as abbreviations, set the :use_short_month key in +options+ to true. If you want
- # to use your own month names, set the :use_month_names key in +options+ to an array of 12 month names.
+ # to use your own month names, set the :use_month_names 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 :use_standalone_month_names key.
# Override the field name using the :field_name option, 'month' by default.
@@ -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
@@ -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?
\ No newline at end of file
+end # if defined?
diff --git a/lib/russian/active_model_ext/custom_error_message.rb b/lib/russian/active_model_ext/custom_error_message.rb
index 4698409..02c7cf7 100644
--- a/lib/russian/active_model_ext/custom_error_message.rb
+++ b/lib/russian/active_model_ext/custom_error_message.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
if defined?(ActiveModel::Errors)
module ActiveModel
@@ -13,19 +13,19 @@ class Errors
# теперь не имеют префикса с названием атрибута если в сообщении об ошибке первым символом указан "^".
#
# Так, например,
- #
+ #
# validates_acceptance_of :accepted_terms, :message => 'нужно принять соглашение'
- #
+ #
# даст сообщение
- #
+ #
# Accepted terms нужно принять соглашение
- #
+ #
# однако,
- #
+ #
# validates_acceptance_of :accepted_terms, :message => '^Нужно принять соглашение'
- #
+ #
# даст сообщение
- #
+ #
# Нужно принять соглашение
#
#
diff --git a/lib/russian/locale/actionview.yml b/lib/russian/locale/actionview.yml
index 20d5ff1..4207a47 100644
--- a/lib/russian/locale/actionview.yml
+++ b/lib/russian/locale/actionview.yml
@@ -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)
diff --git a/lib/russian/locale/activemodel.yml b/lib/russian/locale/activemodel.yml
index 5066327..cda2797 100644
--- a/lib/russian/locale/activemodel.yml
+++ b/lib/russian/locale/activemodel.yml
@@ -6,7 +6,7 @@ ru:
inclusion: "имеет непредусмотренное значение"
exclusion: "имеет зарезервированное значение"
invalid: "имеет неверное значение"
- confirmation: "не совпадает с подтверждением"
+ confirmation: "не совпадает с подтверждаемым значением"
accepted: "нужно подтвердить"
empty: "не может быть пустым"
blank: "не может быть пустым"
diff --git a/lib/russian/locale/activerecord.yml b/lib/russian/locale/activerecord.yml
index 8b67531..4747f9d 100644
--- a/lib/russian/locale/activerecord.yml
+++ b/lib/russian/locale/activerecord.yml
@@ -19,7 +19,7 @@ ru:
inclusion: "имеет непредусмотренное значение"
exclusion: "имеет зарезервированное значение"
invalid: "имеет неверное значение"
- confirmation: "не совпадает с подтверждением"
+ confirmation: "не совпадает с подтверждаемым значением"
accepted: "нужно подтвердить"
empty: "не может быть пустым"
blank: "не может быть пустым"
diff --git a/lib/russian/locale/datetime.rb b/lib/russian/locale/datetime.rb
index a4e62e3..b763a32 100644
--- a/lib/russian/locale/datetime.rb
+++ b/lib/russian/locale/datetime.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
# Context-based month name and day name switching for Russian
#
diff --git a/lib/russian/locale/pluralization.rb b/lib/russian/locale/pluralization.rb
index 20c2a38..7248936 100644
--- a/lib/russian/locale/pluralization.rb
+++ b/lib/russian/locale/pluralization.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
# Правило плюрализации для русского языка, взято из CLDR, http://unicode.org/cldr/
#
@@ -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
}
}
}
}
-}
\ No newline at end of file
+}
diff --git a/lib/russian/locale/transliterator.rb b/lib/russian/locale/transliterator.rb
index 1ef2280..14a6266 100644
--- a/lib/russian/locale/transliterator.rb
+++ b/lib/russian/locale/transliterator.rb
@@ -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)
diff --git a/lib/russian/metaphone.rb b/lib/russian/metaphone.rb
new file mode 100644
index 0000000..bdf03ef
--- /dev/null
+++ b/lib/russian/metaphone.rb
@@ -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
diff --git a/lib/russian/russian_rails.rb b/lib/russian/russian_rails.rb
index f036547..bc317b6 100644
--- a/lib/russian/russian_rails.rb
+++ b/lib/russian/russian_rails.rb
@@ -4,5 +4,5 @@
end
if defined?(ActionView::Helpers)
- require 'action_view_ext/helpers/date_helper'
+ require 'action_view_ext/helpers/date_helper'
end
diff --git a/lib/russian/transliteration.rb b/lib/russian/transliteration.rb
index 27f89af..72d1f38 100644
--- a/lib/russian/transliteration.rb
+++ b/lib/russian/transliteration.rb
@@ -1,7 +1,7 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
module Russian
- # Russian transliteration
+ # Russian transliteration
#
# Транслитерация для букв русского алфавита
module Transliteration
@@ -20,10 +20,12 @@ module Transliteration
"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
"ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"'",
"ы"=>"y","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya",
+ "»"=>"\"","«" => "\"","“"=>"\"","”" => "\"",
}
LOWER_MULTI = {
"ье"=>"ie",
"ьё"=>"ie",
+ "сх"=>"skh",
}
UPPER_SINGLE = {
@@ -39,34 +41,125 @@ module Transliteration
UPPER_MULTI = {
"ЬЕ"=>"IE",
"ЬЁ"=>"IE",
+ "СХ"=>"SKH",
+ }
+
+ REVERSE_LOWER_SINGLE = {
+ "a"=>"а","b"=>"б","c"=>"с","d"=>"д",
+ "e"=>"е","f"=>"ф","g"=>"г","h"=>"х",
+ "i"=>"и","j"=>"й","k"=>"к","l"=>"л",
+ "m"=>"м","n"=>"н","o"=>"о","p"=>"п",
+ "q"=>"к","r"=>"р","s"=>"с","t"=>"т",
+ "u"=>"у","v"=>"в","w"=>"у","x"=>"кс",
+ "y"=>"ы","z"=>"з",
+ }
+ REVERSE_LOWER_MULTI = {
+ "sch"=>"щ","skh"=>"сх",
+ "aya"=>"ая","yaya"=>"яя","oyа"=>"оя","uyа"=>"уя","yyа"=>"ыя","eyа"=>"ея",
+ "aye"=>"ае","oye"=>"ое","uye"=>"уе","yye"=>"ые","eye"=>"ее",
+ "oye"=>"ое","oyo"=>"оё",
+ "ayu"=>"аю","uyu"=>"ую","oyu"=>"ою","uyu"=>"ую","eyu"=>"ею",
+ "yu"=>"ю","ya"=>"я","yo"=>"ё",
+ "ju"=>"ю","ja"=>"я","jo"=>"ё",
+ "yi"=>"ї","ji"=>"ї",
+ "ay"=>"ай","yay"=>"яй","oy"=>"ой","yoy"=>"ёй","uy"=>"уй","yuy"=>"юй","yy"=>"ый","iy"=>"ий","ey"=>"ей",
+ "ay"=>"ай","yay"=>"яй","oy"=>"ой","yoy"=>"ёй","uy"=>"уй","yuy"=>"юй","yy"=>"ый","iy"=>"ий","ey"=>"ей",
+ "ch"=>"ч","zh"=>"ж","sh"=>"ш","ts"=>"ц",
+ "ph"=>"ф",
+ }
+
+ REVERSE_UPPER_SINGLE = {
+ "A"=>"А","B"=>"Б","C"=>"С","D"=>"Д",
+ "E"=>"Е","F"=>"Ф","G"=>"Г","H"=>"Х",
+ "I"=>"И","J"=>"Й","K"=>"К","L"=>"Л",
+ "M"=>"М","N"=>"Н","O"=>"О","P"=>"П",
+ "Q"=>"К","R"=>"Р","S"=>"С","T"=>"Т",
+ "U"=>"У","V"=>"В","W"=>"У","X"=>"КС",
+ "Y"=>"Ы","Z"=>"З","'"=>"Ъ",
+ }
+ REVERSE_UPPER_MULTI = {
+ "SCH"=>"Щ","SKH"=>"СХ",
+ "AYA"=>"АЯ","YAYA"=>"ЯЯ","OYА"=>"ОЯ","UYА"=>"УЯ","YYА"=>"ЫЯ","EYА"=>"ЕЯ",
+ "AYE"=>"АЕ","OYE"=>"ОЕ","UYE"=>"УЕ","YYE"=>"ЫЕ","EYE"=>"ЕЕ",
+ "OYE"=>"ОЕ","OYO"=>"ОЁ",
+ "AYU"=>"АЮ","UYU"=>"УЮ","OYU"=>"ОЮ","UYU"=>"УЮ","EYU"=>"ЕЮ",
+ "YU"=>"Ю","YA"=>"Я","YO"=>"Ё",
+ "JU"=>"Ю","JA"=>"Я","JO"=>"Ё",
+ "YI"=>"Ї","JI"=>"Ї",
+ "AY"=>"АЙ","YAY"=>"ЯЙ","OY"=>"ОЙ","YOY"=>"ЁЙ","UY"=>"УЙ","YUY"=>"ЮЙ","YY"=>"ЫЙ","IY"=>"ИЙ","EY"=>"ЕЙ",
+ "AY"=>"АЙ","YAY"=>"ЯЙ","OY"=>"ОЙ","YOY"=>"ЁЙ","UY"=>"УЙ","YUY"=>"ЮЙ","YY"=>"ЫЙ","IY"=>"ИЙ","EY"=>"ЕЙ",
+ "CH"=>"Ч","ZH"=>"Ж","SH"=>"Ш","TS"=>"Ц",
}
LOWER = (LOWER_SINGLE.merge(LOWER_MULTI)).freeze
UPPER = (UPPER_SINGLE.merge(UPPER_MULTI)).freeze
MULTI_KEYS = (LOWER_MULTI.merge(UPPER_MULTI)).keys.sort_by {|s| s.length}.reverse.freeze
+ MULTI_KEYS_PATTERN = MULTI_KEYS.join('|').freeze
+
+ REVERSE_LOWER = (REVERSE_LOWER_SINGLE.merge(REVERSE_LOWER_MULTI)).freeze
+ REVERSE_UPPER = (REVERSE_UPPER_SINGLE.merge(REVERSE_UPPER_MULTI)).freeze
+ REVERSE_MULTI_KEYS = (REVERSE_LOWER_MULTI.merge(REVERSE_UPPER_MULTI)).keys.sort_by {|s| s.length}.reverse.freeze
+ REVERSE_MULTI_KEYS_PATTERN = REVERSE_MULTI_KEYS.join('|').freeze
# Transliterate a string with russian characters
#
# Возвращает строку, в которой все буквы русского алфавита заменены на похожую по звучанию латиницу
def transliterate(str)
- chars = str.scan(%r{#{MULTI_KEYS.join '|'}|\w|.})
+ convert(str, UPPER, LOWER, MULTI_KEYS_PATTERN)
+ end
+
+ # De-transliterate a latin string into cyrillic characters
+ #
+ # Возвращает строку, в которой все буквы латинского алфавита заменены на похожие по звучанию из кириллицы
+ def detransliterate(str)
+ convert(str, REVERSE_UPPER, REVERSE_LOWER, REVERSE_MULTI_KEYS_PATTERN)
+ end
+
+ def convert(src, *params)
+ send( 'convert_' + src.class.name.downcase, src, *params)
+ end
+
+ def convert_array(arr, *params)
+ arr.map { |a| convert(a, *params) }
+ end
+
+ def convert_string(str, upper, lower, multi_pattern)
+ chars = str.scan(%r{#{multi_pattern}|\w|.})
result = ""
chars.each_with_index do |char, index|
- if UPPER.has_key?(char) && LOWER.has_key?(chars[index+1])
+ result << \
+ if upper.has_key?(char) && lower.has_key?(chars[index+1])
# combined case
- result << UPPER[char].downcase.capitalize
- elsif UPPER.has_key?(char)
- result << UPPER[char]
- elsif LOWER.has_key?(char)
- result << LOWER[char]
+ upper[char].downcase.capitalize
+ elsif upper.has_key?(char)
+ upper[char]
+ elsif lower.has_key?(char)
+ lower[char]
else
- result << char
+ char
end
end
result
end
+
+ LAYOUT_RUS_UPPER = 'ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭЯЧСМИТЬБЮЁ№"'
+ LAYOUT_ENG_UPPER = 'QWERTYUIOP{}ASDFGHJKL:"ZXCVBNM<>~#@'
+
+ LAYOUT_RUS_LOWER = 'йцукенгшщзхъфывапролджэячсмитьбюё'
+ LAYOUT_ENG_LOWER = "qwertyuiop[]asdfghjkl;'zxcvbnm,.`"
+
+ LAYOUT_RUS = (LAYOUT_RUS_LOWER + LAYOUT_RUS_UPPER).freeze
+ LAYOUT_ENG = (LAYOUT_ENG_LOWER + LAYOUT_ENG_UPPER).freeze
+
+ def layout_rus(str)
+ str.to_s.tr(LAYOUT_ENG, LAYOUT_RUS)
+ end
+
+ def layout_eng(str)
+ str.to_s.tr(LAYOUT_RUS, LAYOUT_ENG)
+ end
end
-end
\ No newline at end of file
+end
diff --git a/lib/russian/version.rb b/lib/russian/version.rb
index 716fd76..997d64c 100644
--- a/lib/russian/version.rb
+++ b/lib/russian/version.rb
@@ -6,4 +6,4 @@ module VERSION
STRING = [MAJOR, MINOR, TINY].join('.')
end
-end
\ No newline at end of file
+end
diff --git a/spec/i18n/locale/datetime_spec.rb b/spec/i18n/locale/datetime_spec.rb
index ee2a505..fe65453 100644
--- a/spec/i18n/locale/datetime_spec.rb
+++ b/spec/i18n/locale/datetime_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
require File.dirname(__FILE__) + '/../../spec_helper'
@@ -8,7 +8,7 @@
@date = Date.parse("1985-12-01")
@time = Time.local(1985, 12, 01, 16, 05)
end
-
+
describe "with date formats" do
it "should use default format" do
l(@date).should == "01.12.1985"
@@ -22,7 +22,7 @@
l(@date, :format => :long).should == "01 декабря 1985"
end
end
-
+
describe "with date day names" do
it "should use day names" do
l(@date, :format => "%d %B (%A)").should == "01 декабря (воскресенье)"
@@ -33,27 +33,34 @@
l(@date, :format => "%A").should == "Воскресенье"
l(@date, :format => "%A, %d %B").should == "Воскресенье, 01 декабря"
end
-
+
it "should use abbreviated day names" do
l(@date, :format => "%a").should == "Вс"
l(@date, :format => "%a, %d %b %Y").should == "Вс, 01 дек. 1985"
end
end
-
+
describe "with month names" do
it "should use month names" do
l(@date, :format => "%d %B").should == "01 декабря"
+ l(@date, :format => "%-d %B").should == "1 декабря"
+
+ if RUBY_VERSION > "1.9.2"
+ l(@date, :format => "%1d %B").should == "1 декабря"
+ l(@date, :format => "%2d %B").should == "01 декабря"
+ end
+
l(@date, :format => "%e %B %Y").should == " 1 декабря 1985"
l(@date, :format => "%d %B").should == "01 декабря"
l(@date, :format => "%e %B %Y").should == " 1 декабря 1985"
l(@date, :format => "А было тогда %eе число %B %Y").should == "А было тогда 1е число декабря 1985"
end
-
+
it "should use standalone month names" do
l(@date, :format => "%B").should == "Декабрь"
l(@date, :format => "%B %Y").should == "Декабрь 1985"
end
-
+
it "should use abbreviated month names" do
@date = Date.parse("1985-03-01")
l(@date, :format => "%d %b").should == "01 марта"
@@ -61,7 +68,7 @@
l(@date, :format => "%d %b").should == "01 марта"
l(@date, :format => "%e %b %Y").should == " 1 марта 1985"
end
-
+
it "should use standalone abbreviated month names" do
@date = Date.parse("1985-03-01")
l(@date, :format => "%b").should == "март"
@@ -85,7 +92,7 @@
it "should use long format" do
l(@time, :format => :long).should == "01 декабря 1985, 16:05"
end
-
+
it "should define am and pm" do
I18n.backend.translate(Russian.locale, :"time.am").should_not be_nil
I18n.backend.translate(Russian.locale, :"time.pm").should_not be_nil
diff --git a/spec/i18n/locale/pluralization_spec.rb b/spec/i18n/locale/pluralization_spec.rb
index da15865..15a9636 100644
--- a/spec/i18n/locale/pluralization_spec.rb
+++ b/spec/i18n/locale/pluralization_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
require File.dirname(__FILE__) + '/../../spec_helper'
@@ -10,7 +10,7 @@
end
@backend = I18n.backend
end
-
+
it "should pluralize correctly" do
@backend.send(:pluralize, :'ru', @hash, 1).should == 'one'
@backend.send(:pluralize, :'ru', @hash, 2).should == 'few'
@@ -25,4 +25,4 @@
@backend.send(:pluralize, :'ru', @hash, 2.31).should == 'other'
@backend.send(:pluralize, :'ru', @hash, 3.31).should == 'other'
end
-end
\ No newline at end of file
+end
diff --git a/spec/metaphone_spec.rb b/spec/metaphone_spec.rb
new file mode 100644
index 0000000..a96eb7b
--- /dev/null
+++ b/spec/metaphone_spec.rb
@@ -0,0 +1,42 @@
+# -*- encoding: utf-8 -*-
+
+require File.dirname(__FILE__) + '/spec_helper'
+
+describe Russian do
+ describe "metaphone" do
+ def m(str)
+ Russian::metaphone(str)
+ end
+
+ it "'metaphone' method should perform metaphone generation code" do
+ str = mock(:str)
+ Russian::Metaphone.should_receive(:generate).with(str)
+ Russian.send(:metaphone, str)
+ end
+
+ it "should generate proper metaphone" do
+ m("").should == ""
+ m("ih").should == "IH"
+ m("Это просто некий текст").should == "Т ПРСТ НХ ТХСТ"
+ m("сочный").should == "ШН"
+ m(" 2эта, \"3В21'").should == "Т Ф"
+ m("иван-и-марья").should == "ФН МР"
+ m("много букв").should == m("мнока букафф")
+ m("небольшие опечатки и албанский").should == m("нипалшые опчатги олпансгие")
+ m("китайский ресторан").should == m("кытаски ристаран")
+ m("ранний рассвет").should == m("раненное росифатой")
+ m(Russian.detranslit("pizza")).should == m("пицца")
+ m("парикмахерская").should == m("порехмакерская")
+ m("макдональдс").should == m("магдоналтс")
+ m("поцанчик").should == m("патсанчег")
+ m("напиться").should == m("напицца")
+ m("сейчас").should == m("щаз")
+ m("эта").should == m("этот")
+ end
+
+ it "should generate proper metaphone for mixed russian-english strings" do
+ m("Это кусок строки русских букв v peremeshku s latinizey i амперсандом (pozor!) & something").should ==
+ "Т ХСХ СТРХ РСХ ПХФ F PRMXHK S LTNS I МПРСНТМ PSR SMZNG"
+ end
+ end
+end
diff --git a/spec/russian_spec.rb b/spec/russian_spec.rb
index 6226bf3..81e3349 100644
--- a/spec/russian_spec.rb
+++ b/spec/russian_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
require File.dirname(__FILE__) + '/spec_helper'
@@ -12,38 +12,38 @@
Russian.locale.should == Russian::LOCALE
end
end
-
+
describe "during i18n initialization" do
after(:each) do
I18n.load_path = []
Russian.init_i18n
end
-
+
it "should keep existing translations while switching backends" do
I18n.load_path << File.join(File.dirname(__FILE__), 'fixtures', 'en.yml')
Russian.init_i18n
I18n.t(:foo, :locale => :'en').should == "bar"
end
-
+
it "should keep existing :ru translations while switching backends" do
I18n.load_path << File.join(File.dirname(__FILE__), 'fixtures', 'ru.yml')
Russian.init_i18n
I18n.t(:'date.formats.default', :locale => :'ru').should == "override"
end
-
+
it "should NOT set default locale to Russian locale" do
locale = I18n.default_locale
Russian.init_i18n
I18n.default_locale.should == locale
end
end
-
+
describe "with localize proxy" do
before(:each) do
@time = mock(:time)
@options = { :format => "%d %B %Y" }
end
-
+
%w(l localize).each do |method|
it "'#{method}' should call I18n backend localize" do
I18n.should_receive(:localize).with(@time, @options.merge({ :locale => Russian.locale }))
@@ -51,7 +51,7 @@
end
end
end
-
+
describe "with translate proxy" do
before(:all) do
@object = :bar
@@ -65,7 +65,7 @@
end
end
end
-
+
describe "strftime" do
before(:each) do
@time = mock(:time)
@@ -76,18 +76,18 @@
Russian.should_receive(:localize).with(@time, { :format => format })
Russian.strftime(@time, format)
end
-
+
it "should call localize with object and default format when format is not specified" do
Russian.should_receive(:localize).with(@time, { :format => :default })
Russian.strftime(@time)
end
end
-
+
describe "with pluralization" do
%w(p pluralize).each do |method|
it "'#{method}' should pluralize with variants given" do
variants = %w(вещь вещи вещей вещи)
-
+
Russian.send(method, 1, *variants).should == "вещь"
Russian.send(method, 2, *variants).should == 'вещи'
Russian.send(method, 3, *variants).should == 'вещи'
@@ -99,12 +99,12 @@
Russian.send(method, 131, *variants).should == 'вещь'
Russian.send(method, 3.14, *variants).should == 'вещи'
end
-
+
it "should raise an exception when first parameter is not a number" do
lambda { Russian.send(method, nil, "вещь", "вещи", "вещей") }.should raise_error(ArgumentError)
lambda { Russian.send(method, "вещь", "вещь", "вещи", "вещей") }.should raise_error(ArgumentError)
end
-
+
it "should raise an exception when there are not enough variants" do
lambda { Russian.send(method, 1) }.should raise_error(ArgumentError)
lambda { Russian.send(method, 1, "вещь") }.should raise_error(ArgumentError)
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index b533437..4d1a1a4 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
$TESTING=true
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
diff --git a/spec/transliteration_spec.rb b/spec/transliteration_spec.rb
index a4f256b..60afa46 100644
--- a/spec/transliteration_spec.rb
+++ b/spec/transliteration_spec.rb
@@ -1,4 +1,4 @@
-# -*- encoding: utf-8 -*-
+# -*- encoding: utf-8 -*-
require File.dirname(__FILE__) + '/spec_helper'
@@ -8,6 +8,10 @@ def t(str)
Russian::transliterate(str)
end
+ def dt(str)
+ Russian::Transliteration::detransliterate(str)
+ end
+
%w(transliterate translit).each do |method|
it "'#{method}' method should perform transliteration" do
str = mock(:str)
@@ -16,6 +20,14 @@ def t(str)
end
end
+ %w(detransliterate detranslit).each do |method|
+ it "'#{method}' method should perform de-transliteration" do
+ str = mock(:str)
+ Russian::Transliteration.should_receive(:detransliterate).with(str)
+ Russian.send(method, str)
+ end
+ end
+
# These tests are from rutils, .
it "should transliterate properly" do
@@ -26,13 +38,28 @@ def t(str)
t("ш").should == "sh"
t("Ш").should == "SH"
t("ц").should == "ts"
+ t("схема").should == "skhema"
+ t("“”«»").should == '""""'
end
-
+
+ it "should de-transliterate properly" do
+ dt("Eto prosto nekiy tekst").should == "Ето просто некий текст"
+ dt("sch").should == "щ"
+ dt("Zveryo moyo").should == "Зверё моё"
+ dt("mayskiy izmenyaya moey pamyatyu tvoeyu pohodkoyu vyshla iz maya ob'ektoy matyoy").should == "майский изменяя моей памятю твоею походкою вышла из мая обЪектой матёй"
+ dt("IE explorer").should == "ИЕ експлорер"
+ dt("upuscheniy").should == "упущений"
+ dt("sh").should == "ш"
+ dt("TS").should == "Ц"
+ dt("skhema").should == "схема"
+ dt("philosophy").should == "философы"
+ end
+
it "should properly transliterate mixed russian-english strings" do
- t("Это кусок строки русских букв v peremeshku s latinizey i амперсандом (pozor!) & something").should ==
- "Eto kusok stroki russkih bukv v peremeshku s latinizey i ampersandom (pozor!) & something"
+ t("Это кусок строки русских букв v peremeshku s latinizey i амперсандом (pozor!) & something").should ==
+ "Eto kusok stroki russkih bukv v peremeshku s latinizey i ampersandom (pozor!) & something"
end
-
+
it "should properly transliterate mixed case chars in a string" do
t("НЕВЕРОЯТНОЕ УПУЩЕНИЕ").should == "NEVEROYATNOE UPUSCHENIE"
t("Невероятное Упущение").should == "Neveroyatnoe Upuschenie"
@@ -47,5 +74,39 @@ def t(str)
t("Алябьев").should == "Alyabiev"
t("АЛЯБЬЕВ").should == "ALYABIEV"
end
+
+ it "should process arrays of strings" do
+ arr = %w(раз два три)
+ t(arr).should == arr.map { |a| t(a) }
+ end
+
+ %w(rus eng).each do |lang|
+ it "'layout_#{lang}' method should change string as it would be typed in '#{lang}' keyboard layout" do
+ str = mock(:str)
+ Russian.send("layout_"+lang, str)
+ end
+ end
+
+ def lr(str)
+ Russian.layout_rus(str)
+ end
+
+ def le(str)
+ Russian.layout_eng(str)
+ end
+
+ it "should change input layout to standard russian" do
+ lr('ntcn').should == "тест"
+ lr('gJKBNBYAJHVFWBz').should == "пОЛИТИНФОРМАЦИя"
+ lr('~@#:"M<>').should == 'Ё"№ЖЭЬБЮ'
+ lr("`;',.").should == 'ёжэбю'
+ end
+
+ it "should change input layout to standard english" do
+ le('еуые').should == "test"
+ le('сщТЕФьШтфешЩт').should == "coNTAmInatiOn"
+ le('Ё"№ЖЭЬБЮ').should == '~@#:"M<>'
+ le('ёжэбю').should == "`;',."
+ end
end
-end
\ No newline at end of file
+end