<?xml version="1.0" encoding="utf-8" standalone="yes"?><feed xmlns="http://www.w3.org/2005/Atom">
  <title></title>
  <subtitle></subtitle>
  <id>https://www.endpointdev.com/blog/tags/localization/</id>
  <link href="https://www.endpointdev.com/blog/tags/localization/"/>
  <link href="https://www.endpointdev.com/blog/tags/localization/" rel="self"/>
  <updated>2018-04-12T00:00:00+00:00</updated>
  <author>
    <name>End Point Dev</name>
  </author>
  
    <entry>
      <title>Ruby on Rails: Russian Translation and Pluralization</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2018/04/rails-russian-localization/"/>
      <id>https://www.endpointdev.com/blog/2018/04/rails-russian-localization/</id>
      <published>2018-04-12T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;img src=&#34;/blog/2018/04/rails-russian-localization/localization.jpg&#34; alt=&#34;Coding&#34; /&gt;
&lt;small&gt;[Photo by Matthew Henry of Burst](https://burst.shopify.com/photos/woman-codes)&lt;/small&gt;
&lt;h3 id=&#34;russian-is-hard&#34;&gt;Russian is Hard&lt;/h3&gt;
&lt;p&gt;Translation to Russian is tricky, and what’s even more tricky is coding logic to handle localization and pluralization of Russian (especially when you can’t read it). Here, I’ll explain some of the complexities and approaches I used for localization of a Ruby on Rails application.&lt;/p&gt;
&lt;h3 id=&#34;pluralization&#34;&gt;Pluralization&lt;/h3&gt;
&lt;p&gt;In general, Rails claims to have good localization and pluralization support, but I found that the support for handling more complex translations required customization. The first thing to note is that pluralization in Russian is not quite as simple as it is in English.&lt;/p&gt;
&lt;h5 id=&#34;english&#34;&gt;English&lt;/h5&gt;
&lt;p&gt;In English, we are familiar with pluralization of regular nouns to be appending an ‘s’ to the end of the noun (except for those nouns ending in ‘y’ and ‘o’). Pluralization is irregular in some cases, e.g. “octopus” becomes “octopi”, and Rails can handle some of these special cases for English but may not necessarily understand rules for other languages. See:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pry(main)&amp;gt; pluralize &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1 user&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pry(main)&amp;gt; pluralize &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;user&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2 users&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pry(main)&amp;gt; pluralize &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;octopus&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;1 octopus&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pry(main)&amp;gt; pluralize &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;octopus&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;=&amp;gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;2 octopi&amp;#34;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Wikipedia has a thorough explanation of English plurals &lt;a href=&#34;https://en.wikipedia.org/wiki/English_plurals&#34;&gt;here&lt;/a&gt; for anyone interested.&lt;/p&gt;
&lt;h5 id=&#34;russian&#34;&gt;Russian&lt;/h5&gt;
&lt;p&gt;Russian pluralization is more complex. In the most simplified terms (from my understanding), the mapping can boil down to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;where count is zero, word has one ending&lt;/li&gt;
&lt;li&gt;where count is one, word has another ending&lt;/li&gt;
&lt;li&gt;where count is 2–4, 22–24, 32–34, word has yet another ending&lt;/li&gt;
&lt;li&gt;where count is 5–20, 25–30, 35–40, …: word has yet another ending&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To accomplish this translation and pluralization in Rails, I implemented the following mapping found &lt;a href=&#34;https://stackoverflow.com/questions/6166064/i18n-pluralization&#34;&gt;here&lt;/a&gt;:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:ru&lt;/span&gt; =&amp;gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  { &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:i18n&lt;/span&gt; =&amp;gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    { &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:plural&lt;/span&gt; =&amp;gt;  
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      { &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:keys&lt;/span&gt; =&amp;gt; [&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:zero&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:one&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:few&lt;/span&gt;, &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:other&lt;/span&gt;],
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:rule&lt;/span&gt; =&amp;gt; &lt;span style=&#34;color:#038&#34;&gt;lambda&lt;/span&gt; { |n| 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; n == &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:zero&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;elsif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ( ( n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt; ) == &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;1&lt;/span&gt; ) &amp;amp;&amp;amp; ( ( n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt; != &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;11&lt;/span&gt; ) ) 
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888&#34;&gt;# 1, 21, 31, 41, 51, 61...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:one&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;elsif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ( [&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;2&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;3&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;4&lt;/span&gt;].include?(n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;) \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &amp;amp;&amp;amp; ![&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;13&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;14&lt;/span&gt;].include?(n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;) )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888&#34;&gt;# 2-4, 22-24, 32-34...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:few&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;elsif&lt;/span&gt; ( (n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;) == &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;0&lt;/span&gt; || \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ![&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;5&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;6&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;7&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;8&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;9&lt;/span&gt;].include?(n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;10&lt;/span&gt;) || \
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            ![&lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;11&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;12&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;13&lt;/span&gt;, &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;14&lt;/span&gt;].include?(n % &lt;span style=&#34;color:#00d;font-weight:bold&#34;&gt;100&lt;/span&gt;) )
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#888&#34;&gt;# 0, 5-20, 25-30, 35-40...&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;            &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:other&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        }
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      }   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    }   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  }   
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And here is what our locales looks like for translating the noun ‘user’:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;user:
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  zero: пользователей
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  one: пользователь
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  few: пользователя
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  other: пользователей&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The above mapping helps us solve the initial problem with pluralized translations, but wait, there’s more complexity ahead!&lt;/p&gt;
&lt;h3 id=&#34;contextual-changes-eg-nominative-vs-genitive&#34;&gt;Contextual Changes (e.g. Nominative vs. Genitive)&lt;/h3&gt;
&lt;p&gt;In addition to complexities with pluralization, I had to heavily rely on our &lt;a href=&#34;http://www.musicarussica.com/&#34;&gt;client&lt;/a&gt; to further differentiate &lt;a href=&#34;https://en.wikipedia.org/wiki/Declension&#34;&gt;noun declension&lt;/a&gt;. I’m not a linguist nor an English teacher, but my best explanation here is that there is a difference in noun endings if it is nominative vs. genitive. For example ‘Users’ vs. ‘List of Users’ uses the same pluralization of ‘user’ in English, but in Russian and many other languages, the context influences the word ending here.&lt;/p&gt;
&lt;p&gt;What does this mean for us? It means that simply calling &lt;code&gt;t(&#39;user&#39;, count: 1)&lt;/code&gt; or &lt;code&gt;t(&#39;user&#39;, count: 5)&lt;/code&gt; may not provide the correct localization and pluralization because the text in front of or behind the translation influences its declension. Therefore, we can’t just have the zero, one, few, and other mapping as shown in the above code example.&lt;/p&gt;
&lt;h3 id=&#34;enter-ruby-on-rails-rails-gems-admin--breadcrumbs&#34;&gt;Enter Ruby on Rails, Rails gems (admin &amp;amp; breadcrumbs)&lt;/h3&gt;
&lt;p&gt;In our Ruby on Rails application, we use &lt;a href=&#34;https://github.com/sferik/rails_admin&#34;&gt;RailsAdmin&lt;/a&gt;, a gem to add admin functionality to our application. RailsAdmin, and other gems that we use, use generic formulas of translations based on the pluralization code.&lt;/p&gt;
&lt;p&gt;Examples of locales strings are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;List of %{model_label_plural}&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;%{model_label_plural}&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;New %{model_label}&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;Edit this %{model_label}&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;quot;%{model_label}&amp;quot;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These formulas work fine for English, but they are too simplified for the contextual changes that I previously described.&lt;/p&gt;
&lt;p&gt;Because RailsAdmin is a gem, that means I can override specific elements of it to accommodate Russian, and here’s a short list of how we accomplished this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Retrieved a &lt;a href=&#34;https://gist.github.com/sergey-alekseev/ba3c1d549e28a6721dee&#34;&gt;rails_admin.ru.yml&lt;/a&gt; as a starting point.&lt;/li&gt;
&lt;li&gt;In some cases, removed model_label or model_label_plural entirely from some translations to make more generic messages, e.g. instead of “User successfully saved”, we use some equivalent of “Successful.”&lt;/li&gt;
&lt;li&gt;Added code to override RailsAdmin helper methods used in various parts of RailsAdmin navigation and text rendering.&lt;/li&gt;
&lt;li&gt;Copy views from RailsAdmin source and override entirely to use custom translation mapping in the form of discrete strings.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;hindsight-is-2020&#34;&gt;Hindsight is 20/20&lt;/h3&gt;
&lt;p&gt;When I started working on localization here, I was trying to work within the constraints of the gem and the formulas it used, but I ultimately had to resort to custom overrides of various helper methods and views. While this is not the method I prefer to work with a gem (making the upgrade path more complicated), I felt that this was the best way to handle localization &amp;amp; pluralization, &lt;em&gt;and&lt;/em&gt; allow our client to override these discrete strings in a custom_admin locale file. Unfortunately, I could not find existing support for Rails 5.0 and our gems to handle the localization that I needed, so I would likely approach it similarly in the future.&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;http://www.musicarussica.com/&#34;&gt;Musica Russica&lt;/a&gt; is one of our Ruby on Rails ecommerce clients. The founder, Dr. Vladimir Morosan, was extremely helpful in completing the translation (and corresponding explanation to a software engineer) of a new Ruby on Rails 5.0 site.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Debugging Localization in Rails</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2013/04/debugging-localization-in-rails/"/>
      <id>https://www.endpointdev.com/blog/2013/04/debugging-localization-in-rails/</id>
      <published>2013-04-01T00:00:00+00:00</published>
      <author>
        <name>Mike Farmer</name>
      </author>
      <content type="html">
        &lt;p&gt;Rails offers a very extensive library for handling localization using &lt;a href=&#34;https://github.com/svenfuchs/rails-i18n&#34;&gt;the rails-i18n gem&lt;/a&gt;. If you’ve done any localization using Rails, you know that it can be difficult to keep track of every string on your web application that needs translation. During a recent project, I was looking for an easy way to visually see translation issues while browsing through the UI in our application.&lt;/p&gt;
&lt;h3 id=&#34;missing-translations&#34;&gt;Missing Translations&lt;/h3&gt;
&lt;p&gt;I’ve known for some time that when I was missing a translation for a given text that it would appear in the HTML with a special &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt; tag with the class &lt;code&gt;translation_missing&lt;/code&gt;. So in my global CSS I added the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;translation_missing&lt;/span&gt; { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;red&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;white&lt;/span&gt; &lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;!important&lt;/span&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now when I viewed any page where I had forgotten to add a translation to my en.yml file I could see the text marked in bright red. This served as a great reminder that I needed to add the translation.&lt;/p&gt;
&lt;p&gt;I’m an avid watcher of my rails log while I develop. I almost always have a terminal window right next to my browser that is tailing out the log so I can catch any weirdnesses that may crop up. One thing that I thought would be nice is if the log showed any translation issues on the page it was loading. After some research, I found that the &lt;a href=&#34;https://rubygems.org/gems/i18n&#34;&gt;I18n gem&lt;/a&gt; used by Rails doesn’t give you any obvious hooks for translation errors. There is, however, a section in the &lt;a href=&#34;http://guides.rubyonrails.org/i18n.html#using-different-exception-handlers&#34;&gt;Rails I18n Guide&lt;/a&gt; for adding custom exception handlers for translation issues and this is where I started with something like this in an initializer:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;module&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;I18n&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;just_raise_that_exception&lt;/span&gt;(*args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Rails&lt;/span&gt;.logger.debug args.join(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#04d;background-color:#fff0f0&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;raise&lt;/span&gt; args.first
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;I18n&lt;/span&gt;.exception_handler = &lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:just_raise_that_exception&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This got things started for me. After some small modifications to the logger line, I had the output that I wanted and to make things really stick out, I added some color using the &lt;a href=&#34;http://flori.github.com/term-ansicolor/&#34;&gt;term-ansicolor gem&lt;/a&gt; and came up with this:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;self&lt;/span&gt;.&lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;just_raise_that_exception&lt;/span&gt;(*args)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#038&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;term/ansicolor&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080&#34;&gt;include&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Term&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;ANSIColor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Rails&lt;/span&gt;.logger.debug red(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;--- I18n Missing Translation: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;args.inspect&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; ---&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;raise&lt;/span&gt; args.first
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id=&#34;i18n-fallbacks&#34;&gt;I18n Fallbacks&lt;/h3&gt;
&lt;p&gt;After using this solution for a while I ran into another issue. When I would change the locale in my app to something like es (Spanish) and look for translation issues, I was noticing some text that wasn’t being translated but it wasn’t being marked as red by my CSS. When I looked at the text further I noticed that it wasn’t even being surrounded by the &lt;code&gt;&amp;lt;span class=&amp;quot;translation_missing&amp;quot;&amp;gt;&lt;/code&gt; tag.&lt;/p&gt;
&lt;p&gt;As it turned out, I did have a translation for that text in English, but not in the language that was set to my current locale. The reason for this is what I18n refers to as Fallbacks. Fallbacks tell the I18n what alternate, or default, locale to “fall back&amp;quot; to if a translation isn’t available for the current locale. By default, the fallback locale is en. Since I had a translation for that text in my en.yml there was no indicator that I had “fallen back&amp;quot; even though it was obvious that there was a translation issue.&lt;/p&gt;
&lt;p&gt;Coming up with a way to be notified of fallbacks wasn’t nearly as simple as my initial solution. After a lot of googling and reading in StackOverflow, I found that perhaps the best solution was to &lt;a href=&#34;https://github.com/svenfuchs/i18n/blob/master/lib/i18n/backend/fallbacks.rb#L37&#34;&gt;override the translate method&lt;/a&gt; in the I18n gem. This sounds really scary, but it actually wasn’t too bad. Back in my initializer, I removed the solution that I had originally come up with and added the following:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;module&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;I18n::Backend&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;module&lt;/span&gt; &lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;Fallbacks&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# To liven things up a bit&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#038&#34;&gt;require&lt;/span&gt; &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;term/ansicolor&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080&#34;&gt;include&lt;/span&gt; &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Term&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;ANSIColor&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;translate&lt;/span&gt;(locale, key, options = {})
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;# First things first, if there is an option sent, decorate it and send it back.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; fallback_message(locale, key, &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;super&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; options[&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:fallback&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      default = extract_non_symbol_default!(options) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; options[&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:default&lt;/span&gt;]
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      options[&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:fallback&lt;/span&gt;] = &lt;span style=&#34;color:#080&#34;&gt;true&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;I18n&lt;/span&gt;.fallbacks[locale].each &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt; |fallback|
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080&#34;&gt;catch&lt;/span&gt;(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:exception&lt;/span&gt;) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;do&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888&#34;&gt;# Get the original translation&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          translation = &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;super&lt;/span&gt;(fallback, key, options)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888&#34;&gt;# return the translation if we didn&amp;#39;t need to fall back&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; translation &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; fallback == locale
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#888&#34;&gt;# return the decorated fallback message if we did actually fall back.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          result = fallback_message(locale, key, translation)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;          &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; result &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;unless&lt;/span&gt; result.nil?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;        &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      options.delete(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:fallback&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;super&lt;/span&gt;(locale, &lt;span style=&#34;color:#080&#34;&gt;nil&lt;/span&gt;, options.merge(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:default&lt;/span&gt; =&amp;gt; default)) &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; default
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#888&#34;&gt;# If we get here, then no translation was found.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Rails&lt;/span&gt;.logger.debug red(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;--- I18n Missing Translation: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;locale&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;key&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; ---&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080&#34;&gt;throw&lt;/span&gt;(&lt;span style=&#34;color:#a60;background-color:#fff0f0&#34;&gt;:exception&lt;/span&gt;, &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;I18n&lt;/span&gt;::&lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;MissingTranslation&lt;/span&gt;.new(locale, key, options))
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#888&#34;&gt;# Added this method to log the fallback and decorate the text with a &amp;lt;span&amp;gt; tag.&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;def&lt;/span&gt; &lt;span style=&#34;color:#06b;font-weight:bold&#34;&gt;fallback_message&lt;/span&gt;(locale, key, fallback_text)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#080&#34;&gt;nil&lt;/span&gt; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; fallback_text.nil?
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      keys = key.to_s.split(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;return&lt;/span&gt; fallback_text &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;if&lt;/span&gt; keys.first == &lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#39;platform_ui&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#036;font-weight:bold&#34;&gt;Rails&lt;/span&gt;.logger.debug yellow(&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;&amp;#34;--- I18n Fallback: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;locale&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt;::&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;key&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#d20;background-color:#fff0f0&#34;&gt; ---&amp;#34;&lt;/span&gt;)
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;      &lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;%(&amp;lt;span class=&amp;#34;translation_fallback&amp;#34; title=&amp;#34;translation missing: &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;locale&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;, &lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;key&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;&amp;#34;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;#{&lt;/span&gt;fallback_text&lt;span style=&#34;color:#33b;background-color:#fff0f0&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#2b2;background-color:#f0fff0&#34;&gt;&amp;lt;/span&amp;gt;)&lt;/span&gt;.html_safe
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;    &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;  &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;With this initializer in place, I added the following CSS to my global stylesheet:&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-css&#34; data-lang=&#34;css&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#b06;font-weight:bold&#34;&gt;translation_fallback&lt;/span&gt; { &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;background-color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;green&lt;/span&gt;; &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#080;font-weight:bold&#34;&gt;white&lt;/span&gt; &lt;span style=&#34;color:#c00;font-weight:bold&#34;&gt;!important&lt;/span&gt;; }&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now all missing translation errors and fallbacks were noticeable while browsing the UI and all translation issues were logged to my development log. Now obviously, I don’t want these things showing up in production so I wrapped the whole thing in a &lt;code&gt;if Rails.env.development?&lt;/code&gt; conditional. I could also think of times, like while working on implementing design, that I don’t really care about translation issues as well, so I added a flag for turning it off in development as well.&lt;/p&gt;
&lt;p&gt;You can see my entire solution on &lt;a href=&#34;https://gist.github.com/mikefarmer/5286140#file-debug_localization-rb&#34;&gt;a gist over at GitHub&lt;/a&gt;. It was suggested by a fellow colleague that I should turn this into a gem, but I didn’t see the need if all you had to do is copy and paste this initializer. If a gem is something you’d like to see this in, please let me know and I’ll consider packaging it up.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Spree vs. Magento: Feature List Revisited</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2010/07/spree-vs-magento-feature-list-revisited/"/>
      <id>https://www.endpointdev.com/blog/2010/07/spree-vs-magento-feature-list-revisited/</id>
      <published>2010-07-13T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;A little over a month ago, I wrote an article on &lt;a href=&#34;/blog/2010/06/spree-vs-magento-feature-list/&#34;&gt;Spree vs. Magento Features&lt;/a&gt;. Recently, a client asked me to describe the features mentioned in that article. I thought this was another great opportunity to expand on my response to the client. So, here I am, revisiting ecommerce features in Spree and Magento. The &lt;a href=&#34;/blog/2010/06/spree-vs-magento-feature-list/&#34;&gt;original article&lt;/a&gt; can be referenced to compare availability of these features in Spree and Magento.&lt;/p&gt;
&lt;h3 id=&#34;features-on-a-single-product-or-group-of-product&#34;&gt;Features on a Single Product or Group of Product&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Product reviews and/or ratings&lt;/strong&gt;: functionality to allow customers to review and rate products. See &lt;a href=&#34;https://www.backcountry.com/the-north-face-denali-fleece-jacket-mens#reviews&#34;&gt;a Backcountry.com product page&lt;/a&gt; for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product QnA&lt;/strong&gt;: functionality allow customers to ask and answer questions on products. See &lt;a href=&#34;https://www.backcountry.com/the-north-face-denali-fleece-jacket-mens#qanda&#34;&gt;a Backcountry.com product page&lt;/a&gt; for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product SEO (URL, title, meta data control)&lt;/strong&gt;: functionality to allow site administrators to manage product URLs, product page titles, and product meta data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Advanced/flexible taxonomy&lt;/strong&gt;: functionality to build a custom taxonomy / navigation structure for product browsing. For example, build multiple categories and subcategories with complex hierarchy. The taxonomy at &lt;a href=&#34;https://spreecommerce-demo.herokuapp.com/&#34;&gt;Spree’s demo&lt;/a&gt; includes two categories of brand and category and subcategories in each.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SEO for taxonomy pages&lt;/strong&gt;: functionality to allow site administrators to manage taxonomy URLs, taxonomy page titles, and taxonomy meta data.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configurable product search&lt;/strong&gt;: functionality to allow the developers and site administrators to adjust parameters used in search, such as products to show per page, and to show products with no on hand stock.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Bundled products for discount&lt;/strong&gt;: functionality to allow site administrators to create bundles or group products together and then apply a discount to the entire bundle. For example, product X, Y and Z purchased together will yield a $10.00 discount.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Recently viewed products&lt;/strong&gt;:  functionality to show customers products they recently visited. This can be displayed on other product pages or the navigation pages to aid in navigation back to those products if the user would like to revisit the products. See the image below for an example of this functionality in action at &lt;a href=&#34;https://www.papersource.com/&#34;&gt;Paper Source&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-0-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450761146669666&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-0.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 333px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Soft product support/downloads&lt;/strong&gt;: functionality to sell soft products such as mp3 or pdf files.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product comparison&lt;/strong&gt;: functionality to allow customers to compare multiple products, such as a comparison of price or technical features. See &lt;a href=&#34;http://www.backcountry.com/store/compare.html?chk_compare_TNF0115=1&amp;amp;chk_compare_TNF3203=1&amp;amp;chk_compare_TNF4034=1&#34;&gt;Backcountry.com&lt;/a&gt; for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upsell&lt;/strong&gt;: functionality to encourage the customer to purchase a similar product from a higher price point, or to purchase an add on, may or may not include the functionality to allow site administrators to manage the upsell products.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cross sell&lt;/strong&gt;: functionality to encourage the customer to purchase related items, may or may not include the functionality to allow site administrators to manage the cross sell products. See the image below for an example of this functionality at &lt;a href=&#34;http://www.backcountry.com/&#34;&gt;Backcountry.com&lt;/a&gt; after adding an item to the cart.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-1-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450630306818274&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-1.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 323px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Related items&lt;/strong&gt;: functionality to display related items on product pages, may or may not include the functionality to allow site administrators to manage the related products.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RSS feed of products&lt;/strong&gt;: functionality to produce a RSS feed with product detail releases. &lt;a href=&#34;https://www.steepandcheap.com/&#34;&gt;steepandcheap.com&lt;/a&gt; offers a RSS feed, however, they are unique in that they offer a one deal at a time business model, so the RSS feed contains a stream of products for sale. This may or may not include the functionality to allow site administrators to manage the RSS feed contents.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple images per product&lt;/strong&gt;: functionality to allow site administrators to upload multiple products per image. See &lt;a href=&#34;https://spreecommerce-demo.herokuapp.com/products/ruby-on-rails-baseball-jersey&#34;&gt;a Spree demo product&lt;/a&gt; for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product option selection (variants)&lt;/strong&gt;: functionality to allow site administrators to create and manage variants for products to offer multiple variants per product, such as variants by size and color. See &lt;a href=&#34;https://spreecommerce-demo.herokuapp.com/products/ruby-on-rails-baseball-jersey&#34;&gt;a Spree demo product&lt;/a&gt; for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Wish list&lt;/strong&gt;: functionality to allow customers to create product wish lists. See &lt;a href=&#34;https://www.amazon.com/wishlist&#34;&gt;Amazon.com&lt;/a&gt; for a description of their wish list functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Send product email to friend&lt;/strong&gt;: functionality to allow customers to send emails to their friend to visit a specific product.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Product tagging / search by tagging&lt;/strong&gt;: functionality to allow site administrators to assign tags to products for navigation or searching. See &lt;a href=&#34;http://www.citypass.com/blog/&#34;&gt;CityPass’s blog&lt;/a&gt; for an example of tag use in a content management system; in ecommerce context, the tags would navigate to a set of products instead of a set of blog articles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breadcrumbs&lt;/strong&gt;: functionality that renders the product navigation hierarchy on navigation and product pages to allow customers to navigate to previous pages visited. See &lt;a href=&#34;https://spreecommerce-demo.herokuapp.com/t/brand/rails&#34;&gt;a Spree demo navigation page&lt;/a&gt; for an example.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;cms-features&#34;&gt;CMS Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Blogging functionality&lt;/strong&gt;: functionality to allow site administrators to create, manage and display blog articles.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Static page management&lt;/strong&gt;: functionality to allow site administrators to create, manage, and display static pages such as “About Us”, “Information”.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Media management&lt;/strong&gt;: functionality to allow site administrators to create, manage, and display media such as images, video, audio. See the image below for an example of &lt;a href=&#34;https://www.wordpress.org&#34;&gt;WordPress’s&lt;/a&gt; dashboard for content management.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-2-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450626615883906&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-2.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 341px; height: 400px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Contact us form&lt;/strong&gt;: functionality to allow customers to submit a request for contact. See &lt;a href=&#34;/contact/&#34;&gt;End Point’s contact page&lt;/a&gt; for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Polls&lt;/strong&gt;: functionality to allow site administrators to create and manage basic polls, functionality to allow customers to submit answers to basic polls.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;checkout-support&#34;&gt;Checkout Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;One page checkout&lt;/strong&gt;: functionality to allow customers to complete checkout on one page, rather than move forward through checkout through multiple address, payment pages. See &lt;a href=&#34;https://www.papersource.com/&#34;&gt;Paper Source&lt;/a&gt; or &lt;a href=&#34;https://www.backcountry.com/&#34;&gt;Backcountry.com’s&lt;/a&gt; checkout processes for examples.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Guest checkout&lt;/strong&gt;: functionality to checkout without creating a user account. Checkout at the &lt;a href=&#34;https://spreecommerce-demo.herokuapp.com/&#34;&gt;Spree demo&lt;/a&gt; without being logged in for an example.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SSL support&lt;/strong&gt;: functionality to configure use of SSL during checkout. In Spree’s case, the site administrator may turn SSL off during development and on during production.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Discounts&lt;/strong&gt;: functionality to allow customers to apply discount coupons to orders for a percentage or dollar amount reduction.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Gift certificates&lt;/strong&gt;: functionality to allow customers to purchase and use gift certificates as credit for purchases.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saved shopping cart&lt;/strong&gt;: the functionality to save the products in a customers shopping cart so their shopping cart will be pre-populated on their next visit.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Saved addresses&lt;/strong&gt;: functionality to allow customers to create and manage addresses to be selected during checkout for billing or shipping rather than requiring the customer to re-enter their address. See the image below for an example of using saved addresses during &lt;a href=&#34;https://www.backcountry.com&#34;&gt;Backcountry.com’s&lt;/a&gt; checkout.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-3-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450765449179810&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-3.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 184px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3 id=&#34;shipping-support&#34;&gt;Shipping Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Real time rate lookup (UPS, USPS, FedEx)&lt;/strong&gt;: the functionality to request rates from UPS, USPS, or FedEx during checkout for more accurate rate pricing rather than using a flat shipping rate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Order tracking&lt;/strong&gt;: functionality to allow the site administrators to enter order tracking information and allow the user to review that tracking information, may or may not include sharing this information in a “Your order has been shipped” email.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple shipments per order&lt;/strong&gt;: functionality to allow site administrators to split orders into multiple packages if specific products can not be shipped at the same time or can not be shipped together. See the image below for an example of &lt;a href=&#34;https://www.spreecommerce.org/&#34;&gt;Spree’s&lt;/a&gt; backend shipping interface.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-4-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450647395677138&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-4.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 78px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Complex rate lookup&lt;/strong&gt;: functionality to calculate ship rates based on weight or price.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Free shipping&lt;/strong&gt;: functionality to offer free shipping.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;payment-support&#34;&gt;Payment Support&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multiple payment gateways&lt;/strong&gt;: integration of multiple payment gateways such as Authorize.NET, Beanstream, Paypal, SagePay, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorize.Net&lt;/strong&gt;: integration of the Authorize.Net payment gateway; may or may include the use of profiles (Authorize.Net CIM).&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authorize and capture versus authorize only&lt;/strong&gt;: functionality to allow site administrators to configure whether or not credit cards should be authorized only during checkout completion or authorized and captured. If the credit card is authorized only, site administrators may finalize an order by capturing on the backend interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Checkout&lt;/strong&gt;: integration of &lt;a href=&#34;https://googlecheckout.blogspot.com/&#34;&gt;Google Checkout&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Paypal Express&lt;/strong&gt;: integration of &lt;a href=&#34;https://www.paypal.com/us/webapps/mpp/paypal-checkout&#34;&gt;Paypal Express&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;admin-features&#34;&gt;Admin Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Sales reporting&lt;/strong&gt;: the functionality to display sales statistics, such as profits on sales or year-over-year sales.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sales management tools&lt;/strong&gt;: functionality to allow site administrators to create and manage product sales. For example, the site administrator might create a 50% off sale to cover 25% of the products to begin in a week and end in two weeks.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inventory management&lt;/strong&gt;: functionality to allow the site administrator to manage individual inventory units and their current state (on_hand, shipped, backordered) and order assignment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Purchase order management&lt;/strong&gt;: functionality to allow the site administrator to create and manage purchase orders. See the image below for an example of a potential backend interface for purchase orders in Spree.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-5-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450657470955906&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-5.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 71px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-tier pricing for quantity discounts&lt;/strong&gt;: functionality to allow customers to buy large quantities of products at a discount, the functionality to allow the site administrator to manage the large quantity product discounts.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Landing page tool&lt;/strong&gt;: functionality to create custom landing pages that may include targeted content or products, typically used for advertising or marketing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Batch import and export of products&lt;/strong&gt;: functionality to allow the site administrator to import and export products via admin interface or script rather than entering each product individually.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Multiple sales reports&lt;/strong&gt;: See “Sales reporting” above.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Order fulfillment&lt;/strong&gt;: functionality to allow site administrators to manage fulfillment (inventory selection, shipping) of orders.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Tax Rate Management&lt;/strong&gt;: functionality to manage tax rates per zone, where zones are defined by states and/or countries. Note that in Spree, zones can only be defined by a combination of states and countries and tax rates can be tied to one or more zones.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;user-account-features&#34;&gt;User Account Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;User addresses&lt;/strong&gt;: See “Saved addresses” above.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Feature rich user preferences&lt;/strong&gt;: integration of various user account tools, such as address management, profile management, order review, etc.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Order tracking history&lt;/strong&gt;: functionality to allow a customer to lookup their order history, may or may not include order tracking information.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;site-wide-features&#34;&gt;Site Wide Features&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;: functionality to extend the ecommerce core with modular components.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Appearance Theming&lt;/strong&gt;: functionality to change the appearance of the site.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Ability to customize appearance at category or browsing level&lt;/strong&gt;: functionality to create and manage custom and varied appearances for product browsing pages. For example, the categories &amp;ldquo;Jackets&amp;rdquo; and &amp;ldquo;Pants&amp;rdquo; may have different appearances, motivated by marketing or advertising.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Localization&lt;/strong&gt;: the functionality to translate the ecommerce site to a different language. See the image below for a small example of localization in action in Spree.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-6-big.png&#34; onblur=&#34;try {parent.deselectBloggerImageGracefully();} catch(e) {}&#34;&gt;&lt;img alt=&#34;&#34; border=&#34;0&#34; id=&#34;BLOGGER_PHOTO_ID_5493450639007292738&#34; src=&#34;/blog/2010/07/spree-vs-magento-feature-list-revisited/image-6.png&#34; style=&#34;display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 170px; height: 45px;&#34;/&gt;&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Multi-store, single admin support&lt;/strong&gt;: functionality to manage multiple stores from a single administrative location. An example of this might include &lt;a href=&#34;http://store1.endpoint.com/&#34;&gt;http://store1.endpoint.com/&lt;/a&gt;, and &lt;a href=&#34;http://store2.endpoint.com/&#34;&gt;http://store2.endpoint.com/&lt;/a&gt;, where both can be managed at &lt;a href=&#34;http://admin.endpoint.com/&#34;&gt;http://admin.endpoint.com/&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Support for multiple currencies&lt;/strong&gt;: functionality to translate product prices between currencies.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web service API&lt;/strong&gt;: functionality to retrieve data from the ecommerce application for third party use. See &lt;a href=&#34;https://guides.spreecommerce.org/api/&#34;&gt;Spree’s documentation&lt;/a&gt; on the Spree API.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;System wide SEO&lt;/strong&gt;: general site-wide SEO functionality including features such as sitemap, googlebase integration, URL management, page title management.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Google Analytics&lt;/strong&gt;: functionality to allow site administrators to create and manage Google Analytics Ids, functionality to track traffic and conversion on the frontend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Active community&lt;/strong&gt;: an active developer community with frequent core and extension contributions.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most of the features described above are well known to ecommerce developers, but this list might also serve as a good checklist to review with a potential client during the estimate process to make sure expectations of an ecommerce platform are managed, especially with a young platform such as Spree where some features are not yet included in the core.&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>PubCon Vegas Day 2: International and Mega Site SEO, and Tools for SEO</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2009/11/pubcon-vegas-day-2-international-and/"/>
      <id>https://www.endpointdev.com/blog/2009/11/pubcon-vegas-day-2-international-and/</id>
      <published>2009-11-12T00:00:00+00:00</published>
      <author>
        <name>Steph Skardal</name>
      </author>
      <content type="html">
        &lt;p&gt;On the second day of &lt;a href=&#34;https://www.pubcon.com/&#34;&gt;PubCon Vegas&lt;/a&gt;, I attended several SEO track sessions including “SEO for Ecommerce”, “International and European Site Optimization”, “Mega Site SEO”, and “SEO/SEM Tools”. A mini-summary of several of the sessions is presented below.&lt;/p&gt;
&lt;p&gt;Derrick Wheeler from Microsoft.com spoke on &lt;a href=&#34;https://www.pubcon.com/session-details?action=view&amp;amp;conference=pubcon85&amp;amp;record=116&#34;&gt;Mega Site SEO&lt;/a&gt; about “taming the beast”. Microsoft has 1.2 billion URLs that are comprised of thousands of web properties. For mega site SEO, Derrick highlighted:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Content is NOT king. Structure is! Content is like the princess-in-waiting after structure has been mastered.&lt;/li&gt;
&lt;li&gt;Developing an overall SEO approach and organization to getting structure, content, and authority SEO completed is more valuable or relevant to the actual SEO work. This was a common theme among many of the presentations at PubCon.&lt;/li&gt;
&lt;li&gt;Getting metrics set up at the beginning of SEO work is a very important step to measure and justify progress.&lt;/li&gt;
&lt;li&gt;Don’t be afraid to say no to low priority items.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most developers deal with a large amount of legacy code. Derrick discussed primary issues when working with legacy problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Duplicate and undesirable pages. For Microsoft.com, managing and dealing with 1.2 billion pages results in a lot of duplicate and undesirable pages from the past.&lt;/li&gt;
&lt;li&gt;Multiple redirects.&lt;/li&gt;
&lt;li&gt;Improper error handling (error handling on 404s or 500s).&lt;/li&gt;
&lt;li&gt;International URL structure can be a problem for international sites. Having an appropriate TLD (top level domain) is the best solution, but if that’s not possible, a process should be implemented to regulate the international urls.&lt;/li&gt;
&lt;li&gt;Low Quality Page Titles and Meta Tags. For large sites with hundreds of thousands of pages, it’s really important to have unique page titles and meta descriptions or to have a template that forces uniqueness.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In summary, &lt;strong&gt;structure&lt;/strong&gt; and &lt;strong&gt;internal processes&lt;/strong&gt; are areas to focus on for Mega Site SEO. Legacy problems are something to be aware of when you have a site so large where changes won’t be implemented as quickly as small site changes.&lt;/p&gt;
&lt;p&gt;In &lt;a href=&#34;https://www.pubcon.com/session-details?action=view&amp;amp;conference=pubcon85&amp;amp;record=172&#34;&gt;International and European Search Management&lt;/a&gt;, Michael Bonfils, Nelson James, and Andy Atkins-Krueger discussed international SEO and SEM tactics. Takeaways include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In terms of international search marketing, it’s important to incorporate culture into search optimization and marketing. If it works in one country, it may not work in another country and so don’t offend a culture by not understanding it. Some examples of content differences for targeting different cultures include emphasizing price points, focusing on product quality, and asserting authority or trust on a site.&lt;/li&gt;
&lt;li&gt;It’s also important to understand how linguistics affects your keyword marketing. Automatic translation should not be used (all the speakers mentioned this). A good example of linguistics and search targeting is the use of the search term “soccer cleats”, or “football boots”. In England, the term “football boot” has a very small portion of the traffic share, but singular terms in other languages (“scarpe de calcio”, “botas de futbal”) have a much larger percentage of the search market share. Andy shared many other examples of how direct translation would not be the best keywords to target (“car insurance”, “healthcare”, “30% off”, “cheap flights”).&lt;/li&gt;
&lt;li&gt;Local hosting is important for metrics, linking, and to develop trust. Nelson James shared research that shows that 80% of the top 10 results of the top 30 keywords in china had a ‘.cn’ top level domain, but the other top sites that were ‘.com’ sites are all hosted in china.&lt;/li&gt;
&lt;li&gt;Other technical areas for international search that were mentioned are using the meta language tag, pinyin, charset, and language set. Duplicate content also will become a problem across sites of the same language.&lt;/li&gt;
&lt;li&gt;It’s important to understand the search market share. In Russia, Google shares 35% of the search market and Yandexx has 54%. In China, Baidu has 76% and Google has 22%. There are some reasons that explain these market share differences. Yandexx was written to manage the large Russian vocabulary that Google does not handle as well. Baidu handles search for media better than Google and search traffic in China is much more entertainment driven rather than business driven in the US.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the last session of the day, about 100 tools were discussed in &lt;a href=&#34;https://www.pubcon.com/session-details?action=view&amp;amp;conference=pubcon85&amp;amp;record=210&#34;&gt;SEO/SEM Tools&lt;/a&gt;. I’m planning on writing another blog post with a summary of these tools, but here’s a short list of the tools mentioned by multiple speakers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SEMRush&lt;/li&gt;
&lt;li&gt;Google: Keyword Ad Tool, Webmaster Tools, Adplanner, SocialGraph API, Google Trends, Analytics, Google Insights&lt;/li&gt;
&lt;li&gt;SpyFu: Kombat, Domain Ad History, Smart Search, Keyword Ad History&lt;/li&gt;
&lt;li&gt;SEOBook&lt;/li&gt;
&lt;li&gt;SEOmoz: Linkscape, Mozbar, Top Pages, etc.&lt;/li&gt;
&lt;li&gt;MajesticSEO&lt;/li&gt;
&lt;li&gt;Raven SEO Tools: Website Analytics, Campaign Reports&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Stay tuned for a day 3 and wrap up article!&lt;/p&gt;

      </content>
    </entry>
  
    <entry>
      <title>Spree 0.4.0 Released</title>
      <link rel="alternate" href="https://www.endpointdev.com/blog/2008/10/spree-040-released/"/>
      <id>https://www.endpointdev.com/blog/2008/10/spree-040-released/</id>
      <published>2008-10-10T00:00:00+00:00</published>
      <author>
        <name>Sean Schofield</name>
      </author>
      <content type="html">
        &lt;p&gt;Spree 0.4.0 was officially released today. Spree is a complete open source ecommerce platform written for Ruby on Rails. While Spree technically works “out of the box” as a fully functional store, it is really intended to serve as a strong foundation for a custom commerce solution. Like Rails, Spree is considered to be &lt;a href=&#34;https://guides.spreecommerce.org/developer/about.html#opinionated-commerce&#34;&gt;“opinionated software”&lt;/a&gt;, and it does not seek to solve 100% of the commerce needs of all possible clients. Developers are able to provide the missing functionality by using the powerful &lt;a href=&#34;https://guides.spreecommerce.org/developer/extensions_tutorial.html&#34;&gt;extension system&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The current release of Spree contains many signficant improvements from the previous 0.2.0 release. Some of the highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rails 2.1 support&lt;/li&gt;
&lt;li&gt;SEO improvements&lt;/li&gt;
&lt;li&gt;Security enhancements&lt;/li&gt;
&lt;li&gt;Public assets for extensions&lt;/li&gt;
&lt;li&gt;Mailer templates for extensions&lt;/li&gt;
&lt;li&gt;VAT inclusive pricing&lt;/li&gt;
&lt;li&gt;Taxonomy&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Most open source projects in the Rails space are maintained by a single individual and tend to be limited in scope. For Spree we seek to create a large and healthy open source community similar to the ones found in more mature languages and frameworks. The Spree project has received contributions from over twenty different developers and has been translated into five additional languages.&lt;/p&gt;
&lt;p&gt;I created Spree in late 2007, and End Point later became an official sponsor of the Spree project and employs me and several other Spree contributors.&lt;/p&gt;

      </content>
    </entry>
  
</feed>
