Iteration K2: Translating the Storefront

Now it’s time to begin providing the translated text. Let’s start with the layout, because it’s pretty visible. We replace any text that needs to be translated with calls to I18n.translate. Not only is this method conveniently aliased as I18n.t, but a helper named t is provided.

The parameter to the translate function is a unique dot-qualified name. We can choose any name we like, but if we use the t helper function provided, names that start with a dot will first be expanded using the name of the template. So, let’s do that:

  <nav class=​"side_nav"​>
 
  <div id=​"cart"​ class=​"carts"​>
 
 <%=​ render_if @cart && @cart.​line_items​.​any?​, @cart ​%>
  </div>
 
  <ul>
» <li><a href=​"/"​>​<%=​ t(​'.home'​) ​%>​</a></li>
» <li><a href=​"/questions"​>​<%=​ t(​'.questions'​) ​%>​</a></li>
» <li><a href=​"/news"​>​<%=​ t(​'.news'​) ​%>​</a></li>
» <li><a href=​"/contact"​>​<%=​ t(​'.contact'​) ​%>​</a></li>
  </ul>
 <%​ ​if​ session[​:user_id​] ​%>
  <nav class=​"logged_in_nav"​>
  <ul>
  <li>​<%=​ link_to ​'Orders'​, orders_path ​%>​</li>
  <li>​<%=​ link_to ​'Products'​, products_path ​%>​</li>
  <li>​<%=​ link_to ​'Users'​, users_path ​%>​</li>
  <li>​<%=​ button_to ​'Logout'​, logout_path, ​method: :delete​ ​%>​</li>
  </ul>
  </nav>
 <%​ ​end​ ​%>
 </nav>

Since this view is named layouts/application.html.erb, the English mappings will expand to en.layouts.application. Here’s the corresponding locale file:

 en:
 
  layouts:
  application:
  title: ​"​​The​ ​Pragmatic​ ​Bookshelf"
  home: ​"​​Home"
  questions: ​"​​Questions"
  news: ​"​​News"
  contact: ​"​​Contact"

Here it is in Spanish:

 es:
 
  layouts:
  application:
  title: ​"​​Biblioteca​ ​de​ ​Pragmatic"
  home: ​"​​Inicio"
  questions: ​"​​Preguntas"
  news: ​"​​Noticias"
  contact: ​"​​Contacto"

The format is YAML, the same as the one used to configure the databases. YAML consists of indented names and values, where the indentation in this case matches the structure that we created in our names.

To get Rails to recognize new YAML files, the server needs to be restarted.

Navigating to http://localhost:3000/es now will show some translated text, as shown in the screenshot.

images/s_4_es_works.png

Next to be updated is the main title as well as the Add to Cart button. Both can be found in the store index template:

 <%​ ​if​ notice ​%>
  <aside id=​"notice"​>​<%=​ notice ​%>​</aside>
 <%​ ​end​ ​%>
 
»<h1>​<%=​ t(​'.title_html'​) ​%>​</h1>
 
 <ul class=​"catalog"​>
 <%​ cache @products ​do​ ​%>
 <%​ @products.​each​ ​do​ |product| ​%>
 <%​ cache product ​do​ ​%>
  <li>
 <%=​ image_tag(product.​image_url​) ​%>
  <h2>​<%=​ product.​title​ ​%>​</h2>
  <p>
 <%=​ sanitize(product.​description​) ​%>
  </p>
  <div class=​"price"​>
 <%=​ number_to_currency(product.​price​) ​%>
»<%=​ button_to t(​'.add_html'​), line_items_path(​product_id: ​product),
 remote: ​​true​ ​%>
  </div>
  </li>
 <%​ ​end​ ​%>
 <%​ ​end​ ​%>
 <%​ ​end​ ​%>
 </ul>

And here’s the corresponding updates to the locales files, first in English:

 en:
 
  store:
  index:
  title_html: ​"​​Your​ ​Pragmatic​ ​Catalog"
  add_html: ​"​​Add​ ​to​ ​Cart"

And then in Spanish:

 es:
 
  store:
  index:
  title_html: ​"​​Su​ ​Cat&aacute;logo​ ​de​ ​Pragmatic"
  add_html: ​"​​A&ntilde;adir​ ​al​ ​Carrito"

