diff --git a/.ruby-gemset b/.ruby-gemset new file mode 100644 index 0000000..26d9537 --- /dev/null +++ b/.ruby-gemset @@ -0,0 +1 @@ +russian \ No newline at end of file diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 0000000..0cadbc1 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +2.5.5 diff --git a/.travis.yml b/.travis.yml index 5a7f772..db81c11 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ +notifications: + email: false + +language: ruby rvm: - - 1.8.7 - - 1.9.2 - - ree - - rbx - - jruby + - 2.5 + - 2.6 diff --git a/Gemfile b/Gemfile index 5e900fb..f68a903 100644 --- a/Gemfile +++ b/Gemfile @@ -1,9 +1,4 @@ -source :rubygems +source "https://rubygems.org" -gem 'rake' -gem 'i18n', '>= 0.5.0' -gem 'rspec', '~> 2.7.0' - -# Rails 3+ -gem 'activesupport', '~> 3.0.0' +gemspec diff --git a/Gemfile.lock b/Gemfile.lock index c1abb5d..8767aa3 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,24 +1,47 @@ +PATH + remote: . + specs: + rs_russian (0.16.0) + activesupport (>= 3.0.0, < 6.2.0) + i18n (~> 1.8.0) + unicode (~> 0.4.4) + GEM - remote: http://rubygems.org/ + remote: https://rubygems.org/ specs: - activesupport (3.0.10) - diff-lcs (1.1.3) - i18n (0.6.0) - rake (0.9.2.2) - rspec (2.7.0) - rspec-core (~> 2.7.0) - rspec-expectations (~> 2.7.0) - rspec-mocks (~> 2.7.0) - rspec-core (2.7.1) - rspec-expectations (2.7.0) - diff-lcs (~> 1.1.2) - rspec-mocks (2.7.0) + activesupport (6.1.0) + concurrent-ruby (~> 1.0, >= 1.0.2) + i18n (>= 1.6, < 2) + minitest (>= 5.1) + tzinfo (~> 2.0) + zeitwerk (~> 2.3) + concurrent-ruby (1.1.7) + diff-lcs (1.4.4) + i18n (1.8.5) + concurrent-ruby (~> 1.0) + minitest (5.14.2) + rake (10.5.0) + rspec (2.99.0) + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + rspec-core (2.99.2) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.4) + tzinfo (2.0.4) + concurrent-ruby (~> 1.0) + unicode (0.4.4.4) + zeitwerk (2.4.2) PLATFORMS ruby DEPENDENCIES - activesupport (~> 3.0.0) - i18n (>= 0.5.0) - rake - rspec (~> 2.7.0) + bundler (~> 1.14) + rake (< 11.0) + rs_russian! + rspec (~> 2.14) + +BUNDLED WITH + 1.17.3 diff --git a/README.textile b/README.textile index cf43a1b..74c07e7 100644 --- a/README.textile +++ b/README.textile @@ -1,6 +1,10 @@ -h1. Russian -"!https://secure.travis-ci.org/yaroslav/russian.png!":http://travis-ci.org/yaroslav/russian +h1. rs_russian +"!https://secure.travis-ci.org/rs-pro/russian.png!":http://travis-ci.org/rs-pro/russian +h3. Это форк с вытянутыми pull-реквестами, которые мы хотели использовать. + +Нравится -- пользуйтесь, не нравится -- идите на страницу оригинала: "http://github.com/yaroslav/russian/":http://github.com/yaroslav/russian/ +Jruby и Rubinius не тестируются и скорее всего не работают т.к. нам они не нужны. Поддержка русского языка для Ruby и Rails при помощи библиотеки I18n. @@ -32,41 +36,15 @@ h2. Что такое I18n. История Однако, документация по плюрализации и транслитерации в I18n была неочевидной, а поддержка lambda-переводов для локализации даты-времени была практически "спрятана" в исходном коде, поэтому большинство разработчиков в основном использовали самые базовые таблицы переводов: локализацию Rails и, иногда, — плюрализацию. Возникла мысль выпустить @gem russian@ для последней версии @gem i18n@ и Ruby on Rails с поддержкой всех необходимых функций, но, на этот раз, грамотно сделанных через интерфейсы I18n. К сожалению, "хаки" для Ruby on Rails (хелперы даты-времени) вряд ли когда-либо будут включены в дистрибутив Rails, поэтому использовать их придется отдельно. -h1. Требования - -* Ruby 1.8.7 или 1.9.2 (поддерживается совместимость с JRuby и Rubinius); -"!https://secure.travis-ci.org/yaroslav/russian.png!":http://travis-ci.org/yaroslav/russian - -* Для использования с Rails нужна версия не ниже 3.0 (для более старых версий Rails используйте версии gem russian ветки 0.2); -* Для разработки и тестирования библиотеки вам понадобятся Bundler и RSpec. - h1. Установка -Страница Russian на GitHub -- "http://github.com/yaroslav/russian/":http://github.com/yaroslav/russian/ - -Для установки: - -@gem install russian@ - -Чтобы задать локаль по умолчанию в вашем приложении, используйте - -

