i18n-message 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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,11 @@
1
+ class I18n::Message
2
+ class Format
3
+ include Base
4
+
5
+ protected
6
+
7
+ def scope
8
+ ['formats', super].compact.join('.')
9
+ end
10
+ end
11
+ 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,11 @@
1
+ class I18n::Message
2
+ # Sends Messages as defined through the I18n API instead of using them directly.
3
+ #
4
+ module Gettext
5
+ protected
6
+
7
+ def resolve(subject)
8
+ String === subject ? translate(subject, translate_options(subject)) : super
9
+ end
10
+ end
11
+ end
@@ -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
@@ -0,0 +1,3 @@
1
+ class I18n::Message
2
+ VERSION = "0.0.1"
3
+ end
@@ -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
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ dir = File.dirname(__FILE__)
4
+ $LOAD_PATH.unshift(dir)
5
+
6
+ Dir["#{dir}/**/*_test.rb"].sort.each do |file|
7
+ require file.sub(/^#{dir}\/(.*)\.rb$/, '\1')
8
+ end
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
@@ -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
@@ -0,0 +1,8 @@
1
+ module Api
2
+ module Gettext
3
+ test "subject is a Message, will be translated" do
4
+ store_translations('Message' => 'The Message.new')
5
+ assert_equal 'The Message.new', message('Message').to_s
6
+ end
7
+ end
8
+ end
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
@@ -0,0 +1,7 @@
1
+ module Api
2
+ autoload :Base, 'api/base'
3
+ autoload :Cascade, 'api/cascade'
4
+ autoload :Formatted, 'api/formatted'
5
+ autoload :Gettext, 'api/gettext'
6
+ autoload :Variants, 'api/variants'
7
+ end
@@ -0,0 +1,8 @@
1
+ # encoding: utf-8
2
+
3
+ dir = File.dirname(__FILE__)
4
+ $LOAD_PATH.unshift(dir)
5
+
6
+ Dir["#{dir}/**/*_test.rb"].sort.each do |file|
7
+ require file.sub(/^#{dir}\/(.*)\.rb$/, '\1')
8
+ end
@@ -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,11 @@
1
+ # encoding: utf-8
2
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
3
+
4
+ class I18nMessageVariantsTest < Test::Unit::TestCase
5
+ class Message < I18n::Message
6
+ include Variants
7
+ end
8
+
9
+ include Api::Base
10
+ include Api::Variants
11
+ 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
@@ -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