Rails / I18n: default scope - ruby-on-rails

I'm using the default I18n module for Rails to translate my strings in views.
<%= t("registration.heading") %>
Now, when I'm in the registration-view, all my strings start with registration. I always have to write
<%= t("registration.heading.notice") %>
// or
<%= t(:heading, :scope => :registration) %>
It would be nice to define a default scope for that file (maybe even in the controller), so a call to t automatically adds the defined scope
// controller
set_i18n_default_scope :registration
// view
<%= t(:heading) %>
// --> looks in "registration.heading"
Is this possible?

If you organize your translations adding a view name, as in:
en:
registration:
index:
heading: "Registration heading"
then you may use this:
<%= t(".heading") %>
Notice that the first character is a dot.
You may read about it in Rails Internationalization (I18n) API Guide
If you have texts which are shared amongst numerous views, and you don't want to copy the same translation in each section for each view, you may use YAML references. They are nicely described on wikipedia: http://en.wikipedia.org/wiki/YAML#Repeated_nodes

It is possible. Check section 4.1.4 of the Rails i18n API
4.1.4 “Lazy” Lookup
Rails 2.3 implements a convenient way
to look up the locale inside views.
When you have the following
dictionary:
es: books:
index:
title: "Título"
you can look up the books.index.title value inside
app/views/books/index.html.erb
template like this (note the dot):
<%= t '.title' %>

Regarding Lazy Lookups:
Here's the general solution for this kind of problem
Common Problem: Where is Rails trying to look-up L10N / I18N Strings? - e.g. when doing Lazy Lookups
It's not easy to guess, because it's different for Views, Controllers, Models, Labels, Helpers, or Validations... etc... but...
It's easy to find out directly, using this:
http://www.unixgods.org/Rails/where_is_Rails_trying_to_lookup_L10N_strings.html
this helps figuring out what Rails thinks the current scope is (e.g. when using ".heading")
3 Simple Steps:
create a file ./config/initializers/i18n.rb , as described in the article above
put t('.heading') in your view
start "rails server" and look in the console output where Rails thinks the default location is for '.heading' for this view... e.g. what's the I18N-key
(4. then add the I18N string into the location identified by the key)
Works like a charm :-)

If you want to print out keys that I18n gem's lazy mode is looking for, you can add that in a i18n.rb file in your initializers folder:
module I18n
module Backend
class Simple
module Implementation
alias_method :lookup_orig, :lookup
# Give ability to check I18n looked up keys in lazy mode by setting env var I18N_DEBUG to true
#
def lookup(locale, key, scope = [], options = {})
puts "I18N keys: #{I18n.normalize_keys(locale, key, scope, options[:separator])}" if ENV['I18N_DEBUG']
lookup_orig(locale, key, scope, options)
end
end
end
end
end
(Gist: https://gist.github.com/capripot/6e6cf778ad2db0443280)
And then start your server like for instance:
I18N_DEBUG=true bundle exec rails server

Related

Link to corresponding path in other locale (rails)

I have a multi-lingual application in Ruby on Rails 4. For that I use the following domains:
Swedish: exempel.se
English: example.com
French: fr.example.com
Spanish: es.example.com
I want to be able to link to the corresponding path in another corresponding locale. For example if I am at www.exempel.se/denna-bloggpost I want to be able to easily link to (English/Spanish/French) to e.g. www.example.com/this-here-blog-post and es.example.com/este-posto-de-bloggo (sorry, can't speak Spanish :)).
I understand this is done with link_to 'Spanish', locale => :es but this gives me the url www.exempel.se/denna-bloggpost?locale=es which is not what I want. I expect to access es.example.com/esto-posto-de-bloggo
It seems like default_url_options has something to do with this but I can't make it work.
How do I solve this?
Edit (2017-03-30): I will also need this solution for hreflang in the section.
I am using the route_translator gem.
I have seen several solutions for this but they all include solutions with ?locale=en or are just to simplified (like, only working for one single controller). What I am hoping for is a solution that would do something like this:
<% I18n.available_locales.each |locale| do %>
<% I18n.t(this route e.g. /denna-bloggpost) #=> /este-posto-de-bloggo, /this-blog-post, /le-post-du-blog %>
<% end %>
You can use the locale-specific routes that route_translator generates for you. Run rake routes to see what these are. And then:
# Create links for every other locale
<% (I18n.available_locales - I18n.locale).each |locale| do %>
# Example URL helper here - replace with your own!
<%= Rails.application.routes.url_helpers.send("posts_#{locale}_url",
'denna-bloggpost') %>
<% end %>
In order to create such a dynamic mapping, you must presumably have something like this defined in your application config:
APP_CONFIG = {
# ...
base_urls: {
se: 'exempel.se',
en: 'example.com',
fr: 'fr.example.com',
es: 'es.example.com'
}
# ...
}
(It wouldn't necessarily need to be in this format, of course; this is just an example.)
In the locale switching menu, you can then define your links like this:
link_to("French", "#{APP_CONFIG[:base_urls][:fr]}#{request.env['PATH_INFO']}")
In order to actually set the locale in your application, you could then place something like this in your ApplicationController:
class ApplicationController
before_action :set_locale
def set_locale
I18n.locale = APP_CONFIG[:base_urls].key(request.host) || I18n.default_locale
end
end
For more information, see here: http://guides.rubyonrails.org/i18n.html#managing-the-locale-across-requests
This question is addressed a number of times and many ways. Yet the simplest approach in my opinion is
<%= link_to "ру", request.params.merge( locale: 'ru' ) %>

Accessing Views Within Ruby on Rails Application

I want to make a view for my website coded in RoR wherein all the available path are listed as links. Is there any way to access the views for various models from the program?
For example, something like:
<%model.views.each do |v| %>
<%= link_to v %>
<% end %>
You could use the sitemap_generator or dynamic_sitemaps gem to generate Sitemaps for your application.
You can use named routes, which allows you to create a link to a different part of your rails app, based on names you set in routes.rb. You can also include route parameters, too, which makes it easy to link to models.
In your routes.rb
get 'test_route/:id' => 'example#controller', as :test
In controllers/views:
link_to #example.name, test_path(id: #example.id)
Further reading on named routes
Im not sure why you want this :), but this will give you the routes
Rails.application.routes.routes
if you want to get all the paths as an array
Rails.application.routes.routes.collect {|r| r.path.spec.to_s }

Ruby on Rails: bbc-code and performance

I am using bb-code in a Rails application for postings and comments. At the moment, I have the following to put a post's content in a view:
<%= #post.content.bbcode_to_html.html_safe.gsub('<a', '<a rel="nofollow"') %>
What is the best way to convert the bb-code to html and add "nofollow" to all links?
Thanks!
The bb-ruby gem you are using allows for using custom BBCode translations passed as parameters to the bbcode_to_html method. However, if you really want ALL links to contain the rel="nofollow", I think your best bet is going to be monkey patching them gem itself. Based on the BBRuby source, you want to do this:
module BBRuby
##tags = ##tags.merge({
'Link' => [
/\[url=(.*?)\](.*?)\[\/url\]/mi,
'\2',
'Hyperlink to somewhere else',
'Maybe try looking on [url=http://google.com]Google[/url]?',
:link],
'Link (Implied)' => [
/\[url\](.*?)\[\/url\]/mi,
'\1',
'Hyperlink (implied)',
"Maybe try looking on [url]http://google.com[/url]",
:link],
'Link (Automatic)' => [
/(\A|\s)((https?:\/\/|www\.)[^\s<]+)/,
' \2',
'Hyperlink (automatic)',
'Maybe try looking on http://www.google.com',
:link]
})
end
This will rewrite the BBRuby translator to always include a nofollow attribute. I would put this in config/initializers with a descriptive filename such as bbruby_nofollow_monkeypatch.rb
As for the html_safe, I would leave that as is. As I understand it that is a preferred way of doing it and in my opinion it keeps your intent clear. The above monkey patch makes the line in your view more readable:
<%= #post.content.bbcode_to_html.html_safe %>

