Abusing Rails I18N to Set Page Titles
I got tired of @page_title variables being sprinkled around in controllers and views on Speaker Deck, so I made good use of Rails’ I18n API to define them all in one spot.
My config/locales/en.yml now looks something like this:
en: title: default: "Speaker Deck - Share Presentations without the Mess" account: new: "Sign Up" show: "My Account" categories: show: "%{category}" likes: index: "Presentations Liked by %{user}" passwords: index: "Password Reset" talks: index: "All Presentations" edit: "Edit %{talk}" new: "New Presentation" show: "%{talk}" users: show: "Talks by %{user}"
To make this work, add a #page_title helper method, which looks up the page title translation using the controller and action name.
module TitleHelper def page_title t page_title_translation_key, page_title_context.merge(:default => :"title.default") end def page_title_translation_key :"title.#{controller_name}.#{action_name}" end def page_title_context controller.view_assigns.symbolize_keys end end
The helper also passes all of the instance variables assigned in the controller, so you can use any of those variables in your page title. The only caveat is that we have to define #to_s in order for our model objects to show up properly in the title:
class User < ActiveRecord::Base def to_s username end end
Now in our layout, we can use our new helper:
<title><%= page_title %></title>
I’m really happy with how this little hack worked out. This almost seems like something that should be in Rails core. Maybe I’ll have to submit a pull request…
7 Comments
Great idea, I will definitely give it a try. Thanks!
Hello Brandon, I use a similar approach because, like you, I got tired of doing it :-P
A small note on page_title_translation_key, the key doesn’t need to be a symbol to work, you can use a simple string.
Saying this because you’re converting all these strings into symbols that will not get GC’ed.
As your application grows, more symbols will be allocated.
I know, premature optimization is the root of all evils, yada yada yada :-D
Luis: Good point. Fortunately it will be limited to the number of unique actions that the app has. Speaker Deck is a relatively small app, but it could be a problem with a ridiculously large app.
If you swap out
controller_nameforcontroller_path.gsub('/', '.')in #page_title_translation_key you can even make it work when you have duplicate controller names, for example asessionscontroller for bothusersandadminsVery nice approach, I see only one big problem: how do you manage those actions that render other views?
For example new and update, if there are errors they’d likely render ‘new’ / ‘edit’, instead of redirect to that page. So you would have to add 2 times every title for those pages (and duplication is bad, especially when you have to have to translate them!)
How have you solved this problem?
eric: That’s a good point, and not something that we are handling. It might make sense to have the helper alias some action names (create/update) to related actions (new/edit).
yeah, I came up with this:
def page_title_translation_key
aliases = {’create’ => ‘new’, ‘update’ => ’edit’}
“page_titles.#{controller_name}.#{aliases[action_name] || action_name}”
end
but it happens that some actions (especially single resources, like dashboard, invite, or other) has like a show (eg /invite) which post to create… if you’re going to pull a request for the rails core take care in consideration this too…
Post a Comment