-I18n.default_locale = :ru
-
- -Чтобы установить локаль для текущего треда, используйте - -

-I18n.locale = :ru
-
+В вашем @Gemfile@ сделайте ссылку на gem @russian@: -h2. Ruby on Rails 3.0 и выше +
gem 'rs_russian', '~> 0.7.0'
-В вашем @Gemfile@ сделайте ссылку на gem @russian@: +или -

-gem 'russian', '~> 0.6.0'
-
+
gem "rs_russian", :github => "rs-pro/russian", :branch => "master"
И установите gem в проект с помощью bundler: @@ -74,9 +52,7 @@ gem 'russian', '~> 0.6.0' Далее, укажите -

-config.i18n.default_locale = :ru
-
+
config.i18n.default_locale = :ru
в @config/application.rb@. Если по умолчанию нужна другая локаль, или же нужно переключать локали "на ходу", используйте методы модуля I18n (см. выше). Также ознакомьтесь с "документацией к I18n":http://rdoc.info/github/svenfuchs/i18n/master и "гидом по интернационализации Ruby on Rails":http://guides.rubyonrails.org/i18n.html. @@ -92,14 +68,12 @@ h1. Использование Предыдущие версии Russian форсированно выставляли локаль I18n по умолчанию в @:ru@ (Русский язык), от этого решено было отказаться: в Rails стало неудобно работать с мультиязычными приложениями, так как конструкция вида @config.i18n.default_locale = :en@ не работала. Теперь для использования русского языка в Rails по умолчанию нужно использовать строку -

-config.i18n.default_locale = :ru
+
config.i18n.default_locale = :ru
 
в @config/application.rb@. Для использования Russian отдельно от Rails можно выставить локаль I18n в русскую по умолчанию или для текущего треда, соответственно: -

-I18n.default_locale = :ru
+
I18n.default_locale = :ru
 
 I18n.locale = :ru
 
@@ -116,7 +90,7 @@ I18n.locale = :ru После загрузки Russian можно использовать все стандартные функции библиотеки I18n, пользоваться измененным функционалом для лучшей поддержки русского языка, или использовать хелперы модуля Russian для еще более простой работы с русским языком. -"Документация I18n":http://rdoc.info/github/svenfuchs/i18n/master +"Документация I18n":http://rdoc.info/github/svenfuchs/i18n/master "Гид по интернационализации Ruby on Rails":http://guides.rubyonrails.org/i18n.html. @@ -166,7 +140,7 @@ h3. Валидация @Соглашение об использовании нужно принять соглашение@ если вы указали перевод для имени атрибута. - + Но @validates_acceptance_of :accepted_terms, :message => '^Нужно принять соглашение'@ @@ -181,8 +155,7 @@ h3. Параметризация строк Пример: -

-class Person
+
class Person
   def to_param
     "#{id}-#{name.parameterize}"
   end
@@ -192,8 +165,7 @@ end
 # => #
 
 <%= link_to(@person.name, person_path(@person)) %>
-# => Дональд Кнут
-
+# => Дональд Кнут
_NB:_ Для простоты иногда проще воспользоваться методом @Russian::transliterate@ напрямую (чтобы не зависеть от текущей локали). @@ -205,73 +177,59 @@ h2. Примеры и справка по переводам (I18n) h2. Вспомогательные методы модуля Russian -

-Russian.locale
-Russian::LOCALE
-
+
Russian.locale
+Russian::LOCALE
-- возвращает локаль русского языка (@:'ru'@). -

-Russian::init_i18n
-
+
Russian::init_i18n
-- инициализация Russian. Добавление русских переводов в путь загрузки, включение модулей для плюрализации и транслитерации и перегрузка I18n. _NB:_ Выполняется автоматически при загрузке. -

-Russian::translate
-Russian::t
-
+
Russian::translate
+Russian::t
-- прокси для метода @translate@ I18n, форсирует использование русской локали. -

