russian 0.6.0 → 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 +5 -6
- data/LICENSE +2 -2
- data/README.md +327 -0
- data/Rakefile +15 -8
- data/lib/russian/action_view_ext/helpers/date_helper.rb +136 -101
- data/lib/russian/active_model_ext/custom_error_message.rb +40 -59
- data/lib/russian/locale/actionview.yml +101 -84
- data/lib/russian/locale/activemodel.yml +28 -21
- data/lib/russian/locale/activerecord.yml +57 -52
- data/lib/russian/locale/activesupport.yml +5 -8
- data/lib/russian/locale/datetime.rb +34 -24
- data/lib/russian/locale/datetime.yml +85 -22
- data/lib/russian/locale/pluralization.rb +32 -11
- data/lib/russian/locale/transliterator.rb +10 -9
- data/lib/russian/russian_rails.rb +97 -6
- data/lib/russian/strptime.rb +166 -0
- data/lib/russian/transliteration.rb +87 -53
- data/lib/russian/version.rb +27 -5
- data/lib/russian.rb +378 -78
- data/russian.gemspec +37 -20
- data/sig/russian.rbs +46 -0
- metadata +163 -53
- data/CHANGELOG +0 -132
- data/README.textile +0 -295
- data/TODO +0 -4
- 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 -47
- data/spec/russian_spec.rb +0 -118
- data/spec/spec_helper.rb +0 -7
- data/spec/transliteration_spec.rb +0 -51
|
@@ -1,118 +1,153 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
# (
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
11
|
-
#
|
|
12
|
-
#
|
|
13
|
-
#
|
|
14
|
-
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
3
|
+
module Russian
|
|
4
|
+
# Rails date helper integration with support for standalone month names.
|
|
5
|
+
#
|
|
6
|
+
# The patch teaches Rails date helpers to distinguish between common
|
|
7
|
+
# ("01 декабря") and standalone ("Декабрь") month names when the active
|
|
8
|
+
# locale provides both forms.
|
|
9
|
+
#
|
|
10
|
+
# For Russian, `select_month` always uses standalone month names. Other month
|
|
11
|
+
# rendering helpers switch to standalone names when `:discard_day` or
|
|
12
|
+
# `:use_standalone_month_names` is set. If split translations are unavailable,
|
|
13
|
+
# the implementation falls back to the standard Rails month-name keys.
|
|
14
|
+
#
|
|
15
|
+
#
|
|
16
|
+
# Интеграция с Rails date helper'ами для поддержки отдельностоящих
|
|
17
|
+
# названий месяцев.
|
|
18
|
+
#
|
|
19
|
+
# Патч учит Rails date helper'ы различать контекстные ("01 декабря") и
|
|
20
|
+
# отдельностоящие ("Декабрь") формы названий месяцев, если активная локаль
|
|
21
|
+
# предоставляет обе формы.
|
|
22
|
+
#
|
|
23
|
+
# Для русского языка `select_month` всегда использует отдельностоящие
|
|
24
|
+
# названия месяцев. Остальные helper'ы, рендерящие месяцы, переключаются на
|
|
25
|
+
# отдельностоящие формы, если указан `:discard_day` или
|
|
26
|
+
# `:use_standalone_month_names`. Если раздельных переводов нет, реализация
|
|
27
|
+
# откатывается к стандартным ключам Rails для названий месяцев.
|
|
28
|
+
module ActionViewExt
|
|
29
|
+
# Helper patches injected into Action View.
|
|
30
|
+
#
|
|
31
|
+
#
|
|
32
|
+
# Патчи хелперов, внедряемые в Action View.
|
|
22
33
|
module Helpers
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
34
|
+
# @private
|
|
35
|
+
MONTH_NAME_KEYS = {
|
|
36
|
+
short: {
|
|
37
|
+
common: :"date.common_abbr_month_names",
|
|
38
|
+
standalone: :"date.standalone_abbr_month_names",
|
|
39
|
+
fallback: :"date.abbr_month_names"
|
|
40
|
+
},
|
|
41
|
+
long: {
|
|
42
|
+
common: :"date.common_month_names",
|
|
43
|
+
standalone: :"date.standalone_month_names",
|
|
44
|
+
fallback: :"date.month_names"
|
|
45
|
+
}
|
|
46
|
+
}.freeze
|
|
47
|
+
|
|
48
|
+
# Patch for `ActionView::Helpers::DateHelper`.
|
|
49
|
+
#
|
|
50
|
+
#
|
|
51
|
+
# Патч для `ActionView::Helpers::DateHelper`.
|
|
52
|
+
module DateHelperPatch
|
|
53
|
+
# Builds a `<select>` with month options and forces standalone month
|
|
54
|
+
# names for Russian.
|
|
38
55
|
#
|
|
56
|
+
# The method keeps standard Rails month helper behavior and options,
|
|
57
|
+
# but injects `use_standalone_month_names: true` before delegating to
|
|
58
|
+
# Rails. This makes Russian month names render as standalone forms such
|
|
59
|
+
# as `Декабрь` instead of contextual forms such as `декабря`.
|
|
39
60
|
#
|
|
40
|
-
# ==== Examples
|
|
41
|
-
# # Generates a select field for months that defaults to the current month that
|
|
42
|
-
# # will use keys like "January", "March".
|
|
43
|
-
# select_month(Date.today)
|
|
44
61
|
#
|
|
45
|
-
#
|
|
46
|
-
#
|
|
47
|
-
# select_month(Date.today, :field_name => 'start')
|
|
62
|
+
# Формирует `<select>` со списком месяцев и принудительно использует
|
|
63
|
+
# отдельностоящие названия месяцев для русского языка.
|
|
48
64
|
#
|
|
49
|
-
#
|
|
50
|
-
#
|
|
51
|
-
#
|
|
65
|
+
# Метод сохраняет стандартное поведение и опции Rails month helper'а,
|
|
66
|
+
# но перед делегированием в Rails добавляет
|
|
67
|
+
# `use_standalone_month_names: true`. Благодаря этому для русского
|
|
68
|
+
# языка рендерятся отдельностоящие формы вроде `Декабрь`, а не
|
|
69
|
+
# контекстные формы вроде `декабря`.
|
|
52
70
|
#
|
|
53
|
-
#
|
|
54
|
-
#
|
|
55
|
-
#
|
|
71
|
+
# @param date [Date, Time, DateTime, Integer, nil] Selected month value.
|
|
72
|
+
# Выбранное значение месяца.
|
|
73
|
+
# @param options [Hash] Rails helper options.
|
|
74
|
+
# Опции Rails-хелпера.
|
|
75
|
+
# @option options [Boolean] :use_month_numbers Show month numbers instead of names.
|
|
76
|
+
# Показывать номера месяцев вместо названий.
|
|
77
|
+
# @option options [Boolean] :add_month_numbers Prefix month names with numbers.
|
|
78
|
+
# Добавлять номер месяца перед названием.
|
|
79
|
+
# @option options [Boolean] :use_short_month Use abbreviated month names.
|
|
80
|
+
# Использовать сокращенные названия месяцев.
|
|
81
|
+
# @option options [Array<String>] :use_month_names Custom month names array.
|
|
82
|
+
# Пользовательский массив названий месяцев.
|
|
83
|
+
# @option options [String, Symbol] :field_name Override the field name, `"month"` by default.
|
|
84
|
+
# Переопределить имя поля; по умолчанию используется `"month"`.
|
|
85
|
+
# @option options [Boolean] :use_standalone_month_names Request standalone month names explicitly.
|
|
86
|
+
# Явно запросить отдельностоящие названия месяцев.
|
|
87
|
+
# @param html_options [Hash] HTML options.
|
|
88
|
+
# HTML-опции.
|
|
89
|
+
# @return [String] HTML for the select tag.
|
|
90
|
+
# HTML для select-тега.
|
|
56
91
|
#
|
|
57
|
-
#
|
|
58
|
-
#
|
|
59
|
-
#
|
|
92
|
+
# @example Default Russian output
|
|
93
|
+
# select_month(Date.new(2024, 12, 1))
|
|
94
|
+
# # => uses standalone month names for :ru
|
|
60
95
|
#
|
|
61
|
-
#
|
|
62
|
-
#
|
|
63
|
-
#
|
|
96
|
+
# @example Custom field name
|
|
97
|
+
# select_month(Date.new(2024, 12, 1), field_name: "start")
|
|
98
|
+
# # => overrides the generated field name
|
|
64
99
|
#
|
|
100
|
+
# @example Abbreviated standalone month names
|
|
101
|
+
# select_month(Date.new(2024, 12, 1), use_short_month: true)
|
|
102
|
+
# # => uses abbreviated standalone month names
|
|
65
103
|
def select_month(date, options = {}, html_options = {})
|
|
66
|
-
|
|
104
|
+
super(date, options.merge(use_standalone_month_names: true), html_options)
|
|
67
105
|
end
|
|
68
106
|
end
|
|
69
|
-
|
|
70
|
-
|
|
107
|
+
|
|
108
|
+
# @private
|
|
109
|
+
module DateTimeSelectorPatch
|
|
71
110
|
private
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
I18n.translate(key, :locale => @options[:locale])
|
|
113
|
-
end
|
|
114
|
-
|
|
111
|
+
|
|
112
|
+
# Returns translated month names for the current selector options.
|
|
113
|
+
#
|
|
114
|
+
# The method chooses between common and standalone month-name
|
|
115
|
+
# translations depending on `:discard_day`,
|
|
116
|
+
# `:use_standalone_month_names`, and `:use_short_month`. If split
|
|
117
|
+
# common/standalone translations are not defined for the current
|
|
118
|
+
# locale, it falls back to the standard Rails month-name keys.
|
|
119
|
+
#
|
|
120
|
+
#
|
|
121
|
+
# Возвращает переведенные названия месяцев для текущих
|
|
122
|
+
# опций selector'а.
|
|
123
|
+
#
|
|
124
|
+
# Метод выбирает между контекстными и отдельностоящими переводами
|
|
125
|
+
# названий месяцев в зависимости от `:discard_day`,
|
|
126
|
+
# `:use_standalone_month_names` и `:use_short_month`. Если для текущей
|
|
127
|
+
# локали не определены раздельные контекстные и отдельностоящие
|
|
128
|
+
# переводы, метод откатывается к стандартным ключам Rails.
|
|
129
|
+
#
|
|
130
|
+
# @return [Array<String, nil>] Month names array with `nil` at index `0`.
|
|
131
|
+
# Массив названий месяцев с `nil` на позиции `0`.
|
|
132
|
+
def translated_month_names
|
|
133
|
+
I18n.translate(translated_month_names_key, locale: month_names_locale)
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def translated_month_names_key
|
|
137
|
+
month_name_keys = MONTH_NAME_KEYS.fetch(@options[:use_short_month] ? :short : :long)
|
|
138
|
+
return month_name_keys[:fallback] unless I18n.exists?(month_name_keys[:common], month_names_locale)
|
|
139
|
+
|
|
140
|
+
standalone_month_names? ? month_name_keys[:standalone] : month_name_keys[:common]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
def standalone_month_names?
|
|
144
|
+
@options[:discard_day] || @options[:use_standalone_month_names]
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def month_names_locale
|
|
148
|
+
@options[:locale] || I18n.locale
|
|
149
|
+
end
|
|
115
150
|
end
|
|
116
151
|
end
|
|
117
152
|
end
|
|
118
|
-
end
|
|
153
|
+
end
|
|
@@ -1,70 +1,51 @@
|
|
|
1
|
-
#
|
|
1
|
+
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
3
|
+
module Russian
|
|
4
|
+
# Extensions for ActiveModel integration.
|
|
5
|
+
#
|
|
6
|
+
#
|
|
7
|
+
# Расширения для интеграции с ActiveModel.
|
|
8
|
+
module ActiveModelExt
|
|
9
|
+
# Patch for `ActiveModel::Error.full_message`.
|
|
10
|
+
# Validation messages prefixed with `^` suppress the humanized
|
|
11
|
+
# attribute name in the resulting full message.
|
|
12
|
+
#
|
|
13
|
+
#
|
|
14
|
+
# Патч для `ActiveModel::Error.full_message`.
|
|
15
|
+
# Сообщения валидации с префиксом `^` подавляют humanized-имя
|
|
16
|
+
# атрибута в итоговом полном сообщении.
|
|
17
|
+
module ErrorPatch
|
|
18
|
+
# Builds a full validation message and optionally suppresses the
|
|
19
|
+
# attribute name when the message starts with `^`.
|
|
11
20
|
#
|
|
12
|
-
# Переопределяет метод ActiveModel::Errors.full_messages. Сообщения об ошибках для атрибутов
|
|
13
|
-
# теперь не имеют префикса с названием атрибута если в сообщении об ошибке первым символом указан "^".
|
|
14
21
|
#
|
|
15
|
-
#
|
|
16
|
-
#
|
|
17
|
-
# validates_acceptance_of :accepted_terms, :message => 'нужно принять соглашение'
|
|
18
|
-
#
|
|
19
|
-
# даст сообщение
|
|
20
|
-
#
|
|
21
|
-
# Accepted terms нужно принять соглашение
|
|
22
|
-
#
|
|
23
|
-
# однако,
|
|
24
|
-
#
|
|
25
|
-
# validates_acceptance_of :accepted_terms, :message => '^Нужно принять соглашение'
|
|
26
|
-
#
|
|
27
|
-
# даст сообщение
|
|
28
|
-
#
|
|
29
|
-
# Нужно принять соглашение
|
|
22
|
+
# Строит полное сообщение валидации и при необходимости подавляет имя
|
|
23
|
+
# атрибута, если сообщение начинается с `^`.
|
|
30
24
|
#
|
|
25
|
+
# @param attribute [String, Symbol] Attribute name.
|
|
26
|
+
# Имя атрибута.
|
|
27
|
+
# @param message [#to_s] Validation message.
|
|
28
|
+
# Сообщение валидации.
|
|
29
|
+
# @param base [Object] Model instance.
|
|
30
|
+
# Экземпляр модели.
|
|
31
|
+
# @return [String] Full validation message.
|
|
32
|
+
# Полное сообщение валидации.
|
|
31
33
|
#
|
|
32
|
-
#
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# end
|
|
38
|
-
#
|
|
39
|
-
# company = Company.create(:address => '123 First St.')
|
|
40
|
-
# company.errors.full_messages # =>
|
|
41
|
-
# ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"]
|
|
42
|
-
def full_messages
|
|
43
|
-
full_messages = []
|
|
34
|
+
# @example
|
|
35
|
+
# ActiveModel::Error.full_message(:agreement, "^Нужно согласиться с соглашением", record)
|
|
36
|
+
# # => "Нужно согласиться с соглашением"
|
|
37
|
+
def full_message(attribute, message, base)
|
|
38
|
+
return super unless suppress_attribute_name?(attribute, message)
|
|
44
39
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
next if messages.empty?
|
|
48
|
-
|
|
49
|
-
if attribute == :base
|
|
50
|
-
messages.each {|m| full_messages << m }
|
|
51
|
-
else
|
|
52
|
-
attr_name = attribute.to_s.gsub('.', '_').humanize
|
|
53
|
-
attr_name = @base.class.human_attribute_name(attribute, :default => attr_name)
|
|
54
|
-
options = { :attribute => attr_name, :default => "%{attribute} %{message}" }
|
|
40
|
+
message.to_s.delete_prefix("^")
|
|
41
|
+
end
|
|
55
42
|
|
|
56
|
-
|
|
57
|
-
if m =~ /^\^/
|
|
58
|
-
full_messages << m[1..-1]
|
|
59
|
-
else
|
|
60
|
-
full_messages << I18n.t(:"errors.format", options.merge(:message => m))
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
end
|
|
64
|
-
end
|
|
43
|
+
private
|
|
65
44
|
|
|
66
|
-
|
|
45
|
+
# @private
|
|
46
|
+
def suppress_attribute_name?(attribute, message)
|
|
47
|
+
attribute.to_s != "base" && message.to_s.start_with?("^")
|
|
67
48
|
end
|
|
68
49
|
end
|
|
69
50
|
end
|
|
70
|
-
end
|
|
51
|
+
end
|