splendeo_translator 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc ADDED
@@ -0,0 +1,163 @@
1
+ = SplendeoSplendeoTranslator - i18n tooling for Rails
2
+
3
+ SplendeoTranslator 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. SplendeoTranslator 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: SplendeoTranslator 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/splendeo/SplendeoTranslator.git
25
+
26
+ To install as a gem add the following to config/environment.rb:
27
+
28
+ config.gem "SplendeoTranslator"
29
+
30
+ == RDocs
31
+
32
+ {The RDocs are online}[http://splendeo.github.com/SplendeoTranslator/rdoc/index.html] or can be generated via <tt>rake rdoc</tt> in the SplendeoTranslator plugin directory.
33
+
34
+ == Problems or Suggestions
35
+
36
+ Please {file an issue in the Github bug tracker}[http://github.com/splendeo/SplendeoTranslator/issues/] or contact me.
37
+
38
+ == Simple +translate+ Everywhere
39
+
40
+ SplendeoTranslator 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, SplendeoTranslator 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 SplendeoTranslator 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
+ SplendeoTranslator 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
+ SplendeoTranslator.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 SplendeoTranslator 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
+
123
+ == Key fallback
124
+
125
+ Let's say that you don't want to have to extract your English strings. You can use them directly as strings for other languages:
126
+
127
+ # In the configuration
128
+ SplendeoTranslator.key_fallback(true)
129
+
130
+ # In your views/controllers
131
+ t('My Title in Plain English') will return 'My Title in Plain English' if no translation is found
132
+
133
+ # In your es.yml file, you will have to quote your plain-english keys:
134
+ 'My Title in Plain English': "Mi Título en Español"
135
+
136
+ == Testing Help
137
+
138
+ * <tt>SplendeoTranslator.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>SplendeoTranslator.strict_mode(false)</tt> (in test_helper for example).
139
+ * <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:
140
+
141
+ assert_translated do
142
+ # Will assert that all keys find valid translations inside the block
143
+ get :show
144
+ end
145
+
146
+ * If you're trying to avoid hard-coding strings in tests, you can still use the lookup that is added to models and controllers:
147
+
148
+ # Inside a test exercising a BlogPostController (@controller created in setup method)
149
+ get :show, :id => 123
150
+ # the byline should be in the body - uses @controller to make lookup easy (automatically knows controller name and action)
151
+ assert_match @controller.t('byline', :name => "Mike"), @response.body
152
+
153
+ * 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>SplendeoTranslator.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>SplendeoTranslator.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.
154
+
155
+ * 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>.
156
+
157
+ == Changelog
158
+
159
+ 1.0.0 - 4/17/2009 - Declaring 1.0 after successfully using SplendeoTranslator in production.
160
+
161
+ Bug reports welcome. {Patches very welcome}[http://github.com/splendeo/SplendeoTranslator].
162
+
163
+ Copyright (c) 2009 {Mike Champion}[http://splendeo.org], released under the MIT license.
data/Rakefile ADDED
@@ -0,0 +1,75 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ begin
5
+ require 'jeweler'
6
+ Jeweler::Tasks.new do |gemspec|
7
+ gemspec.name = "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"]
13
+ end
14
+ rescue LoadError
15
+ puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
16
+ end
17
+
18
+
19
+ # Use Hanna for pretty RDocs (if installed), otherwise normal rdocs
20
+ begin
21
+ require 'hanna/rdoctask'
22
+ rescue LoadError
23
+ require 'rake/rdoctask'
24
+ end
25
+
26
+ desc 'Default: run unit tests.'
27
+ task :default => :test
28
+
29
+ desc 'Test the translator plugin.'
30
+ Rake::TestTask.new(:test) do |t|
31
+ t.libs << 'lib'
32
+ t.libs << 'test'
33
+ t.pattern = 'test/**/*_test.rb'
34
+ t.verbose = true
35
+ end
36
+
37
+ desc 'Generate documentation for the translator plugin.'
38
+ Rake::RDocTask.new(:rdoc) do |rdoc|
39
+ rdoc.rdoc_dir = 'rdoc'
40
+ rdoc.title = 'Translator - i18n tooling for Rails'
41
+ rdoc.options << '--line-numbers' << '--inline-source' << '--webcvs=http://github.com/graysky/translator/tree/master/'
42
+ rdoc.rdoc_files.include('README.rdoc')
43
+ rdoc.rdoc_files.include('lib/**/*.rb')
44
+ end
45
+
46
+ desc "Publish rdocs to Github on special gh-pages branch. Assumes local branch gh-pages"
47
+ task :publish_rdoc do
48
+ # Build the rdocs
49
+ safe_system("rake rerdoc")
50
+ move("rdoc", "rdoc-tmp")
51
+
52
+ git("co gh-pages")
53
+ # Remove existing docs
54
+ git("rm -rf --quiet rdoc")
55
+ move("rdoc-tmp", "rdoc")
56
+ # Add new ones
57
+ git("add .")
58
+ # Push the changes
59
+ git("commit -a -m 'updating rdocs'")
60
+ git("push origin HEAD")
61
+
62
+ git("co master")
63
+ #system("open coverage/index.html") if PLATFORM['darwin']
64
+ end
65
+
66
+ def git(cmd)
67
+ safe_system("git " + cmd)
68
+ end
69
+
70
+ def safe_system(cmd)
71
+ if !system(cmd)
72
+ puts "Failed: #{cmd}"
73
+ exit
74
+ end
75
+ end
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 0
3
+ :patch: 0
4
+ :major: 1
@@ -0,0 +1,385 @@
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 SplendeoTranslator
7
+ # Error for use within SplendeoTranslator
8
+ class SplendeoTranslatorError < StandardError #:nodoc:
9
+ end
10
+
11
+ # SplendeoTranslator 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 show the raw key if the locale doesn't provide a translation
21
+ @@key_fallback_mode = false
22
+
23
+ # Whether to pseudo-translate all fetched strings
24
+ @@pseudo_translate = false
25
+
26
+ # Pseudo-translation text to prend to fetched strings.
27
+ # Used as a visible marker. Default is "["
28
+ @@pseudo_prepend = "["
29
+
30
+ # Pseudo-translation text to append to fetched strings.
31
+ # Used as a visible marker. Default is "]"
32
+ @@pseudo_append = "]"
33
+
34
+ # An optional callback to be notified when there are missing translations in views
35
+ @@missing_translation_callback = nil
36
+
37
+ # Invokes the missing translation callback, if it is defined
38
+ def self.missing_translation_callback(exception, key, options = {}) #:nodoc:
39
+ @@missing_translation_callback.call(exception, key, options) if !@@missing_translation_callback.nil?
40
+ end
41
+
42
+ # Set an optional block that gets called when there's a missing translation within a view.
43
+ # This can be used to log missing translations in production.
44
+ #
45
+ # Block takes two required parameters:
46
+ # - exception (original I18n::MissingTranslationData that was raised for the failed translation)
47
+ # - key (key that was missing)
48
+ # - options (hash of options sent to SplendeoTranslator)
49
+ # Example:
50
+ # set_missing_translation_callback do |ex, key, options|
51
+ # logger.info("Failed to find #{key}")
52
+ # end
53
+ def self.set_missing_translation_callback(&block)
54
+ @@missing_translation_callback = block
55
+ end
56
+
57
+ # Performs lookup with a given scope. The scope should be an array of strings or symbols
58
+ # ordered from highest to lowest scoping. For example, for a given PicturesController
59
+ # with an action "show" the scope should be ['pictures', 'show'] which happens automatically.
60
+ #
61
+ # The key and options parameters follow the same rules as the I18n library (they are passed through).
62
+ #
63
+ # The search order is from most specific scope to most general (and then using a default value, if provided).
64
+ # So continuing the previous example, if the key was "title" and options included :default => 'Some Picture'
65
+ # then it would continue searching until it found a value for:
66
+ # * pictures.show.title
67
+ # * pictures.title
68
+ # * title
69
+ # * use the default value (if provided)
70
+ #
71
+ # The key itself can contain a scope. For example, if there were a set of shared error messages within the
72
+ # Pictures controller, that could be found using a key like "errors.deleted_picture". The inital search with
73
+ # narrowest scope ('pictures.show.errors.deleted_picture') will not find a value, but the subsequent search with
74
+ # broader scope ('pictures.errors.deleted_picture') will find the string.
75
+ #
76
+ def self.translate_with_scope(scope, key, options={})
77
+ scope ||= [] # guard against nil scope
78
+
79
+ # Let Rails 2.3 handle keys starting with "."
80
+ raise SplendeoTranslatorError, "Skip keys with leading dot" if key.to_s.first == "."
81
+
82
+ # Keep the original options clean
83
+ original_scope = scope.dup
84
+ scoped_options = {}.merge(options)
85
+
86
+ # Raise to know if the key was found
87
+ scoped_options[:raise] = true
88
+
89
+ # Remove any default value when searching with scope
90
+ scoped_options.delete(:default)
91
+
92
+ str = nil # the string being looked for
93
+
94
+ # Loop through each scope until a string is found.
95
+ # Example: starts with scope of [:blog_posts :show] then tries scope [:blog_posts] then
96
+ # without any automatically added scope ("[]").
97
+ while str.nil?
98
+ # Set scope to use for search
99
+ scoped_options[:scope] = scope
100
+
101
+ begin
102
+ # try to find key within scope (dup the options because I18n modifies the hash)
103
+ str = I18n.translate(key, scoped_options.dup)
104
+ rescue I18n::MissingTranslationData => exc
105
+ # did not find the string, remove a layer of scoping.
106
+ # break when there are no more layers to remove (pop returns nil)
107
+ break if scope.pop.nil?
108
+ end
109
+ end
110
+
111
+ # return the key itself if translator is on key_fallback mode
112
+ str ||= key if SplendeoTranslator.key_fallback?
113
+
114
+ # If a string is not yet found, potentially check the default locale if in fallback mode.
115
+ if str.nil? && SplendeoTranslator.fallback? && (I18n.locale != I18n.default_locale) && options[:locale].nil?
116
+ # Recurse original request, but in the context of the default locale
117
+ str ||= SplendeoTranslator.translate_with_scope(original_scope, key, options.merge({:locale => I18n.default_locale}))
118
+ end
119
+
120
+ # If a string was still not found, fall back to trying original request (gets default behavior)
121
+ str ||= I18n.translate(key, options)
122
+
123
+ # If pseudo-translating, prepend / append marker text
124
+ if SplendeoTranslator.pseudo_translate? && !str.nil?
125
+ str = SplendeoTranslator.pseudo_prepend + str + SplendeoTranslator.pseudo_append
126
+ end
127
+
128
+ str
129
+ end
130
+
131
+ class << SplendeoTranslator
132
+
133
+ # Generic translate method that mimics <tt>I18n.translate</tt> (e.g. no automatic scoping) but includes locale fallback
134
+ # and strict mode behavior.
135
+ def translate(key, options={})
136
+ SplendeoTranslator.translate_with_scope([], key, options)
137
+ end
138
+
139
+ alias :t :translate
140
+ end
141
+
142
+ # When fallback mode is enabled if a key cannot be found in the set locale,
143
+ # it uses the default locale. So, for example, if an app is mostly localized
144
+ # to Spanish (:es), but a new page is added then Spanish users will continue
145
+ # to see mostly Spanish content but the English version (assuming the <tt>default_locale</tt> is :en)
146
+ # for the new page that has not yet been translated to Spanish.
147
+ def self.fallback(enable = true)
148
+ @@fallback_mode = enable
149
+ end
150
+
151
+ # If fallback mode is enabled
152
+ def self.fallback?
153
+ @@fallback_mode
154
+ end
155
+
156
+ # When key_fallback mode is enabled, if a key cannot be found in the set locale,
157
+ # it will return the key
158
+ def self.key_fallback(enable = true)
159
+ @@key_fallback_mode = enable
160
+ end
161
+
162
+ # If key_fallback mode is enabled
163
+ def self.key_fallback?
164
+ @@key_fallback_mode
165
+ end
166
+
167
+ # Toggle whether to true an exception on *all* +MissingTranslationData+ exceptions
168
+ # Useful during testing to ensure all keys are found.
169
+ # Passing +true+ enables strict mode, +false+ installs the default exception handler which
170
+ # does not raise on +MissingTranslationData+
171
+ def self.strict_mode(enable_strict = true)
172
+ @@strict_mode = enable_strict
173
+
174
+ if enable_strict
175
+ # Switch to using contributed exception handler
176
+ I18n.exception_handler = :strict_i18n_exception_handler
177
+ else
178
+ I18n.exception_handler = :default_exception_handler
179
+ end
180
+ end
181
+
182
+ # Get if it is in strict mode
183
+ def self.strict_mode?
184
+ @@strict_mode
185
+ end
186
+
187
+ # Toggle a pseudo-translation mode that will prepend / append special text
188
+ # to all fetched strings. This is useful during testing to view pages and visually
189
+ # confirm that strings have been fully extracted into locale bundles.
190
+ def self.pseudo_translate(enable = true)
191
+ @@pseudo_translate = enable
192
+ end
193
+
194
+ # If pseudo-translated is enabled
195
+ def self.pseudo_translate?
196
+ @@pseudo_translate
197
+ end
198
+
199
+ # Pseudo-translation text to prepend to fetched strings.
200
+ # Used as a visible marker. Default is "[["
201
+ def self.pseudo_prepend
202
+ @@pseudo_prepend
203
+ end
204
+
205
+ # Set the pseudo-translation text to prepend to fetched strings.
206
+ # Used as a visible marker.
207
+ def self.pseudo_prepend=(v)
208
+ @@pseudo_prepend = v
209
+ end
210
+
211
+ # Pseudo-translation text to append to fetched strings.
212
+ # Used as a visible marker. Default is "]]"
213
+ def self.pseudo_append
214
+ @@pseudo_append
215
+ end
216
+
217
+ # Set the pseudo-translation text to append to fetched strings.
218
+ # Used as a visible marker.
219
+ def self.pseudo_append=(v)
220
+ @@pseudo_append = v
221
+ end
222
+
223
+ # Additions to TestUnit to make testing i18n easier
224
+ module Assertions
225
+
226
+ # Assert that within the block there are no missing translation keys.
227
+ # This can be used in a more tailored way that the global +strict_mode+
228
+ #
229
+ # Example:
230
+ # assert_translated do
231
+ # str = "Test will fail for #{I18n.t('a_missing_key')}"
232
+ # end
233
+ #
234
+ def assert_translated(msg = nil, &block)
235
+
236
+ # Enable strict mode to force raising of MissingTranslationData
237
+ SplendeoTranslator.strict_mode(true)
238
+
239
+ msg ||= "Expected no missing translation keys"
240
+
241
+ begin
242
+ yield
243
+ # Credtit for running the assertion
244
+ assert(true, msg)
245
+ rescue I18n::MissingTranslationData => e
246
+ # Fail!
247
+ assert_block(build_message(msg, "Exception raised:\n?", e)) {false}
248
+ ensure
249
+ # uninstall strict exception handler
250
+ SplendeoTranslator.strict_mode(false)
251
+ end
252
+
253
+ end
254
+ end
255
+
256
+ module I18nExtensions
257
+ # Add an strict exception handler for testing that will raise all exceptions
258
+ def strict_i18n_exception_handler(exception, locale, key, options)
259
+ # Raise *all* exceptions
260
+ raise exception
261
+ end
262
+
263
+ end
264
+ end
265
+
266
+ module ActionView #:nodoc:
267
+ class Base
268
+ # Redefine the +translate+ method in ActionView (contributed by TranslationHelper) that is
269
+ # context-aware of what view (or partial) is being rendered.
270
+ # Initial scoping will be scoped to [:controller_name :view_name]
271
+ def translate_with_context(key, options={})
272
+ # default to an empty scope
273
+ scope = []
274
+
275
+ # Use the template for scoping if there is a templ
276
+ unless self.template.nil?
277
+ # The outer scope will typically be the controller name ("blog_posts")
278
+ # but can also be a dir of shared partials ("shared").
279
+ outer_scope = self.template.base_path
280
+
281
+ # The template will be the view being rendered ("show.erb" or "_ad.erb")
282
+ inner_scope = self.template.name
283
+
284
+ # Partials template names start with underscore, which should be removed
285
+ inner_scope.sub!(/^_/, '')
286
+
287
+ scope = [outer_scope, inner_scope]
288
+ end
289
+
290
+ # In the case of a missing translation, fall back to letting TranslationHelper
291
+ # put in span tag for a translation_missing.
292
+ begin
293
+ SplendeoTranslator.translate_with_scope(scope, key, options.merge({:raise => true}))
294
+ rescue SplendeoTranslator::SplendeoTranslatorError, I18n::MissingTranslationData => exc
295
+ # Call the original translate method
296
+ str = translate_without_context(key, options)
297
+
298
+ # View helper adds the translation missing span like:
299
+ # In strict mode, do not allow TranslationHelper to add "translation missing" span like:
300
+ # <span class="translation_missing">en, missing_string</span>
301
+ if str =~ /span class\=\"translation_missing\"/
302
+ # In strict mode, do not allow TranslationHelper to add "translation missing"
303
+ raise if SplendeoTranslator.strict_mode?
304
+
305
+ # Invoke callback if it is defined
306
+ SplendeoTranslator.missing_translation_callback(exc, key, options)
307
+ end
308
+
309
+ str
310
+ end
311
+ end
312
+
313
+ alias_method_chain :translate, :context
314
+ alias :t :translate
315
+ end
316
+ end
317
+
318
+ module ActionController #:nodoc:
319
+ class Base
320
+
321
+ # Add a +translate+ (or +t+) method to ActionController that is context-aware of what controller and action
322
+ # is being invoked. Initial scoping will be [:controller_name :action_name] when looking up keys. Example would be
323
+ # +['posts' 'show']+ for the +PostsController+ and +show+ action.
324
+ def translate_with_context(key, options={})
325
+ SplendeoTranslator.translate_with_scope([self.controller_name, self.action_name], key, options)
326
+ end
327
+
328
+ alias_method_chain :translate, :context
329
+ alias :t :translate
330
+ end
331
+ end
332
+
333
+ module ActiveRecord #:nodoc:
334
+ class Base
335
+ # Add a +translate+ (or +t+) method to ActiveRecord that is context-aware of what model is being invoked.
336
+ # Initial scoping of [:model_name] where model name is like 'blog_post' (singular - *not* the table name)
337
+ def translate(key, options={})
338
+ SplendeoTranslator.translate_with_scope([self.class.name.underscore], key, options)
339
+ end
340
+
341
+ alias :t :translate
342
+
343
+ # Add translate as a class method as well so that it can be used in validate statements, etc.
344
+ class << Base
345
+
346
+ def translate(key, options={}) #:nodoc:
347
+ SplendeoTranslator.translate_with_scope([self.name.underscore], key, options)
348
+ end
349
+
350
+ alias :t :translate
351
+ end
352
+ end
353
+ end
354
+
355
+ module ActionMailer #:nodoc:
356
+ class Base
357
+
358
+ # Add a +translate+ (or +t+) method to ActionMailer that is context-aware of what mailer and action
359
+ # is being invoked. Initial scoping of [:mailer_name :action_name] where mailer_name is like 'comment_mailer'
360
+ # and action_name is 'comment_notification' (note: no "deliver_" or "create_")
361
+ def translate(key, options={})
362
+ SplendeoTranslator.translate_with_scope([self.mailer_name, self.action_name], key, options)
363
+ end
364
+
365
+ alias :t :translate
366
+ end
367
+ end
368
+
369
+ module I18n
370
+ # Install the strict exception handler for testing
371
+ extend SplendeoTranslator::I18nExtensions
372
+ end
373
+
374
+ module Test # :nodoc: all
375
+ module Unit
376
+ class TestCase
377
+ include SplendeoTranslator::Assertions
378
+ end
379
+ end
380
+ end
381
+
382
+ # In test environment, enable strict exception handling for missing translations
383
+ if (defined? RAILS_ENV) && (RAILS_ENV == "test")
384
+ SplendeoTranslator.strict_mode(true)
385
+ end