-Russian::localize
-Russian::l
-
+
Russian::localize
+Russian::l
-- прокси для метода @localize@ I18n, форсирует использование русской локали. -

-Russian::strftime
+
Russian::strftime
 
 Russian::strftime(Time.now)
 => "Пн, 01 сент. 2008, 11:12:43 +0300"
 Russian::strftime(Time.now, "%d %B")
 >> "01 сентября"
 Russian::strftime(Time.now, "%B")
-=> "Сентябрь"
-
+=> "Сентябрь"
-- @strftime@ с форсированием русской локали (упрощенный вариант @localize@) -

-Russian::pluralize
+
Russian::pluralize
 Russian::p
 
 Russian.p(1, "вещь", "вещи", "вещей")
 => "вещь"
-Russian.p(2, "вещь", "вещи", "вещей")
-=> "вещи"
+Russian.p(2, "%n вещь", "%n вещи", "%n вещей")
+=> "2 вещи"
 Russian.p(10, "вещь", "вещи", "вещей")
 => "вещей"
 Russian.p(3.14, "вещь", "вещи", "вещей", "вещи") # последний вариант используется для дробных величин
-=> "вещи"
-
+=> "вещи"
-- упрощенная (без использования хешей I18n) плюрализация для русского языка -

-Russian::transliterate
+
Russian::transliterate
 Russian::translit
 
 Russian.translit("рубин")
 => "rubin"
 Russian.translit("Hallo Юлику Тарханову")