Note that since title_html and add_html end in the characters _html, we’re free to use HTML entity names for characters that don’t appear on our keyboard. If we didn’t name the translation key this way, what you’d end up seeing on the page is the markup. This is yet another convention that Rails has adopted to make your coding life easier. Rails will also treat names that contain html as a component (in other words, the string .html.) as HTML key names.

By refreshing the page in the browser window, we see the results shown in the following screenshot.

images/s_5_more_es.png

Feeling confident, we move on to the cart partial, replacing text that needs translation as well as adding the locale to the new_order_path:

 <article>
 <%​ ​if​ notice ​%>
  <aside id=​"notice"​>​<%=​ notice ​%>​</aside>
 <%​ ​end​ ​%>
 
» <h2>​<%=​ t(​'.title'​) ​%>​</h2>
  <table>
 
 <%=​ render(cart.​line_items​) ​%>
  <tfoot>
  <tr>
  <th colspan=​"2"​>Total:</th>
  <td class=​"price"​>​<%=​ number_to_currency(cart.​total_price​) ​%>​</td>
  </tr>
  </tfoot>
  </table>
 
  <div class=​"actions"​>
»<%=​ button_to t(​'.empty'​), cart,
 method: :delete​,
 data: ​{ ​confirm: ​​'Are you sure?'​ } ​%>
 
 
»<%=​ button_to t(​'.checkout'​), new_order_path(​locale: ​I18n.​locale​),
 
 method: :get​,
 class: ​​"checkout"​​%>
  </div>
 </article>

And again, here are the translations:

 en:
 
  carts:
  cart:
  title: ​"​​Your​ ​Cart"
  empty: ​"​​Empty​ ​cart"
  checkout: ​"​​Checkout"
 es:
 
  carts:
  cart:
  title: ​"​​Carrito​ ​de​ ​la​ ​Compra"
  empty: ​"​​Vaciar​ ​Carrito"
  checkout: ​"​​Comprar"

Refreshing the page, we see the cart title and buttons have been translated, as shown in the following screenshot.

images/t_1_cart_translated_currency_in_english.png

We need to be careful here. The logic to render the cart is rendered in two places: first in the storefront and second in response to pushing the Añadir al Carrito (Add to Cart) button via Ajax. Sure enough, when we click that button, we see the cart rendered in English. To fix this, we need to pass the locale on the remote call:

  <div class=​"price"​>
 <%=​ number_to_currency(product.​price​) ​%>
 <%=​ button_to t(​'.add_html'​),
» line_items_path(​product_id: ​product, ​locale: ​I18n.​locale​),
 remote: ​​true​ ​%>
  </div>

We now notice our next problem. Languages are not the only thing that varies from locale to locale; currencies do too. And the customary way that numbers are presented varies too.

So first we check with our customer and we verify that we’re not worrying about exchange rates at the moment (whew!), because that’ll be taken care of by the credit card and/or wire companies, but we do need to display the string USD or $US after the value when we’re showing the result in Spanish.

Another variation is the way that numbers themselves are displayed. Decimal values are delimited by a comma, and separators for the thousands place are indicated by a dot.

Currency is a lot more complicated than it first appears, and there are a lot of decisions to be made. Fortunately, Rails knows to look in your translations file for this information; all we need to do is supply it. Here it is for en:

 en:
 
  number:
  currency:
  format:
  unit: ​"​​$"
  precision: ​2
  separator: ​"​​."
  delimiter: ​"​​,"
  format: ​"​​%u%n"

Here it is for es:

 es:
 
  number:
  currency:
  format:
  unit: ​"​​$US"
  precision: ​2
  separator: ​"​​,"
  delimiter: ​"​​."
  format: ​"​​%n&nbsp;%u"

We’ve specified the unit, precision, separator, and delimiter for number.currency.format. That much is pretty self-explanatory. The format is a bit more involved: %n is a placeholder for the number; &nbsp; is a nonbreaking space character, preventing this value from being split across multiple lines; and %u is a placeholder for the unit. See the following screenshot for the result.

images/t_1_cart_translated.png
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.217.108.11