russian 0.2.7 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +203 -0
- data/Gemfile +8 -0
- data/LICENSE +2 -2
- data/README.md +327 -0
- data/Rakefile +12 -50
- data/lib/russian/action_view_ext/helpers/date_helper.rb +136 -95
- data/lib/russian/active_model_ext/custom_error_message.rb +51 -0
- data/lib/russian/locale/actionview.yml +150 -83
- data/lib/russian/locale/activemodel.yml +57 -0
- data/lib/russian/locale/activerecord.yml +66 -61
- data/lib/russian/locale/activesupport.yml +5 -8
- data/lib/russian/locale/datetime.rb +49 -0
- data/lib/russian/locale/datetime.yml +90 -23
- data/lib/russian/locale/pluralization.rb +49 -0
- data/lib/russian/locale/transliterator.rb +18 -0
- data/lib/russian/russian_rails.rb +99 -0
- data/lib/russian/strptime.rb +166 -0
- data/lib/russian/transliteration.rb +87 -53
- data/lib/russian/version.rb +31 -0
- data/lib/russian.rb +382 -103
- data/russian.gemspec +43 -0
- data/sig/russian.rbs +46 -0
- metadata +197 -86
- data/CHANGELOG +0 -108
- data/README.textile +0 -298
- data/TODO +0 -10
- data/init.rb +0 -3
- data/lib/russian/active_record_ext/custom_error_message.rb +0 -163
- data/lib/russian/active_support_ext/parameterize.rb +0 -31
- data/lib/russian/backend/advanced.rb +0 -134
- data/lib/russian/locale/pluralize.rb +0 -25
- data/lib/vendor/i18n/MIT-LICENSE +0 -20
- data/lib/vendor/i18n/README.textile +0 -20
- data/lib/vendor/i18n/Rakefile +0 -5
- data/lib/vendor/i18n/i18n.gemspec +0 -27
- data/lib/vendor/i18n/lib/i18n/backend/simple.rb +0 -214
- data/lib/vendor/i18n/lib/i18n/exceptions.rb +0 -53
- data/lib/vendor/i18n/lib/i18n.rb +0 -199
- data/lib/vendor/i18n/test/all.rb +0 -5
- data/lib/vendor/i18n/test/i18n_exceptions_test.rb +0 -100
- data/lib/vendor/i18n/test/i18n_test.rb +0 -125
- data/lib/vendor/i18n/test/locale/en.rb +0 -1
- data/lib/vendor/i18n/test/locale/en.yml +0 -3
- data/lib/vendor/i18n/test/simple_backend_test.rb +0 -568
- data/lib/vendor/i18n_label/README.textile +0 -38
- data/lib/vendor/i18n_label/Rakefile +0 -11
- data/lib/vendor/i18n_label/init.rb +0 -1
- data/lib/vendor/i18n_label/install.rb +0 -1
- data/lib/vendor/i18n_label/lib/i18n_label.rb +0 -23
- data/lib/vendor/i18n_label/spec/i18n_label_spec.rb +0 -20
- data/lib/vendor/i18n_label/spec/spec_helper.rb +0 -10
- data/lib/vendor/i18n_label/tasks/i18n_label_tasks.rake +0 -4
- data/lib/vendor/i18n_label/uninstall.rb +0 -1
- data/spec/fixtures/en.yml +0 -4
- data/spec/fixtures/ru.yml +0 -4
- data/spec/i18n/locale/datetime_spec.rb +0 -99
- data/spec/i18n/locale/pluralization_spec.rb +0 -28
- data/spec/locale_spec.rb +0 -129
- data/spec/russian_spec.rb +0 -136
- data/spec/spec_helper.rb +0 -7
- data/spec/transliteration_spec.rb +0 -51
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
require "time"
|
|
5
|
+
|
|
6
|
+
module Russian
|
|
7
|
+
# Localized `strptime` helpers for Russian month and weekday names.
|
|
8
|
+
#
|
|
9
|
+
# The module normalizes Russian textual date/time tokens to the English
|
|
10
|
+
# tokens expected by Ruby's native parsers, then delegates to
|
|
11
|
+
# `Date.strptime`, `Time.strptime`, or `DateTime.strptime`.
|
|
12
|
+
#
|
|
13
|
+
#
|
|
14
|
+
# Локализованные хелперы `strptime` для русских названий месяцев и дней
|
|
15
|
+
# недели.
|
|
16
|
+
#
|
|
17
|
+
# Модуль нормализует русские текстовые токены даты и времени к английским
|
|
18
|
+
# токенам, которые ожидают стандартные parser'ы Ruby, а затем делегирует
|
|
19
|
+
# работу в `Date.strptime`, `Time.strptime` или `DateTime.strptime`.
|
|
20
|
+
module Strptime
|
|
21
|
+
module_function
|
|
22
|
+
|
|
23
|
+
# Parses a localized Russian date string with `Date.strptime`.
|
|
24
|
+
#
|
|
25
|
+
#
|
|
26
|
+
# Разбирает локализованную русскую строку даты через `Date.strptime`.
|
|
27
|
+
#
|
|
28
|
+
# @param string [String] Localized date string.
|
|
29
|
+
# Локализованная строка даты.
|
|
30
|
+
# @param format [String] Optional `strptime` format string.
|
|
31
|
+
# Строка формата `strptime`.
|
|
32
|
+
# @return [Date] Parsed date.
|
|
33
|
+
# Разобранная дата.
|
|
34
|
+
def date_strptime(string, format = "%F")
|
|
35
|
+
Date.strptime(normalize_input(string, format), format, Date::ITALY)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Parses a localized Russian date/time string with `Time.strptime`.
|
|
39
|
+
#
|
|
40
|
+
#
|
|
41
|
+
# Разбирает локализованную русскую строку даты и времени через
|
|
42
|
+
# `Time.strptime`.
|
|
43
|
+
#
|
|
44
|
+
# @param string [String] Localized date/time string.
|
|
45
|
+
# Локализованная строка даты и времени.
|
|
46
|
+
# @param format [String] `strptime` format string.
|
|
47
|
+
# Строка формата `strptime`.
|
|
48
|
+
# @param now [Time] Optional base time passed to `Time.strptime`.
|
|
49
|
+
# Базовое значение времени, передаваемое в `Time.strptime`.
|
|
50
|
+
# @return [Time] Parsed time.
|
|
51
|
+
# Разобранное время.
|
|
52
|
+
def time_strptime(string, format, now = Time.now)
|
|
53
|
+
Time.strptime(normalize_input(string, format), format, now)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Parses a localized Russian date/time string with `DateTime.strptime`.
|
|
57
|
+
#
|
|
58
|
+
#
|
|
59
|
+
# Разбирает локализованную русскую строку даты и времени через
|
|
60
|
+
# `DateTime.strptime`.
|
|
61
|
+
#
|
|
62
|
+
# @param string [String] Localized date/time string.
|
|
63
|
+
# Локализованная строка даты и времени.
|
|
64
|
+
# @param format [String] Optional `strptime` format string.
|
|
65
|
+
# Строка формата `strptime`.
|
|
66
|
+
# @return [DateTime] Parsed datetime.
|
|
67
|
+
# Разобранный `DateTime`.
|
|
68
|
+
def datetime_strptime(string, format = "%FT%T%z")
|
|
69
|
+
DateTime.strptime(normalize_input(string, format), format, Date::ITALY)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# @private
|
|
73
|
+
def normalize_input(string, format)
|
|
74
|
+
return string unless string.is_a?(String) && format.is_a?(String)
|
|
75
|
+
|
|
76
|
+
replacements = localized_replacements(format)
|
|
77
|
+
return string if replacements.empty?
|
|
78
|
+
|
|
79
|
+
token_regexp = Regexp.new(
|
|
80
|
+
"(?<!\\p{L})(?:#{replacements.keys.sort_by(&:length).reverse.map do |token|
|
|
81
|
+
Regexp.escape(token)
|
|
82
|
+
end.join("|")})(?!\\p{L})",
|
|
83
|
+
Regexp::IGNORECASE
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
string.gsub(token_regexp) { |token| replacements.fetch(token.downcase) }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# @private
|
|
90
|
+
def localized_replacements(format)
|
|
91
|
+
directives = directives_in(format)
|
|
92
|
+
replacements = {}
|
|
93
|
+
|
|
94
|
+
replacements.merge!(localized_tokens(month_names_key(format), Date::MONTHNAMES)) if directives.include?("B")
|
|
95
|
+
|
|
96
|
+
if directives.include?("b")
|
|
97
|
+
replacements.merge!(localized_tokens(abbr_month_names_key(format), Date::ABBR_MONTHNAMES))
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
replacements.merge!(localized_tokens(day_names_key(format), Date::DAYNAMES)) if directives.include?("A")
|
|
101
|
+
|
|
102
|
+
replacements.merge!(localized_tokens(abbr_day_names_key(format), Date::ABBR_DAYNAMES)) if directives.include?("a")
|
|
103
|
+
|
|
104
|
+
replacements
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# @private
|
|
108
|
+
def localized_tokens(key, english_names)
|
|
109
|
+
localized_names = I18n.t(key, locale: Russian::LOCALE).compact
|
|
110
|
+
english_names = english_names.compact
|
|
111
|
+
|
|
112
|
+
localized_names.zip(english_names).each_with_object({}) do |(localized_name, english_name), replacements|
|
|
113
|
+
replacements[localized_name.downcase] = english_name
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @private
|
|
118
|
+
def directives_in(format)
|
|
119
|
+
directives = []
|
|
120
|
+
index = 0
|
|
121
|
+
|
|
122
|
+
while index < format.length
|
|
123
|
+
if format[index] != "%"
|
|
124
|
+
index += 1
|
|
125
|
+
next
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
if format[index + 1] == "%"
|
|
129
|
+
index += 2
|
|
130
|
+
next
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
index += 1
|
|
134
|
+
index += 1 while index < format.length && Russian::STRPTIME_DIRECTIVE_MODIFIERS.include?(format[index])
|
|
135
|
+
index += 1 while index < format.length && format[index].match?(/\d/)
|
|
136
|
+
|
|
137
|
+
index += 1 if index < format.length && %w[E O].include?(format[index])
|
|
138
|
+
|
|
139
|
+
directives << format[index] if index < format.length
|
|
140
|
+
index += 1
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
directives
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# @private
|
|
147
|
+
def month_names_key(format)
|
|
148
|
+
Russian::LOCALIZE_MONTH_NAMES_MATCH.match?(format) ? :"date.common_month_names" : :"date.standalone_month_names"
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
# @private
|
|
152
|
+
def abbr_month_names_key(format)
|
|
153
|
+
Russian::LOCALIZE_ABBR_MONTH_NAMES_MATCH.match?(format) ? :"date.common_abbr_month_names" : :"date.standalone_abbr_month_names"
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# @private
|
|
157
|
+
def day_names_key(format)
|
|
158
|
+
Russian::LOCALIZE_STANDALONE_DAY_NAMES_MATCH.match?(format) ? :"date.standalone_day_names" : :"date.common_day_names"
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# @private
|
|
162
|
+
def abbr_day_names_key(format)
|
|
163
|
+
Russian::LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH.match?(format) ? :"date.common_abbr_day_names" : :"date.standalone_abbr_day_names"
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
end
|
|
@@ -1,72 +1,106 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Russian
|
|
4
|
-
# Russian transliteration
|
|
4
|
+
# Russian transliteration tables and helpers.
|
|
5
5
|
#
|
|
6
|
-
#
|
|
6
|
+
# Transliteration is heavily based on the
|
|
7
|
+
# [rutils](https://github.com/julik/rutils) gem by
|
|
8
|
+
# Julian "julik" Tarkhanov and contributors, then cleaned up and
|
|
9
|
+
# adapted for this gem.
|
|
10
|
+
#
|
|
11
|
+
#
|
|
12
|
+
# Таблицы и хелперы для русской транслитерации.
|
|
13
|
+
#
|
|
14
|
+
# Транслитерация во многом основана на gem
|
|
15
|
+
# [rutils](https://github.com/julik/rutils) Юлика Тарханова и
|
|
16
|
+
# соавторов, а затем упрощена и адаптирована для этого gem'а.
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# Russian::Transliteration.transliterate("Юлия")
|
|
20
|
+
# # => "Yuliya"
|
|
21
|
+
#
|
|
22
|
+
# Russian::Transliteration.transliterate("Н.П. Шерстяков")
|
|
23
|
+
# # => "N.P. Sherstyakov"
|
|
7
24
|
module Transliteration
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# Transliteration heavily based on rutils gem by Julian "julik" Tarkhanov and Co.
|
|
11
|
-
# <http://rutils.rubyforge.org/>
|
|
12
|
-
# Cleaned up and optimized.
|
|
25
|
+
module_function
|
|
13
26
|
|
|
27
|
+
# @private
|
|
14
28
|
LOWER_SINGLE = {
|
|
15
|
-
"і"=>"i","ґ"=>"g","ё"=>"yo","№"=>"#","є"=>"e",
|
|
16
|
-
"ї"=>"yi","а"=>"a","б"=>"b",
|
|
17
|
-
"в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"zh",
|
|
18
|
-
"з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
|
|
19
|
-
"м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
|
|
20
|
-
"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
|
|
21
|
-
"ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"'",
|
|
22
|
-
"ы"=>"y","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya"
|
|
23
|
-
}
|
|
29
|
+
"і" => "i", "ґ" => "g", "ё" => "yo", "№" => "#", "є" => "e",
|
|
30
|
+
"ї" => "yi", "а" => "a", "б" => "b",
|
|
31
|
+
"в" => "v", "г" => "g", "д" => "d", "е" => "e", "ж" => "zh",
|
|
32
|
+
"з" => "z", "и" => "i", "й" => "y", "к" => "k", "л" => "l",
|
|
33
|
+
"м" => "m", "н" => "n", "о" => "o", "п" => "p", "р" => "r",
|
|
34
|
+
"с" => "s", "т" => "t", "у" => "u", "ф" => "f", "х" => "h",
|
|
35
|
+
"ц" => "ts", "ч" => "ch", "ш" => "sh", "щ" => "sch", "ъ" => "'",
|
|
36
|
+
"ы" => "y", "ь" => "", "э" => "e", "ю" => "yu", "я" => "ya"
|
|
37
|
+
}.freeze
|
|
38
|
+
# @private
|
|
24
39
|
LOWER_MULTI = {
|
|
25
|
-
"ье"=>"ie",
|
|
26
|
-
"ьё"=>"ie"
|
|
27
|
-
}
|
|
40
|
+
"ье" => "ie",
|
|
41
|
+
"ьё" => "ie"
|
|
42
|
+
}.freeze
|
|
28
43
|
|
|
44
|
+
# @private
|
|
29
45
|
UPPER_SINGLE = {
|
|
30
|
-
"Ґ"=>"G","Ё"=>"YO","Є"=>"E","Ї"=>"YI","І"=>"I",
|
|
31
|
-
"А"=>"A","Б"=>"B","В"=>"V","Г"=>"G",
|
|
32
|
-
"Д"=>"D","Е"=>"E","Ж"=>"ZH","З"=>"Z","И"=>"I",
|
|
33
|
-
"Й"=>"Y","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N",
|
|
34
|
-
"О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T",
|
|
35
|
-
"У"=>"U","Ф"=>"F","Х"=>"H","Ц"=>"TS","Ч"=>"CH",
|
|
36
|
-
"Ш"=>"SH","Щ"=>"SCH","Ъ"=>"'","Ы"=>"Y","Ь"=>"",
|
|
37
|
-
"Э"=>"E","Ю"=>"YU","Я"=>"YA"
|
|
38
|
-
}
|
|
46
|
+
"Ґ" => "G", "Ё" => "YO", "Є" => "E", "Ї" => "YI", "І" => "I",
|
|
47
|
+
"А" => "A", "Б" => "B", "В" => "V", "Г" => "G",
|
|
48
|
+
"Д" => "D", "Е" => "E", "Ж" => "ZH", "З" => "Z", "И" => "I",
|
|
49
|
+
"Й" => "Y", "К" => "K", "Л" => "L", "М" => "M", "Н" => "N",
|
|
50
|
+
"О" => "O", "П" => "P", "Р" => "R", "С" => "S", "Т" => "T",
|
|
51
|
+
"У" => "U", "Ф" => "F", "Х" => "H", "Ц" => "TS", "Ч" => "CH",
|
|
52
|
+
"Ш" => "SH", "Щ" => "SCH", "Ъ" => "'", "Ы" => "Y", "Ь" => "",
|
|
53
|
+
"Э" => "E", "Ю" => "YU", "Я" => "YA"
|
|
54
|
+
}.freeze
|
|
55
|
+
# @private
|
|
39
56
|
UPPER_MULTI = {
|
|
40
|
-
"ЬЕ"=>"IE",
|
|
41
|
-
"ЬЁ"=>"IE"
|
|
42
|
-
}
|
|
57
|
+
"ЬЕ" => "IE",
|
|
58
|
+
"ЬЁ" => "IE"
|
|
59
|
+
}.freeze
|
|
43
60
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
61
|
+
# @private
|
|
62
|
+
LOWER = LOWER_SINGLE.merge(LOWER_MULTI).freeze
|
|
63
|
+
# @private
|
|
64
|
+
UPPER = UPPER_SINGLE.merge(UPPER_MULTI).freeze
|
|
65
|
+
# @private
|
|
66
|
+
TITLE = UPPER.transform_values(&:capitalize).freeze
|
|
67
|
+
# @private
|
|
68
|
+
MULTI_KEYS = LOWER_MULTI.merge(UPPER_MULTI).keys.sort_by(&:length).reverse.freeze
|
|
69
|
+
# @private
|
|
70
|
+
TOKEN_RE = /#{Regexp.union(MULTI_KEYS).source}|./m
|
|
47
71
|
|
|
48
|
-
#
|
|
72
|
+
# Transliterates a string containing Cyrillic characters.
|
|
73
|
+
#
|
|
74
|
+
# The method preserves non-Cyrillic characters and follows the historical
|
|
75
|
+
# casing rules of the gem.
|
|
76
|
+
#
|
|
77
|
+
#
|
|
78
|
+
# Транслитерирует строку, содержащую кириллические символы.
|
|
79
|
+
#
|
|
80
|
+
# Метод сохраняет некириллические символы и следует историческим правилам
|
|
81
|
+
# gem'а для регистра.
|
|
82
|
+
#
|
|
83
|
+
# @param str [String] String to transliterate.
|
|
84
|
+
# Строка для транслитерации.
|
|
85
|
+
# @return [String] Transliteration result.
|
|
86
|
+
# Результат транслитерации.
|
|
49
87
|
#
|
|
50
|
-
#
|
|
88
|
+
# @example
|
|
89
|
+
# Russian::Transliteration.transliterate("Привет, мир!")
|
|
90
|
+
# # => "Privet, mir!"
|
|
51
91
|
def transliterate(str)
|
|
52
|
-
|
|
92
|
+
tokens = str.scan(TOKEN_RE)
|
|
53
93
|
|
|
54
|
-
|
|
94
|
+
tokens.each_with_index.map do |token, index|
|
|
95
|
+
lower = LOWER[token]
|
|
96
|
+
next lower if lower
|
|
55
97
|
|
|
56
|
-
|
|
57
|
-
if
|
|
58
|
-
|
|
59
|
-
result << UPPER[char].downcase.capitalize
|
|
60
|
-
elsif UPPER.has_key?(char)
|
|
61
|
-
result << UPPER[char]
|
|
62
|
-
elsif LOWER.has_key?(char)
|
|
63
|
-
result << LOWER[char]
|
|
64
|
-
else
|
|
65
|
-
result << char
|
|
66
|
-
end
|
|
67
|
-
end
|
|
98
|
+
upper = UPPER[token]
|
|
99
|
+
next TITLE[token] if upper && LOWER[tokens[index + 1]]
|
|
100
|
+
next upper if upper
|
|
68
101
|
|
|
69
|
-
|
|
102
|
+
token
|
|
103
|
+
end.join
|
|
70
104
|
end
|
|
71
105
|
end
|
|
72
|
-
end
|
|
106
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Russian
|
|
4
|
+
# Gem version constants.
|
|
5
|
+
#
|
|
6
|
+
# The version is split into major, minor, and tiny components, plus a string
|
|
7
|
+
# representation.
|
|
8
|
+
#
|
|
9
|
+
#
|
|
10
|
+
# Константы версии gem'а.
|
|
11
|
+
#
|
|
12
|
+
# Версия разбита на major, minor и tiny-компоненты, а также на строковое
|
|
13
|
+
# представление.
|
|
14
|
+
#
|
|
15
|
+
# @example
|
|
16
|
+
# Russian::VERSION::STRING
|
|
17
|
+
# # => "1.0.0"
|
|
18
|
+
module VERSION
|
|
19
|
+
MAJOR = 1
|
|
20
|
+
MINOR = 0
|
|
21
|
+
TINY = 0
|
|
22
|
+
|
|
23
|
+
# Full version string.
|
|
24
|
+
#
|
|
25
|
+
# Полная строка версии.
|
|
26
|
+
#
|
|
27
|
+
# @return [String] Full version string.
|
|
28
|
+
# Полная строка версии.
|
|
29
|
+
STRING = [MAJOR, MINOR, TINY].join(".")
|
|
30
|
+
end
|
|
31
|
+
end
|