Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Finally: Ukrainian transliteration, allow to load selected locales #192

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 10 additions & 3 deletions CHANGELOG.md
Original file line number Original file line Diff line number Diff line change
@@ -1,8 +1,15 @@
##

- uses I18n.available_locales to load selected locales
- added transliteration rule for Ukrainian

## 0.5.1 (2012-03-01) ## 0.5.1 (2012-03-01)


- Add pluralization and transliteration rules for non-English-like locales - pluralization and transliteration work out of the box
- Remove translations for will_paginate gem - added pluralization rules for non-English-like locales
- bring activemodel and activerecord namespaces back which was removed in 21c8006 - added transliteration rule for Russian
- removed translations for will_paginate gem
- brought activemodel and activerecord namespaces back which was removed in 21c8006


## 0.4.0 (2012-02-10) ## 0.4.0 (2012-02-10)


Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -17,6 +17,19 @@ or run this command:


Note that your rails version must be 3.0 or higher if you want to install `rails-i18n` as a gem. For rails 2.x, install it manually as described below. Note that your rails version must be 3.0 or higher if you want to install `rails-i18n` as a gem. For rails 2.x, install it manually as described below.


## Configuration

By default `rails-i18n` loads all locale files, pluralization and
transliteration rules available in the gem. This behaviour can be changed, if you
specify in `config/environments/*` the locales which have to be loaded via
`I18n.available_locales` option:

config.i18n.available_locales = ['es-CO', :de]

or

config.i18n.available_locales = :nl

## Manual installation ## Manual installation


