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 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