fdl_translator 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ pkg
File without changes
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Mike Champion
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.
@@ -0,0 +1,149 @@
1
+ = Translator - i18n tooling for Rails
2
+
3
+ Translator makes using the internationalization (i18n) facility introduced in Rails 2.2 simpler through:
4
+ * keeping your code DRY using simple conventions
5
+ * make testing easier to catch missing keys
6
+ * supplying a graceful "fallback" mode when a translation is missing in a user's locale
7
+
8
+ == The Problem
9
+
10
+ The (very!) helpful I18n[http://api.rubyonrails.org/classes/I18n.html] library finds keys in locale bundles (and more), but doesn't know anything about Rails applications. Applications that have a lot of strings need a system of keeping them organized. Translator adds smarts to controllers, views, models & mailers to follow a simple convention when finding keys. Having a convention for the hierarchy of keys within locale bundles that makes it easier to code and maintain, while still using the capabilities of the underlying I18n library. (Note: Translator does not depend on how the actual YAML/Ruby files are stored in the filesystem.)
11
+
12
+ Quick example - if you follow the key convention of structuring your locale bundle like:
13
+ blog_posts: # controller
14
+ show: # action
15
+ title: "My Awesome Blog Post"
16
+ byline: "Written by {{author}}"
17
+
18
+ Then when writing the <tt>BlogPostsController.show</tt> action you can just use <tt>t('title')</tt> to fetch the string (equivalent to <tt>I18n.translate('blog_posts.show.title')</tt>). Similarly, in the <tt>show.erb</tt> template you can get use <tt>t('byline', :author => "Mike")</tt>. This extends to models and mailers as well. As they say, "Look at all the things I'm not doing!"
19
+
20
+ == Installation
21
+
22
+ To install this plugin into your Rails app (2.2 or 2.3+):
23
+
24
+ ./script/plugin install git://github.com/graysky/translator.git
25
+
26
+ To install as a gem add the following to config/environment.rb:
27
+
28
+ config.gem "graysky-translator", :lib => "translator", :source => "http://gems.github.com"
29
+
30
+ == RDocs
31
+
32
+ {The RDocs are online}[http://graysky.github.com/translator/rdoc/index.html] or can be generated via <tt>rake rdoc</tt> in the translator plugin directory.
33
+
34
+ == Problems or Suggestions
35
+
36
+ Please {file an issue in the Github bug tracker}[http://github.com/graysky/translator/issues/] or contact me.
37
+
38
+ == Simple +translate+ Everywhere
39
+
40
+ Translator adds an enhanced +translate+ (or shorter +t+) method to:
41
+ * ActionController
42
+ * ActionView
43
+ * ActiveRecord
44
+ * ActionMailer
45
+
46
+ In the spirit of Rails, the convention for a hierarchy of keys borrows the same layout as the typical "views" directory. A sample Blog application is used as an example.
47
+
48
+ For controllers/views/mailers it is:
49
+ en: # locale
50
+ # the controller name
51
+ blog_posts:
52
+ # the action name
53
+ index:
54
+ key: "Hello World"
55
+
56
+ # partials w/o underscore (template "_footer.erb")
57
+ footer:
58
+ key: "My Copyright"
59
+
60
+ # "layouts" is fixed
61
+ layouts:
62
+ # the layout name (template "main.erb")
63
+ main:
64
+ key: "My App Name"
65
+
66
+ # for shared partials called like: render :template => "shared/user"
67
+ # where "shared" is the directory name
68
+ shared:
69
+ # partial name w/o underscore (template "_user.erb")
70
+ user:
71
+ key: "Foo"
72
+
73
+ # the full mailer name
74
+ blog_comment_mailer:
75
+ # the method name (does not include "deliver")
76
+ comment_notification:
77
+ subject: "New Comment"
78
+
79
+ For models it is:
80
+ en:
81
+ # The model name
82
+ blog_post:
83
+ key: "Custom validation error"
84
+
85
+
86
+ === Key Lookup
87
+
88
+ When a key is looked up, Translator adds extra scoping to the lookup based on where it is called from. For:
89
+ * Controllers & views the scope includes <tt>[:controller_name, :action_name]</tt>. (For shared partials it is <tt>[:template_path, :partial_name]</tt>)
90
+ * Mailers the scope includes <tt>[:mailer_name, :method_name]</tt>
91
+ * Models the scope includes <tt>[:model_name]</tt>
92
+
93
+ But what happens if you want to share strings across a controller? Let's say you have error messages that are set in flash notices
94
+ and then are shared between actions in a controller defined in the locale bundle like:
95
+ blog_posts:
96
+ errors:
97
+ permission_denied: "Permission denied to read this blog post"
98
+
99
+ If Translator doesn't find the original key, it will remove a layer of scoping and try again.
100
+ So if in our Blogs controller +show+ action we want to set a <tt>flash[:error]</tt> to a permission denied message it can find the string by calling <tt>t('errors.permission_denied')</tt>.
101
+ Translator will first look for "blog_posts.show.errors.permission_denied", which doesn't exist. So it will then try to find
102
+ "blog_posts.errors.permission_denied" and return the correct string. This can be used to create greater levels of scoping, or to force finding
103
+ global strings (e.g. <tt>t("global.app_name")</tt>).
104
+
105
+ == Graceful Locale Fallback
106
+
107
+ Let's say you've extracted all your English strings, and even had them translated to Spanish to make your Spanish-speaking users extra happy. Then you have a brilliant idea for a new feature that needs to go live before the new pages are translated into Spanish. You still want your Spanish-speaking users to keep seeing the site in Spanish, but for these new pages to fallback to English. (While not exactly ideal, it is better than having "translation missing" messages or not externalizing strings.) To enable this fallback behavior:
108
+
109
+ # In the configuration
110
+ I18n.default_locale = :en
111
+
112
+ # Enable the fallback mode to try :es first, then :en
113
+ Translator.fallback(true)
114
+
115
+ # Set in the code based on user's preference, their IP address, etc.
116
+ I18n.locale = :es
117
+
118
+ # Everything else stays the same, but after Translator tries the normal scoping rules
119
+ # in Spanish (:es), it will apply the same rules for the default locale (:en)
120
+ t('page_title')
121
+
122
+ == Testing Help
123
+
124
+ * <tt>Translator.strict_mode</tt> will cause an exception to be raised for any missing translations. Enabled by default during testing to help find mistyped or accidently forgotten keys. It can be disabled by calling <tt>Translator.strict_mode(false)</tt> (in test_helper for example).
125
+ * <tt>assert_translated</tt> takes a block and asserts that all lookups within that block have real translations. It is a more targeted version of <tt>strict_mode</tt>. Example:
126
+
127
+ assert_translated do
128
+ # Will assert that all keys find valid translations inside the block
129
+ get :show
130
+ end
131
+
132
+ * If you're trying to avoid hard-coding strings in tests, you can still use the lookup that is added to models and controllers:
133
+
134
+ # Inside a test exercising a BlogPostController (@controller created in setup method)
135
+ get :show, :id => 123
136
+ # the byline should be in the body - uses @controller to make lookup easy (automatically knows controller name and action)
137
+ assert_match @controller.t('byline', :name => "Mike"), @response.body
138
+
139
+ * Pseudo-translation mode. Pseudo-translation wraps all extracted strings with leading and trailing text so that you can spot if you forgot any. It can be enabled by <tt>Translator.pseudo_translate</tt> (in an environment file or locale.rb for example). It does not change the lookup process (e.g. <tt>t('blog_title')</tt>) but will transform the returned string from "My Blog" to "[[ My Blog ]]". The text that is prepended / appended can be set by calling <tt>Translator.pseudo_prepend = "@@"</tt> (or +append+). <b>Pro Tip:</b> This can also be used to see how a layout will display in a localized language that is longer than the default. or example, German words tend to be significantly longer than their English equivalents. By padding all strings you can test how a layout will adapt and make changes.
140
+
141
+ * Rake task to validate that YAML files are, in fact, valid YAML. Useful when getting back translations from a 3rd party service, this can be a quick way to catch a missing quote. Run like <tt>rake i18n:validate_yml</tt> and it will check all .yml files below <tt>RAILS_ROOT/config/locales</tt>.
142
+
143
+ == Changelog
144
+
145
+ 1.0.0 - 4/17/2009 - Declaring 1.0 after successfully using Translator in production.
146
+
147
+ Bug reports welcome. {Patches very welcome}[http://github.com/graysky/translator].
148
+
149
+ Copyright (c) 2009 {Mike Champion}[http://graysky.org], released under the MIT license.
@@ -0,0 +1,76 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = "fdl_translator"
8
+ gemspec.summary = "Rails extentions to simplify internationalization"
9
+ gemspec.email = "mike@graysky.org"
10
+ gemspec.homepage = "http://github.com/graysky/translator"
11
+ gemspec.description = "Translator makes using Rails internationalization simpler"
12
+ gemspec.authors = ["Mike Champion", "Justin Smestad"]
13
+ end
14
+ Jeweler::GemcutterTasks.new
15
+ rescue LoadError
16
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
17
+ end
18
+
19
+
20
+ # Use Hanna for pretty RDocs (if installed), otherwise normal rdocs
21
+ begin
22
+ require 'hanna/rdoctask'
23
+ rescue LoadError
24
+ require 'rake/rdoctask'
25
+ end
26
+
27
+ desc 'Default: run unit tests.'
28
+ task :default => :test
29
+
30
+ desc 'Test the translator plugin.'
31
+ Rake::TestTask.new(:test) do |t|
32
+ t.libs << 'lib'
33
+ t.libs << 'test'
34
+ t.pattern = 'test/**/*_test.rb'
35
+ t.verbose = true
36
+ end
37
+
38
+ desc 'Generate documentation for the translator plugin.'
39
+ Rake::RDocTask.new(:rdoc) do |rdoc|
40
+ rdoc.rdoc_dir = 'rdoc'
41
+ rdoc.title = 'Translator - i18n tooling for Rails'
42
+ rdoc.options << '--line-numbers' << '--inline-source' << '--webcvs=http://github.com/graysky/translator/tree/master/'
43
+ rdoc.rdoc_files.include('README.rdoc')
44
+ rdoc.rdoc_files.include('lib/**/*.rb')
45
+ end
46
+
47
+ desc "Publish rdocs to Github on special gh-pages branch. Assumes local branch gh-pages"
48
+ task :publish_rdoc do
49
+ # Build the rdocs
50
+ safe_system("rake rerdoc")
51
+ move("rdoc", "rdoc-tmp")
52
+
53
+ git("co gh-pages")
54
+ # Remove existing docs
55
+ git("rm -rf --quiet rdoc")
56
+ move("rdoc-tmp", "rdoc")
57
+ # Add new ones
58
+ git("add .")
59
+ # Push the changes
60
+ git("commit -a -m 'updating rdocs'")
61
+ git("push origin HEAD")
62
+
63
+ git("co master")
64
+ #system("open coverage/index.html") if PLATFORM['darwin']
65
+ end
66
+
67
+ def git(cmd)
68
+ safe_system("git " + cmd)
69
+ end
70
+
71
+ def safe_system(cmd)
72
+ if !system(cmd)
73
+ puts "Failed: #{cmd}"
74
+ exit
75
+ end
76
+ end
@@ -0,0 +1,5 @@
1
+ ---
2
+ :patch: 1
3
+ :major: 1
4
+ :build:
5
+ :minor: 0
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'translator'
@@ -0,0 +1,3 @@
1
+ unless Rails::VERSION::MAJOR >= 2 && Rails::VERSION::MINOR >= 2
2
+ raise "This version of Translator requires Rails 2.2 or higher."
3
+ end
@@ -0,0 +1,360 @@
1
+ require 'active_support'
2
+ require 'action_view/helpers/translation_helper'
3
+
4
+ # Extentions to make internationalization (i18n) of a Rails application simpler.
5
+ # Support the method +translate+ (or shorter +t+) in models/view/controllers/mailers.
6
+ module Translator
7
+ # Error for use within Translator
8
+ class TranslatorError < StandardError #:nodoc:
9
+ end
10
+
11
+ # Translator version
12
+ VERSION = '1.0.0'
13
+
14
+ # Whether strict mode is enabled
15
+ @@strict_mode = false
16
+
17
+ # Whether to fallback from the set locale to the default locale
18
+ @@fallback_mode = false
19
+
20
+ # Whether to pseudo-translate all fetched strings
21
+ @@pseudo_translate = false
22
+
23
+ # Pseudo-translation text to prend to fetched strings.
24
+ # Used as a visible marker. Default is "["
25
+ @@pseudo_prepend = "["
26
+
27
+ # Pseudo-translation text to append to fetched strings.
28
+ # Used as a visible marker. Default is "]"
29
+ @@pseudo_append = "]"
30
+
31
+ # An optional callback to be notified when there are missing translations in views
32
+ @@missing_translation_callback = nil
33
+
34
+ # Invokes the missing translation callback, if it is defined
35
+ def self.missing_translation_callback(exception, key, options = {}) #:nodoc:
36
+ @@missing_translation_callback.call(exception, key, options) if !@@missing_translation_callback.nil?
37
+ end
38
+
39
+ # Set an optional block that gets called when there's a missing translation within a view.
40
+ # This can be used to log missing translations in production.
41
+ #
42
+ # Block takes two required parameters:
43
+ # - exception (original I18n::MissingTranslationData that was raised for the failed translation)
44
+ # - key (key that was missing)
45
+ # - options (hash of options sent to translator)
46
+ # Example:
47
+ # set_missing_translation_callback do |ex, key, options|
48
+ # logger.info("Failed to find #{key}")
49
+ # end
50
+ def self.set_missing_translation_callback(&block)
51
+ @@missing_translation_callback = block
52
+ end
53
+
54
+ # Performs lookup with a given scope. The scope should be an array of strings or symbols
55
+ # ordered from highest to lowest scoping. For example, for a given PicturesController
56
+ # with an action "show" the scope should be ['pictures', 'show'] which happens automatically.
57
+ #
58
+ # The key and options parameters follow the same rules as the I18n library (they are passed through).
59
+ #
60
+ # The search order is from most specific scope to most general (and then using a default value, if provided).
61
+ # So continuing the previous example, if the key was "title" and options included :default => 'Some Picture'
62
+ # then it would continue searching until it found a value for:
63
+ # * pictures.show.title
64
+ # * pictures.title
65
+ # * title
66
+ # * use the default value (if provided)
67
+ #
68
+ # The key itself can contain a scope. For example, if there were a set of shared error messages within the
69
+ # Pictures controller, that could be found using a key like "errors.deleted_picture". The inital search with
70
+ # narrowest scope ('pictures.show.errors.deleted_picture') will not find a value, but the subsequent search with
71
+ # broader scope ('pictures.errors.deleted_picture') will find the string.
72
+ #
73
+ def self.translate_with_scope(scope, key, options={})
74
+ scope ||= [] # guard against nil scope
75
+
76
+ # Let Rails 2.3 handle keys starting with "."
77
+ raise TranslatorError, "Skip keys with leading dot" if key.to_s.first == "."
78
+
79
+ # Keep the original options clean
80
+ original_scope = scope.dup
81
+ scoped_options = {}.merge(options)
82
+
83
+ # Raise to know if the key was found
84
+ scoped_options[:raise] = true
85
+
86
+ # Remove any default value when searching with scope
87
+ scoped_options.delete(:default)
88
+
89
+ str = nil # the string being looked for
90
+
91
+ # Loop through each scope until a string is found.
92
+ # Example: starts with scope of [:blog_posts :show] then tries scope [:blog_posts] then
93
+ # without any automatically added scope ("[]").
94
+ while str.nil?
95
+ # Set scope to use for search
96
+ scoped_options[:scope] = scope
97
+
98
+ begin
99
+ # try to find key within scope (dup the options because I18n modifies the hash)
100
+ str = I18n.translate(key, scoped_options.dup)
101
+ rescue I18n::MissingTranslationData => exc
102
+ # did not find the string, remove a layer of scoping.
103
+ # break when there are no more layers to remove (pop returns nil)
104
+ break if scope.pop.nil?
105
+ end
106
+ end
107
+
108
+ # If a string is not yet found, potentially check the default locale if in fallback mode.
109
+ if str.nil? && Translator.fallback? && (I18n.locale != I18n.default_locale) && options[:locale].nil?
110
+ # Recurse original request, but in the context of the default locale
111
+ str ||= Translator.translate_with_scope(original_scope, key, options.merge({:locale => I18n.default_locale}))
112
+ end
113
+
114
+ # If a string was still not found, fall back to trying original request (gets default behavior)
115
+ str ||= I18n.translate(key, options)
116
+
117
+ # If pseudo-translating, prepend / append marker text
118
+ if Translator.pseudo_translate? && !str.nil?
119
+ str = Translator.pseudo_prepend + str + Translator.pseudo_append
120
+ end
121
+
122
+ str
123
+ end
124
+
125
+ class << Translator
126
+
127
+ # Generic translate method that mimics <tt>I18n.translate</tt> (e.g. no automatic scoping) but includes locale fallback
128
+ # and strict mode behavior.
129
+ def translate(key, options={})
130
+ Translator.translate_with_scope([], key, options)
131
+ end
132
+
133
+ alias :t :translate
134
+ end
135
+
136
+ # When fallback mode is enabled if a key cannot be found in the set locale,
137
+ # it uses the default locale. So, for example, if an app is mostly localized
138
+ # to Spanish (:es), but a new page is added then Spanish users will continue
139
+ # to see mostly Spanish content but the English version (assuming the <tt>default_locale</tt> is :en)
140
+ # for the new page that has not yet been translated to Spanish.
141
+ def self.fallback(enable = true)
142
+ @@fallback_mode = enable
143
+ end
144
+
145
+ # If fallback mode is enabled
146
+ def self.fallback?
147
+ @@fallback_mode
148
+ end
149
+
150
+ # Toggle whether to true an exception on *all* +MissingTranslationData+ exceptions
151
+ # Useful during testing to ensure all keys are found.
152
+ # Passing +true+ enables strict mode, +false+ installs the default exception handler which
153
+ # does not raise on +MissingTranslationData+
154
+ def self.strict_mode(enable_strict = true)
155
+ @@strict_mode = enable_strict
156
+
157
+ if enable_strict
158
+ # Switch to using contributed exception handler
159
+ I18n.exception_handler = :strict_i18n_exception_handler
160
+ else
161
+ I18n.exception_handler = :default_exception_handler
162
+ end
163
+ end
164
+
165
+ # Get if it is in strict mode
166
+ def self.strict_mode?
167
+ @@strict_mode
168
+ end
169
+
170
+ # Toggle a pseudo-translation mode that will prepend / append special text
171
+ # to all fetched strings. This is useful during testing to view pages and visually
172
+ # confirm that strings have been fully extracted into locale bundles.
173
+ def self.pseudo_translate(enable = true)
174
+ @@pseudo_translate = enable
175
+ end
176
+
177
+ # If pseudo-translated is enabled
178
+ def self.pseudo_translate?
179
+ @@pseudo_translate
180
+ end
181
+
182
+ # Pseudo-translation text to prepend to fetched strings.
183
+ # Used as a visible marker. Default is "[["
184
+ def self.pseudo_prepend
185
+ @@pseudo_prepend
186
+ end
187
+
188
+ # Set the pseudo-translation text to prepend to fetched strings.
189
+ # Used as a visible marker.
190
+ def self.pseudo_prepend=(v)
191
+ @@pseudo_prepend = v
192
+ end
193
+
194
+ # Pseudo-translation text to append to fetched strings.
195
+ # Used as a visible marker. Default is "]]"
196
+ def self.pseudo_append
197
+ @@pseudo_append
198
+ end
199
+
200
+ # Set the pseudo-translation text to append to fetched strings.
201
+ # Used as a visible marker.
202
+ def self.pseudo_append=(v)
203
+ @@pseudo_append = v
204
+ end
205
+
206
+ # Additions to TestUnit to make testing i18n easier
207
+ module Assertions
208
+
209
+ # Assert that within the block there are no missing translation keys.
210
+ # This can be used in a more tailored way that the global +strict_mode+
211
+ #
212
+ # Example:
213
+ # assert_translated do
214
+ # str = "Test will fail for #{I18n.t('a_missing_key')}"
215
+ # end
216
+ #
217
+ def assert_translated(msg = nil, &block)
218
+
219
+ # Enable strict mode to force raising of MissingTranslationData
220
+ Translator.strict_mode(true)
221
+
222
+ msg ||= "Expected no missing translation keys"
223
+
224
+ begin
225
+ yield
226
+ # Credtit for running the assertion
227
+ assert(true, msg)
228
+ rescue I18n::MissingTranslationData => e
229
+ # Fail!
230
+ assert_block(build_message(msg, "Exception raised:\n?", e)) {false}
231
+ ensure
232
+ # uninstall strict exception handler
233
+ Translator.strict_mode(false)
234
+ end
235
+
236
+ end
237
+ end
238
+
239
+ module I18nExtensions
240
+ # Add an strict exception handler for testing that will raise all exceptions
241
+ def strict_i18n_exception_handler(exception, locale, key, options)
242
+ # Raise *all* exceptions
243
+ raise exception
244
+ end
245
+
246
+ end
247
+ end
248
+
249
+ module ActionView #:nodoc:
250
+ class Base
251
+ # Redefine the +translate+ method in ActionView (contributed by TranslationHelper) that is
252
+ # context-aware of what view (or partial) is being rendered.
253
+ # Initial scoping will be scoped to [:controller_name :view_name]
254
+ def translate_with_context(key, options={})
255
+ # The outer scope will typically be the controller name ("blog_posts")
256
+ # but can also be a dir of shared partials ("shared").
257
+ outer_scope = self.template.base_path.split('/')
258
+
259
+ # The template will be the view being rendered ("show.erb" or "_ad.erb")
260
+ inner_scope = self.template.name
261
+
262
+ # Partials template names start with underscore, which should be removed
263
+ inner_scope.sub!(/^_/, '')
264
+
265
+ # In the case of a missing translation, fall back to letting TranslationHelper
266
+ # put in span tag for a translation_missing.
267
+ begin
268
+ Translator.translate_with_scope([outer_scope, inner_scope].flatten, key, options.merge({:raise => true}))
269
+ rescue Translator::TranslatorError, I18n::MissingTranslationData => exc
270
+ # Call the original translate method
271
+ str = translate_without_context(key, options)
272
+
273
+ # View helper adds the translation missing span like:
274
+ # In strict mode, do not allow TranslationHelper to add "translation missing" span like:
275
+ # <span class="translation_missing">en, missing_string</span>
276
+ if str =~ /span class\=\"translation_missing\"/
277
+ # In strict mode, do not allow TranslationHelper to add "translation missing"
278
+ raise if Translator.strict_mode?
279
+
280
+ # Invoke callback if it is defined
281
+ Translator.missing_translation_callback(exc, key, options)
282
+ end
283
+
284
+ str
285
+ end
286
+ end
287
+
288
+ alias_method_chain :translate, :context
289
+ alias :t :translate
290
+ end
291
+ end
292
+
293
+ module ActionController #:nodoc:
294
+ class Base
295
+
296
+ # Add a +translate+ (or +t+) method to ActionController that is context-aware of what controller and action
297
+ # is being invoked. Initial scoping will be [:controller_name :action_name] when looking up keys. Example would be
298
+ # +['posts' 'show']+ for the +PostsController+ and +show+ action.
299
+ def translate_with_context(key, options={})
300
+ Translator.translate_with_scope([self.controller_path.split('/'), self.action_name].flatten, key, options)
301
+ end
302
+
303
+ alias_method_chain :translate, :context
304
+ alias :t :translate
305
+ end
306
+ end
307
+
308
+ module ActiveRecord #:nodoc:
309
+ class Base
310
+ # Add a +translate+ (or +t+) method to ActiveRecord that is context-aware of what model is being invoked.
311
+ # Initial scoping of [:model_name] where model name is like 'blog_post' (singular - *not* the table name)
312
+ def translate(key, options={})
313
+ Translator.translate_with_scope([self.class.name.underscore], key, options)
314
+ end
315
+
316
+ alias :t :translate
317
+
318
+ # Add translate as a class method as well so that it can be used in validate statements, etc.
319
+ class << Base
320
+
321
+ def translate(key, options={}) #:nodoc:
322
+ Translator.translate_with_scope([self.name.underscore], key, options)
323
+ end
324
+
325
+ alias :t :translate
326
+ end
327
+ end
328
+ end
329
+
330
+ module ActionMailer #:nodoc:
331
+ class Base
332
+
333
+ # Add a +translate+ (or +t+) method to ActionMailer that is context-aware of what mailer and action
334
+ # is being invoked. Initial scoping of [:mailer_name :action_name] where mailer_name is like 'comment_mailer'
335
+ # and action_name is 'comment_notification' (note: no "deliver_" or "create_")
336
+ def translate(key, options={})
337
+ Translator.translate_with_scope([self.mailer_name.split('/'), self.action_name].flatten, key, options)
338
+ end
339
+
340
+ alias :t :translate
341
+ end
342
+ end
343
+
344
+ module I18n
345
+ # Install the strict exception handler for testing
346
+ extend Translator::I18nExtensions
347
+ end
348
+
349
+ module Test # :nodoc: all
350
+ module Unit
351
+ class TestCase
352
+ include Translator::Assertions
353
+ end
354
+ end
355
+ end
356
+
357
+ # In test environment, enable strict exception handling for missing translations
358
+ if (defined? RAILS_ENV) && (RAILS_ENV == "test")
359
+ Translator.strict_mode(true)
360
+ end