object_scoped_i18n 0.1.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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/README.rdoc +62 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/lib/object_scoped_i18n.rb +69 -0
- data/spec/locale.yml +4 -0
- data/spec/object_scoped_i18n_spec.rb +77 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +30 -0
- metadata +86 -0
data/.document
ADDED
data/.gitignore
ADDED
data/README.rdoc
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
= object_scoped_i18n
|
2
|
+
|
3
|
+
Translate using i18n and scope accoring to the object's place in Ruby's
|
4
|
+
hierarchial structure.
|
5
|
+
|
6
|
+
To use, extend the class:
|
7
|
+
|
8
|
+
class Admin < User
|
9
|
+
extend ObjectScopedI18n
|
10
|
+
end
|
11
|
+
|
12
|
+
You can now call translations on the object:
|
13
|
+
|
14
|
+
Admin.translate(:name)
|
15
|
+
|
16
|
+
Which calls I18n like this:
|
17
|
+
|
18
|
+
I18n.translate(:"admin.name", :default => [:"user.name", :"object.name"])
|
19
|
+
|
20
|
+
Which looks up "admin.name" first; if it didn't found that, it looks up
|
21
|
+
"user.name", including any included modules, all way up.
|
22
|
+
|
23
|
+
Namespaces are introduced as extra scope.
|
24
|
+
|
25
|
+
class SomeModule::SomeClass
|
26
|
+
end
|
27
|
+
|
28
|
+
SomeModule::SomeClass.translate(:name)
|
29
|
+
|
30
|
+
Will be the same as:
|
31
|
+
|
32
|
+
I18n.translate(:"some_module.some_class.name", :default => {...})
|
33
|
+
|
34
|
+
You can off course use all the options you would normally use with I18n.
|
35
|
+
|
36
|
+
== Why?
|
37
|
+
|
38
|
+
Because I wanted something that was like ActiveRecord's human_attribute_name,
|
39
|
+
but consitently over other objects too.
|
40
|
+
|
41
|
+
== So what about human_attribute_name?
|
42
|
+
|
43
|
+
You can override it, so it's use object_scoped_i18n:
|
44
|
+
|
45
|
+
class ActiveRecord::Base
|
46
|
+
extend ObjectScopedI18n
|
47
|
+
def self.human_attribute_name(key, options = {})
|
48
|
+
translate(key, {:default => key.to_s.humanize, :scope => [:activerecord, :attributes]}.merge(options))
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
You now change the scope if you like. Also, you'll get global translations for
|
53
|
+
free, for columns like "created_at" and "updated_at".
|
54
|
+
|
55
|
+
== Installation
|
56
|
+
|
57
|
+
Just gem install object_scoped_i18n and require it in your project, like you're used to.
|
58
|
+
|
59
|
+
|
60
|
+
== Copyright
|
61
|
+
|
62
|
+
Copyright (c) 2009 Iain Hecker. Released under the MIT license.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "object_scoped_i18n"
|
8
|
+
gem.summary = %Q{Translate using i18n and scope it according to the object's place in Ruby's hierarchial structure}
|
9
|
+
gem.description = %Q{Translate using i18n and scope it according to the object's place in Ruby's hierarchial structure.
|
10
|
+
Using ancestors to build up the default option of I18n.translate. Works in much the same way as ActiveRecords human_attribute_name}
|
11
|
+
gem.email = "iain@iain.nl"
|
12
|
+
gem.homepage = "http://github.com/iain/object_scoped_i18n"
|
13
|
+
gem.authors = ["Iain Hecker"]
|
14
|
+
gem.add_development_dependency "rspec", ">= 1.2.9"
|
15
|
+
gem.add_dependency "i18n"
|
16
|
+
# gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
|
17
|
+
end
|
18
|
+
Jeweler::GemcutterTasks.new
|
19
|
+
rescue LoadError
|
20
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
21
|
+
end
|
22
|
+
|
23
|
+
require 'spec/rake/spectask'
|
24
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
25
|
+
spec.libs << 'lib' << 'spec'
|
26
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
27
|
+
end
|
28
|
+
|
29
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
30
|
+
spec.libs << 'lib' << 'spec'
|
31
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
32
|
+
spec.rcov = true
|
33
|
+
end
|
34
|
+
|
35
|
+
task :spec => :check_dependencies
|
36
|
+
|
37
|
+
task :default => :spec
|
38
|
+
|
39
|
+
require 'rake/rdoctask'
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "object_scoped_i18n #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'i18n' unless Object.const_defined?(:I18n)
|
2
|
+
|
3
|
+
# Translate using i18n and scope accoring to the object's place in Ruby's
|
4
|
+
# hierarchial structure.
|
5
|
+
#
|
6
|
+
# To use, extend the class:
|
7
|
+
#
|
8
|
+
# class Admin < User
|
9
|
+
# extend ObjectScopedI18n
|
10
|
+
# end
|
11
|
+
#
|
12
|
+
# You can now call translations on the object:
|
13
|
+
#
|
14
|
+
# Admin.translate(:name)
|
15
|
+
#
|
16
|
+
# Which calls I18n like this:
|
17
|
+
#
|
18
|
+
# I18n.translate(:"admin.name", :default => [:"user.name", :"object.name"])
|
19
|
+
#
|
20
|
+
# Which looks up "admin.name" first; if it didn't found that, it looks up
|
21
|
+
# "user.name", including any included modules, all way up.
|
22
|
+
#
|
23
|
+
# Namespaces are introduced as extra scope.
|
24
|
+
#
|
25
|
+
# class SomeModule::SomeClass
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# SomeModule::SomeClass.translate(:name)
|
29
|
+
#
|
30
|
+
# Will be the same as:
|
31
|
+
#
|
32
|
+
# I18n.translate(:"some_module.some_class.name", :default => {...})
|
33
|
+
#
|
34
|
+
# You can off course use all the options you would normally use with I18n.
|
35
|
+
module ObjectScopedI18n
|
36
|
+
|
37
|
+
# Perform a basic translation, depending on the object it was called on.
|
38
|
+
def translate(key, options = {}, &block)
|
39
|
+
I18n.translate(*object_scoped_i18n_options(key, options.dup), &block)
|
40
|
+
end
|
41
|
+
alias t translate
|
42
|
+
|
43
|
+
# Same as 'translate' but raises an exception if no translation was found.
|
44
|
+
def translate!(key, options = {}, &block)
|
45
|
+
I18n.translate!(*object_scoped_i18n_options(key, options.dup), &block)
|
46
|
+
end
|
47
|
+
alias t! translate!
|
48
|
+
|
49
|
+
def object_scoped_i18n_options(key, options = {})
|
50
|
+
separator = options[:separator] || I18n.default_separator
|
51
|
+
translation_tree = self.ancestors.map do |mod|
|
52
|
+
# Yes, this looks like the ActiveSupport#underscore method, but it's
|
53
|
+
# a bit different. I needed to have the namespace separator after
|
54
|
+
# the downcase method, because I don't want to downcase that.
|
55
|
+
# Besides, now this gem doesn't have an ActiveSupport dependency.
|
56
|
+
scope_name = mod.to_s.
|
57
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
58
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
59
|
+
tr("-", "_").
|
60
|
+
downcase.
|
61
|
+
gsub(/::/, separator)
|
62
|
+
:"#{scope_name}#{separator}#{key}"
|
63
|
+
end
|
64
|
+
translation_key = translation_tree.shift
|
65
|
+
options[:default] = (options[:default] || []) + translation_tree
|
66
|
+
[ translation_key, options ]
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
data/spec/locale.yml
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "ObjectScopedI18n" do
|
4
|
+
|
5
|
+
describe "#translate" do
|
6
|
+
|
7
|
+
it "should send a i18n call" do
|
8
|
+
I18n.should_receive(:translate).with(:foo, :bar)
|
9
|
+
Monkey.should_receive(:object_scoped_i18n_options).with(:some_method, {}).and_return([:foo, :bar])
|
10
|
+
Monkey.translate(:some_method)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should alias to 't'" do
|
14
|
+
I18n.should_receive(:translate).with(:foo, :bar)
|
15
|
+
Monkey.should_receive(:object_scoped_i18n_options).with(:some_method, {}).and_return([:foo, :bar])
|
16
|
+
Monkey.t(:some_method)
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#translate!" do
|
22
|
+
|
23
|
+
it "should send a i18n call" do
|
24
|
+
I18n.should_receive(:translate!).with(:foo, :bar)
|
25
|
+
Monkey.should_receive(:object_scoped_i18n_options).with(:some_method, {}).and_return([:foo, :bar])
|
26
|
+
Monkey.translate!(:some_method)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should alias to 't!'" do
|
30
|
+
I18n.should_receive(:translate!).with(:foo, :bar)
|
31
|
+
Monkey.should_receive(:object_scoped_i18n_options).with(:some_method, {}).and_return([:foo, :bar])
|
32
|
+
Monkey.t!(:some_method)
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "#object_scoped_i18n_options" do
|
38
|
+
|
39
|
+
it "should scope properly" do # Look at locale.yml to see what happened
|
40
|
+
Monkey.t!(:something, :scope => "translation_scope")
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should translate scoped" do
|
44
|
+
subject = Scoped::SomeClass.object_scoped_i18n_options(:my_method)
|
45
|
+
subject[0].should == :"scoped.some_class.my_method"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should know an included module" do
|
49
|
+
subject = Scoped::SomeClass.object_scoped_i18n_options(:my_method)
|
50
|
+
subject[1][:default][0].should == :"scoped.included_module.my_method"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should know super class" do
|
54
|
+
subject = Scoped::SomeClass.object_scoped_i18n_options(:my_method)
|
55
|
+
subject[1][:default][1].should == :"scoped.super_class.my_method"
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should override separator" do
|
59
|
+
subject = Monkey.object_scoped_i18n_options(:my_method, :separator => "X")
|
60
|
+
subject[0].should == :"monkeyXmy_method"
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should use I18n's default separator" do
|
64
|
+
old_separator, I18n.default_separator = I18n.default_separator, "Y"
|
65
|
+
subject = Monkey.object_scoped_i18n_options(:my_method)
|
66
|
+
subject[0].should == :"monkeyYmy_method"
|
67
|
+
I18n.default_separator = old_separator
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should leave other options untouched" do
|
71
|
+
subject = Monkey.object_scoped_i18n_options(:my_method, :my_options => "x")
|
72
|
+
subject[1][:my_options].should == "x"
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
data/spec/spec.opts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
3
|
+
require 'object_scoped_i18n'
|
4
|
+
require 'spec'
|
5
|
+
require 'spec/autorun'
|
6
|
+
|
7
|
+
Spec::Runner.configure do |config|
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
I18n.load_path << File.dirname(__FILE__) + '/locale.yml'
|
12
|
+
|
13
|
+
module Scoped
|
14
|
+
module IncludedModule
|
15
|
+
end
|
16
|
+
class SuperClass
|
17
|
+
end
|
18
|
+
class SomeClass < SuperClass
|
19
|
+
extend ObjectScopedI18n
|
20
|
+
include IncludedModule
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
class Animal
|
25
|
+
extend ObjectScopedI18n
|
26
|
+
end
|
27
|
+
|
28
|
+
class Monkey < Animal
|
29
|
+
|
30
|
+
end
|
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: object_scoped_i18n
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Iain Hecker
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-12-13 00:00:00 +01:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: rspec
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 1.2.9
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: i18n
|
27
|
+
type: :runtime
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
description: |-
|
36
|
+
Translate using i18n and scope it according to the object's place in Ruby's hierarchial structure.
|
37
|
+
Using ancestors to build up the default option of I18n.translate. Works in much the same way as ActiveRecords human_attribute_name
|
38
|
+
email: iain@iain.nl
|
39
|
+
executables: []
|
40
|
+
|
41
|
+
extensions: []
|
42
|
+
|
43
|
+
extra_rdoc_files:
|
44
|
+
- README.rdoc
|
45
|
+
files:
|
46
|
+
- .document
|
47
|
+
- .gitignore
|
48
|
+
- README.rdoc
|
49
|
+
- Rakefile
|
50
|
+
- VERSION
|
51
|
+
- lib/object_scoped_i18n.rb
|
52
|
+
- spec/locale.yml
|
53
|
+
- spec/object_scoped_i18n_spec.rb
|
54
|
+
- spec/spec.opts
|
55
|
+
- spec/spec_helper.rb
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://github.com/iain/object_scoped_i18n
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options:
|
62
|
+
- --charset=UTF-8
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: "0"
|
70
|
+
version:
|
71
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: "0"
|
76
|
+
version:
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.3.5
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Translate using i18n and scope it according to the object's place in Ruby's hierarchial structure
|
84
|
+
test_files:
|
85
|
+
- spec/object_scoped_i18n_spec.rb
|
86
|
+
- spec/spec_helper.rb
|