Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

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

Closed
wants to merge 5 commits into from

2 participants

@nashbridges

Detailed explanation is in the #191

@kuroda
Collaborator

@nashbridges

Your pull request has been applied and I have pushed rails-i18n gem as 0.6.0.beta1.

Thanks a lot.

@kuroda kuroda closed this
@kuroda
Collaborator

@nashbridges

I have committed a quick patch (b42bbba) to uk.rb for Ruby 1.8 support.

Could you have a look?

@nashbridges

@kuroda Please, give me some time for this. It would be great to provide more cleaner solution, which I'm working on. I think there's no emergency situation regarding 1.8, so it can wait day or two.

@kuroda
Collaborator

No problem. Take your time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
13 CHANGELOG.md
@@ -1,8 +1,15 @@
+##
+
+- uses I18n.available_locales to load selected locales
+- added transliteration rule for Ukrainian
+
## 0.5.1 (2012-03-01)
-- Add pluralization and transliteration rules for non-English-like locales
-- Remove translations for will_paginate gem
-- bring activemodel and activerecord namespaces back which was removed in 21c8006
+- pluralization and transliteration work out of the box
+- added pluralization rules for non-English-like locales
+- 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)
View
13 README.md
@@ -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.
+## 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
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.
View
15 lib/rails_i18n/railtie.rb
@@ -2,11 +2,13 @@
module RailsI18n
class Railtie < ::Rails::Railtie #:nodoc:
- initializer 'rails-i18n' do
+ initializer 'rails-i18n' do |app|
RailsI18n::Railtie.instance_eval do
- add('rails/locale/*.yml')
- add('rails/pluralization/*.rb')
- add('rails/transliteration/*.{rb,yml}')
+ pattern = pattern_from app.config.i18n.available_locales
+
+ add("rails/locale/#{pattern}.yml")
+ add("rails/pluralization/#{pattern}.rb")
+ add("rails/transliteration/#{pattern}.{rb,yml}")
init_pluralization_module
end
@@ -19,6 +21,11 @@ def self.add(pattern)
I18n.load_path.concat(files)
end
+ def self.pattern_from(args)
+ array = Array(args || [])
+ array.blank? ? '*' : "{#{array.join ','}}"
+ end
+
def self.init_pluralization_module
I18n.backend.class.send(:include, I18n::Backend::Pluralization)
end
View
2  rails-i18n.gemspec
@@ -11,7 +11,7 @@ Gem::Specification.new do |s|
s.files = Dir.glob("lib/**/*") + Dir.glob("rails/locale/*") +
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.require_path = 'lib'
s.rubyforge_project = '[none]'
View
113 rails/transliteration/ru.rb
@@ -1,65 +1,84 @@
+# encoding: utf-8
+
# (c) Yaroslav Markin, Julian "julik" Tarkhanov and Co
# https://github.com/yaroslav/russian/blob/master/lib/russian/transliteration.rb
module RailsI18n
module Transliteration
module Russian
- LOWER_SINGLE = {
- "і"=>"i","ґ"=>"g","ё"=>"yo",""=>"#","є"=>"e",
- "ї"=>"yi","а"=>"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",
- }
+ class << self
+ def rule
+ lambda do |string|
+ chars = string.scan(%r{#{multi_keys.join '|'}|\w|.})
- LOWER_MULTI = {
- "ье"=>"ie",
- "ьё"=>"ie",
- }
+ result = ""
- 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|
+ 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
+ end
- UPPER_MULTI = {
- "ЬЕ"=>"IE",
- "ЬЁ"=>"IE",
- }
+ result
+ end
+ end
- 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
+ private
- def self.rule
- lambda do |string|
- chars = string.scan(%r{#{MULTI_KEYS.join '|'}|\w|.})
+ # use instance variables instead of constants to prevent warnings
+ # on re-evaling after I18n.reload!
- 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|
- 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
+ (upper_single.merge(upper_multi)).freeze
+ end
+ end
+
+ def lower
+ @lower ||= begin
+ lower_single = {
+ "і"=>"i","ґ"=>"g","ё"=>"yo",""=>"#","є"=>"e",
+ "ї"=>"yi","а"=>"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",
+ }
+
+ (lower_single.merge(lower_multi)).freeze
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
View
104 rails/transliteration/uk.rb
@@ -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 }}}}
View
24 spec/integration/backend_reload_spec.rb
@@ -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
View
50 spec/integration/optional_locale_loading_spec.rb
@@ -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
View
205 spec/unit/transliteration/ukrainian.rb
@@ -0,0 +1,205 @@
+# encoding: utf-8
+
+# Below is an implementation of the official transliteration rules
+# http://zakon2.rada.gov.ua/laws/show/55-2010-%D0%BF
+
+shared_examples "Ukrainian transliteration" do
+
+ it "properly transliterates 'ь'" do
+ t("Ь").should == ''
+ t("ь").should == ''
+ end
+
+ it "properly transliterates 'Аa'" do
+ t('А').should == 'A'
+ t('а').should == 'a'
+ end
+
+ it "properly transliterates 'Бб'" do
+ t('Б').should == 'B'
+ t('б').should == 'b'
+ end
+
+ it "properly transliterates 'Вв'" do
+ t('В').should == 'V'
+ t('в').should == 'v'
+ end
+
+ it "properly transliterates 'Гг'" do
+ t('Г').should == 'H'
+ t('г').should == 'h'
+ end
+
+ it "properly transliterates 'Ґґ'" do
+ t('Ґ').should == 'G'
+ t('ґ').should == 'g'
+ end
+
+ it "properly transliterates 'Дд'" do
+ t('Д').should == 'D'
+ t('д').should == 'd'
+ end
+
+ it "properly transliterates 'Ее'" do
+ t('Е').should == 'E'
+ t('е').should == 'e'
+ end
+
+ it "properly transliterates 'Жж'" do
+ t('Ж').should == 'ZH'
+ t('ж').should == 'zh'
+ end
+
+ it "properly transliterates 'Зз'" do
+ t('З').should == 'Z'
+ t('з').should == 'z'
+ end
+
+ it "properly transliterates 'Ии'" do
+ t('И').should == 'Y'
+ t('и').should == 'y'
+ end
+
+ it "properly transliterates 'Іі'" do
+ t('І').should == 'I'
+ t('і').should == 'i'
+ end
+
+ it "properly transliterates 'Кк'" do
+ t('К').should == 'K'
+ t('к').should == 'k'
+ end
+
+ it "properly transliterates 'Лл'" do
+ t('Л').should == 'L'
+ t('л').should == 'l'
+ end
+
+ it "properly transliterates 'Мм'" do
+ t('М').should == 'M'
+ t('м').should == 'm'
+ end
+
+ it "properly transliterates 'Нн'" do
+ t('Н').should == 'N'
+ t('н').should == 'n'
+ end
+
+ it "properly transliterates 'Оо'" do
+ t('О').should == 'O'
+ t('о').should == 'o'
+ end
+
+ it "properly transliterates 'Пп'" do
+ t('П').should == 'P'
+ t('п').should == 'p'
+ end
+
+ it "properly transliterates 'Рр'" do
+ t('Р').should == 'R'
+ t('р').should == 'r'
+ end
+
+ it "properly transliterates 'Сс'" do
+ t('С').should == 'S'
+ t('с').should == 's'
+ end
+
+ it "properly transliterates 'Тт'" do
+ t('Т').should == 'T'
+ t('т').should == 't'
+ end
+
+ it "properly transliterates 'Уу'" do
+ t('У').should == 'U'
+ t('у').should == 'u'
+ end
+
+ it "properly transliterates 'Фф'" do
+ t('Ф').should == 'F'
+ t('ф').should == 'f'
+ end
+
+ it "properly transliterates 'Хх'" do
+ t('Х').should == 'KH'
+ t('х').should == 'kh'
+ end
+
+ it "properly transliterates 'Цц'" do
+ t('Ц').should == 'TS'
+ t('ц').should == 'ts'
+ end
+
+ it "properly transliterates 'Чч'" do
+ t('Ч').should == 'CH'
+ t('ч').should == 'ch'
+ end
+
+ it "properly transliterates 'Шш'" do
+ t('Ш').should == 'SH'
+ t('ш').should == 'sh'
+ end
+
+ it "properly transliterates 'Щщ'" do
+ t('Щ').should == 'SHCH'
+ t('щ').should == 'shch'
+ end
+
+ it "properly transliterates 'зг'" do
+ t('зг').should == 'zgh'
+ t('Згори').should == 'Zghory'
+ t('РОЗГОН').should == 'ROZGHON'
+ end
+
+ it "properly transliterates apostrophe" do
+ t("д'Арк").should == 'dArk'
+ t('д’Арк').should == 'dArk'
+ t("ці 'треба' залишити").should == "tsi 'treba' zalyshyty"
+ end
+
+ it "properly transliterates 'Єє'" do
+ t('Єнакієве').should == 'Yenakiieve'
+ t('євродолар').should == 'yevrodolar'
+ t('Гаєвич').should == 'Haievych'
+ t("Короп'є").should == 'Koropie'
+ end
+
+ it "properly transliterates 'Її'" do
+ t('Їжакевич').should == 'Yizhakevych'
+ t('їсти').should == 'yisty'
+ t('Кадиївка').should == 'Kadyivka'
+ t("Мар'їне").should == 'Marine'
+ end
+
+ it "properly transliterates 'Йй'" do
+ t('Йосипівка').should == 'Yosypivka'
+ t('йоржик').should == 'yorzhyk'
+ t('Стрий').should == 'Stryi'
+ t('Андрій').should == 'Andrii'
+ end
+
+ it "properly transliterates 'Юю'" do
+ t('Юрій').should == 'Yurii'
+ t('юрба').should == 'yurba'
+ t('Корюківка').should == 'Koriukivka'
+ end
+
+ it "properly transliterates 'Яя'" do
+ t('Яготин').should == 'Yahotyn'
+ t('ялина').should == 'yalyna'
+ t('Костянтин').should == 'Kostiantyn'
+ t("Знам'янка").should == 'Znamianka'
+ t('Феодосія').should == 'Feodosiia'
+ end
+
+ it "properly transliterates mixed case chars in a string" do
+ t("ЖОЗЕФ МОНЬЄ").should == "ZHOZEF MONIE"
+ t("СПАЛАХ, поЇхали, МаріЯ").should == "SPALAKH, poIkhaly, MariIA"
+ t("ЖаН жеНе").should == "ZhaN zheNe"
+ end
+
+ it "properly transliterates strings with punctuation, digits and symbols" do
+ t("© Іван Кошелівець. Жанна д'Арк. Київ 1997, ISBN 5-7372-0031-0").should ==
+ "© Ivan Koshelivets. Zhanna dArk. Kyiv 1997, ISBN 5-7372-0031-0"
+ end
+end
View
7 spec/unit/transliteration_spec.rb
@@ -4,6 +4,7 @@
require 'support/transliteration_file'
require 'unit/transliteration/ordinary'
+require 'unit/transliteration/ukrainian'
describe "Transliteration rule for" do
transliterations_dir = File.join('rails', 'transliteration')
@@ -63,4 +64,10 @@ def t(string)
t("АЛЯБЬЕВ").should == "ALYABIEV"
end
end
+
+ describe "Ukrainian", :locale => :uk do
+ it_behaves_like "an ordinary transliteration rule"
+
+ include_examples "Ukrainian transliteration"
+ end
end
Something went wrong with that request. Please try again.