-=> "Hallo Yuliku Tarhanovu"
-
+=> "Hallo Yuliku Tarhanovu"
-- транслитерация русских букв в строке. diff --git a/Rakefile b/Rakefile index 0e65175..3e4c4ac 100644 --- a/Rakefile +++ b/Rakefile @@ -1,10 +1,10 @@ -require 'rubygems' -require 'rspec/core/rake_task' -require 'rubygems/specification' +require 'bundler/setup' +Bundler::GemHelper.install_tasks -task :default => :spec -desc "Run specs" -RSpec::Core::RakeTask.new do |t| - t.pattern = FileList['spec/**/*_spec.rb'] - t.rspec_opts = %w(-fs --color) +begin + require 'rspec/core/rake_task' + RSpec::Core::RakeTask.new(:spec) +rescue LoadError end + +task :default => :spec diff --git a/TODO b/TODO deleted file mode 100644 index cc5550d..0000000 --- a/TODO +++ /dev/null @@ -1,4 +0,0 @@ -TODO -==== -* RDoc - diff --git a/lib/rs_russian.rb b/lib/rs_russian.rb new file mode 100644 index 0000000..6696867 --- /dev/null +++ b/lib/rs_russian.rb @@ -0,0 +1 @@ +require 'russian' \ No newline at end of file diff --git a/lib/russian.rb b/lib/russian.rb index 7c426eb..da172d5 100644 --- a/lib/russian.rb +++ b/lib/russian.rb @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# coding: utf-8 $KCODE = 'u' if RUBY_VERSION < "1.9" @@ -7,11 +7,25 @@ $:.push File.join(File.dirname(__FILE__), 'russian') require 'russian_rails' +if RUBY_ENGINE == "jruby" + require 'unicode_utils/upcase' +else + require 'unicode' +end + +require 'active_support/core_ext/module/attribute_accessors' + module Russian extend self - + autoload :Transliteration, 'transliteration' - + + if respond_to?(:cattr_accessor) + cattr_accessor :force_standalone + else + mattr_accessor :force_standalone + end + # Russian locale LOCALE = :'ru' @@ -21,11 +35,11 @@ def locale end # Regexp machers for context-based russian month names and day names translation - LOCALIZE_ABBR_MONTH_NAMES_MATCH = /(%[-\d]?d|%e)(.*)(%b)/ - LOCALIZE_MONTH_NAMES_MATCH = /(%[-\d]?d|%e)(.*)(%B)/ + LOCALIZE_ABBR_MONTH_NAMES_MATCH = /(%[-_0^#:]*(\d+)*[EO]?d|%[-_0^#:]*(\d+)*[EO]?e)(.*)(%b)/ + LOCALIZE_MONTH_NAMES_MATCH = /(%[-_0^#:]*(\d+)*[EO]?d|%[-_0^#:]*(\d+)*[EO]?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,30 +53,31 @@ 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 }) + localize(object, { :format => check_strftime_format(object, format) }) end - + # Simple pluralization proxy # - # Usage: + # Usage: # Russian.pluralize(1, "вещь", "вещи", "вещей") # Russian.pluralize(3.14, "вещь", "вещи", "вещей", "вещи") + # Russina.pluralize(5, "Произошла %n ошибка", "Произошло %n ошибки", "Произошло %n ошибок") def pluralize(n, *variants) raise ArgumentError, "Must have a Numeric as a first parameter" unless n.is_a?(Numeric) raise ArgumentError, "Must have at least 3 variants for pluralization" if variants.size < 3 raise ArgumentError, "Must have at least 4 variants for pluralization" if (variants.size < 4 && n != n.round) - variants_hash = pluralization_variants_to_hash(*variants) + variants_hash = pluralization_variants_to_hash(n, *variants) I18n.backend.send(:pluralize, LOCALE, variants_hash, n) end alias :p :pluralize @@ -76,16 +91,32 @@ def transliterate(str) Russian::Transliteration.transliterate(str) end alias :translit :transliterate - + protected + + def check_strftime_format(object, format) + %w(A a B b).each do |key| + if format =~ /%\^#{key}/ + if RUBY_ENGINE == "jruby" + format = format.gsub("%^#{key}", UnicodeUtils.upcase(localize(object, { :format => "%#{key}" } ))) + else + format = format.gsub("%^#{key}", Unicode::upcase(localize(object, { :format => "%#{key}" } ))) + end + end + end + + format + end + # 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) + def pluralization_variants_to_hash(n, *variants) + variants.map!{ |variant| variant.gsub '%n', n.to_s } { :one => variants[0], :few => variants[1], @@ -96,3 +127,8 @@ def pluralization_variants_to_hash(*variants) end Russian.init_i18n + +if Object.const_defined?('RailsAdmin') + require 'rails_admin_datetime' +end + diff --git a/lib/russian/action_view_ext/helpers/date_helper.rb b/lib/russian/action_view_ext/helpers/date_helper.rb index 9a1b598..c5e7f43 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,10 +108,10 @@ def translated_month_names key = :'date.month_names' end end - + I18n.translate(key, :locale => @options[:locale]) end - + end end end diff --git a/lib/russian/active_model_ext/custom_error_message.rb b/lib/russian/active_model_ext/custom_error_message.rb index 4698409..59ca598 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 @@ -8,63 +8,42 @@ class Errors # Non-base messages are prefixed with the attribute name as usual UNLESS they begin with '^' # in which case the attribute name is omitted. # E.g. validates_acceptance_of :accepted_terms, :message => '^Please accept the terms of service' - # - # Переопределяет метод ActiveModel::Errors.full_messages. Сообщения об ошибках для атрибутов - # теперь не имеют префикса с названием атрибута если в сообщении об ошибке первым символом указан "^". - # - # Так, например, - # - # validates_acceptance_of :accepted_terms, :message => 'нужно принять соглашение' - # - # даст сообщение - # - # Accepted terms нужно принять соглашение - # - # однако, - # - # validates_acceptance_of :accepted_terms, :message => '^Нужно принять соглашение' - # - # даст сообщение - # - # Нужно принять соглашение - # - # - # Returns all the full error messages in an array. - # - # class Company - # validates_presence_of :name, :address, :email - # validates_length_of :name, :in => 5..30 - # end - # - # company = Company.create(:address => '123 First St.') - # company.errors.full_messages # => - # ["Name is too short (minimum is 5 characters)", "Name can't be blank", "Address can't be blank"] - def full_messages - full_messages = [] - - each do |attribute, messages| - messages = Array.wrap(messages) - next if messages.empty? - - if attribute == :base - messages.each {|m| full_messages << m } - else - attr_name = attribute.to_s.gsub('.', '_').humanize - attr_name = @base.class.human_attribute_name(attribute, :default => attr_name) - options = { :attribute => attr_name, :default => "%{attribute} %{message}" } - - messages.each do |m| - if m =~ /^\^/ - full_messages << m[1..-1] + + def full_message(attribute, message) + return message if attribute == :base + attr_name = attribute.to_s.tr('.', '_').humanize + attr_name = @base.class.human_attribute_name(attribute, default: attr_name) + + if message =~ /^\^/ + message[1..-1] + else + I18n.t(:"errors.format", { + default: "%{attribute} %{message}", + attribute: attr_name, + message: message + }) + end + end + + alias_method :to_hash_old, :to_hash + def to_hash(full_messages = false) + if full_messages + self.to_hash_old.each_with_object({}) do |(attribute, array), messages| + messages[attribute] = array.map { |message| full_message(attribute, message) } + end + else + self.to_hash_old.map do |k, vs| + m = vs.map do |v| + if v =~ /^\^/ + v[1..-1] else - full_messages << I18n.t(:"errors.format", options.merge(:message => m)) + v end end - end + {k => m} + end.reduce(:merge) end - - full_messages end end end -end # if defined? +end diff --git a/lib/russian/locale/actionview.yml b/lib/russian/locale/actionview.yml index 4207a47..c536d90 100644 --- a/lib/russian/locale/actionview.yml +++ b/lib/russian/locale/actionview.yml @@ -14,7 +14,7 @@ ru: precision: 3 significant: false strip_insignificant_zeros: false - + # Used in number_to_currency() currency: format: @@ -30,14 +30,14 @@ ru: precision: 2 significant: false strip_insignificant_zeros: false - + # Used in number_to_percentage() percentage: format: # These three are to override number.format and are optional - # separator: + # separator: delimiter: "" - + # Used in number_to_precision() precision: format: @@ -45,20 +45,20 @@ ru: # separator: delimiter: "" # precision: - + # Used in number_to_human_size() human: format: # These three are to override number.format and are optional - # separator: + # separator: delimiter: "" precision: 1 significant: false strip_insignificant_zeros: false - + # Rails 2.2 # storage_units: [байт, КБ, МБ, ГБ, ТБ] - + # Rails 2.3+ storage_units: # Storage units output formatting. diff --git a/lib/russian/locale/activemodel.yml b/lib/russian/locale/activemodel.yml index 5066327..1aa830b 100644 --- a/lib/russian/locale/activemodel.yml +++ b/lib/russian/locale/activemodel.yml @@ -36,7 +36,7 @@ ru: odd: "может иметь лишь четное значение" even: "может иметь лишь нечетное значение" record_invalid: "Возникли ошибки: %{errors}" - + template: # Заголовок сообщения об ошибке header: diff --git a/lib/russian/locale/activerecord.yml b/lib/russian/locale/activerecord.yml index 8b67531..f22d9a2 100644 --- a/lib/russian/locale/activerecord.yml +++ b/lib/russian/locale/activerecord.yml @@ -13,7 +13,7 @@ ru: # The values :model, :attribute and :value are always available for interpolation # The value :count is available when applicable. Can be used for pluralization. # - # You can use ^-prefixed messages as well to get rid of human attribute name appearing + # You can use ^-prefixed messages as well to get rid of human attribute name appearing # before your message in validation messages. messages: inclusion: "имеет непредусмотренное значение" @@ -82,7 +82,7 @@ ru: # # # Overrides default messages - + # Перевод названий атрибутов моделей. Используется в Model.human_attribute_name(attribute). #attributes: # Например, @@ -92,4 +92,4 @@ ru: # # # Overrides model and default messages. - + diff --git a/lib/russian/locale/activesupport.yml b/lib/russian/locale/activesupport.yml index b67c62e..c19df57 100644 --- a/lib/russian/locale/activesupport.yml +++ b/lib/russian/locale/activesupport.yml @@ -1,16 +1,16 @@ ru: # Используется в array.to_sentence -# -# +# +# # Used in array.to_sentence. support: array: # Rails 2.2 sentence_connector: "и" skip_last_comma: true - + # Rails 2.3 words_connector: ", " two_words_connector: " и " last_word_connector: " и " - + diff --git a/lib/russian/locale/datetime.rb b/lib/russian/locale/datetime.rb index a4e62e3..3f2c6cb 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 # @@ -7,28 +7,28 @@ :ru => { :date => { :abbr_day_names => lambda { |key, options| - if options[:format] && options[:format] =~ Russian::LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH + if options[:format] && options[:format] =~ Russian::LOCALIZE_STANDALONE_ABBR_DAY_NAMES_MATCH && !Russian.force_standalone :'date.common_abbr_day_names' else :'date.standalone_abbr_day_names' end }, :day_names => lambda { |key, options| - if options[:format] && options[:format] =~ Russian::LOCALIZE_STANDALONE_DAY_NAMES_MATCH + if options[:format] && options[:format] =~ Russian::LOCALIZE_STANDALONE_DAY_NAMES_MATCH && !Russian.force_standalone :'date.standalone_day_names' else :'date.common_day_names' end }, :abbr_month_names => lambda { |key, options| - if options[:format] && options[:format] =~ Russian::LOCALIZE_ABBR_MONTH_NAMES_MATCH + if options[:format] && options[:format] =~ Russian::LOCALIZE_ABBR_MONTH_NAMES_MATCH && !Russian.force_standalone :'date.common_abbr_month_names' else :'date.standalone_abbr_month_names' end }, :month_names => lambda { |key, options| - if options[:format] && options[:format] =~ Russian::LOCALIZE_MONTH_NAMES_MATCH + if options[:format] && options[:format] =~ Russian::LOCALIZE_MONTH_NAMES_MATCH && !Russian.force_standalone :'date.common_month_names' else :'date.standalone_month_names' diff --git a/lib/russian/locale/datetime.yml b/lib/russian/locale/datetime.yml index 2f2a825..3fc1293 100644 --- a/lib/russian/locale/datetime.yml +++ b/lib/russian/locale/datetime.yml @@ -12,7 +12,7 @@ ru: default: "%d.%m.%Y" short: "%d %b" long: "%d %B %Y" - + # Названия дней недели -- контекстные и отдельностоящие common_day_names: [воскресенье, понедельник, вторник, среда, четверг, пятница, суббота] standalone_day_names: [Воскресенье, Понедельник, Вторник, Среда, Четверг, Пятница, Суббота] @@ -21,19 +21,19 @@ ru: # Названия месяцев -- сокращенные и полные, плюс отдельностоящие. # Не забудьте nil в начале массиве (~) - # + # # # Don't forget the nil at the beginning; there's no such thing as a 0th month common_month_names: [~, января, февраля, марта, апреля, мая, июня, июля, августа, сентября, октября, ноября, декабря] standalone_month_names: [~, Январь, Февраль, Март, Апрель, Май, Июнь, Июль, Август, Сентябрь, Октябрь, Ноябрь, Декабрь] - common_abbr_month_names: [~, янв., февр., марта, апр., мая, июня, июля, авг., сент., окт., нояб., дек.] - standalone_abbr_month_names: [~, янв., февр., март, апр., май, июнь, июль, авг., сент., окт., нояб., дек.] - + common_abbr_month_names: [~, янв, фев, мар, апр, мая, июн, июл, авг, сен, окт, ноя, дек] + standalone_abbr_month_names: [~, янв, фев, мар, апр, май, июн, июл, авг, сен, окт, ноя, дек] + # Порядок компонентов даты для хелперов # # # Used in date_select and datime_select. - order: + order: - :day - :month - :year @@ -44,7 +44,7 @@ ru: default: "%a, %d %b %Y, %H:%M:%S %z" short: "%d %b, %H:%M" long: "%d %B %Y, %H:%M" - + # am/pm решено перевести как "утра/вечера" :) am: "утра" pm: "вечера" diff --git a/lib/russian/locale/pluralization.rb b/lib/russian/locale/pluralization.rb index 20c2a38..178cd41 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,8 +19,8 @@ :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 } } } 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/rails_admin_datetime.rb b/lib/russian/rails_admin_datetime.rb new file mode 100644 index 0000000..4184732 --- /dev/null +++ b/lib/russian/rails_admin_datetime.rb @@ -0,0 +1,51 @@ +require 'rails_admin/support/datetime' + +class RailsAdmin::Support::Datetime + class << self + alias_method :delocalize_without_russian, :delocalize + def delocalize(date_string, format) + ret = date_string + if I18n.locale == :ru + format.to_s.scan(/%[AaBbp]/) do |match| + case match + when '%B' + english = I18n.t('date.month_names', :locale => :en)[1..-1] + common_month_names = I18n.t('date.common_month_names')[1..-1] + common_month_names.each_with_index {|m, i| ret = ret.gsub(/#{m}/i, english[i]) } unless ret.blank? + when '%b' + english = I18n.t('date.abbr_month_names', :locale => :en)[1..-1] + common_abbr_month_names = I18n.t('date.common_abbr_month_names')[1..-1] + common_abbr_month_names.each_with_index {|m, i| ret = ret.gsub(/#{m}/i, english[i]) } unless ret.blank? + end + end + end + ret = delocalize_without_russian(ret, format) + ret + end + end +end + +require 'rails_admin/config/fields/types/datetime' + +module RailsAdmin + module Config + module Fields + module Types + class Datetime < RailsAdmin::Config::Fields::Base + register_instance_option :formatted_value do + ret = if time = (value || default_value) + opt = {format: strftime_format, standalone: true} + Russian.force_standalone = true + r = ::I18n.l(time, opt) + Russian.force_standalone = false + r + else + ''.html_safe + end + ret + end + end + end + 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..8dbc2d0 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 @@ -44,29 +44,21 @@ module Transliteration 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 + SCAN_REGEX = %r{#{MULTI_KEYS.join '|'}|\w|.}.freeze # Transliterate a string with russian characters # # Возвращает строку, в которой все буквы русского алфавита заменены на похожую по звучанию латиницу def transliterate(str) - chars = str.scan(%r{#{MULTI_KEYS.join '|'}|\w|.}) + chars = str.scan(SCAN_REGEX) - result = "" + result = '' chars.each_with_index do |char, index| - 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] - else - result << char - end + result << ( LOWER[char] || ( ( upper = UPPER[char] ) ? LOWER[chars[index+1]] ? upper.capitalize : upper : char ) ) end result end end -end \ No newline at end of file +end diff --git a/lib/russian/version.rb b/lib/russian/version.rb index 716fd76..59b2e21 100644 --- a/lib/russian/version.rb +++ b/lib/russian/version.rb @@ -1,9 +1,3 @@ module Russian - module VERSION - MAJOR = 0 - MINOR = 6 - TINY = 0 - - STRING = [MAJOR, MINOR, TINY].join('.') - end -end \ No newline at end of file + VERSION = "0.16.0" +end diff --git a/russian.gemspec b/russian.gemspec index 21076d9..4e86089 100644 --- a/russian.gemspec +++ b/russian.gemspec @@ -3,24 +3,26 @@ $: << File.expand_path('../lib', __FILE__) require 'russian/version' -Gem::Specification.new do |s| - s.name = %q{russian} - s.version = Russian::VERSION::STRING +Gem::Specification.new do |spec| + spec.name = "rs_russian" + spec.version = Russian::VERSION + spec.authors = ["glebtv", "Yaroslav Markin"] + spec.email = ["glebtv@gmail.com", "yaroslav@markin.net"] + spec.description = %q{Russian language support for Ruby and Rails} + spec.summary = %q{Russian language support for Ruby and Rails} + spec.homepage = "https://github.com/rs-pro/russian" + spec.license = "MIT" - s.required_rubygems_version = '>= 1.3.5' - s.authors = ["Yaroslav Markin"] - s.autorequire = %q{russian} - s.description = %q{Russian language support for Ruby and Rails} - s.email = %q{yaroslav@markin.net} - s.extra_rdoc_files = ["README.textile", "LICENSE", "CHANGELOG", "TODO"] - s.files = Dir.glob("{lib,spec}/**/**") + %w(CHANGELOG Gemfile LICENSE Rakefile README.textile russian.gemspec TODO) - s.platform = Gem::Platform::RUBY - s.homepage = %q{http://github.com/yaroslav/russian/} - s.require_paths = ["lib"] - s.summary = %q{Russian language support for Ruby and Rails} + spec.files = `git ls-files`.split($/) + spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) } + spec.test_files = spec.files.grep(%r{^(test|spec|features)/}) + spec.require_paths = ["lib"] - s.add_dependency('i18n', '>= 0.5.0') + spec.add_dependency 'i18n', '~> 1.8.0' + spec.add_dependency 'unicode', '~> 0.4.4' + spec.add_dependency 'activesupport', ['>= 3.0.0', '< 6.2.0'] - s.add_development_dependency 'activesupport', '>= 3.0.0' - s.add_development_dependency 'rspec', '~> 2.7.0' + spec.add_development_dependency 'bundler', '~> 1.14' + spec.add_development_dependency 'rake', '< 11.0' + spec.add_development_dependency 'rspec', '~> 2.14' end diff --git a/spec/i18n/locale/datetime_spec.rb b/spec/i18n/locale/datetime_spec.rb index 46d52c7..810403c 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' @@ -15,7 +15,7 @@ end it "should use short format" do - l(@date, :format => :short).should == "01 дек." + l(@date, :format => :short).should == "01 дек" end it "should use long format" do @@ -36,7 +36,12 @@ it "should use abbreviated day names" do l(@date, :format => "%a").should == "Вс" - l(@date, :format => "%a, %d %b %Y").should == "Вс, 01 дек. 1985" + l(@date, :format => "%a, %d %b %Y").should == "Вс, 01 дек 1985" + end + + it "should use uppercased day names" do + Russian::strftime(@date, "%^a").should == "ВС" + Russian::strftime(@date, "%^A").should == "ВОСКРЕСЕНЬЕ" end end @@ -48,6 +53,10 @@ if RUBY_VERSION > "1.9.2" l(@date, :format => "%1d %B").should == "1 декабря" l(@date, :format => "%2d %B").should == "01 декабря" + l(@date, :format => "%10d %B").should == "0000000001 декабря" + l(@date, :format => "%-e %B %Y").should == "1 декабря 1985" + l(@date, :format => "%_3d %B %Y").should == " 1 декабря 1985" + l(@date, :format => "%3_d %B %Y").should == "%3_d Декабрь 1985" end l(@date, :format => "%e %B %Y").should == " 1 декабря 1985" @@ -63,16 +72,21 @@ it "should use abbreviated month names" do @date = Date.parse("1985-03-01") - l(@date, :format => "%d %b").should == "01 марта" - 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 => "%d %b").should == "01 мар" + 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" + end + + it "should use uppercased month names" do + Russian::strftime(@date, "%^b").should == "ДЕК" + Russian::strftime(@date, "%^B").should == "ДЕКАБРЬ" end it "should use standalone abbreviated month names" do @date = Date.parse("1985-03-01") - l(@date, :format => "%b").should == "март" - l(@date, :format => "%b %Y").should == "март 1985" + l(@date, :format => "%b").should == "мар" + l(@date, :format => "%b %Y").should == "мар 1985" end end @@ -82,11 +96,11 @@ describe "with time formats" do it "should use default format" do - l(@time).should =~ /^Вс, 01 дек. 1985, 16:05:00/ + l(@time).should match(/^Вс, 01 дек 1985, 16:05:00/) end it "should use short format" do - l(@time, :format => :short).should == "01 дек., 16:05" + l(@time, :format => :short).should == "01 дек, 16:05" end it "should use long format" do diff --git a/spec/i18n/locale/pluralization_spec.rb b/spec/i18n/locale/pluralization_spec.rb index da15865..0135643 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' diff --git a/spec/locale_spec.rb b/spec/locale_spec.rb index ebfd56a..3f3726e 100644 --- a/spec/locale_spec.rb +++ b/spec/locale_spec.rb @@ -1,4 +1,4 @@ -# -*- encoding: utf-8 -*- +# -*- encoding: utf-8 -*- require File.dirname(__FILE__) + '/spec_helper' @@ -6,7 +6,7 @@ before(:all) do Russian.init_i18n end - + %w( date.formats.default date.formats.short @@ -19,28 +19,28 @@ date.abbr_month_names date.standalone_abbr_month_names date.order - + time.formats.default time.formats.short time.formats.long time.am time.pm - ).each do |key| + ).each do |key| it "should define '#{key}' in datetime translations" do lookup(key).should_not be_nil end end - + it "should load pluralization rules" do lookup(:'i18n.plural.rule').should_not be_nil - lookup(:'i18n.plural.rule').is_a?(Proc).should be_true + lookup(:'i18n.plural.rule').is_a?(Proc).should be true end it "should load transliteration rule" do lookup(:'i18n.transliterate.rule').should_not be_nil - lookup(:'i18n.transliterate.rule').is_a?(Proc).should be_true + lookup(:'i18n.transliterate.rule').is_a?(Proc).should be true end - + def lookup(*args) I18n.backend.send(:lookup, Russian.locale, *args) end diff --git a/spec/russian_spec.rb b/spec/russian_spec.rb index 6226bf3..2a0555d 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,27 @@ Russian.send(method, 131, *variants).should == 'вещь' Russian.send(method, 3.14, *variants).should == 'вещи' end - + + it "should pluralize with %n as number" do + variants = ['Произошла %n ошибка', 'Произошло %n ошибки', 'Произошло %n ошибок', 'Произошло %n ошибки'] + + Russian.send(method, 1, *variants).should == 'Произошла 1 ошибка' + Russian.send(method, 2, *variants).should == 'Произошло 2 ошибки' + Russian.send(method, 3, *variants).should == 'Произошло 3 ошибки' + Russian.send(method, 5, *variants).should == 'Произошло 5 ошибок' + Russian.send(method, 10, *variants).should == 'Произошло 10 ошибок' + Russian.send(method, 21, *variants).should == 'Произошла 21 ошибка' + Russian.send(method, 29, *variants).should == 'Произошло 29 ошибок' + Russian.send(method, 129, *variants).should == 'Произошло 129 ошибок' + Russian.send(method, 131, *variants).should == 'Произошла 131 ошибка' + Russian.send(method, 3.14, *variants).should == 'Произошло 3.14 ошибки' + 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..4eedb5b 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' @@ -27,12 +27,12 @@ def t(str) t("Ш").should == "SH" t("ц").should == "ts" 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"