How can I send emails in Rails 3 using the recipient's locale?
How can I send mails in a mailer using the recipient's locale. I have the preferred locale for each user in the database. Notice this is different from the current locale (I18n.locale), as long as the current user doesn't have to be the recipient. So the difficult thing is to use the mailer in a different locale without changing I18n.lo开发者_如何转开发cale:
def new_follower(user, follower)
@follower = follower
@user = user
mail :to=>@user.email
end
Using I18n.locale = @user.profile.locale before mail :to=>... would solve the mailer issue, but would change the behaviour in the rest of the thread.
I believe the best way to do this is with the great method I18n.with_locale
, it allows you to temporarily change the I18n.locale
inside a block, you can use it like this:
def new_follower(user, follower)
@follower = follower
@user = user
I18n.with_locale(@user.profile.locale) do
mail to: @user.email
end
end
And it'll change the locale just to send the email, immediately changing back after the block ends.
Source: http://www.rubydoc.info/docs/rails/2.3.8/I18n.with_locale
This answer was a dirty hack that ignored I18n's with_locale
method, which is in another answer. The original answer (which works but you shouldn't use it) is below.
Quick and dirty:
class SystemMailer < ActionMailer::Base
def new_follower(user, follower)
@follower = follower
@user = user
using_locale(@user.profile.locale){mail(:to=>@user.email)}
end
protected
def using_locale(locale, &block)
original_locale = I18n.locale
I18n.locale = locale
return_value = yield
I18n.locale = original_locale
return_value
end
end
in the most resent version of rails at this time it's sufficient to use "I18n.locale = account.locale" in the controller and make multiple views with the following naming strategy welcome.html.erb, welcome.it.html.erb and e.g. welcome.fr.html.erb
None of the above is really working since the version 3 to translate both subject and content and be sure that the locale is reseted back to the original one... so I did the following (all mailer inherit from that class:
class ResourceMailer < ActionMailer::Base
def mail(headers={}, &block)
I18n.locale = mail_locale
super
ensure
reset_locale
end
def i18n_subject(options = {})
I18n.locale = mail_locale
mailer_scope = self.class.mailer_name.gsub('/', '.')
I18n.t(:subject, options.merge(:scope => [mailer_scope, action_name], :default => action_name.humanize))
ensure
reset_locale
end
def set_locale(locale)
@mail_locale = locale
end
protected
def mail_locale
@mail_locale || I18n.locale
end
def reset_locale
I18n.locale = I18n.default_locale
end
end
You just need to set the locale before you call the mail() method:
set_locale @user.locale
You can use the i18n_subject method which scope the current path so everything is structured:
mail(:subject => i18n_subject(:name => @user.name)
This simple plugin was developed for rails 2 but seems to work in rails 3 too.
http://github.com/Bertg/i18n_action_mailer
With it you can do the following:
def new_follower(user, follower)
@follower = follower
@user = user
set_locale user.locale
mail :to => @user.email, :subject => t(:new_follower_subject)
end
The subject and mail templates are then translated using the user's locale.
Here's an updated version that also supports the '.key' short-hand notation, so you don't have to spell out each key in its entirety.
http://github.com/larspind/i18n_action_mailer
The problem with the mentioned plugins are that they don't work in all situations, for example doing User.human_name or User.human_attribute_name(...) will not translate correctly. The following is the easiest and guaranteed method to work:
stick this somewhere (in initializers or a plugin):
module I18nActionMailer def self.included(base) base.class_eval do include InstanceMethods alias_method_chain :create!, :locale end end module InstanceMethods def create_with_locale!(method_name, *parameters) original_locale = I18n.locale begin create_without_locale!(method_name, *parameters) ensure I18n.locale = original_locale end end end end ActionMailer::Base.send(:include, I18nActionMailer)
and then in your mailer class start your method by setting the desired locale, for example:
def welcome(user) I18n.locale = user.locale # etc. end
精彩评论