Download the locale files that are found in the directory [rails/locale](http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale/) and put them into the `config/locales` directory of your Rails application. Download the locale files that are found in the directory [rails/locale](http://github.com/svenfuchs/rails-i18n/tree/master/rails/locale/) and put them into the `config/locales` directory of your Rails application.
Expand Down
15 changes: 11 additions & 4 deletions lib/rails_i18n/railtie.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@


module RailsI18n module RailsI18n
class Railtie < ::Rails::Railtie #:nodoc: class Railtie < ::Rails::Railtie #:nodoc:
initializer 'rails-i18n' do initializer 'rails-i18n' do |app|
RailsI18n::Railtie.instance_eval do RailsI18n::Railtie.instance_eval do
add('rails/locale/*.yml') pattern = pattern_from app.config.i18n.available_locales
add('rails/pluralization/*.rb')
add('rails/transliteration/*.{rb,yml}') add("rails/locale/#{pattern}.yml")
add("rails/pluralization/#{pattern}.rb")
add("rails/transliteration/#{pattern}.{rb,yml}")


init_pluralization_module init_pluralization_module
end end
Expand All @@ -19,6 +21,11 @@ def self.add(pattern)
I18n.load_path.concat(files) I18n.load_path.concat(files)
end end


def self.pattern_from(args)
array = Array(args || [])
array.blank? ? '*' : "{#{array.join ','}}"
end

def self.init_pluralization_module def self.init_pluralization_module
I18n.backend.class.send(:include, I18n::Backend::Pluralization) I18n.backend.class.send(:include, I18n::Backend::Pluralization)
end end
Expand Down
2 changes: 1 addition & 1 deletion rails-i18n.gemspec
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Gem::Specification.new do |s|


s.files = Dir.glob("lib/**/*") + Dir.glob("rails/locale/*") + s.files = Dir.glob("lib/**/*") + Dir.glob("rails/locale/*") +
Dir.glob("rails/pluralization/*") + Dir.glob("rails/transliteration/*") + Dir.glob("rails/pluralization/*") + Dir.glob("rails/transliteration/*") +
Dir.glob("will_paginate/*") + %w(README.md MIT-LICENSE.txt) %w(README.md MIT-LICENSE.txt)
s.platform = Gem::Platform::RUBY s.platform = Gem::Platform::RUBY
s.require_path = 'lib' s.require_path = 'lib'
s.rubyforge_project = '[none]' s.rubyforge_project = '[none]'
Expand Down
113 changes: 66 additions & 47 deletions rails/transliteration/ru.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,65 +1,84 @@
# encoding: utf-8

# (c) Yaroslav Markin, Julian "julik" Tarkhanov and Co # (c) Yaroslav Markin, Julian "julik" Tarkhanov and Co
# https://github.com/yaroslav/russian/blob/master/lib/russian/transliteration.rb # https://github.com/yaroslav/russian/blob/master/lib/russian/transliteration.rb


module RailsI18n module RailsI18n
module Transliteration module Transliteration
module Russian module Russian
LOWER_SINGLE = { class << self
"і"=>"i","ґ"=>"g","ё"=>"yo","№"=>"#","є"=>"e", def rule
"ї"=>"yi","а"=>"a","б"=>"b", lambda do |string|
"в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"zh", chars = string.scan(%r{#{multi_keys.join '|'}|\w|.})
"з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
"м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
"ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"'",
"ы"=>"y","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya",
}


LOWER_MULTI = { result = ""
"ье"=>"ie",
"ьё"=>"ie",
}


UPPER_SINGLE = { chars.each_with_index do |char, index|
"Ґ"=>"G","Ё"=>"YO","Є"=>"E","Ї"=>"YI","І"=>"I", if upper.has_key?(char) && lower.has_key?(chars[index+1])
"А"=>"A","Б"=>"B","В"=>"V","Г"=>"G", # combined case
"Д"=>"D","Е"=>"E","Ж"=>"ZH","З"=>"Z","И"=>"I", result << upper[char].downcase.capitalize
"Й"=>"Y","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N", elsif upper.has_key?(char)
"О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T", result << upper[char]
"У"=>"U","Ф"=>"F","Х"=>"H","Ц"=>"TS","Ч"=>"CH", elsif lower.has_key?(char)
"Ш"=>"SH","Щ"=>"SCH","Ъ"=>"'","Ы"=>"Y","Ь"=>"", result << lower[char]
"Э"=>"E","Ю"=>"YU","Я"=>"YA", else
} result << char
end
end


UPPER_MULTI = { result
"ЬЕ"=>"IE", end
"ЬЁ"=>"IE", end
}


LOWER = (LOWER_SINGLE.merge(LOWER_MULTI)).freeze private
UPPER = (UPPER_SINGLE.merge(UPPER_MULTI)).freeze
MULTI_KEYS = (LOWER_MULTI.merge(UPPER_MULTI)).keys.sort_by {|s| s.length}.reverse.freeze


def self.rule # use instance variables instead of constants to prevent warnings
lambda do |string| # on re-evaling after I18n.reload!
chars = string.scan(%r{#{MULTI_KEYS.join '|'}|\w|.})


result = "" def upper
@upper ||= begin
upper_single = {
"Ґ"=>"G","Ё"=>"YO","Є"=>"E","Ї"=>"YI","І"=>"I",
"А"=>"A","Б"=>"B","В"=>"V","Г"=>"G",
"Д"=>"D","Е"=>"E","Ж"=>"ZH","З"=>"Z","И"=>"I",
"Й"=>"Y","К"=>"K","Л"=>"L","М"=>"M","Н"=>"N",
"О"=>"O","П"=>"P","Р"=>"R","С"=>"S","Т"=>"T",
"У"=>"U","Ф"=>"F","Х"=>"H","Ц"=>"TS","Ч"=>"CH",
"Ш"=>"SH","Щ"=>"SCH","Ъ"=>"'","Ы"=>"Y","Ь"=>"",
"Э"=>"E","Ю"=>"YU","Я"=>"YA",
}


chars.each_with_index do |char, index| (upper_single.merge(upper_multi)).freeze
if UPPER.has_key?(char) && LOWER.has_key?(chars[index+1]) end
# combined case end
result << UPPER[char].downcase.capitalize
elsif UPPER.has_key?(char) def lower
result << UPPER[char] @lower ||= begin
elsif LOWER.has_key?(char) lower_single = {
result << LOWER[char] "і"=>"i","ґ"=>"g","ё"=>"yo","№"=>"#","є"=>"e",
else "ї"=>"yi","а"=>"a","б"=>"b",
result << char "в"=>"v","г"=>"g","д"=>"d","е"=>"e","ж"=>"zh",
end "з"=>"z","и"=>"i","й"=>"y","к"=>"k","л"=>"l",
"м"=>"m","н"=>"n","о"=>"o","п"=>"p","р"=>"r",
"с"=>"s","т"=>"t","у"=>"u","ф"=>"f","х"=>"h",
"ц"=>"ts","ч"=>"ch","ш"=>"sh","щ"=>"sch","ъ"=>"'",
"ы"=>"y","ь"=>"","э"=>"e","ю"=>"yu","я"=>"ya",
}

(lower_single.merge(lower_multi)).freeze
end end
end

def upper_multi
@upper_multi ||= { "ЬЕ"=>"IE", "ЬЁ"=>"IE" }
end

def lower_multi
@lower_multi ||= { "ье"=>"ie", "ьё"=>"ie" }
end


result def multi_keys
@multi_keys ||= (lower_multi.merge(upper_multi)).keys.sort_by {|s| s.length}.reverse.freeze
end end
end end
end end
Expand Down
104 changes: 104 additions & 0 deletions rails/transliteration/uk.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,104 @@
# encoding: utf-8

module RailsI18n
module Transliteration
module Ukrainian
class << self
def rule
lambda do |string|
string.gsub(/./) do |char|
# Regexp.last_match is local to the thread and method scope
# of the method that did the pattern match.
@pre_match, @post_match = $`, $'

case char
when 'Ж'
lookahead_upcase 'ZH'
when 'Х'
lookahead_upcase 'KH'
when 'Ц'
lookahead_upcase 'TS'
when 'Ч'
lookahead_upcase 'CH'
when 'Ш'
lookahead_upcase 'SH'
when 'Щ'
lookahead_upcase 'SHCH'
when 'г'
behind =~ /з/i ? 'gh' : 'h'
when 'Г'
behind =~ /з/i ? lookahead_upcase('GH') : 'H'
when 'є'
letter?(behind) ? 'ie' : 'ye'
when 'Є'
letter?(behind) ? lookahead_upcase('IE') : lookahead_upcase('YE')
when 'ї'
letter?(behind) ? 'i' : 'yi'
when 'Ї'
letter?(behind) ? 'I' : lookahead_upcase('YI')
when 'й'
letter?(behind) ? 'i' : 'y'
when 'Й'
letter?(behind) ? 'I' : 'Y'
when 'ю'
letter?(behind) ? 'iu' : 'yu'
when 'Ю'
letter?(behind) ? lookahead_upcase('IU') : lookahead_upcase('YU')
when 'я'
letter?(behind) ? 'ia' : 'ya'
when 'Я'
letter?(behind) ? lookahead_upcase('IA') : lookahead_upcase('YA')
when "'"
# remove apostrophe inside a word
letter?(behind) && letter?(ahead) ? '' : "'"
else
straight_lookup[char] || char
end
end
end
end

private

def behind
@pre_match && @pre_match[-1]
end

def ahead
@post_match && @post_match[0]
end

def downcased?(symbol)
symbol =~ /\p{Ll}/
end

# apostrophe can be inside a word
# TODO what about hyphen?
def letter?(symbol)
symbol =~ /[\p{L}'’]/
end

def lookahead_upcase(word)
downcased?(ahead) ? word.capitalize : word.upcase
end

def straight_lookup
@straight_lookup ||= {
'а'=>'a','б'=>'b','в'=>'v','ґ'=>'g','д'=>'d','е'=>'e','ж'=>'zh',
'з'=>'z','и'=>'y','і'=>'i','к'=>'k','л'=>'l','м'=>'m','н'=>'n','о'=>'o',
'п'=>'p','р'=>'r','с'=>'s','т'=>'t','у'=>'u','ф'=>'f','х'=>'kh','ц'=>'ts',
'ч'=>'ch','ш'=>'sh','щ'=>'shch','ь'=>'','’'=>'',
'А'=>'A','Б'=>'B','В'=>'V','Ґ'=>'G','Д'=>'D','Е'=>'E',
'З'=>'Z','И'=>'Y','І'=>'I','К'=>'K','Л'=>'L','М'=>'M','Н'=>'N','О'=>'O',
'П'=>'P','Р'=>'R','С'=>'S','Т'=>'T','У'=>'U','Ф'=>'F','Ь'=>''
}
end
end
end
end
end

{ :uk => {
:i18n => {
:transliterate => {
:rule => RailsI18n::Transliteration::Ukrainian.rule }}}}
24 changes: 24 additions & 0 deletions spec/integration/backend_reload_spec.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,24 @@
require 'spec_helper'

describe "I18n backend reloading" do
let(:app) do
RailsI18n::Spec::FakeApp
end

context "when called twice" do
let(:errors) do
app.run(lambda do
$stderr = StringIO.new
2.times do
I18n.reload!
I18n.t :hello
end
$stderr.string
end)
end

it "doesn't produce warnings" do
errors.should == ''
end
end
end
50 changes: 50 additions & 0 deletions spec/integration/optional_locale_loading_spec.rb
Original file line number Original file line Diff line number Diff line change
@@ -0,0 +1,50 @@
# encoding: utf-8

require 'spec_helper'

describe "Rails-i18n" do
let(:app) do
RailsI18n::Spec::FakeApp
end

context "when i18n.available_locales are specified in config" do
let(:i18n_results) do
de_translate = ->{ I18n.t "helpers.select.prompt", :locale => :de }
ru_translate = ->{ I18n.t "helpers.select.prompt", :locale => :ru }
uk_transliterate = ->{ I18n.transliterate 'Рубі!', :locale => :uk }
bg_transliterate = ->{ I18n.transliterate 'Рубі!', :locale => :bg }

app.run(de_translate, ru_translate, uk_transliterate, bg_transliterate) do |config|
config.i18n.available_locales = [:ru, :uk]
end
end

it "loads only specified locales" do
de_translate, ru_translate, uk_transliterate, bg_transliterate = *i18n_results

de_translate.should == 'translation missing: de.helpers.select.prompt'
ru_translate.should == 'Выберите: '
uk_transliterate.should == 'Rubi!'
bg_transliterate.should == '????!'
end
end

context "when single locale is assigned to i18n.available_locales" do
let(:translations) do
fr = ->{ I18n.t "helpers.select.prompt" }
it = ->{ I18n.t "helpers.select.prompt", :locale => :it }

app.run(fr, it) do |config|
config.i18n.default_locale = 'fr'
config.i18n.available_locales = 'fr'
end
end

it "loads only this locale" do
fr_translation, it_translation = *translations

fr_translation.should == 'Veuillez sélectionner'
it_translation.should == 'translation missing: it.helpers.select.prompt'
end
end
end
Loading