<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>I18n on Marcello Barnaba</title>
    <link>https://sindro.me/tags/i18n/</link>
    <description>Recent content in I18n on Marcello Barnaba</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Wed, 14 Feb 2018 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://sindro.me/tags/i18n/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>A Shameless Translation Memory Importer for Pontoon</title>
      <link>https://sindro.me/posts/2018-02-14-translation-memory-pontoon/</link>
      <pubDate>Wed, 14 Feb 2018 00:00:00 +0000</pubDate>
      <guid>https://sindro.me/posts/2018-02-14-translation-memory-pontoon/</guid>
      <description>&lt;div class=&#34;retrospective&#34;&gt;&#xA;  &lt;span class=&#34;retrospective-icon&#34;&gt;&amp;#x1f50d;&lt;/span&gt;&#xA;  &lt;div class=&#34;retrospective-body&#34;&gt;&#xA;    &lt;em&gt;2026 retrospective&lt;/em&gt;&lt;br&gt;&#xA;    The repo at &lt;a href=&#34;https://github.com/ifad/translation-memory&#34; target=&#34;_blank&#34;&gt;github.com/ifad/translation-memory&lt;/a&gt; is still public, still has no README, and the Pontoon fork it talks to remains private. &lt;a href=&#34;https://github.com/mozilla/pontoon&#34; target=&#34;_blank&#34;&gt;Mozilla&amp;rsquo;s upstream&lt;/a&gt; is open and very much alive. Whether anyone at IFAD still runs Pontoon eight years on, I honestly don&amp;rsquo;t know — I built this for one project on my desk, not as a corporate workflow change. The hyphen-stripping regex did its job for the months I needed it. Then, presumably, the next Pontoon schema migration broke something. That&amp;rsquo;s what happens to integrations that talk to a database directly.&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;&lt;a href=&#34;http://www.ifad.org/&#34; target=&#34;_blank&#34;&gt;IFAD&lt;/a&gt; is a UN agency that operates in &lt;a href=&#34;https://www.ifad.org/en/web/operations/languages&#34; target=&#34;_blank&#34;&gt;English, French, Spanish, and Arabic&lt;/a&gt;. Every public-facing string in our Rails apps needs to exist in four languages, which means we have a translation team, which means we have a translation workflow, which on most projects involves a &lt;a href=&#34;https://en.wikipedia.org/wiki/Computer-assisted_translation&#34; target=&#34;_blank&#34;&gt;desktop CAT tool&lt;/a&gt;, files attached to emails, and translation memories shipped around as XML.&lt;/p&gt;&#xA;&lt;p&gt;That workflow does not survive a project I&amp;rsquo;m building right now. It&amp;rsquo;s a Rails web app on a tight schedule, the source strings change every week, and by the time a translator has finished a TM file and emailed it back the strings have already moved. I need translators and developers looking at the same database in real time. I pick &lt;a href=&#34;https://pontoon.mozilla.org/&#34; target=&#34;_blank&#34;&gt;Mozilla Pontoon&lt;/a&gt; — open-source, free, adaptable, written in Django, backed by Postgres — and stand it up for my project. The catch: there is a corpus of translations from the previous tool that I want to seed Pontoon with on day one, so the translators don&amp;rsquo;t start from a blank slate.&lt;/p&gt;&#xA;&lt;p&gt;Today I start a &lt;a href=&#34;https://github.com/ifad/translation-memory&#34; target=&#34;_blank&#34;&gt;translation-memory&lt;/a&gt; repo and write the first parser. The project is described, with all due engineering humility, as &lt;a href=&#34;https://github.com/ifad/translation-memory&#34; target=&#34;_blank&#34;&gt;&amp;ldquo;Parser for TMX, SDL/XLIFF and TXML files and shameless importer into Mozilla Pontoon&amp;rdquo;&lt;/a&gt;. The &amp;ldquo;shameless&amp;rdquo; part is doing a lot of work in that sentence.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Active Gibberish</title>
      <link>https://sindro.me/posts/2008-01-22-active-gibberish/</link>
      <pubDate>Tue, 22 Jan 2008 00:00:00 +0000</pubDate>
      <guid>https://sindro.me/posts/2008-01-22-active-gibberish/</guid>
      <description>&lt;div class=&#34;retrospective&#34;&gt;&#xA;  &lt;span class=&#34;retrospective-icon&#34;&gt;&amp;#x1f50d;&lt;/span&gt;&#xA;  &lt;div class=&#34;retrospective-body&#34;&gt;&#xA;    &lt;em&gt;2026 retrospective&lt;/em&gt;&lt;br&gt;&#xA;    The Gibberish plugin and this entire approach are long dead. Rails 2.2 (2008) added built-in I18n support, and since Rails 3 the standard way is &lt;code&gt;config/locales/*.yml&lt;/code&gt; with the &lt;code&gt;i18n&lt;/code&gt; gem. ActiveRecord error messages, field names, and all UI strings are handled natively — no plugins, no monkey-patching.&#xA;  &lt;/div&gt;&#xA;&lt;/div&gt;&#xA;&#xA;&lt;p&gt;&lt;strong&gt;UPDATE: you don’t need this code, because starting from the 2.2 version of Rails, localization support is built-in.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;localization-for-active-record-error-messages&#34; id=&#34;localization-for-active-record-error-messages&#34;&gt;Localization for Active Record error messages&lt;a class=&#34;heading-anchor&#34; href=&#34;#localization-for-active-record-error-messages&#34; aria-label=&#34;Link to this section&#34;&gt;¶&lt;/a&gt;&#xA;&lt;/h2&gt;&#xA;&lt;p&gt;Today I had to answer one of the questions every non-English Rails developer&#xA;stumbles upon sooner or later.. how to localize AR error messages for pleasant&#xA;appearance to a non-english customer ;).&lt;/p&gt;&#xA;&lt;p&gt;First off, thanks to &lt;a href=&#34;http://errtheblog.com&#34; target=&#34;_blank&#34;&gt;defunkt’s&lt;/a&gt; excellent gibberish&#xA;plugin and to the way AR validation errors are exposed, the task was&#xA;accomplished in an easy and clean manner, without messing too much with AR’s&#xA;internals.&lt;/p&gt;&#xA;&lt;p&gt;I started by translating every default AR error message, with this translation&#xA;file located in &lt;code&gt;lang/it.yml&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# Active Record errors&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;#&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_accepted&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;     &lt;span class=&#34;s2&#34;&gt;&amp;#34;deve essere accettato&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_not_a_number&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;non è un numero&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_blank&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;è un campo obbligatorio&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_empty&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;è un campo obbligatorio&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_inclusion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;non è nella lista dei valori validi&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_too_long&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;     &lt;span class=&#34;s2&#34;&gt;&amp;#34;è troppo lungo (massimo %d caratteri)&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_exclusion&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;è riservato&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_too_short&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;    &lt;span class=&#34;s2&#34;&gt;&amp;#34;è troppo corto (minimo %d caratteri)&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_invalid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;      &lt;span class=&#34;s2&#34;&gt;&amp;#34;non è valido&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_wrong_length&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;è errato, dovrebbe essere di %d caratteri&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_confirmation&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;non corrisponde&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_taken&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;        &lt;span class=&#34;s2&#34;&gt;&amp;#34;esiste già&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;# This one is not a default key, but I use it in my validations&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;ss&#34;&gt;ar_greater_zero&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;s2&#34;&gt;&amp;#34;deve essere maggiore di zero&amp;#34;&lt;/span&gt; &#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;and four lines in &lt;code&gt;config/environment.rb&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-ruby&#34; data-lang=&#34;ruby&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;no&#34;&gt;Gibberish&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;current_language&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;ss&#34;&gt;:it&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;no&#34;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default_error_messages&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;no&#34;&gt;ActiveRecord&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;::&lt;/span&gt;&lt;span class=&#34;no&#34;&gt;Errors&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;default_error_messages&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;inject&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;({})&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;|&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;h&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;update&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;string&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;ar_&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;#{&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;si&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;s2&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;intern&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;# &amp;lt;em&amp;gt;Gibberish magic&amp;lt;/em&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;The first one simply sets Italian (:it) as the default language, the inject&#xA;builds a new &lt;code&gt;error_messages&lt;/code&gt; hash using Gibberish to translate the default ones.&#xA;I named every AR error key in my translation file with an “ar_” prefix, in&#xA;order to avoid possible future key clashes. Finally, AR array is overwritten&#xA;with the new one freshly built.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