How best to DRY will_paginate options

I have 8 controllers using will_paginate to paginate their index pages. I'd like to override the defaults for "Previous" and "Next" on each without having to specify the same options 8 times. Is there a way to override the defaults only once (perhaps by subclassing will_paginate).
will_paginate uses I18n so you can just use that.
Given you use English as the default locale the following line should be present in application.rb:
config.i18n.default_locale = :en
you can then change the text of the pagination links by adding the following to config/locales/will_paginate.en.yml:
en:
will_paginate:
previous_label: "← go back"
next_label: "go forward →"
Alternatively you can add them to your default translations file: config/locales/en.yml
but I have found that it quickly becomes to large to handle.
Note: If you use another locale, for instance es, for this to work you need to at least replace the en: keys within the YAML files to es: and to be concise about naming your files,
use either config/locales/will_paginate.es.yml or config/locales/es.yml.
I'm assuming you're doing something like this in your controllers:
will_paginate #collection, :previous_label => '< go back', :next_label => 'go forward >'
Your problem is that you want to use these labels everywhere in your application, so it's pointless to repeat them. In that case, you could define a helper like this:
def paginate(collection, options = {})
defaults = {
:previous_label => '< go back',
:next_label => 'go forward >',
}
options = defaults.merge(options)
will_paginate collection, options
end
After that, calling paginate #collection in your views will use your defaults and still let you override them if necessary.
EDIT: suweller's response is definitely the better way to go in this case, especially considering it's approved by mislav, the plugin creator :). I'd completely forgotten about the translation file option. My solution could probably be useful in the general case, when the helper is not configurable in a similar way.

Implementing sanitize simple_format in rails 2.3.8

I have created an application that allows for users to input lots of different data (posts, comments, etc.). The simple_format is good for me for now I just want to protect against crazy stuff. I haven't used sanitize before and after reading some guides I am still a little confused on how to implement. Hoping I can get some direction here.
Let's say I am collecting #post.body. How do I remove any <div> tags or <script> tags that might be entered by the user? I am assuming that in the view it would look something like this:
<%= sanatize(simple_format #post.body) %>
...but where do I define what tags aren't allowed? In the Post model or in a sanitize_helper? What is the correct syntax here?
Here's the documentation link for the sanitize method in Rails 2.3.8. With that in mind you'll be able to define allowed tags in this way:
<%= sanitize(simple_format(#post.body), :tags => %w(p span strong)) %>
Note that you can define them also inside the Rails Initializer:
Rails::Initializer.run do |config|
config.action_view.sanitized_allowed_tags = 'table', 'tr', 'td'
end
I hope you find this helpful!

Resources