i18n-message 0.0.1
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/MIT-LICENSE +20 -0
- data/README.textile +72 -0
- data/RakeFile +28 -0
- data/lib/i18n/message/base.rb +55 -0
- data/lib/i18n/message/cascade.rb +33 -0
- data/lib/i18n/message/format.rb +11 -0
- data/lib/i18n/message/formatted.rb +42 -0
- data/lib/i18n/message/gettext.rb +11 -0
- data/lib/i18n/message/variants.rb +27 -0
- data/lib/i18n/message/version.rb +3 -0
- data/lib/i18n/message.rb +14 -0
- data/test/all.rb +8 -0
- data/test/api/base.rb +51 -0
- data/test/api/cascade.rb +18 -0
- data/test/api/formatted.rb +21 -0
- data/test/api/gettext.rb +8 -0
- data/test/api/other.rb +51 -0
- data/test/api/variants.rb +21 -0
- data/test/api.rb +7 -0
- data/test/message/all.rb +8 -0
- data/test/message/all_features_test.rb +26 -0
- data/test/message/base_test.rb +15 -0
- data/test/message/cascade_test.rb +25 -0
- data/test/message/formatted_test.rb +16 -0
- data/test/message/gettext_test.rb +19 -0
- data/test/message/variants_test.rb +11 -0
- data/test/test_case_declarative.rb +23 -0
- data/test/test_helper.rb +27 -0
- metadata +102 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Sven Fuchs & Mateo Murphy
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.textile
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
h1. I18n Message
|
2
|
+
|
3
|
+
h2. Problems solved
|
4
|
+
|
5
|
+
* Messages in class method calls are treated as plain text by default
|
6
|
+
(users might optionally want to treat them as translation keys for
|
7
|
+
gettext-style class method calls).
|
8
|
+
* Symbols in class method calls are treated as translation keys.
|
9
|
+
* Use messages from class method calls consistently with translation keys that
|
10
|
+
are implicitly used for a particular validation.
|
11
|
+
* Different translation variants (such as :full_message) for the same message
|
12
|
+
must be possible.
|
13
|
+
* Translation calls should optionally be able to cascade over scopes.
|
14
|
+
* Support format strings, e.g. "{{attribute}} {{message}}", transparently
|
15
|
+
|
16
|
+
h2. Classes
|
17
|
+
|
18
|
+
The Error class is the meant to work as a default Error class in ActiveModel.
|
19
|
+
|
20
|
+
I18n::Message is the main base class and is supposed to work situations such as
|
21
|
+
error messages, form labels etc.
|
22
|
+
|
23
|
+
The Format class is used internally to format other strings (see below).
|
24
|
+
|
25
|
+
h2. Features
|
26
|
+
|
27
|
+
The Message class comes with six modules that each provide a single feature.
|
28
|
+
This way everything's completely optional and pluggable (thus extensible and
|
29
|
+
easy to customize) even though we might choose to not impose this complexity
|
30
|
+
on the enduser (and maybe pick a default configuration/provide a configuration
|
31
|
+
dsl instead).
|
32
|
+
|
33
|
+
h3. I18n::Message::Base
|
34
|
+
|
35
|
+
This module just takes a Message OR translation key (Symbol) and interpolation
|
36
|
+
values. Calling #to_s will use the string or translate the key and interpolate
|
37
|
+
the values. The module is organized in a way so that other modules can hook in
|
38
|
+
easily.
|
39
|
+
|
40
|
+
h3. I18n::Message::Gettext
|
41
|
+
|
42
|
+
This module will also translate Messages. This behavior is frequently asked for
|
43
|
+
by people who want to use Gettext-style translation keys in class-level calls
|
44
|
+
as in validates_presence_of :foo, :message => 'The message'
|
45
|
+
|
46
|
+
h3. I18n::Message::Variants
|
47
|
+
|
48
|
+
This module adds the ability to specify Hashes as strings both at class-level
|
49
|
+
and in translation data. E.g.:
|
50
|
+
|
51
|
+
validates_presence_of :foo, :message => { :short => 'Short!', :full => 'The full message!' }
|
52
|
+
|
53
|
+
Calling #to_s on the I18n::Message instance will take a variant key and try to
|
54
|
+
find and use the variant. It defaults to the :short variant.
|
55
|
+
|
56
|
+
h3. I18n::Message::Formatted
|
57
|
+
|
58
|
+
This module adds the ability to specify format strings both at class-level and
|
59
|
+
in translation data. E.g.:
|
60
|
+
|
61
|
+
validates_presence_of :foo, :format => 'The formatted {{message}}.'
|
62
|
+
|
63
|
+
This module also works in combination with the Variants module in the way one
|
64
|
+
would expect:
|
65
|
+
|
66
|
+
validates_presence_of :foo, :message => { :short => 'foo', :full => 'FOO' }
|
67
|
+
:format => { :full => 'The formatted {{message}}.' }
|
68
|
+
|
69
|
+
message.to_s(:full) would then wrap the :full variant 'FOO' into the :full
|
70
|
+
format string and yield 'The formatted FOO'. message.to_s (defaults to :short)
|
71
|
+
would just yield 'foo' as expected.
|
72
|
+
|
data/RakeFile
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
$: << File.expand_path('../lib', __FILE__)
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'i18n/message'
|
4
|
+
|
5
|
+
task :default => [:test]
|
6
|
+
|
7
|
+
Rake::TestTask.new(:test) do |t|
|
8
|
+
t.pattern = "#{File.dirname(__FILE__)}/test/all.rb"
|
9
|
+
t.verbose = true
|
10
|
+
end
|
11
|
+
Rake::Task['test'].comment = "Run all tests"
|
12
|
+
|
13
|
+
begin
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |s|
|
16
|
+
s.name = "i18n-message"
|
17
|
+
s.version = I18n::Message::VERSION
|
18
|
+
s.summary = "Object-oriented abstraction for looking up translations from I18n.translate"
|
19
|
+
s.description = %(I18n::Message is an object-oriented abstraction for looking up translations
|
20
|
+
from I18n.translate. This is useful for storing lookup information in contexts
|
21
|
+
such as ActiveModel validation error I18n.)
|
22
|
+
s.homepage = "http://github.com/svenfuchs/i18n_message"
|
23
|
+
s.authors = ["Sven Fuchs", "Mateo Murphy"]
|
24
|
+
s.files = FileList["[A-Z]*", "{lib,test}/**/*"]
|
25
|
+
end
|
26
|
+
rescue LoadError
|
27
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
28
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class I18n::Message
|
2
|
+
# Encapsulates the patterns of:
|
3
|
+
#
|
4
|
+
# * using a plain Message (as in validates_presence_of :email, :message => "can't be blank")
|
5
|
+
# * translating a Symbol (as in validates_presence_of :email, :message => :blank)
|
6
|
+
# * interpolating given values to the resulting string.
|
7
|
+
#
|
8
|
+
module Base
|
9
|
+
attr_reader :subject, :options, :scope
|
10
|
+
|
11
|
+
attr_reader :subject, :scope, :default, :values
|
12
|
+
|
13
|
+
def initialize(subject = nil, options = {})
|
14
|
+
@subject, @options = subject, options
|
15
|
+
@options ||= {}
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s(variant = nil)
|
19
|
+
resolve(subject)
|
20
|
+
end
|
21
|
+
|
22
|
+
def <=>(other)
|
23
|
+
to_s <=> other
|
24
|
+
end
|
25
|
+
|
26
|
+
protected
|
27
|
+
|
28
|
+
def resolve(subject)
|
29
|
+
case subject
|
30
|
+
when Proc
|
31
|
+
resolve(subject.call)
|
32
|
+
when String
|
33
|
+
interpolate(subject)
|
34
|
+
else
|
35
|
+
translate(subject, translate_options(subject))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
INTERPOLATION_SYNTAX_PATTERN = /(\\)?\{\{([^\}]+)\}\}/
|
40
|
+
def interpolate(subject)
|
41
|
+
s = subject.gsub(INTERPOLATION_SYNTAX_PATTERN) do
|
42
|
+
$1 ? "{{#{$2.to_sym}}}" : "%{#{$2.to_sym}}"
|
43
|
+
end
|
44
|
+
s % options
|
45
|
+
end
|
46
|
+
|
47
|
+
def translate(subject, options)
|
48
|
+
I18n.t(subject, options.dup)
|
49
|
+
end
|
50
|
+
|
51
|
+
def translate_options(subject)
|
52
|
+
{ :scope => scope, :raise => true }.merge(options)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'active_support/core_ext/string/inflections'
|
3
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
4
|
+
|
5
|
+
class I18n::Message
|
6
|
+
# Encapsulates the pattern of looking up a translation key from several
|
7
|
+
# scopes.
|
8
|
+
#
|
9
|
+
module Cascade
|
10
|
+
def self.included(base)
|
11
|
+
base.class_eval do
|
12
|
+
cattr_accessor :cascade_options # FIXME use inheritable_attribute_accessor
|
13
|
+
self.cascade_options = { :step => 2, :skip_root => true }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def options
|
18
|
+
super.update(:cascade => self.class.cascade_options)
|
19
|
+
end
|
20
|
+
|
21
|
+
def scope
|
22
|
+
scopes = self.class.cascade_options[:scopes]
|
23
|
+
scopes = [super] + scopes.map do |scope|
|
24
|
+
if options[scope]
|
25
|
+
value = options[scope]
|
26
|
+
value = value.class.name unless value.is_a?(String) || value.is_a?(Symbol)
|
27
|
+
"#{scope}s.#{value.to_s.underscore}"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
scopes.compact.join('.')
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'active_support/core_ext/class/attribute_accessors'
|
2
|
+
|
3
|
+
class I18n::Message
|
4
|
+
# Encapsulates the pattern of wrapping a string with a format string.
|
5
|
+
#
|
6
|
+
module Formatted
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
class << self
|
10
|
+
def format_class # FIXME use inheritable_attribute_accessor
|
11
|
+
@format_class ||= Format
|
12
|
+
end
|
13
|
+
|
14
|
+
def format_class=(format_class)
|
15
|
+
@format_class = format_class
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_reader :format
|
22
|
+
|
23
|
+
def initialize(subject = nil, options = {})
|
24
|
+
@format = options.delete(:format)
|
25
|
+
super
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s(variant = nil)
|
29
|
+
formatted(super(variant), variant || :default)
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def formatted(string, variant)
|
35
|
+
# TODO :message is ActiveModel::Error specific, isn't it?
|
36
|
+
self.class.format_class.new(format || variant, :message => string).to_s(variant)
|
37
|
+
rescue I18n::MissingTranslationData
|
38
|
+
string
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class I18n::Message
|
2
|
+
# Encapsulates the pattern of strings having multiple variations as :short
|
3
|
+
# message, :full message etc.
|
4
|
+
#
|
5
|
+
module Variants
|
6
|
+
attr_reader :variant
|
7
|
+
|
8
|
+
def to_s(variant = nil)
|
9
|
+
@variant = variant
|
10
|
+
resolve(Hash === subject ? subject[variant || :short] : subject)
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def translate(subject, options)
|
16
|
+
super(:"#{subject}.#{variant || :short}", variant_translate_options(options))
|
17
|
+
rescue I18n::MissingTranslationData => e
|
18
|
+
super(subject, options).tap { |result| raise(e) unless result.is_a?(String) }
|
19
|
+
end
|
20
|
+
|
21
|
+
# uuuuuuurghs.
|
22
|
+
def variant_translate_options(options)
|
23
|
+
options[:default].map! { |key| :"#{key}.#{variant || :short}" } if options[:default].is_a?(Array)
|
24
|
+
options
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/lib/i18n/message.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'i18n'
|
2
|
+
require 'i18n/core_ext/string/interpolate'
|
3
|
+
require 'i18n/message/version'
|
4
|
+
|
5
|
+
class I18n::Message
|
6
|
+
autoload :Base, 'i18n/message/base'
|
7
|
+
autoload :Cascade, 'i18n/message/cascade'
|
8
|
+
autoload :Gettext, 'i18n/message/gettext'
|
9
|
+
autoload :Format, 'i18n/message/format'
|
10
|
+
autoload :Formatted, 'i18n/message/formatted'
|
11
|
+
autoload :Variants, 'i18n/message/variants'
|
12
|
+
|
13
|
+
include Base
|
14
|
+
end
|
data/test/all.rb
ADDED
data/test/api/base.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Api
|
2
|
+
module Base
|
3
|
+
# NOT TRANSLATED
|
4
|
+
|
5
|
+
# e.g. validates_presence_of :email, :message => "message"
|
6
|
+
test "subject is a Message, no format key given" do
|
7
|
+
assert_equal 'message', message('message').to_s
|
8
|
+
end
|
9
|
+
|
10
|
+
test "subject evaluates to a Message, no format key given" do
|
11
|
+
assert_equal 'message', message(Proc.new {'message'}).to_s
|
12
|
+
end
|
13
|
+
|
14
|
+
# interpolation
|
15
|
+
test "subject is a Message, interpolates a variable" do
|
16
|
+
assert_equal 'FOO', message('%{foo}', :foo => 'FOO').to_s
|
17
|
+
end
|
18
|
+
|
19
|
+
test "subject evaluates to a Message, interpolates a variable" do
|
20
|
+
assert_equal 'FOO', message(Proc.new {'%{foo}'}, :foo => 'FOO').to_s
|
21
|
+
end
|
22
|
+
|
23
|
+
test "subject is a Message, bogus interpolation variable, does not raise" do
|
24
|
+
assert_nothing_raised { message('foo', :foo => 'FOO').to_s }
|
25
|
+
end
|
26
|
+
|
27
|
+
test "subject evaluates to a Message, bogus interpolation variable, does not raise" do
|
28
|
+
assert_nothing_raised { message(Proc.new {'foo'}, :foo => 'FOO').to_s }
|
29
|
+
end
|
30
|
+
|
31
|
+
# TRANSLATED
|
32
|
+
|
33
|
+
# e.g. validates_presence_of :email / translations :blank => 'No email?'
|
34
|
+
test "subject is a Symbol, no format key given, translation is a Message" do
|
35
|
+
store_translations(:blank => 'No email?')
|
36
|
+
assert_equal 'No email?', message(:blank).to_s
|
37
|
+
end
|
38
|
+
|
39
|
+
# INTERPOLATION
|
40
|
+
test "subject is a Symbol, translation is a Message, interpolates a variable" do
|
41
|
+
store_translations(:foo => '{{foo}}')
|
42
|
+
assert_equal 'FOO', message(:foo, :foo => 'FOO').to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
test "subject evaluates to a Symbol, translation is a Message, interpolates a variable" do
|
46
|
+
store_translations(:foo => '{{foo}}')
|
47
|
+
assert_equal 'FOO', message(Proc.new { :foo }, :foo => 'FOO').to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
end
|
data/test/api/cascade.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module Api
|
2
|
+
module Cascade
|
3
|
+
test "returns translation from attribute scope" do
|
4
|
+
store_translations(:'models.model.attributes.attribute.message' => 'message')
|
5
|
+
assert_equal 'message', message(:message, :model => 'model', :attribute => 'attribute').to_s
|
6
|
+
end
|
7
|
+
|
8
|
+
test "returns translation from model scope" do
|
9
|
+
store_translations(:'models.model.message' => 'message')
|
10
|
+
assert_equal 'message', message(:message, :model => 'model', :attribute => 'attribute').to_s
|
11
|
+
end
|
12
|
+
|
13
|
+
test "returns translation from errors scope" do
|
14
|
+
store_translations(:message => 'message')
|
15
|
+
assert_equal 'message', message(:message, :model => 'model', :attribute => 'attribute').to_s
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Api
|
2
|
+
module Formatted
|
3
|
+
test "subject Message given, format Message given" do
|
4
|
+
assert_equal 'formatted message', message('message', :format => 'formatted %{message}').to_s
|
5
|
+
end
|
6
|
+
|
7
|
+
test "subject Message given, format Hash given" do
|
8
|
+
assert_equal 'formatted message', message('message', :format => { :full => 'formatted %{message}' }).to_s(:full)
|
9
|
+
end
|
10
|
+
|
11
|
+
test "uses a format to wrap a translated message" do
|
12
|
+
store_translations(:blank => 'blank')
|
13
|
+
assert_equal "formatted blank", message(:blank, :format => 'formatted %{message}').to_s
|
14
|
+
end
|
15
|
+
|
16
|
+
test "uses a translated format to wrap a message" do
|
17
|
+
store_translations(:blank => 'blank', :'formats.full' => 'full %{message}')
|
18
|
+
assert_equal "full blank", message(:blank).to_s(:full)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/test/api/gettext.rb
ADDED
data/test/api/other.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
module Api
|
2
|
+
|
3
|
+
module TranslatedVariants
|
4
|
+
# # validates_presence_of :email / translations :blank => { :short => 'No email?' }
|
5
|
+
# test "subject is a Symbol, format key :short given, translation is a Hash w/ :short key" do
|
6
|
+
# store_translations(:blank => { :short => 'No email?' })
|
7
|
+
# assert_equal 'No email?', message(:blank).to_s(:short)
|
8
|
+
# end
|
9
|
+
#
|
10
|
+
# not implemented
|
11
|
+
# test "subject is a Symbol, format key :full given, translation is a Hash w/ :short key" do
|
12
|
+
# store_translations(:blank => { :short => 'No email?' })
|
13
|
+
# assert_equal 'No email?', message(:blank).to_s(:full)
|
14
|
+
# end
|
15
|
+
|
16
|
+
# # validates_presence_of :email / translations :blank => { :short => 'No email?', :full => "full" }
|
17
|
+
# test "subject is a Symbol, format key :short given, translation is a Hash w/ :short and :full keys" do
|
18
|
+
# store_translations(:blank => { :short => 'No email?', :full => "full" })
|
19
|
+
# assert_equal 'No email?', message(:blank).to_s(:short)
|
20
|
+
# end
|
21
|
+
#
|
22
|
+
# test "subject is a Symbol, format key :full given, translation is a Hash w/ :short and :full keys" do
|
23
|
+
# store_translations(:blank => { :short => 'No email?', :full => "full" })
|
24
|
+
# assert_equal "full", message(:blank).to_s(:full)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# # e.g. validates_presence_of :email, :message => { :short => :foo } / translations :blank => { :short => 'No email?' }
|
28
|
+
# test "subject is a Hash, format key :short given, translation is a Hash w/ :short key" do
|
29
|
+
# store_translations(:foo => { :short => 'No email?' })
|
30
|
+
# assert_equal 'No email?', message(:blank, :short => :foo).to_s(:short)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# # not implemented
|
34
|
+
# # test "subject is a Hash, format key :full given, translation is a Hash w/ :short key" do
|
35
|
+
# # store_translations(:foo => { :short => 'No email?' })
|
36
|
+
# # assert_equal 'No email?', message(:blank, :short => :foo).to_s(:full)
|
37
|
+
# # end
|
38
|
+
#
|
39
|
+
# # e.g. validates_presence_of :email, :message => { :short => :foo, :full => :foo } / translations :blank => { :short => 'No email?' }
|
40
|
+
# test "subject is a Hash, format key :short given, translation is a Hash w/ :short and :full key" do
|
41
|
+
# store_translations(:foo => { :short => 'No email?' })
|
42
|
+
# assert_equal 'No email?', message(:blank, :short => :foo, :full => :foo).to_s(:short)
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# # not implemented
|
46
|
+
# # test "subject is a Hash, format key :full given, translation is a Hash w/ :short and :full key" do
|
47
|
+
# # store_translations(:foo => { :short => 'No email?' })
|
48
|
+
# # assert_equal 'No email?', message(:blank, :short => :foo, :full => :foo).to_s(:full)
|
49
|
+
# # end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Api
|
2
|
+
module Variants
|
3
|
+
# e.g. validates_presence_of :email, :message => "message"
|
4
|
+
test "subject is a Message, variant :short" do
|
5
|
+
assert_equal 'message', message('message').to_s(:short)
|
6
|
+
end
|
7
|
+
|
8
|
+
test "subject is a Message, variant :full" do
|
9
|
+
assert_equal 'message', message('message').to_s(:full)
|
10
|
+
end
|
11
|
+
|
12
|
+
# e.g. validates_presence_of :email, :message => { :short => "short", :full => "full" } }
|
13
|
+
test "subject is a Hash w/ :short and :full messages, variant :short" do
|
14
|
+
assert_equal 'short', message(:short => 'short', :full => "full").to_s(:short)
|
15
|
+
end
|
16
|
+
|
17
|
+
test "subject is a Hash w/ :short and :full messages, variant :full" do
|
18
|
+
assert_equal "full", message(:short => 'short', :full => "full").to_s(:full)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/test/api.rb
ADDED
data/test/message/all.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
3
|
+
|
4
|
+
class I18nMessageAllFeaturesTest < Test::Unit::TestCase
|
5
|
+
class Format < I18n::Message::Format
|
6
|
+
include I18n::Message::Variants
|
7
|
+
end
|
8
|
+
|
9
|
+
class Message < I18n::Message
|
10
|
+
include Cascade
|
11
|
+
include Variants
|
12
|
+
include Formatted
|
13
|
+
|
14
|
+
self.format_class = Format
|
15
|
+
end
|
16
|
+
|
17
|
+
def setup
|
18
|
+
I18n.backend = CascadingBackend.new
|
19
|
+
Message.cascade_options = { :step => 2, :skip_root => false, :scopes => [:model, :attribute] }
|
20
|
+
end
|
21
|
+
|
22
|
+
include Api::Base
|
23
|
+
include Api::Cascade
|
24
|
+
include Api::Variants
|
25
|
+
include Api::Formatted
|
26
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path('../../test_helper', __FILE__)
|
3
|
+
|
4
|
+
class I18nMessageBaseTest < Test::Unit::TestCase
|
5
|
+
class Message < I18n::Message
|
6
|
+
end
|
7
|
+
|
8
|
+
def setup
|
9
|
+
I18n.backend = I18n::Backend::Simple.new
|
10
|
+
I18n.backend.send(:init_translations) # so our translations won't be overwritten by Rails
|
11
|
+
end
|
12
|
+
|
13
|
+
include Api::Base
|
14
|
+
# include Api::NonFormatted
|
15
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
3
|
+
|
4
|
+
class I18nMessageCascadeTest < Test::Unit::TestCase
|
5
|
+
class Message < I18n::Message
|
6
|
+
include Cascade
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
I18n.backend = CascadingBackend.new
|
11
|
+
Message.cascade_options = { :step => 2, :skip_root => false, :scopes => [:model, :attribute] }
|
12
|
+
end
|
13
|
+
|
14
|
+
include Api::Base
|
15
|
+
include Api::Cascade
|
16
|
+
end
|
17
|
+
|
18
|
+
class I18nMessageCascadeVariantsTest < I18nMessageCascadeTest
|
19
|
+
class Message < I18nMessageCascadeTest::Message
|
20
|
+
include Variants
|
21
|
+
end
|
22
|
+
|
23
|
+
include Api::Variants
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
3
|
+
|
4
|
+
class I18nMessageFormattedTest < Test::Unit::TestCase
|
5
|
+
class Format < I18n::Message::Format
|
6
|
+
include I18n::Message::Variants
|
7
|
+
end
|
8
|
+
|
9
|
+
class Message < I18n::Message
|
10
|
+
include Formatted
|
11
|
+
self.format_class = Format
|
12
|
+
end
|
13
|
+
|
14
|
+
include Api::Base
|
15
|
+
include Api::Formatted
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
3
|
+
|
4
|
+
class I18nMessageGettextTest < Test::Unit::TestCase
|
5
|
+
class Message < I18n::Message
|
6
|
+
include Gettext
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup
|
10
|
+
store_translations(
|
11
|
+
:foo => 'foo',
|
12
|
+
:message => 'message',
|
13
|
+
:'%{foo}' => '%{foo}'
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
include Api::Base
|
18
|
+
include Api::Gettext
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Declarative
|
2
|
+
def self.included(base)
|
3
|
+
base.class_eval do
|
4
|
+
def test(name, &block)
|
5
|
+
name = "test_#{name.gsub(/\s+/,'_')}".to_sym
|
6
|
+
block ||= lambda { flunk "No implementation provided for #{name}" }
|
7
|
+
|
8
|
+
defined = instance_method(name) rescue false
|
9
|
+
raise("#{name} is already defined in #{self}") if defined
|
10
|
+
|
11
|
+
define_method(name, &block)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
include Declarative
|
19
|
+
end
|
20
|
+
|
21
|
+
class Module
|
22
|
+
include Declarative
|
23
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
$:.unshift File.expand_path("../lib", File.dirname(__FILE__))
|
2
|
+
$:.unshift(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'rubygems'
|
5
|
+
require 'test/unit'
|
6
|
+
require 'test_case_declarative'
|
7
|
+
require 'api'
|
8
|
+
|
9
|
+
require 'i18n/message'
|
10
|
+
|
11
|
+
class Test::Unit::TestCase
|
12
|
+
def teardown
|
13
|
+
I18n.backend = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def message(*args)
|
17
|
+
self.class.const_get(:Message).new(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def store_translations(data)
|
21
|
+
I18n.backend.store_translations(:en, data)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CascadingBackend < I18n::Backend::Simple
|
26
|
+
include I18n::Backend::Cascade
|
27
|
+
end
|
metadata
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: i18n-message
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Sven Fuchs
|
8
|
+
- Mateo Murphy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2010-02-25 00:00:00 +01:00
|
14
|
+
default_executable:
|
15
|
+
dependencies: []
|
16
|
+
|
17
|
+
description: |-
|
18
|
+
I18n::Message is an object-oriented abstraction for looking up translations
|
19
|
+
from I18n.translate. This is useful for storing lookup information in contexts
|
20
|
+
such as ActiveModel validation error I18n.
|
21
|
+
email:
|
22
|
+
executables: []
|
23
|
+
|
24
|
+
extensions: []
|
25
|
+
|
26
|
+
extra_rdoc_files:
|
27
|
+
- README.textile
|
28
|
+
files:
|
29
|
+
- MIT-LICENSE
|
30
|
+
- README.textile
|
31
|
+
- RakeFile
|
32
|
+
- lib/i18n/message.rb
|
33
|
+
- lib/i18n/message/base.rb
|
34
|
+
- lib/i18n/message/cascade.rb
|
35
|
+
- lib/i18n/message/format.rb
|
36
|
+
- lib/i18n/message/formatted.rb
|
37
|
+
- lib/i18n/message/gettext.rb
|
38
|
+
- lib/i18n/message/variants.rb
|
39
|
+
- lib/i18n/message/version.rb
|
40
|
+
- test/all.rb
|
41
|
+
- test/api.rb
|
42
|
+
- test/api/base.rb
|
43
|
+
- test/api/cascade.rb
|
44
|
+
- test/api/formatted.rb
|
45
|
+
- test/api/gettext.rb
|
46
|
+
- test/api/other.rb
|
47
|
+
- test/api/variants.rb
|
48
|
+
- test/message/all.rb
|
49
|
+
- test/message/all_features_test.rb
|
50
|
+
- test/message/base_test.rb
|
51
|
+
- test/message/cascade_test.rb
|
52
|
+
- test/message/formatted_test.rb
|
53
|
+
- test/message/gettext_test.rb
|
54
|
+
- test/message/variants_test.rb
|
55
|
+
- test/test_case_declarative.rb
|
56
|
+
- test/test_helper.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/svenfuchs/i18n_message
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
version: "0"
|
71
|
+
version:
|
72
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: "0"
|
77
|
+
version:
|
78
|
+
requirements: []
|
79
|
+
|
80
|
+
rubyforge_project:
|
81
|
+
rubygems_version: 1.3.5
|
82
|
+
signing_key:
|
83
|
+
specification_version: 3
|
84
|
+
summary: Object-oriented abstraction for looking up translations from I18n.translate
|
85
|
+
test_files:
|
86
|
+
- test/all.rb
|
87
|
+
- test/api/base.rb
|
88
|
+
- test/api/cascade.rb
|
89
|
+
- test/api/formatted.rb
|
90
|
+
- test/api/gettext.rb
|
91
|
+
- test/api/other.rb
|
92
|
+
- test/api/variants.rb
|
93
|
+
- test/api.rb
|
94
|
+
- test/message/all.rb
|
95
|
+
- test/message/all_features_test.rb
|
96
|
+
- test/message/base_test.rb
|
97
|
+
- test/message/cascade_test.rb
|
98
|
+
- test/message/formatted_test.rb
|
99
|
+
- test/message/gettext_test.rb
|
100
|
+
- test/message/variants_test.rb
|
101
|
+
- test/test_case_declarative.rb
|
102
|
+
- test/test_helper.rb
|