fdl_translator 1.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.
@@ -0,0 +1,23 @@
1
+ require 'yaml'
2
+
3
+ # Internationalization tasks
4
+ namespace :i18n do
5
+
6
+ desc "Validates YAML locale bundles"
7
+ task :validate_yml => [:environment] do |t, args|
8
+
9
+ # Grab all the yaml bundles in config/locales
10
+ bundles = Dir.glob(File.join(RAILS_ROOT, 'config', 'locales', '**', '*.yml'))
11
+
12
+ # Attempt to load each bundle
13
+ bundles.each do |bundle|
14
+
15
+ begin
16
+ YAML.load_file( bundle )
17
+ rescue Exception => exc
18
+ puts "Error loading: #{bundle}"
19
+ puts exc.to_s
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,89 @@
1
+ # Stub a Blog Posts controller
2
+ class BlogPostsController < ActionController::Base
3
+
4
+ # Sets up view paths so tests will work
5
+ before_filter :fix_view_paths
6
+
7
+ # Simulate auth filter
8
+ before_filter :authorize, :only => [:admin]
9
+
10
+ layout "blog_layout", :only => :show_with_layout
11
+
12
+ def index
13
+ # Pull out sample strings for index to the fake blog
14
+ @page_title = t('title')
15
+ @intro = translate(:intro, :owner => "Ricky Rails")
16
+ render :nothing => true, :layout => false
17
+ end
18
+
19
+ def show
20
+ # Sample blog post
21
+ render :template => "blog_posts/show"
22
+ end
23
+
24
+ def about
25
+ # About page
26
+ render :template => "blog_posts/about"
27
+ end
28
+
29
+ # Render the show action with a layout
30
+ def show_with_layout
31
+ render :template => "blog_posts/show"
32
+ end
33
+
34
+ # The archives action references a view helper
35
+ def archives
36
+ render :template => "blog_posts/archives"
37
+ end
38
+
39
+ # View that has a key that doesn't reference a valid string
40
+ def missing_translation
41
+ render :template => "blog_posts/missing_translation"
42
+ end
43
+
44
+ def different_formats
45
+ # Get the same tagline using the different formats
46
+ @taglines = []
47
+ @taglines << t('global.sub.key') # dot-sep keys
48
+ @taglines << t('sub.key', :scope => :global) # dot-sep keys with scope
49
+ @taglines << t('key', :scope => 'global.sub') # string key with dot-sep scope
50
+ @taglines << t(:key, :scope => 'global.sub') # symbol key with dot-sep score
51
+ @taglines << t(:key, :scope => %w(global sub))
52
+ render :nothing => true
53
+ end
54
+
55
+ # Partial template, but stored within this controller
56
+ def footer_partial
57
+ render :partial => "footer"
58
+ end
59
+
60
+ # Partial that is shared across controllers
61
+ def header_partial
62
+ render :partial => "shared/header"
63
+ end
64
+
65
+ def admin
66
+ # Simulate an admin page that has a protection scheme
67
+ end
68
+
69
+ def default_value
70
+ # Get a default value if the string isn't there
71
+ @title = t('not_there', :default => 'the default')
72
+ render :nothing => true
73
+ end
74
+
75
+ protected
76
+
77
+ # Simulate an auth system that prevents login
78
+ def authorize
79
+ # set a flash with a common message
80
+ flash[:error] = t('flash.invalid_login')
81
+ redirect_to :action => :index
82
+ end
83
+
84
+ def fix_view_paths
85
+ # Append the view path to get the correct views/partials
86
+ self.append_view_path("#{File.dirname(__FILE__)}/../views")
87
+ end
88
+
89
+ end
@@ -0,0 +1,10 @@
1
+ # Helper
2
+ module BlogPostsHelper
3
+
4
+ # Get the list of archives
5
+ def get_archives
6
+ # Will be scoped to controller.action ("blog_posts.archives")
7
+ t('title')
8
+ end
9
+
10
+ end
@@ -0,0 +1,10 @@
1
+ # A mailer for new comments on the fake blog
2
+ class BlogCommentMailer < ActionMailer::Base
3
+ # Send email about new comments
4
+ def comment_notification
5
+ @subject = t('subject')
6
+ end
7
+ end
8
+
9
+ # Set the path to where the mail template will be found
10
+ BlogCommentMailer.template_root = "#{File.dirname(__FILE__)}/../views"
@@ -0,0 +1,14 @@
1
+ # Model of a blog post, defined in schema.rb
2
+ class BlogPost < ActiveRecord::Base
3
+
4
+ # text for a permalink
5
+ def self.permalink(url)
6
+ t('permalink', :url => url)
7
+ end
8
+
9
+ # Has a title, author and body
10
+ def written_by
11
+ # Get sting like "Written by Ricky"
12
+ t('byline', :author => self.author)
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ Subject: <%= @subject %>
2
+
3
+ From,
4
+
5
+ <%= t('signoff' )%>
@@ -0,0 +1,3 @@
1
+ <hr />
2
+
3
+ <p><%= t('copyright') %></p>
@@ -0,0 +1,6 @@
1
+ <!-- Fake About page -->
2
+ <%# Bio exists in English & Spanish %>
3
+ <%= t('bio') %>
4
+
5
+ <%# Subscribe only exists in English %>
6
+ <%= t('subscribe_feed') %>
@@ -0,0 +1,2 @@
1
+ <%# Call to BlogPostsHelper %>
2
+ <%= get_archives() %>
@@ -0,0 +1,2 @@
1
+ <!-- Key should not be found -->
2
+ <p><%= t('missing_string') %></p>
@@ -0,0 +1,4 @@
1
+ <!-- Simulate blog posting page -->
2
+ <h1><%= t('title') %></h1>
3
+
4
+ <p><%= t('body', :name => 'hobbes') %></h1>
@@ -0,0 +1,9 @@
1
+ <html>
2
+
3
+ <body>
4
+ <h1><%= t('blog_title') %></h1>
5
+
6
+ <%= yield %>
7
+
8
+ </body>
9
+ </html>
@@ -0,0 +1,2 @@
1
+ <!-- The header for my awesome blog -->
2
+ <h1><%= translate('blog_name') %></h1>
@@ -0,0 +1,11 @@
1
+ ActiveRecord::Schema.define do
2
+
3
+ create_table "blog_posts", :force => true do |t|
4
+ t.column "title",:string
5
+ t.column "body", :text
6
+ t.column "author", :string
7
+ t.column "created_at", :datetime
8
+ t.column "updated_at", :datetime
9
+
10
+ end
11
+ end
@@ -0,0 +1,56 @@
1
+ en:
2
+ # Global strings
3
+ global:
4
+ sub:
5
+ key: "Hello i18n World"
6
+
7
+ # Controller
8
+ blog_posts:
9
+ # shared strings
10
+ bio: "Hello!"
11
+ subscribe_feed: "Subscribe to my feed!"
12
+
13
+ # typical actions
14
+ index:
15
+ title: "My Blog Posts"
16
+ intro: "Welcome to the blog of {{owner}}"
17
+ # specific post
18
+ show:
19
+ title: "Catz Are Cute"
20
+ body: "My cat {{name}} is the most awesome"
21
+ category: "catz, lolz"
22
+ # archives action - key used from a view helper
23
+ archives:
24
+ title: "My Blog Archives"
25
+ # footer partial (non-shared)
26
+ footer:
27
+ copyright: "Copyright 2009"
28
+
29
+ # Flash messages not specific to one action, but within a single controller
30
+ flash:
31
+ invalid_login: "Invalid login"
32
+
33
+ # shared partials in the "shared" dir
34
+ shared:
35
+ header:
36
+ blog_name: "Ricky Rocks Rails"
37
+
38
+ # Layouts
39
+ layouts:
40
+ blog_layout:
41
+ blog_title: "The Blog of Ricky"
42
+
43
+ #
44
+ # ActiveRecord models (note singular)
45
+ #
46
+ blog_post:
47
+ byline: "Written by {{author}}"
48
+ permalink: "Permalink to {{url}}"
49
+
50
+ #
51
+ # ActionMailers
52
+ #
53
+ blog_comment_mailer:
54
+ comment_notification:
55
+ subject: "New Comment Notification"
56
+ signoff: "Your Faithful Emailing Bot"
@@ -0,0 +1,16 @@
1
+ # Spanish version (pardon the bad translations)
2
+ es:
3
+ # Global strings
4
+ global:
5
+ sub:
6
+ key: "Hola i18n Mundo"
7
+
8
+ # Controller
9
+ blog_posts:
10
+ # shared strings
11
+ bio: "Hola!"
12
+
13
+ # typical actions
14
+ index:
15
+ # Purposely has the intro but *not* "title" key
16
+ intro: "Bienvenidos a el blog de {{owner}}"
@@ -0,0 +1,90 @@
1
+ # Load Rails from the app, which allows picking up a frozen rails install
2
+ # instead of from the gems
3
+ #
4
+ # Borrowed from setup in classic_pagination plugin
5
+ plugin_root = File.join(File.dirname(__FILE__), '..')
6
+ # is the plugin installed in an application?
7
+ app_root = plugin_root + '/../../..'
8
+
9
+ if File.directory? app_root + '/config'
10
+ Object.const_set(:RAILS_ENV, ENV["RAILS_ENV"] ||= "test") unless defined?(RAILS_ENV)
11
+ Object.const_set(:RAILS_ROOT, app_root) unless defined?(RAILS_ROOT)
12
+ require "#{RAILS_ROOT}/config/environment"
13
+ end
14
+
15
+ require 'pp'
16
+ require 'test/unit'
17
+ require 'rubygems'
18
+ require 'active_support'
19
+ require 'active_support/test_case'
20
+
21
+ require 'action_controller'
22
+ require 'action_controller/test_process'
23
+ require 'action_mailer'
24
+ require 'active_record'
25
+ require 'active_record/fixtures'
26
+
27
+ require 'action_pack'
28
+ require 'action_view'
29
+ require 'action_view/helpers'
30
+
31
+ # Load the Translator init after loading Rails
32
+ require File.dirname(__FILE__) + '/../init'
33
+
34
+ # Set up an ActiveRecord connection to sqlite db for testing
35
+ # Define the connector
36
+ class ActiveRecordTestConnector
37
+ cattr_accessor :able_to_connect
38
+ cattr_accessor :connected
39
+
40
+ # Set our defaults
41
+ self.connected = false
42
+ self.able_to_connect = true
43
+
44
+ class << self
45
+ def setup
46
+ unless self.connected || !self.able_to_connect
47
+ setup_connection
48
+ load_schema
49
+ self.connected = true
50
+ end
51
+ rescue Exception => e # errors from ActiveRecord setup
52
+ $stderr.puts "\nSkipping ActiveRecord assertion tests: #{e}"
53
+ self.able_to_connect = false
54
+ end
55
+
56
+ private
57
+
58
+ def setup_connection
59
+ if Object.const_defined?(:ActiveRecord)
60
+ defaults = { :database => ':memory:' }
61
+ begin
62
+ options = defaults.merge :adapter => 'sqlite3', :timeout => 500
63
+ ActiveRecord::Base.establish_connection(options)
64
+ ActiveRecord::Base.configurations = { 'sqlite3_ar_integration' => options }
65
+ ActiveRecord::Base.connection
66
+ rescue Exception # errors from establishing a connection
67
+ $stderr.puts 'SQLite 3 unavailable; trying SQLite 2.'
68
+ options = defaults.merge :adapter => 'sqlite'
69
+ ActiveRecord::Base.establish_connection(options)
70
+ ActiveRecord::Base.configurations = { 'sqlite2_ar_integration' => options }
71
+ ActiveRecord::Base.connection
72
+ end
73
+
74
+ Object.send(:const_set, :QUOTED_TYPE, ActiveRecord::Base.connection.quote_column_name('type')) unless Object.const_defined?(:QUOTED_TYPE)
75
+ else
76
+ raise "Can't setup connection since ActiveRecord isn't loaded."
77
+ end
78
+ end
79
+
80
+ # Loads the schema.rb
81
+ def load_schema
82
+ # Silence the output of creating the db
83
+ silence_stream(STDOUT) do
84
+ Dir.glob(File.dirname(__FILE__) + "/fixtures/schema.rb").each {|f| require f}
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ ActiveRecordTestConnector.setup
@@ -0,0 +1,353 @@
1
+ require 'test_helper'
2
+
3
+ # Include the models/helpers directories on the load path.
4
+ [:models, :helpers, :controllers].each do |path|
5
+ $:.unshift "#{File.dirname(__FILE__)}/fixtures/app/#{path}"
6
+ end
7
+
8
+ # sample AR model
9
+ require 'blog_post'
10
+ # sample ActionMailer
11
+ require 'blog_comment_mailer'
12
+ # sample controller
13
+ require 'blog_posts_controller'
14
+
15
+ # Set up simple routing for testing
16
+ ActionController::Routing::Routes.reload rescue nil
17
+ ActionController::Routing::Routes.draw do |map|
18
+ map.connect ':controller/:action/:id'
19
+ end
20
+
21
+ # For Rails 2.2 compat
22
+ parent_module = ActiveSupport::TestCase
23
+
24
+ if Rails::VERSION::MAJOR == 2 && Rails::VERSION::MINOR > 2
25
+ # Rails 2.3 compat
26
+ parent_module = ActionController::TestCase
27
+ end
28
+
29
+ # Test Translator functionality
30
+ class TranslatorTest < parent_module
31
+
32
+ def setup
33
+ # Create test locale bundle
34
+ I18n.backend = I18n::Backend::Simple.new
35
+
36
+ # tell the I18n library where to find your translations
37
+ I18n.load_path += Dir.glob(File.join(File.dirname(__FILE__), 'locales', '*.{yml,rb}'))
38
+
39
+ # reset the locale
40
+ I18n.default_locale = :en
41
+ I18n.locale = :en
42
+
43
+ # Set up test env
44
+ @controller = BlogPostsController.new
45
+ @request = ActionController::TestRequest.new
46
+ @response = ActionController::TestResponse.new
47
+ super
48
+ end
49
+
50
+ ### ActionController Tests
51
+
52
+ # Test that translate gets typical controller scoping
53
+ def test_controller_simple
54
+ get :index
55
+ assert_response :success
56
+ assert_not_nil assigns
57
+ # Test that controller could translate
58
+ assert_equal I18n.t('blog_posts.index.title'), assigns(:page_title)
59
+ assert_equal I18n.translate('blog_posts.index.intro', :owner => "Ricky Rails"), assigns(:intro)
60
+ end
61
+
62
+ # Test that if something that breaks convention is still processed correctly
63
+ # This case breaks with standard key hierarchy convention
64
+ def test_controller_different_formats
65
+ get :different_formats
66
+ assert_response :success
67
+ assert_not_nil assigns(:taglines)
68
+
69
+ expected = "Hello i18n World" # copied from en.yml
70
+
71
+ assigns(:taglines).each do |str|
72
+ assert_equal expected, str
73
+ end
74
+ end
75
+
76
+ # Test call to translate with default value
77
+ def test_controller_with_defaults
78
+ get :default_value
79
+ assert_response :success
80
+ assert_not_nil assigns(:title)
81
+
82
+ # TODO: Need better way to check that the default was only returned as last resort.
83
+ assert_equal 'the default', assigns(:title)
84
+ end
85
+
86
+ # TODO: Test bulk lookup
87
+ def test_bulk_lookup
88
+ # flunk
89
+ end
90
+
91
+ # Translator should raise an exception on a leading dot key to
92
+ # preserve Rails 2.3 behavior. It is caught & handled
93
+ def test_leading_dot_key
94
+ assert_raise Translator::TranslatorError do
95
+ Translator.translate_with_scope(["blog_posts", "show"], ".category")
96
+ end
97
+ end
98
+
99
+ # Test that first the most specific scope will be tried (controller.action) then
100
+ # back off to just the outer scope (controller)
101
+ def test_controller_shared_messages
102
+ get :admin
103
+ assert_response :redirect
104
+
105
+ # Test that t should have tried the outer scope
106
+ assert_equal I18n.t('blog_posts.flash.invalid_login'), flash[:error]
107
+ end
108
+
109
+ ### ActionView Tests
110
+
111
+ # Test that translate works in Views.
112
+ # Also tests that a dotted key (".foo") can be accepted used, since
113
+ # Rails 2.3 supports it
114
+ def test_view_show
115
+ get :show
116
+ assert_response :success
117
+ post_title = I18n.translate('blog_posts.show.title')
118
+ post_body = I18n.t('blog_posts.show.body', :name => 'hobbes') # matches show.erb
119
+
120
+ assert_match /#{post_title}/, @response.body
121
+ assert_match /#{post_body}/, @response.body
122
+ end
123
+
124
+ # Test that layouts can pull strings
125
+ def test_show_with_layout
126
+ get :show_with_layout
127
+ assert_response :success
128
+
129
+ blog_title = I18n.t('layouts.blog_layout.blog_title')
130
+ assert_match /#{blog_title}/, @response.body
131
+ end
132
+
133
+ # Test that partials pull strings from their own key
134
+ def test_view_partial
135
+ get :footer_partial
136
+ assert_response :success
137
+
138
+ footer = I18n.t('blog_posts.footer.copyright')
139
+ assert_match /#{footer}/, @response.body
140
+ end
141
+
142
+ def test_header_partial
143
+ get :header_partial
144
+ assert_response :success
145
+
146
+ blog_name = I18n.t('shared.header.blog_name')
147
+ assert_match /#{blog_name}/, @response.body
148
+ end
149
+
150
+ # Test that view helpers inherit correct scoping
151
+ def test_view_helpers
152
+ get :archives
153
+ assert_response :success
154
+
155
+ archives_title = I18n.t('blog_posts.archives.title')
156
+ assert_match /#{archives_title}/, @response.body
157
+ end
158
+
159
+ # Test that original behavior of TranslationHelper is not undone.
160
+ # It adds a <span class="translation_missing"> that should still be there
161
+ def test_missing_translation_show_in_span
162
+ Translator.strict_mode(false)
163
+
164
+ get :missing_translation
165
+ assert_response :success
166
+
167
+ # behavior added by TranslationHelper
168
+ assert_match /span class="translation_missing"/, @response.body, "Should be a span tag translation_missing"
169
+ end
170
+
171
+ # Test that strict mode prevents TranslationHelper from adding span.
172
+ def test_strict_mode_in_views
173
+ Translator.strict_mode(true)
174
+
175
+ get :missing_translation
176
+ assert_response :error
177
+ assert_match /18n::MissingTranslationData/, @response.body, "Exception should be for a missing translation"
178
+ end
179
+
180
+ ### ActionMailer Tests
181
+
182
+ def test_mailer
183
+ mail = BlogCommentMailer.create_comment_notification
184
+ # Subject is fetched from the mailer action
185
+ subject = I18n.t('blog_comment_mailer.comment_notification.subject')
186
+
187
+ # Signoff is fetched in the mail template (via addition to ActionView)
188
+ signoff = I18n.t('blog_comment_mailer.comment_notification.signoff')
189
+
190
+ assert_match /#{subject}/, mail.body
191
+ assert_match /#{signoff}/, mail.body
192
+ end
193
+
194
+ ### ActiveRecord tests
195
+
196
+ # Test that a model's method can call translate
197
+ def test_model_calling_translate
198
+ post = nil
199
+ author = "Ricky"
200
+ assert_nothing_raised do
201
+ post = BlogPost.create(:title => "First Post!", :body => "Starting my new blog about RoR", :author => author)
202
+ end
203
+ assert_not_nil post
204
+
205
+ assert_equal I18n.t('blog_post.byline', :author => author), post.written_by
206
+ end
207
+
208
+ # Test that the translate method is added as a class method too so that it can
209
+ # be used in validate calls, etc.
210
+ def test_class_method_translate
211
+
212
+ url = "http://ricky.blog"
213
+ # Call a static method
214
+ assert_equal I18n.t('blog_post.permalink', :url => url), BlogPost.permalink(url)
215
+ end
216
+
217
+ ### TestUnit helpers
218
+
219
+ def test_strict_mode
220
+ Translator.strict_mode(true)
221
+
222
+ # With strict mode on, exception should be thrown
223
+ assert_raise I18n::MissingTranslationData do
224
+ str = "Exception should be raised #{I18n.t('the_missing_key')}"
225
+ end
226
+
227
+ Translator.strict_mode(false)
228
+
229
+ assert_nothing_raised do
230
+ str = "Exception should not be raised #{I18n.t('the_missing_key')}"
231
+ end
232
+ end
233
+
234
+ # Fetch a miss
235
+ def test_assert_translated
236
+ # Within the assert_translated block, any missing keys fail the test
237
+ assert_raise Test::Unit::AssertionFailedError do
238
+ assert_translated do
239
+ str = "Exception should be raised #{I18n.t('the_missing_key')}"
240
+ end
241
+ end
242
+
243
+ assert_nothing_raised do
244
+ str = "Exception should not be raised #{I18n.t('the_missing_key')}"
245
+ end
246
+ end
247
+
248
+ # Test that marker text appears in when using pseudo-translation
249
+ def test_pseudo_translate
250
+ Translator.pseudo_translate(true)
251
+
252
+ # Create a blog post that uses translate to create a byline
253
+ blog_post = BlogPost.create!(:author => "Ricky")
254
+ assert_not_nil blog_post
255
+
256
+ assert_match Translator.pseudo_prepend, blog_post.written_by, "Should start with prepend text"
257
+ assert_match Translator.pseudo_append, blog_post.written_by, "Should end with append text"
258
+ end
259
+
260
+ # Test that markers can be changed
261
+ def test_pseudo_translate_with_diff_markers
262
+ Translator.pseudo_translate(true)
263
+
264
+ start_marker = "!!"
265
+ end_marker = "%%"
266
+
267
+ # Set the new markers
268
+ Translator.pseudo_prepend = start_marker
269
+ Translator.pseudo_append = end_marker
270
+
271
+ get :footer_partial
272
+ assert_response :success
273
+
274
+ # Test that the view has the pseudo-translated strings
275
+ copyright = I18n.t('blog_posts.footer.copyright')
276
+ assert_match /#{start_marker + copyright + end_marker}/, @response.body
277
+ end
278
+
279
+ # Test that if fallback mode is enabled, the default locale is used if
280
+ # the set locale can't be found
281
+ def test_fallback
282
+ # Enable fallback mode
283
+ Translator.fallback(true)
284
+
285
+ # Set the locale to Spanish
286
+ I18n.locale = :es
287
+
288
+ # The index action fetchs 2 keys - 1 has a Spanish translation (intro), 1 does not
289
+ get :index
290
+ assert_response :success
291
+ assert_not_nil assigns
292
+
293
+ # Test that controller could translate the intro from spanish
294
+ assert_equal I18n.t('blog_posts.index.intro', :owner => "Ricky Rails"), assigns(:intro)
295
+
296
+ # Test that global strings are found correctly when they have a prefix
297
+ assert_equal I18n.t('global.sub.key', :locale => :es), @controller.t('global.sub.key')
298
+
299
+ # Should find the English version
300
+ I18n.locale = :en # reset local so call to I18n pulls correct string
301
+ assert_equal I18n.translate('blog_posts.index.title'), assigns(:page_title)
302
+
303
+ # Test that global strings are found correctly when they have a prefix
304
+ assert_equal I18n.t('global.sub.key', :locale => :en), @controller.t('global.sub.key')
305
+ end
306
+
307
+ # Test that fallback
308
+ def test_fallback_with_scoping_backoff
309
+
310
+ # Enable fallback mode
311
+ Translator.fallback(true)
312
+
313
+ # Set the locale to Spanish
314
+ I18n.locale = :es
315
+
316
+ get :about
317
+ assert_response :success
318
+
319
+ # Test that the Spanish version was found
320
+ bio = I18n.t('blog_posts.bio', :locale => :es)
321
+ assert_match /#{bio}/, @response.body
322
+
323
+ # Only English version of this string
324
+ subscribe = I18n.t('blog_posts.subscribe_feed', :locale => :en)
325
+ assert_match /#{subscribe}/, @response.body
326
+ end
327
+
328
+ # Test that we can set up a callback for missing translations
329
+ def test_missing_translation_callback
330
+ test_exception = nil
331
+ test_key = nil
332
+ test_options = nil
333
+
334
+ Translator.set_missing_translation_callback do |ex, key, options|
335
+ test_exception = ex
336
+ test_key = key
337
+ test_options = options
338
+ end
339
+
340
+ get :missing_translation
341
+ assert_response :success
342
+ assert_equal "missing_string", test_key
343
+ assert_not_nil test_options
344
+ assert_not_nil test_exception
345
+ end
346
+
347
+ # Test the generic translate method on Translator that does lookup without a scope, but includes fallback behavior.
348
+ def test_generic_translate_methods
349
+ assert_equal I18n.t('blog_posts.index.intro', :owner => "Ricky Rails"), Translator.translate('blog_posts.index.intro', :owner => "Ricky Rails")
350
+ assert_equal I18n.t('blog_posts.footer.copyright'), Translator.t('blog_posts.footer.copyright')
351
+ end
352
+
353
+ end