<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Lost in Translation]]></title><description><![CDATA[Localisation tips & tricks]]></description><link>https://www.cornelia-schulz.net</link><generator>RSS for Node</generator><lastBuildDate>Fri, 27 Aug 2021 01:29:57 GMT</lastBuildDate><item><title><![CDATA[Localisation in Vue with i18next]]></title><description><![CDATA[Localisation in Vue with i18next Having worked a little with Vue recently, I came across i18next for localisation in Vue. I18next is an…]]></description><link>https://www.cornelia-schulz.net/2019-05-12-localisation-in-vue/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2019-05-12-localisation-in-vue/</guid><pubDate>Sun, 12 May 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;Localisation in Vue with i18next&lt;/h2&gt;
&lt;p&gt;Having worked a little with Vue recently, I came across i18next for localisation in Vue. I18next is an internationalisation-framework written in and for JavaScript. You can find some more info in their &lt;a href=&quot;https://www.i18next.com/&quot; title=&quot;documentation pages&quot;&gt;documentation pages&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;I was curious if it was easy to set up, so I added to a little practice project I have been working on. The repository I used can be found &lt;a href=&quot;https://github.com/cornelia-schulz/frontend-mentor-huddle-alternating-sections&quot; title=&quot;here&quot;&gt;here&lt;/a&gt; and the actual site is &lt;a href=&quot;https://hopeful-knuth-d5f28e.netlify.com/&quot; title=&quot;here&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To get started, set up a new project with &lt;code&gt;vue create app-name&lt;/code&gt;. Then use &lt;code&gt;npm install i18next @panter/vue-i18next&lt;/code&gt; or &lt;code&gt;yarn add i18next @panter/vue-i18next&lt;/code&gt; to add i18next to your Vue project. Next set up i18next in index.js:&lt;/p&gt;
&lt;p&gt;index.js
&lt;div id=&quot;gist96174422&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        &lt;div class=&quot;js-gist-file-update-container js-task-list-container file-box&quot;&gt;
  &lt;div id=&quot;file-index-js&quot; class=&quot;file my-2&quot;&gt;
    
  &lt;div itemprop=&quot;text&quot; class=&quot;Box-body p-0 blob-wrapper data type-javascript  &quot;&gt;

      
&lt;table class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;8&quot; data-paste-markdown-skip&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L1&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;import&lt;/span&gt; &lt;span class=pl-v&gt;Vue&lt;/span&gt; &lt;span class=pl-k&gt;from&lt;/span&gt; &lt;span class=pl-s&gt;&amp;#39;vue&amp;#39;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L2&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;import&lt;/span&gt; &lt;span class=pl-s1&gt;i18next&lt;/span&gt; &lt;span class=pl-k&gt;from&lt;/span&gt; &lt;span class=pl-s&gt;&amp;#39;i18next&amp;#39;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L3&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;import&lt;/span&gt; &lt;span class=pl-v&gt;VueI18Next&lt;/span&gt; &lt;span class=pl-k&gt;from&lt;/span&gt; &lt;span class=pl-s&gt;&amp;#39;@panter/vue-i18next&amp;#39;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L4&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;import&lt;/span&gt; &lt;span class=pl-v&gt;App&lt;/span&gt; &lt;span class=pl-k&gt;from&lt;/span&gt; &lt;span class=pl-s&gt;&amp;#39;./App.vue&amp;#39;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L5&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;import&lt;/span&gt; &lt;span class=pl-s1&gt;en&lt;/span&gt; &lt;span class=pl-k&gt;from&lt;/span&gt; &lt;span class=pl-s&gt;&amp;#39;./locales/en.json&amp;#39;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L6&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;6&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC6&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;import&lt;/span&gt; &lt;span class=pl-s1&gt;de&lt;/span&gt; &lt;span class=pl-k&gt;from&lt;/span&gt; &lt;span class=pl-s&gt;&amp;#39;./locales/de.json&amp;#39;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L7&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;7&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC7&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L8&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;8&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC8&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;const&lt;/span&gt; &lt;span class=pl-s1&gt;locales&lt;/span&gt; &lt;span class=pl-c1&gt;=&lt;/span&gt; &lt;span class=pl-kos&gt;{&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L9&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;9&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC9&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-c1&gt;en&lt;/span&gt;: &lt;span class=pl-s1&gt;en&lt;/span&gt;&lt;span class=pl-kos&gt;,&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L10&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;10&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC10&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-c1&gt;de&lt;/span&gt;: &lt;span class=pl-s1&gt;de&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L11&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;11&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC11&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L12&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;12&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC12&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L13&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;13&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC13&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-v&gt;Vue&lt;/span&gt;&lt;span class=pl-kos&gt;.&lt;/span&gt;&lt;span class=pl-en&gt;use&lt;/span&gt;&lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-v&gt;VueI18Next&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L14&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;14&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC14&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L15&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;15&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC15&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-s1&gt;i18next&lt;/span&gt;&lt;span class=pl-kos&gt;.&lt;/span&gt;&lt;span class=pl-en&gt;init&lt;/span&gt;&lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-kos&gt;{&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L16&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;16&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC16&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-c1&gt;lng&lt;/span&gt;: &lt;span class=pl-s&gt;&amp;#39;en&amp;#39;&lt;/span&gt;&lt;span class=pl-kos&gt;,&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L17&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;17&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC17&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-c1&gt;fallbackLng&lt;/span&gt;: &lt;span class=pl-s&gt;&amp;#39;en&amp;#39;&lt;/span&gt;&lt;span class=pl-kos&gt;,&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L18&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;18&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC18&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-c1&gt;resources&lt;/span&gt;: &lt;span class=pl-kos&gt;{&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L19&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;19&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC19&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=pl-c1&gt;en&lt;/span&gt;: &lt;span class=pl-kos&gt;{&lt;/span&gt; &lt;span class=pl-c1&gt;translation&lt;/span&gt;: &lt;span class=pl-s1&gt;locales&lt;/span&gt;&lt;span class=pl-kos&gt;.&lt;/span&gt;&lt;span class=pl-c1&gt;en&lt;/span&gt; &lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;span class=pl-kos&gt;,&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L20&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;20&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC20&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=pl-c1&gt;de&lt;/span&gt;: &lt;span class=pl-kos&gt;{&lt;/span&gt; &lt;span class=pl-c1&gt;translation&lt;/span&gt;: &lt;span class=pl-s1&gt;locales&lt;/span&gt;&lt;span class=pl-kos&gt;.&lt;/span&gt;&lt;span class=pl-c1&gt;de&lt;/span&gt; &lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L21&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;21&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC21&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L22&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;22&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC22&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L23&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;23&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC23&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L24&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;24&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC24&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;const&lt;/span&gt; &lt;span class=pl-s1&gt;i18n&lt;/span&gt; &lt;span class=pl-c1&gt;=&lt;/span&gt; &lt;span class=pl-k&gt;new&lt;/span&gt; &lt;span class=pl-v&gt;VueI18Next&lt;/span&gt;&lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-s1&gt;i18next&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L25&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;25&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC25&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;
&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L26&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;26&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC26&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-k&gt;if&lt;/span&gt; &lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-smi&gt;document&lt;/span&gt;&lt;span class=pl-kos&gt;.&lt;/span&gt;&lt;span class=pl-en&gt;getElementById&lt;/span&gt;&lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-s&gt;&amp;#39;app&amp;#39;&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt; &lt;span class=pl-kos&gt;{&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L27&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;27&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC27&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-c&gt;/* eslint-disable-next-line no-new */&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L28&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;28&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC28&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-k&gt;new&lt;/span&gt; &lt;span class=pl-v&gt;Vue&lt;/span&gt;&lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-kos&gt;{&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L29&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;29&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC29&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=pl-c1&gt;el&lt;/span&gt;: &lt;span class=pl-s&gt;&amp;#39;#app&amp;#39;&lt;/span&gt;&lt;span class=pl-kos&gt;,&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L30&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;30&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC30&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=pl-c1&gt;i18n&lt;/span&gt;: &lt;span class=pl-s1&gt;i18n&lt;/span&gt;&lt;span class=pl-kos&gt;,&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L31&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;31&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC31&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=pl-en&gt;render&lt;/span&gt;: &lt;span class=pl-s1&gt;h&lt;/span&gt; &lt;span class=pl-c1&gt;=&amp;gt;&lt;/span&gt; &lt;span class=pl-en&gt;h&lt;/span&gt;&lt;span class=pl-kos&gt;(&lt;/span&gt;&lt;span class=pl-v&gt;App&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L32&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;32&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC32&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;  &lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;span class=pl-kos&gt;)&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-index-js-L33&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;33&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-index-js-LC33&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&lt;span class=pl-kos&gt;}&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
&lt;/table&gt;


  &lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6/raw/73469a18603e089bdeb22357449ec68f797a295f/index.js&quot; style=&quot;float:right&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6#file-index-js&quot;&gt;index.js&lt;/a&gt;
        hosted with &amp;#10084; by &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Looking at the code in index.js above in detail, we are first importing i18next and @panter/vue-i18next, then we are using &lt;code&gt;i18next.init&lt;/code&gt; to initialise it and set the resources. In my example I set English as my source and fallback language and German as additional language. I decided to store my text in .json files in a &quot;locales&quot; folder. The folder contains one file per language. Both files contain the same keys with text in the corresponding language.&lt;/p&gt;
&lt;p&gt;en.json:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist96174422&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        &lt;div class=&quot;js-gist-file-update-container js-task-list-container file-box&quot;&gt;
  &lt;div id=&quot;file-en-json&quot; class=&quot;file my-2&quot;&gt;
    
  &lt;div itemprop=&quot;text&quot; class=&quot;Box-body p-0 blob-wrapper data type-json  &quot;&gt;

      
&lt;table class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;8&quot; data-paste-markdown-skip&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-en-json-L1&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-en-json-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;{&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-en-json-L2&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-en-json-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;message&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;hello&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-en-json-L3&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-en-json-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;tryitfree&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;Try it free&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-en-json-L4&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-en-json-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;readytobuild&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;Ready to build your community?&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-en-json-L5&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-en-json-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
      &lt;/tr&gt;
&lt;/table&gt;


  &lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6/raw/73469a18603e089bdeb22357449ec68f797a295f/en.json&quot; style=&quot;float:right&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6#file-en-json&quot;&gt;en.json&lt;/a&gt;
        hosted with &amp;#10084; by &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;And de.json:&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist96174422&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        &lt;div class=&quot;js-gist-file-update-container js-task-list-container file-box&quot;&gt;
  &lt;div id=&quot;file-de-json&quot; class=&quot;file my-2&quot;&gt;
    
  &lt;div itemprop=&quot;text&quot; class=&quot;Box-body p-0 blob-wrapper data type-json  &quot;&gt;

      
&lt;table class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;8&quot; data-paste-markdown-skip&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-de-json-L1&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-de-json-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;{&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-de-json-L2&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-de-json-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;message&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;hallo&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-de-json-L3&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-de-json-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;tryitfree&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;Probiere es kostenlos&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;,&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-de-json-L4&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;4&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-de-json-LC4&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;    &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;readytobuild&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;: &lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;Bist du bereit, deine Community aufzubauen?&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-de-json-L5&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;5&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-de-json-LC5&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;}&lt;/td&gt;
      &lt;/tr&gt;
&lt;/table&gt;


  &lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6/raw/73469a18603e089bdeb22357449ec68f797a295f/de.json&quot; style=&quot;float:right&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6#file-de-json&quot;&gt;de.json&lt;/a&gt;
        hosted with &amp;#10084; by &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Now that we set up i18next and initialised it, it is available globally in our project and we can use &lt;code&gt;$t&lt;/code&gt; in our various components to import our keys with their translations from the locale.json files into our components. And the great thing is you don&apos;t need to import anything else in the components, just use it.&lt;/p&gt;
&lt;p&gt;&lt;div id=&quot;gist96174422&quot; class=&quot;gist&quot;&gt;
    &lt;div class=&quot;gist-file&quot; translate=&quot;no&quot;&gt;
      &lt;div class=&quot;gist-data&quot;&gt;
        &lt;div class=&quot;js-gist-file-update-container js-task-list-container file-box&quot;&gt;
  &lt;div id=&quot;file-header-vue&quot; class=&quot;file my-2&quot;&gt;
    
  &lt;div itemprop=&quot;text&quot; class=&quot;Box-body p-0 blob-wrapper data type-vue  &quot;&gt;

      
&lt;table class=&quot;highlight tab-size js-file-line-container&quot; data-tab-size=&quot;8&quot; data-paste-markdown-skip&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-header-vue-L1&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;1&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-header-vue-LC1&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt; &lt;span class=&quot;pl-e&quot;&gt;class&lt;/span&gt;=&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;try&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-header-vue-L2&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;2&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-header-vue-LC2&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;   {{ &lt;span class=&quot;pl-en&quot;&gt;$t&lt;/span&gt;(&lt;span class=&quot;pl-s&quot;&gt;&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;tryitfree&lt;span class=&quot;pl-pds&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;) }}&lt;/td&gt;
      &lt;/tr&gt;
      &lt;tr&gt;
        &lt;td id=&quot;file-header-vue-L3&quot; class=&quot;blob-num js-line-number&quot; data-line-number=&quot;3&quot;&gt;&lt;/td&gt;
        &lt;td id=&quot;file-header-vue-LC3&quot; class=&quot;blob-code blob-code-inner js-file-line&quot;&gt;&amp;lt;/&lt;span class=&quot;pl-ent&quot;&gt;button&lt;/span&gt;&amp;gt;&lt;/td&gt;
      &lt;/tr&gt;
&lt;/table&gt;


  &lt;/div&gt;

  &lt;/div&gt;
&lt;/div&gt;

      &lt;/div&gt;
      &lt;div class=&quot;gist-meta&quot;&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6/raw/73469a18603e089bdeb22357449ec68f797a295f/Header.vue&quot; style=&quot;float:right&quot;&gt;view raw&lt;/a&gt;
        &lt;a href=&quot;https://gist.github.com/cornelia-schulz/8027717cd0a5e26df6d3bc0c8ddd57f6#file-header-vue&quot;&gt;Header.vue&lt;/a&gt;
        hosted with &amp;#10084; by &lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;&lt;/p&gt;
&lt;p&gt;Last but not least we should give the user an option to change the language using &lt;code&gt;i18next.changeLanguage&lt;/code&gt;. You can find more information about Panter i18next in &lt;a href=&quot;https://panter.github.io/vue-i18next/guide/started.html&quot; title=&quot;the documentation&quot;&gt;the documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The initial set up of the i18next plugin for Vue is very easy to implement. The documentation was straight forward and easy to follow. There are quite a few options that I haven&apos;t explored yet but certainly intend to in the near future. Have you used this plugin? What are your experiences?&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Localisation in WordPress]]></title><description><![CDATA[Localisation in WordPress Part 1 Recently I have been looking into how to work with WordPress and I was curious if it is easy to localise…]]></description><link>https://www.cornelia-schulz.net/2019-03-17-localisation-in-wordpress-part-1/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2019-03-17-localisation-in-wordpress-part-1/</guid><pubDate>Sun, 17 Mar 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Localisation in WordPress Part 1&lt;/h1&gt;
&lt;p&gt;Recently I have been looking into how to work with WordPress and I was curious if it is easy to localise your site once you have set up some content in it.&lt;/p&gt;
&lt;p&gt;In this blog post I&apos;m looking at how to localise the WordPress interface as well as content. If you are looking for information about how to prepare plugins for internationalisation, have a look at the &lt;a href=&quot;https://codex.WordPress.org/I18n_for_WordPress_Developers&quot; title=&quot;WordPress documenation&quot;&gt;WordPress documentation&lt;/a&gt;. I will not be covering this in this post.&lt;/p&gt;
&lt;p&gt;Localisation happens after internationalisation and is important for everyone who is interested in localising their WordPress site. It&apos;s the process during which your theme and content get translated and adapted for a specific market and language.&lt;/p&gt;
&lt;p&gt;There are two steps that you might be interested in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How to use a localised version of WordPress&lt;/li&gt;
&lt;li&gt;How to translate your content&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How to use a localised version of WordPress&lt;/h2&gt;
&lt;p&gt;If you haven&apos;t installed WordPress yet, simply head over to their site &lt;a href=&quot;https://WordPress.org/&quot; title=&quot;WordPress.org&quot;&gt;WordPress.org&lt;/a&gt; and download your localised version of WordPress and unzip it in your preferred installation directory. Normally that&apos;s public_html. Then create a database for WordPress on your web server and add a MySQL user with all the necessary privileges. Next edit the wp-config.php file and add your database information. Finally run the WordPress installation by accessing the URL in a web browser.&lt;/p&gt;
&lt;p&gt;If you already have WordPress installed and would like to change the language of the user interface, simply log into your dashboard, click on Settings &gt; General, then scroll down to the bottom of your page to Site Language and select the language of your choice from the dropdown.&lt;/p&gt;
&lt;p&gt;However, this will only change the language used in the backend of your WordPress site. All the content you have written as well as your theme and any plugins you use will remain in the language you set them up in. To translate content, you require a separate plugin.&lt;/p&gt;
&lt;h2&gt;Localisation Plugins&lt;/h2&gt;
&lt;h3&gt;WeGlot&lt;/h3&gt;
&lt;p&gt;There are a number of plugins out there. When I looked up plugins, I initially tried out &lt;a href=&quot;https://weglot.com/&quot; title=&quot;WeGlot&quot;&gt;WeGlot&lt;/a&gt;, which has a free version available to test the setup. It was very easy to set up and intuitive to use. Once you create an account with WeGlot, they will take you through the setup step by step.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/WeGlot-617c87ced45818c97ecb24716440f5bb.jpg&quot; alt=&quot;WeGlot Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;One drawback for me was that translations are edited in your WeGlot account rather than directly in WordPress.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/WeGlot1-6354df4218b1cc94d367684e6140a1eb.jpg&quot; alt=&quot;WeGlot Translations&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Polylang&lt;/h3&gt;
&lt;p&gt;A second plugin I tried was &lt;a href=&quot;https://en-au.wordpress.org/plugins/polylang/&quot; title=&quot;Polylang&quot;&gt;Polylang&lt;/a&gt;. The plugin was very easy to set up. Simply install it via the plugins section and activate it. Once installed, you can set up the langauges you would like to localise into.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/Polylang-5eaaae877e55100c07bf17ca6caaf24a.jpg&quot; alt=&quot;Polylang Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;Here it&apos;s important to set up your base language (which in my case was English UK) first. This is especially important if you already have some content in your site. Once you have your base language, you can then add any number of additional languages. Once you set up your languages, you can then easily add the translation of your posts and pages via the editor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/Polylang1-285c7afd3978d1326c3a21bce208e0ea.jpg&quot; alt=&quot;Polylang Translations&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Transposh&lt;/h3&gt;
&lt;p&gt;The third plugin I tried was &lt;a href=&quot;http://transposh.org/&quot; title=&quot;Transposh&quot;&gt;Transposh&lt;/a&gt;. It took me a little bit longer to set up but once it&apos;s set up, it&apos;s incredibly easy to use.&lt;/p&gt;
&lt;p&gt;To install the plugin, log into your dashboard, click on Plugins &gt; Add New and search for Transposh, then install and activate the plugin. Next click on Transposh and go to the settings to enable the full version of your plugin. To do that simply tick the box at the top of the Settings page and save your change.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/transposh1-36ccc23e7a096e5d7caa139a7da5e148.jpg&quot; alt=&quot;Transposh Settings&quot;&gt;&lt;/p&gt;
&lt;p&gt;To update, simply click on Dashboard and Update. This will notify you that there is a new update for your plugins. Click on Plugins and install the updated version of Transposh.&lt;/p&gt;
&lt;p&gt;Next go back to Transposh, click on Languages and click on the languages you would like to localise your site into. Don&apos;t forget to save to apply your changes. You can pre-translate into those languages by clicking on Utilities and selecting &quot;Translate All Now&quot;. Once you have done that, make sure to proofread those translations as they are machine translations and probably extremely rough. To proofread, we need to enable the widget on the site first. Go to Appearance on your Dashboard and select Widgets, then look for Transposh and select where on your page you would like to show the Widget.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/transposh2-f59b22b96aa8665cf8b93e8c767bfe96.jpg&quot; alt=&quot;Transposh Widget&quot;&gt;&lt;/p&gt;
&lt;p&gt;I added my widget to the footer. Once that&apos;s been added, you can then head over to your site and either add or edit the translations. Since I added the widget to the footer, I have to scroll all the way down to the footer and to find &quot;Edit translations&quot; with the flags for the languages I can update.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/transposh3-992cd681555b43e226e9cdbee0e25da9.jpg&quot; alt=&quot;Transposh Widget&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once I click on the language (flag) I want to update I will see a lot of colourful marks on the page which indicate what content can be changed.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/transposh4-1339269c47accfefd70d2f573c3176d9.jpg&quot; alt=&quot;Transposh Widget&quot;&gt;&lt;/p&gt;
&lt;p&gt;Simply click on what you would like to update or add and add your translations. There will most likely be some Google translated hints for you already.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/transposh5-886e4c8653a4f644c741a55e44bb12a2.jpg&quot; alt=&quot;Transposh Widget&quot;&gt;&lt;/p&gt;
&lt;p&gt;Once you are done, click on the tick to save the translation. If you would like to see how many translations have been added, you can do so in the Dashboard by clicking on Transposh and on Translation Editor.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/transposh6-19a014835a6d336192931e73959b38d9.jpg&quot; alt=&quot;Transposh Widget&quot;&gt;&lt;/p&gt;
&lt;p&gt;One thing you probably should check is who can add translations. Go into the Transposh settings and there right at the top you will see some check boxes. By default anybody can edit your translations, which is probably not what you want, so simply check the appropriate check boxes and then save your changes.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This is just a quick and simple overview on how to get started with localisation in WordPress. There are many more plugins out there. Some are free and some are paid. It&apos;s probably worth trying a few out and seeing which one suits your needs best. Have you done any localisation in WordPress? What was your experience? Let me know in the comments.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Software localisation into Arabic Part 2]]></title><description><![CDATA[Software localisation into Arabic Part 2 In my  last blog post  I talked about considerations about what language to choose when localising…]]></description><link>https://www.cornelia-schulz.net/2019-02-10-localisation-into-arabic-part-2/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2019-02-10-localisation-into-arabic-part-2/</guid><pubDate>Sun, 10 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Software localisation into Arabic Part 2&lt;/h1&gt;
&lt;p&gt;In my &lt;a href=&quot;https://www.cornelia-schulz.net/2019-02-08-localisation-into-arabic-part-1&quot; title=&quot;last blog post&quot;&gt;last blog post&lt;/a&gt; I talked about considerations about what language to choose when localising into Arabic. In this post I&apos;d like to talk more about some technical challenges when localising into Arabic.&lt;/p&gt;
&lt;p&gt;Arabic language interfaces present some particular challenges in relation to their visual design. Those challenges range from the obvious issue of the right to left (RTL) layout to other usability considerations related to images, icons and type font and size.&lt;/p&gt;
&lt;h2&gt;RTL&lt;/h2&gt;
&lt;p&gt;The Arabic writing system is bi-directional, cursive, and context dependent. Arabic text runs from right to left (RTL) but numbers and Latin text, such as global brand names are written from left to right (LTR). There are therefore mixed direction of text segments. So when building a search functionality, both Arabic and English text needs to be searchable. It could prove useful to accomodate common spelling mistakes in the search results.&lt;/p&gt;
&lt;p&gt;Because Arabic is written right to left, applications will be read from the top right-hand corner and elements on the page need to be aligned to the right-hand side. Research has shown that user behaviour on Arabic sites mirrors the F-shaped reading pattern that is typical of users on English speaking websites. Users start reading in the top right hand corner, scan across the top and then down the right-hand side.&lt;/p&gt;
&lt;p&gt;The BBC website is a very good example of the difference in layout between &lt;a href=&quot;https://www.bbc.com/&quot; title=&quot;BBC.com website in English&quot;&gt;English&lt;/a&gt; and &lt;a href=&quot;https://www.bbc.com/arabic&quot; title=&quot;BBC.com website in Arabic&quot;&gt;Arabic&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/BBC-screenshots-4416da6abcd378dac74918dceece3d6a.jpg&quot; alt=&quot;Screenshots of the BBC website in English and Arabic&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Images&lt;/h2&gt;
&lt;p&gt;Graphics and icons are also affected by text direction. However logos and icons are a good example of elements that keep their LTR alignment on an RTL website or application. International logos will often stay the same but icons that indicate a direction might change. Tables and charts are typically mirror-imaged horizontally.&lt;/p&gt;
&lt;p&gt;You should carefully consider the images you choose to use in your application and how your users will perceive them. Keep in mind the different cultural and social norms and how these norms affect the perception of images you use.&lt;/p&gt;
&lt;h2&gt;Font &amp;#x26; Text Size&lt;/h2&gt;
&lt;p&gt;Arabic characters are generally a bit shorter and wider than Latin characters. This means that they take up more space horizontally and they also need a bigger font size to be more readable. So take into account that you generally need at least 30% more space for Arabic text compared to English. You will probably find yourself resizing most dialog boxes in your content.&lt;/p&gt;
&lt;p&gt;Arabic script is always cursive, whether handwritten or printed. Because it is cursive, 22 of the letters can take four different shapes depending on their position in a word and the surrounding characters: initial, middle, final or isolated position. The graphic below from &lt;a href=&quot;http://arabicquick.com/learn-the-arabic-letter-ya/&quot; title=&quot;arabicquick.com&quot;&gt;arabicquick.com&lt;/a&gt; illustrates the different shapes of the letter ya depending on its position in a word.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/ya-fe58c591618cb87686520c7f929e8afa.png&quot; alt=&quot;Different shapes of the letter ya in Arabic&quot;&gt;&lt;/p&gt;
&lt;p&gt;Upper and lower case do not exist in Arabic. To emphasize or highlight words, use quotation marks. Abbreviations and acronyms are very rarely used. They should be translated in the full form they stand for (For example: RAM should be translated as ذاكرة الوصول العشوائي.&lt;/p&gt;
&lt;h2&gt;Numbers&lt;/h2&gt;
&lt;p&gt;Websites and software applications should support all Arabic regional standards, such as date/time/number/currency/address format and calendar information, as well as sorting and indexing rules. Arabic numerals can be written  in Hindi or Arabic digits.&lt;/p&gt;
&lt;h2&gt;Cultural considerations &amp;#x26; translation&lt;/h2&gt;
&lt;p&gt;Many Arabs are Muslims. When you create content, take cultural and religious sensitivity into account (especially in graphics and images). Translators may also have restrictions concerning the content of the material they’re willing to translate. Most Arab countries do not work on Fridays and Saturdays. Their work week begins therefore on Sundays.&lt;/p&gt;
&lt;p&gt;Terminology management is extremely important in the localisation process into Arabic. One of the first steps should involve solving the issue of terminology - a glossary should be created. Only experienced Arabic translators with an expert knowledge of the field can accurately create custom Arabic terms which will be understood by your target audience.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The demand for localising websites and apps into Arabic is increasing. Yet there are many challenges, both of technical and linguistic nature. While researching culture and established standards of web design and usability are a good starting point, you should consider doing user research with real end users in your target markets to create a usable product with a great user experience.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Software localisation into Arabic Part 1]]></title><description><![CDATA[Software localisation into Arabic Part 1 If you want to be successful online, you need to design for good user experience. That means if you…]]></description><link>https://www.cornelia-schulz.net/2019-02-08-localisation-into-arabic-part-1/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2019-02-08-localisation-into-arabic-part-1/</guid><pubDate>Fri, 08 Feb 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Software localisation into Arabic Part 1&lt;/h1&gt;
&lt;p&gt;If you want to be successful online, you need to design for good user experience. That means if you are creating a website for Arab users, you need to apply UX and usability considerations that are specific to your target audience in that region.&lt;/p&gt;
&lt;p&gt;A great user experience will make users return to your website or app. If the experience is poor, they simply won&apos;t.&lt;/p&gt;
&lt;p&gt;Arabic is the fifth most widely spoken language throughout the world. It&apos;s mostly spoken in the Middle East and North Africa. It is one of the oldest languages and is the official language in 26 countries. However, it is very under represented when it comes to the internet.&lt;/p&gt;
&lt;p&gt;The written word is always going to be the backbone of any website or application. When users find it difficult to understand the content of your website or app, they will become frustrated and dissatisfied.&lt;/p&gt;
&lt;p&gt;Arabic tends to be a more &apos;wordy&apos; language than English. Often certain English words or phrases cannot be translated into Arabic directly and they have to be described rather than translated word by word. This can lead to problems when there is only limited space available, e.g. on a mobile screen.&lt;/p&gt;
&lt;p&gt;It is also important to remember that there is no single form of Arab culture and language. There are three forms of Arabic: Classical or Qur’anic Arabic, Modern Standard Arabic and Spoken or Colloquial Arabic.&lt;/p&gt;
&lt;p&gt;Modern Standard Arabic derives from classical Arabic. It is the language that is taught in schools and universities and it is used in news media, literature, science and technology and for administrative purposes across North Africa and the Middle East. This language is a written language only and can be perceived as quite formal.&lt;/p&gt;
&lt;p&gt;If your website or application uses quite a formal tone overall, this might be the language to use for your translations. If on the other hand you are using a more chatty tone, then translation will be a lot harder because there are various forms of spoken Arabic. Some of these dialects are similar while others are mutually incomprehensible.&lt;/p&gt;
&lt;p&gt;Deciding on the form of Arabic you use will be influenced by a number of different factors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-- Are your target users based in a single country or are you targeting the whole region?&lt;/li&gt;
&lt;li&gt;-- Do you have the resources and capabilities to have your website or application cater to local dialects?&lt;/li&gt;
&lt;li&gt;-- What’s the tone of voice that you want your website or application to convey?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It’s important to fully understand who your target users are and then make your decisions accordingly.&lt;/p&gt;
&lt;p&gt;Have you had any experience localising into Arabic? Let me know in the comments.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Detecting user locales in JavaScript and React]]></title><description><![CDATA[Detecting user locales in JavaScript and React Detecting the location of your website’s users is useful for a variety of reasons. You might…]]></description><link>https://www.cornelia-schulz.net/2019-01-11-detecting-user-locales-in-javascript-and-react/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2019-01-11-detecting-user-locales-in-javascript-and-react/</guid><pubDate>Fri, 11 Jan 2019 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Detecting user locales in JavaScript and React&lt;/h1&gt;
&lt;p&gt;Detecting the location of your website’s users is useful for a variety of reasons. You might for instance want to display different content, perhaps in different languages for people from different countries, or display targeted information to visitors from different locations.&lt;/p&gt;
&lt;h2&gt;What is a user locale?&lt;/h2&gt;
&lt;p&gt;A user locale indicates which default settings a user wants to use to format dates, times, currency, and large numbers. The user locale is not the language. The only influence the user locale has on the language is on the names of the days and months. For example, if you use the long date format to display &quot;November 25, 2018,&quot; the &quot;November&quot; string will change based on the user locale. When the user locale gets changed, it adds an input locale with all the default settings for the associated language. Applications and websites should use these settings to present data to the user.&lt;/p&gt;
&lt;p&gt;There are different ways to detect a user locale:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-- Geo IP&lt;/li&gt;
&lt;li&gt;-- Accept-Language request header&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Geo IP refers to the method of locating a computer&apos;s geographic location by identifying its IP address. A lot of websites use Geo IP to guess the location users are visiting from. &lt;a href=&quot;https://www.iplocation.net/&quot; title=&quot;IP Location Finder&quot;&gt;IP Location Finder&lt;/a&gt; is an easy demo for information that can be gathered that way.&lt;/p&gt;
&lt;p&gt;This approach can be quite expensive to implement and it is not always accurate either. In today&apos;s world people travel a lot, which means their location doesn&apos;t necessarily represent their desired locale.&lt;/p&gt;
&lt;p&gt;The Accept-Language request HTTP header provides information about the languages that the user is able to understand and about what locale the user prefers. Browsers set this information based on their user interface language. Users are able to change this but they rarely do.&lt;/p&gt;
&lt;p&gt;Using the Accept-Language header is a good starting point for determining the language of the user. Originally the Accept-Language header was intended to specify a user&apos;s language. But because a lot of applications also need to know the locale of a user, Accept-Language has been used to determine this information.&lt;/p&gt;
&lt;p&gt;If you use Accept-Language to determine this information, you should give the user an option to override the language and cultural settings if they would like to do so. The information in Accept-Language header might might be out of the user&apos;s control if they are travelling and are using an internet cafe or they are borrowing a friend&apos;s computer for example.&lt;/p&gt;
&lt;p&gt;In React you can easily use the accept-language package. This package extracts user locales from HTTP headers and compares them to the ones you offer on your website. If none of the locales match, then the default locale of your website will be used.&lt;/p&gt;
&lt;p&gt;To use the package, install it with npm or yarn:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;npm install --save accept-language  npm install --save cookie-parser js-cookie
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next import the libraries in the server.js file and set it up as follows:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import cookieParser from &apos;cookie-parser&apos;;
import acceptLanguage from &apos;accept-language&apos;;

acceptLanguage.languages([&apos;en&apos;, &apos;de&apos;]);

const app = express();

app.use(cookieParser());

function detectLocale(req) {
  const cookieLocale = req.cookies.locale;

  return acceptLanguage.get(cookieLocale || req.headers[&apos;accept-language&apos;]) || &apos;en&apos;;
}
…

app.use((req, res) =&gt; {
  const locale = detectLocale(req);
  const componentHTML = ReactDom.renderToString(&amp;#x3C;App /&gt;);

  res.cookie(&apos;locale&apos;, locale, { maxAge: (new Date() * 0.001) + (365 * 24 * 3600) });
  return res.end(renderHTML(componentHTML));
});
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example both English and German are accepted locales. The detectLocale function looks first for a locale from a cookie and if there is none, it will fetch the information from the Accept-Language header. &lt;/p&gt;
&lt;p&gt;If you just need the user&apos;s preferred language, the &lt;a href=&quot;https://developer.mozilla.org/it/docs/Web/API/NavigatorLanguage/language&quot; title=&quot;window.navigator object&quot;&gt;window.navigator object&lt;/a&gt; contains a read-only property navigator.language that returns a string representing the preferred language of the user, which tends to be the language of the browser user interface.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;var lang = window.navigator.language
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;User locales are useful to answer questions such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;-- What numeric formats does the user expect?&lt;/li&gt;
&lt;li&gt;-- How should dates and times be formatted?&lt;/li&gt;
&lt;li&gt;-- What is the user&apos;s preferred language?&lt;/li&gt;
&lt;li&gt;-- What is the user&apos;s time zone?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are different ways to determine this information, however, none of them are 100% perfect. Whatever way you decide to implement your user locale detection, give the user an option to change it because people borrow from friends or use internet cafes and should be allowed to pick their own preferences.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Localisation and web accessibility]]></title><description><![CDATA[Localisation and web accessibility Web accessibility means that websites and tools are designed and developed so that anybody even if they…]]></description><link>https://www.cornelia-schulz.net/2018-12-29-localisation-and-web-accessibility/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-12-29-localisation-and-web-accessibility/</guid><pubDate>Sat, 29 Dec 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Localisation and web accessibility&lt;/h1&gt;
&lt;p&gt;Web accessibility means that websites and tools are designed and developed so that anybody even if they have any disabilities can use them. More specifically, people can perceive, understand, navigate, interact with  and contribute to the web. Web accessibility is also beneficial for people without disabilities.&lt;/p&gt;
&lt;p&gt;For example, a key principle of web accessibility is designing web sites and software that are flexible
enough to meet different user needs, preferences, and situations. Sometimes such flexibility
also benefits people using a slow internet connection or people with &quot;temporary disabilities&quot;, such as a broken arm, and people with changing abilities due to aging.&lt;/p&gt;
&lt;p&gt;Internationally, a number of initiatives such as Web Content Accessibility Guidelines (WCAG) have been implemented to develop guidelines for web accessibility to generate content that is usable by everybody.&lt;/p&gt;
&lt;p&gt;The WCAG guidelines aim for perceivability, understandability, operability and robustness. Here are some of the things that can be done to improve the accessibility of a website.&lt;/p&gt;
&lt;h2&gt;Perceivability&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Provide captions, text or other alternatives for non-text content.&lt;/li&gt;
&lt;li&gt;Create content that can be presented in different ways without losing meaning.&lt;/li&gt;
&lt;li&gt;Make it easier for users to see and hear content.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Understandability&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Make text readable and understandable.&lt;/li&gt;
&lt;li&gt;Make content appear and operate in predictable ways.&lt;/li&gt;
&lt;li&gt;Help users avoid and correct mistakes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Operability&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Make all functionality available from a keyboard.&lt;/li&gt;
&lt;li&gt;Make it easy to use inputs other than keyboard.&lt;/li&gt;
&lt;li&gt;Help users navigate and find content.&lt;/li&gt;
&lt;li&gt;Give users enough time to read and use content.&lt;/li&gt;
&lt;li&gt;Do not use content that causes seizures or physical reactions.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Robustness&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Content must be robust enough that it can be interpreted reliably by a wide variety tools, including assistive technologies.&lt;/li&gt;
&lt;li&gt;As technologies and tools evolve, the content should remain accessible at all times.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All these guidelines can be found with detailed descriptions on the &lt;a href=&quot;https://www.w3.org/WAI/WCAG21/quickref/#ensure-compat&quot; title=&quot;W3 website&quot;&gt;W3 website&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;How does localisation fit into the criterias mentioned above?&lt;/h1&gt;
&lt;h2&gt;Perceivable&lt;/h2&gt;
&lt;p&gt;Many websites provide an increasing amount of content that is not text-based, such as images, sound, video and interactive controls. These elements are not perceivable for every user and therefore a text alternative has to be provided. This text alternative can then be presented in a way that they can perceive, that is, auditory (text-to-speech), tactile (Braille) or visual (displayed on the screen) output. When localising accessible web content it is essential to not only to localise the original content, but also to pay special attention to localising the alternatives to that content.&lt;/p&gt;
&lt;p&gt;Another perception-related issue is the sequence of the content. If the sequence in which content is
presented to the user influences its meaning, then a correct reading sequence should be available to
screen readers. Reading sequences are not necessarily the same in all languages, so special attention should be paid to correctly localising the reading sequence.&lt;/p&gt;
&lt;p&gt;Some websites use background audio to present their content. WCAG recommends that a user has access to versions of speech content in which there is no background audio or the background audio can be turned off. If such content is present, localisation can add dubbed speech in the target language which should work as foreground audio and should be at least 20 decibles louder than the background audio if present.&lt;/p&gt;
&lt;h2&gt;Understandable&lt;/h2&gt;
&lt;p&gt;The key issues for localisation under the understandable principle are related to language identification,
unusual words, reading level, pronunciation, error management and help.&lt;/p&gt;
&lt;p&gt;It is important to identify the human language used on a website, so software can correctly handle
language changes and present information to the user. When the language is set correctly screen readers can present the content in that language and search engines will find pages in a user-defined language. During the localisation process the language of the page and language of parts should be clearly defined.&lt;/p&gt;
&lt;p&gt;Unusual words and abbreviations can make it difficult for the users to understand the web content and should be defined appropriately. Such unusual words, idioms and jargon should either be avoided or defined. Abbreviations or acronyms should have their meaning or expanded form. These should also be maintained in the localised content.&lt;/p&gt;
&lt;p&gt;Generally text should not require a more advanced reading ability than the lower secondary education level as defined in (UNESCO, 1997). If for some reason this is not possible, then the developers should provide an additional version of the text with lower reading ability requirements. This is an important requirement for people with reading difficulties. The reading level of the original content should be maintained during the localisation process.&lt;/p&gt;
&lt;p&gt;Labels, instructions and help related to interactive content, such as forms should be clear and precise. This
is a key issue for people with comprehension difficulties as well as screen reader users. Always indicate clearly which form elements are mandatory so that users know what needs to be completed. When localising interactive elements, special attention should be paid to making the localised labels, instructions and help
useful for the intended users.&lt;/p&gt;
&lt;p&gt;Web content should prevent errors, identify any mistakes made and, finally, make suggestions to help users to correct errors. When localising the error management content, care should be taken that the correct terminology and formatting of the target language and region are used.&lt;/p&gt;
&lt;h2&gt;Operable&lt;/h2&gt;
&lt;p&gt;The key issues for localisation under the operable principle are related to page titles, focus order, link purpose and headings.&lt;/p&gt;
&lt;p&gt;All web pages should be titled. Titles appear in the title bar of the web browser and also appear as the website name when storing bookmarks. When localising a page, special attention should be paid to the page title in order to maintain the information provided by the original version of the content.&lt;/p&gt;
&lt;p&gt;Focus order is the order in which the components of a web page receive focus when pressing the tab key. WCAG states that the focus order should preserve meaning and operability to ensure that keyboard users have a similar experience to users of pointing devices. When localising, it is important to bear in mind whether the target language has a different reading order and/or direction than the source language. If it does, localisation specialists should ensure that the focus order does not change the meaning and operability.&lt;/p&gt;
&lt;p&gt;Link content (the text and/or image) should clearly indicate where the user will go or what will happen when clicking the link. This is useful for people with cognitive impairments and for people (like blind or deaf-blind people) that use link-based browsing, which only navigates through the links, rather than the full page. When links get localised, special care should be taken to provide adequate information about the purpose of a link.&lt;/p&gt;
&lt;p&gt;Overall headings, labels and section headings should clearly represent their purpose, so users can
easily navigate through the structure of a page. This is useful for people using the keyboard or for
people with cognitive impairments. Therefore pay special attention to the descriptions contained in headings, labels and sections when localising a page.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;In conclusion localisation of content is necessary to maintain or increase the accessibility of web content for a wider audience. This will benefit all users and not just users with certain disabilities.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[React Hooks]]></title><description><![CDATA[React Hooks The React team recently introduced a new feature in version 16.7.0-alpha - React Hooks. A lot of chatter in various React forums…]]></description><link>https://www.cornelia-schulz.net/2018-11-03-react-hooks/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-11-03-react-hooks/</guid><pubDate>Sat, 03 Nov 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;React Hooks&lt;/h1&gt;
&lt;p&gt;The React team recently introduced a new feature in version 16.7.0-alpha - React Hooks. A lot of chatter in various React forums made me want to have a look what React Hooks are all about, so I went ahead and tried a few of them out. I should mention that they are currently still an experimental proposal and their implementation may change. It&apos;s worth keeping an eye on the &lt;a href=&quot;https://reactjs.org/docs/hooks-intro.html&quot; title=&quot;Official React documentation&quot;&gt;official documentation&lt;/a&gt; for the latest update on this new feature.&lt;/p&gt;
&lt;p&gt;React Hooks were introduced to let you use state in stateless or functional components. Using Hooks you no longer will have to change your component into a class if you need state.&lt;/p&gt;
&lt;p&gt;A number of Hooks are already built into 16.7.0-alpha:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;useState&lt;/li&gt;
&lt;li&gt;useEffect&lt;/li&gt;
&lt;li&gt;useContext&lt;/li&gt;
&lt;li&gt;useCallback&lt;/li&gt;
&lt;li&gt;useMemo&lt;/li&gt;
&lt;li&gt;useReducer&lt;/li&gt;
&lt;li&gt;useRef&lt;/li&gt;
&lt;li&gt;useLayoutEffect&lt;/li&gt;
&lt;li&gt;useImperativeMethods&lt;/li&gt;
&lt;li&gt;useMutationEffect&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can also create custom Hooks.&lt;/p&gt;
&lt;p&gt;To start using React Hooks, first use npm or yarn and install version 16.7.0-alpha.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;yarn add react@16.7.0-alpha.0
yarn add react-dom@16.7.0-alpha.0
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I created a small &lt;a href=&quot;https://github.com/cornelia-schulz/bookclub&quot; title=&quot;Practice repository&quot;&gt;practice repository&lt;/a&gt; on Github where you can find all the code that appears in this post. &lt;/p&gt;
&lt;h2&gt;State hooks&lt;/h2&gt;
&lt;p&gt;Without a state Hook you&apos;d have to create a class to keep track of count and its state in the component below:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import React from &apos;react&apos;

class Counter extends React.Component {
  this.state = {
    count: 0
  }
  const [count, setCount] = useState(0)

  render() {
    return (
      &amp;#x3C;div className=&apos;counter&apos;&gt;
        &amp;#x3C;button onClick={() =&gt; this.setState({ count: this.state.count + 1 })}&gt;Click me&amp;#x3C;/button&gt;
        &amp;#x3C;p&gt;You clicked the button {this.state.count} times.&amp;#x3C;/p&gt;
      &amp;#x3C;/div&gt;
    )
  }
}
export default Counter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;State Hooks simply let you use state inside a functional component.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { useState } from &apos;react&apos;

function Counter() {
  const [count, setCount] = useState(0)

  return (
    &amp;#x3C;div className=&apos;counter&apos;&gt;
      &amp;#x3C;button onClick={() =&gt; setCount(count +1)}&gt;Click me&amp;#x3C;/button&gt;
      &amp;#x3C;p&gt;You clicked the button {count} times.&amp;#x3C;/p&gt;
    &amp;#x3C;/div&gt;
  )
}
export default Counter
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Above, useState is the Hook. React will preserve the local state of the variable count in between re-renders. UseState has only one argument (0) - because the counter starts from 0. 0 is only used on the initial render.&lt;/p&gt;
&lt;h2&gt;Effect hooks&lt;/h2&gt;
&lt;p&gt;Effect Hooks are used to tell React that your component needs to do something after render. They run after every single render by default. If that&apos;s not quite what you want, this behaviour can be customised to suit.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import {useState, useEffect} from &apos;react&apos;
import {getAllBooks} from &apos;../apiClient&apos;

function Books() {
  const [books, setBooks] = useState([])

  useEffect(() =&gt; {
    getAllBooks()
      .then(books =&gt; {
        setBooks(books)
      })
  })

  return (
    &amp;#x3C;div className=&apos;books&apos;&gt;
      &amp;#x3C;h2&gt;Books&amp;#x3C;/h2&gt;
      &amp;#x3C;ul&gt;
        {books.map(book =&gt; {
          return &amp;#x3C;li key={book.id}&gt;{book.title}&amp;#x3C;/li&gt;
        })}
      &amp;#x3C;/ul&gt;
    &amp;#x3C;/div&gt;
  )
}
export default Books
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the example above useEffect is used to pass a function to fetch some book titles from a simple database. In a class based component the same function would have been called from within componentDidMount.&lt;/p&gt;
&lt;h2&gt;Custom hooks&lt;/h2&gt;
&lt;p&gt;You can also write some custom Hooks to use within your React components. The React team suggests prefixing Hooks with &quot;use&quot;, just to make it easier to keep track of the types of components in your code.&lt;/p&gt;
&lt;p&gt;usePrevious Hook:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { useRef, useEffect } from &apos;react&apos;

export function usePrevious(value) {
    const ref = useRef()
    useEffect(() =&gt; {
      ref.current = value
    })
    return ref.current
  }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This custom Hook uses useRef to keep track of the previous state of the value that is getting passed into it.&lt;/p&gt;
&lt;p&gt;The usePrevious Hook can then be used in other components such as the Counter component I mentioned above:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { useState } from &apos;react&apos;
import { usePrevious } from &apos;./usePrevious&apos;

function Counter() {
  const [count, setCount] = useState(0)
  conts prevCount = usePrevious(count)

  return (
    &amp;#x3C;div className=&apos;counter&apos;&gt;
      &amp;#x3C;button onClick={() =&gt; setCount(count +1)}&gt;Click me&amp;#x3C;/button&gt;
      &amp;#x3C;p&gt;You clicked the button {count} times.&amp;#x3C;/p&gt;
      &amp;#x3C;p&gt;Count before the last click: {prevCount}, current count: {count}&amp;#x3C;/p&gt;
    &amp;#x3C;/div&gt;
  )
}
export default Counter
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;A few points&lt;/h2&gt;
&lt;p&gt;Hooks are still experimental and their implementation will probably change in the future, so it&apos;s probably best not to rewrite all your code to use them yet. They are compatible with all your current components, so maybe give them a try when you create your next component.&lt;/p&gt;
&lt;p&gt;Hooks should only be called at the top level of a React function component. Don’t call Hooks inside loops, conditions, or nested functions. This is to ensure that Hooks are getting called in the same order of every render and the state is correctly maintained.&lt;/p&gt;
&lt;p&gt;Hooks are fully encapsulated — each time you call a Hook, it calls on isolated local state within the current component.&lt;/p&gt;
&lt;p&gt;More React Hooks rules can be found in the &lt;a href=&quot;https://reactjs.org/docs/hooks-rules.html&quot; title=&quot;React Hooks Rules&quot;&gt;React documentation&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Check out the &lt;a href=&quot;https://reactjs.org/docs/hooks-intro.html&quot; title=&quot;Official React documentation&quot;&gt;documentation&lt;/a&gt; for Hooks proposal to learn more about React hooks. The &lt;a href=&quot;https://reactjs.org/docs/hooks-faq.html&quot; title=&quot;FAQs about Hooks&quot;&gt;FAQ section&lt;/a&gt; will probably answer a lot of questions you may have as well.
The React team also &lt;a href=&quot;https://github.com/reactjs/rfcs/pull/68&quot; title=&quot;Hook feature feedback&quot;&gt;collects feedback&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Have you tried the new React Hooks feature yet? Feel free to leave a comment below.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Testing React and I18next with Jest]]></title><description><![CDATA[Testing React and I18next with Jest In  my last blog post  I showed you how to use I18next within my React application. In this post I'd…]]></description><link>https://www.cornelia-schulz.net/2018-10-20-I18next-testing-with-Jest/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-10-20-I18next-testing-with-Jest/</guid><pubDate>Sat, 20 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Testing React and I18next with Jest&lt;/h1&gt;
&lt;p&gt;In &lt;a href=&quot;https://www.cornelia-schulz.net/2018-10-07-localisation-With-I18next&quot; title=&quot;Localisation with I18next&quot;&gt;my last blog post&lt;/a&gt; I showed you how to use I18next within my React application. In this post I&apos;d like to share how to test your components that contain strings generated with I18next. In my &lt;a href=&quot;https://github.com/cornelia-schulz/photolocations&quot; title=&quot;Photo Locations&quot;&gt;Photo Locations project&lt;/a&gt; I use Jest and Enzyme to test my code.&lt;/p&gt;
&lt;p&gt;So first of all, if you haven&apos;t already, install Jest and Enzyme using either Yarn or npm. Follow the instructions in the &lt;a href=&quot;https://jestjs.io/docs/en/tutorial-react&quot; title=&quot;Jest tutorial for React&quot;&gt;Jest tutorial for React.&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;yarn add jest enzyme
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next in your main directory of your project, create a folder called _&lt;strong&gt;_mocks__&lt;/strong&gt; because you won&apos;t actually want to use your live configuration for your tests. In the _&lt;strong&gt;_mocks__&lt;/strong&gt; folder, create a file called react-i18next.js and copy the following code which can also be found in the &lt;a href=&quot;https://github.com/i18next/react-i18next/blob/master/example/test-jest/__mocks__/react-i18next.js&quot; title=&quot;I18next test documentation&quot;&gt;I18next documentation&lt;/a&gt; into the file.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;const React = require (&apos;react&apos;);
const reactI18next = require (&apos;react-i18next&apos;);

const hasChildren = node =&gt;
  node &amp;#x26;&amp;#x26; (node.children || (node.props &amp;#x26;&amp;#x26; node.props.children));

const getChildren = node =&gt;
  node &amp;#x26;&amp;#x26; node.children ? node.children : node.props &amp;#x26;&amp;#x26; node.props.children;

const renderNodes = reactNodes =&gt; {
  if (typeof reactNodes === &apos;string&apos;) {
    return reactNodes;
  }

  return Object.keys (reactNodes).map ((key, i) =&gt; {
    const child = reactNodes[key];
    const isElement = React.isValidElement (child);

    if (typeof child === &apos;string&apos;) {
      return child;
    }
    if (hasChildren (child)) {
      const inner = renderNodes (getChildren (child));
      return React.cloneElement (child, {...child.props, key: i}, inner);
    } else if (typeof child === &apos;object&apos; &amp;#x26;&amp;#x26; !isElement) {
      return Object.keys (child).reduce (
        (str, childKey) =&gt; `${str}${child[childKey]}`,
        &apos;&apos;
      );
    }

    return child;
  });
};

module.exports = {
  // this mock makes sure any components using the translate HoC receive the t function as a prop
  withNamespaces: () =&gt; Component =&gt; props =&gt; (
    &amp;#x3C;Component t={k =&gt; k} {...props} /&gt;
  ),
  Trans: ({children}) =&gt; renderNodes (children),
  NamespacesConsumer: ({children}) =&gt; children (k =&gt; k, {i18n: {}}),

  // mock if needed
  Interpolate: reactI18next.Interpolate,
  I18nextProvider: reactI18next.I18nextProvider,
  loadNamespaces: reactI18next.loadNamespaces,
  reactI18nextModule: reactI18next.reactI18nextModule,
  setDefaults: reactI18next.setDefaults,
  getDefaults: reactI18next.getDefaults,
  setI18n: reactI18next.setI18n,
  getI18n: reactI18next.getI18n,
};
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that&apos;s done, it&apos;s time to create a folder called tests in the root directory of your project to start writing some tests. &lt;/p&gt;
&lt;p&gt;For this blog, we will be testing that the h1 tag in my About.jsx component displays correctly. To do this, create a file called &lt;a href=&quot;https://github.com/cornelia-schulz/photolocations/blob/master/tests/client/components/About.test.js&quot; title=&quot;About.test.js&quot;&gt;&quot;About.test.js&quot;&lt;/a&gt; inside the tests folder.&lt;/p&gt;
&lt;p&gt;First import all the dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import React from &apos;react&apos;
import { configure, shallow, mount } from &apos;enzyme&apos;
import Adapter from &apos;enzyme-adapter-react-16&apos;
import {About} from &apos;../../../client/components/About&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next create an adapter to be able to run Enzyme tests:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javscript&quot;&gt;configure({adapter: new Adapter()})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then you can start writing the actual test:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;test(&apos;&amp;#x3C;About/&gt; renders h1 component with given content&apos;, () =&gt; {
  const expected = &apos;About Photo Locations&apos;
  const wrapper = shallow(&amp;#x3C;About t={(k) =&gt; &apos;About Photo Locations&apos;} /&gt;)
  const actual = wrapper.find(&apos;h1&apos;).text()

  expect(actual).toEqual(expected)
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The first line simply describes what the test is expected to do. Create the variable &quot;expected&quot; and give the text which is expected to appear in the About page header. Next shallow render the About component and pass it the text you want it to render, rather than calling up the json file and looking up the string. Then create a variable called actual to look up the text that is contained in the h1 tag. Last but not least compare the &quot;expected&quot; variable to the &quot;actual&quot; variable to ensure they match.&lt;/p&gt;
&lt;p&gt;To find out more about the different rendering methods that Enzyme uses, such as shallow, mount or render, check out the &lt;a href=&quot;https://airbnb.io/enzyme/docs/api/shallow.html&quot; title=&quot;Enzyme documentation&quot;&gt;Enzyme documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To run the test, type:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;jest about
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;into the console.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/static/jest-about-4f2ad213c34a740ae7910fc847e27018.jpg&quot; alt=&quot;Running jest about&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Something to watch out for&lt;/h2&gt;
&lt;p&gt;Because the mock react-i18next.js file contains the ES6 spread operator, which is not initially supported by Jest, I had to add:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;yarn add @babel/plugin-syntax-object-rest-spread
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I also upgraded Babel to version 7 to support this.&lt;/p&gt;
&lt;p&gt;Have you tried writing tests for I18next with Jest yet? Feel free to share your experience in the comments section below.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Localisation in React with I18next]]></title><description><![CDATA[Localisation in React with I18next Recently I participated in the pretty awesome Dev Academy Web Developer bootcamp to learn React and…]]></description><link>https://www.cornelia-schulz.net/2018-10-07-localisation-With-I18next/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-10-07-localisation-With-I18next/</guid><pubDate>Sun, 07 Oct 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Localisation in React with I18next&lt;/h1&gt;
&lt;p&gt;Recently I participated in the pretty awesome Dev Academy Web Developer bootcamp to learn React and fullstack development and I enjoyed that immensely. I asked myself what&apos;s a good way to localise content in React applications? After some googling I came across &lt;a href=&quot;https://www.i18next.com/&quot; title=&quot;i18next documentation&quot;&gt;i-18next&lt;/a&gt; and more specifically &lt;a href=&quot;https://github.com/i18next/react-i18next&quot; title=&quot;react-i18next documentation&quot;&gt;react-i18next&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I18next is an internationalisation framework and provides a lot of functionalities, such as pluralisation &quot;out of the box&quot;. I thought I&apos;d give it a try to see how easily it integrates with an existing application which I have been using to practise my React skills. The application is called Photo Locations and the code can be found on &lt;a href=&quot;https://github.com/cornelia-schulz/photolocations&quot; title=&quot;Photo Locations on Github&quot;&gt;Github&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;To get started, I used yarn to install the following packages:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;yarn add react-i18next i18next i18next-browser-languagedetector i18next-xhr-backend
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In my application I use webpack and I found the following package extremely helpful too:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;yarn add -d @alienfast/i18next-loader
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next I added the following lines to the modules section my webpack config to configure i18next-loader:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  test: /locales/,
  loader: &apos;@alienfast/i18next-loader&apos;,
  // options here
  //query: { overrides: [ &apos;../node_modules/lib/locales&apos; ] }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that was done, it was time to initialise i18next and to configure where I wanted to store my language string files. To do that I created an i18n.js file in my client directory.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import i18n from &apos;i18next&apos;
import Backend from &apos;i18next-xhr-backend&apos;
import LanguageDetector from &apos;i18next-browser-languagedetector&apos;
import { reactI18nextModule } from &apos;react-i18next&apos;

i18n
  .use(Backend)
  .use(LanguageDetector)
  .init({
    fallbackLng: &apos;en&apos;,

    // have a common namespace used around the full app
    ns: [&apos;strings&apos;],
    defaultNS: &apos;strings&apos;,

    debug: true,

    interpolation: {
      escapeValue: false,
    },

    react: {
      wait: true
    }
  })

export default i18n
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the file I specified that I am going to store my translations in a file named strings. It is good practise to use the same file name for all your languages and store them in differnt folders based on their locale or language code. That&apos;s what I did next.&lt;/p&gt;
&lt;p&gt;To set up some text I created a folder called locales in my public folder which contains other static assets, such as images or CSS files. Within the locales folder I set up two languages for now, German (de) and my base language English (en).&lt;/p&gt;
&lt;p&gt;In each language folder I then created a file called strings.json. All text will now be stored in these files in a simple json key:value structure. To make it easeier to see where my individual strings are being used, I created a json object for each individual component:&lt;/p&gt;
&lt;p&gt;locales/en/strings.json&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &quot;header&quot;: {
    &quot;home&quot;: &quot;Home&quot;,
    &quot;about&quot;: &quot;About&quot;,
    &quot;contact&quot;: &quot;Contact&quot;
  },
  &quot;contact&quot;: {
    &quot;contact_header&quot;: &quot;Get in touch!&quot;,
    &quot;name&quot;: &quot;Your name:&quot;,
    &quot;email&quot;: &quot;Your email:&quot;,
    &quot;message&quot;: &quot;Your message:&quot;,
    &quot;send&quot;: &quot;Send&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;locales/de/strings.json&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;{
  &quot;header&quot;: {
    &quot;home&quot;: &quot;Start&quot;,
    &quot;about&quot;: &quot;Über&quot;,
    &quot;contact&quot;: &quot;Kontakt&quot;
  },
  &quot;contact&quot;: {
    &quot;contact_header&quot;: &quot;Schicke eine Nachricht&quot;,
    &quot;name&quot;: &quot;Dein Name:&quot;,
    &quot;email&quot;: &quot;Deine E-Mail:&quot;,
    &quot;message&quot;: &quot;Deine Nachricht:&quot;,
    &quot;send&quot;: &quot;Senden&quot;
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;As you can see in my two little examples above, both the English and the German json files contain the same keys on the left hand side, which I will be using to load the translations onto my pages from my components.&lt;/p&gt;
&lt;p&gt;But before I could use the keys in the component, I had to import i18next into my index.js file and include it in the render method:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import i18n from &apos;./i18n&apos;

document.addEventListener (&apos;DOMContentLoaded&apos;, () =&gt; {
  render (
    &amp;#x3C;Provider store={store}&gt;
      &amp;#x3C;I18nextProvider i18n={i18n}&gt;
        &amp;#x3C;BrowserRouter&gt;
          &amp;#x3C;App /&gt;
        &amp;#x3C;/BrowserRouter&gt;
      &amp;#x3C;/I18nextProvider&gt;
    &amp;#x3C;/Provider&gt;,
    document.getElementById (&apos;app&apos;)
  )
})
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next I added &quot;withNamespaces&quot; to my App.jsx file and included it in the export, so other components have access to i18n via their props.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { withNamespaces } from &apos;react-i18next&apos;
class App extends React.Component {
  ...
}
export default withNamespaces(&apos;strings&apos;)(App)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once that was done, I could call i18next from my components to actually display my content in both English and German. In my example here I&apos;m looking at the Header.jsx file. First I imported I18n at the top of my file. Then I wrapped the content of my render section into an &lt;I18&gt; tag. Next I simply used {t(&apos;key.from.json.file&apos;)} wherever I had some text:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-javascript&quot;&gt;import { withNamespaces } from &apos;react-i18next&apos;
import i18n from &apos;i18next&apos;

class Header extends React.Component {
  constructor(props) {
    super(props)
    this.changeLanguage = this.changeLanguage.bind(this)
  }

  changeLanguage(language) {
    i18n.changeLanguage(language)
    this.props.setLanguage(language)
  }

  render() {
    let { t, i18n } = this.props
    return (
      &amp;#x3C;header&gt;
        &amp;#x3C;nav className=&quot;navbar&quot; role=&quot;navigation&quot;&gt;
          &amp;#x3C;div className=&quot;logo header  header-left&quot;&gt;
            &amp;#x3C;img src=&quot;/images/Logo.PNG&quot; alt=&quot;Photo Locations&quot; /&gt;
          &amp;#x3C;/div&gt;
          &amp;#x3C;div className=&quot;languages&quot;&gt;
          &amp;#x3C;button className=&quot;button language&quot; onClick={() =&gt; this.changeLanguage(&apos;de&apos;)}&gt;{t(&apos;languages.de&apos;)}&amp;#x3C;/button&gt;
          &amp;#x3C;button className=&quot;button language&quot; onClick={() =&gt; this.changeLanguage(&apos;en&apos;)}&gt;{t(&apos;languages.en&apos;)}&amp;#x3C;/button&gt;
          &amp;#x3C;/div&gt;
          &amp;#x3C;div className=&quot;header&quot;&gt;
            &amp;#x3C;Route exact path=&apos;/&apos; component={Search} /&gt;
          &amp;#x3C;/div&gt;
          &amp;#x3C;div className=&quot;dropdown header&quot;&gt;
            &amp;#x3C;button className=&quot;dropbtn&quot; onClick={this.toggleVisibility}&gt;
              &amp;#x3C;i className=&quot;fa fa-bars&quot; aria-hidden=&quot;true&quot;&gt;&amp;#x3C;/i&gt;
            &amp;#x3C;/button&gt;
            &amp;#x3C;div className=&quot;dropdown-content&quot;&gt;
              &amp;#x3C;Link to=&quot;/&quot;&gt;{t(&apos;header.home&apos;)}&amp;#x3C;/Link&gt;
              &amp;#x3C;Link to=&quot;/about&quot;&gt;{t(&apos;header.about&apos;)}&amp;#x3C;/Link&gt;
              &amp;#x3C;Link to=&quot;/contact&quot;&gt;{t(&apos;header.contact&apos;)}&amp;#x3C;/Link&gt;
            &amp;#x3C;/div&gt;
          &amp;#x3C;/div&gt;
        &amp;#x3C;/nav&gt;
      &amp;#x3C;/header&gt;
    )
  }
}

function mapDispatchToProps(dispatch) {
  return {
    setLanguage: (language) =&gt; {
      return dispatch(setLanguage(language))
    }
  }
}

export default withNamespaces(&apos;strings&apos;)(connect (null, mapDispatchToProps)(Header))
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To quickly test the functionality of changing the language I added some buttons, which will be integrated into the menu later on. The full code can be found on &lt;a href=&quot;https://github.com/cornelia-schulz/photolocations&quot; title=&quot;Photo Locations on Github&quot;&gt;Github&lt;/a&gt; .&lt;/p&gt;
&lt;p&gt;All in all I just loved how straight forward it was to get going with I18n and I will certainly explore this component more as I&apos;d love to be able to show off my newly learned React skills to my family in Germany as well.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Language Hierarchies]]></title><description><![CDATA[Language Hierarchies When working with languages you will probably come across culture specific languages such as German spoken in Germany…]]></description><link>https://www.cornelia-schulz.net/2018-09-13-language-hierarchies/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-09-13-language-hierarchies/</guid><pubDate>Thu, 13 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Language Hierarchies&lt;/h1&gt;
&lt;p&gt;When working with languages you will probably come across culture specific languages such as German spoken in Germany, German spoken in Austria or Swiss German. It makes sense to organise your translated files in such a way that your German speaking customers only ever see German. However, if you are missing translations for a specific software string, it is good practise to fall back to your default culture and not show your customers that a string is missing or not show them anything at all.&lt;/p&gt;
&lt;p&gt;We can use language hierarchies to organise these fall-backs. But what&apos;s the best way to organise yourself?&lt;/p&gt;
&lt;h2&gt;Have a base language&lt;/h2&gt;
&lt;p&gt;At the top of language hierarchies you always have a base language. A base language is the language your company operates in or writes all their content in. You will always have strings available in this langauge and it is the source language for all your translations.&lt;/p&gt;
&lt;h2&gt;Keep translations neutral&lt;/h2&gt;
&lt;p&gt;Below the base language you have your culture neutral resource files. A neutral culture is associated with a language but not a country or region. For example French (fr) or German (de) are neutral language codes because they don&apos;t specify the country where the language is spoken in. It is best practise to store most of your translations in such a culture neutral file.&lt;/p&gt;
&lt;h2&gt;Then add some specifics&lt;/h2&gt;
&lt;p&gt;Of course you want to make sure that your translations read completely natural to your customers in all your target markets. So there will be country or region specific terms for some words. These should be stored in culture specific resource files. A specific culture is associated with a language and a country or region. For example German from Germany is de-DE, Canadian French is fr-CA, etc.&lt;/p&gt;
&lt;p&gt;Organising your language resource files according to specificity and creating language hierarchies is a good way to ensure that you don&apos;t show any blank spaces or missing strings. It also means you don&apos;t need to store a huge amount of strings twice or more times for every single market.&lt;/p&gt;
&lt;p&gt;Having read a bit about the theory, how do you organise language hierarchies? Feel free to share your thoughts in the comments section.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Machine translations]]></title><description><![CDATA[Machine translations Almost everyone probably has heard of services such as Google Translate. Machine translation is the technical term for…]]></description><link>https://www.cornelia-schulz.net/2018-08-08-machine-translations/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-08-08-machine-translations/</guid><pubDate>Wed, 08 Aug 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Machine translations&lt;/h1&gt;
&lt;p&gt;Almost everyone probably has heard of services such as Google Translate. Machine translation is the technical term for any computerised translation service. On a very basic level machine translation works by a simple substitution of words in one language for words in another. It is not quite an alternative to human translation yet as the following lines will show.&lt;/p&gt;
&lt;p&gt;First serious attempts of automated or machine translation were made in the 1950s with rule based systems (RBTM), which combined a number of grammatical rules and dictionaries. The big wave of research occurred in the 1980s when an increased amount of content needing translation inspired statistical machine translation (SMT). This method is based on large volumes of analysed data for specific language combinations. Statistical machine translations were used by the German computer scientist Franz Joseph Och to develop Google translate in the early 2000s.&lt;/p&gt;
&lt;p&gt;Since 2007, SMT and SMT-RBTM hybrids were used to build sophisticated translation platforms. One example is &quot;Moses&quot;, a statistical machine translation system funded by the European Commission. The system was trained by passing it a collection of translated texts and once trained the system quickly found the highest-probability translation with the help of an efficient search algorithm. However, all of those systems still needed a lot of human editing.&lt;/p&gt;
&lt;p&gt;Simultaneously, the industry developed less ambitious computer-assisted translation tools (CAT-tools), which can handle a lot of different file formats. These can also be combined with machine translation options. The translation memories and glossaries that these tools generate speed up the translation process enormously, especially for repetitive texts and updates and provide an easier terminology management and better quality control. &lt;/p&gt;
&lt;p&gt;The newest development in terms of machine translation is neural machine translation (NMT) or deep neural machine translation. Like statistical machine translation, the system starts by learning from a variety of translated texts but the difference is that this learning happens largely without human intervention through artificial intelligence. Simple neural networks simply take the same input and turn it into the same output every single time. Recurrent neural networks do this a bit more cleverly. They do not only take the input itself but also take into account the input around the actual input, which will result in much more accurate translations.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;German original:&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;Sollten sich Unklarheiten betreffend der Auslegung einer oder mehrerer der nachstehenden Vertragsbestimmungen ergeben, gilt im Zweifel die für den Auftraggeber günstigere Auslegung.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SMT translation:&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Should ambiguities concerning the interpretation of one or more of the following provisions of the Treaty, is in doubt for the customer more favorable interpretation.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NMT translation:&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;In the event of any uncertainties concerning the interpretation of one or more of the following provisions of the contract, the interpretation which is more favorable to the contracting entity shall apply.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;It appears that neural machine translation copes much better with syntax and produces a much more natural output. This is due to the fact that the system is able to translate the semantic meaning of entire phrases rather than translating word by word.&lt;/p&gt;
&lt;p&gt;At first sight this makes post-editing a much simpler process and means it is actually post-editing rather than a complete re-translation. However, this is still in early phases of testing and neural machine translation still only processes one sentence at the time, which can lead to errors in ambiguous phrases, where human translators would take the wider context into account:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Example:&lt;/em&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;1st sentence:&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;The water was cold and the current strong. I went to the bank. My feet sunk into the mud.&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NMT translation:&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Das Wasser war kalt und die Strömung stark, als ich zur Bank ging. Meine Füße versanken im Schlamm.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;2nd sentence:&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;I had run out of cash. I went to the bank. It had just closed.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;NMT translation:&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Ich hatte kein Bargeld mehr, also ging ich zur Bank, aber sie hatte geschlossen.&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;In both of these sentences, neural machine translation renders the English word “bank” as “Bank” in  German, i. e. the financial institution. It did not identify the alternative meaning, i.e. river bank. Also, the pronoun “it” in the second sentence is translated as “es” (neutral) when it should be “sie” (feminine because “Bank” in German is feminine).&lt;/p&gt;
&lt;p&gt;However, just by changing the first example a little bit, we can illustrate the strength of neural machine translation compared to statistical machine translation because it can accommodate the semantic qualities of words within a sentence:
1st sentence: The water was cold and the current strong, when I went to the bank. My feet sunk into the mud.
NMT translation: Ich hatte kein Bargeld mehr, also ging ich zur Bank, aber sie hatte gerade geschlossen.&lt;/p&gt;
&lt;p&gt;This time the neural machine translation chose the correct pronoun.&lt;/p&gt;
&lt;p&gt;Neural machine translation is still in its infancy and there are things which are not generally understood just yet. One example is that NMT sometimes leaves out whole chunks of text for no apparent reasons. Another issue for language service providers to consider is data security, since most neural machine translation systems generally run in the cloud. However, some systems, such as SDL Trados 2017 already incorporate this technology via an API and one certainty is that we should keep an eye on this rapidly developing technology.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Glossaries and translation memories]]></title><description><![CDATA[Glossaries and translation memories Glossaries A glossary is a list of standardised terms in the source language of a company. Translation…]]></description><link>https://www.cornelia-schulz.net/2018-06-11-glossaries-and-translation-memories/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-06-11-glossaries-and-translation-memories/</guid><pubDate>Mon, 11 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Glossaries and translation memories&lt;/h1&gt;
&lt;h2&gt;Glossaries&lt;/h2&gt;
&lt;p&gt;A glossary is a list of standardised terms in the source language of a company.&lt;/p&gt;
&lt;p&gt;Translation glossaries ensure consistency and clarity in all translated materials by helping eliminate uncertainty. No matter what product you are working on, it pays to create a list of all the important terms. These terms should then be used consistently by all translators and reviewers.&lt;/p&gt;
&lt;p&gt;Here are a few points to consider when creating a glossary:&lt;/p&gt;
&lt;p&gt;Structure the glossary with purpose
Include only terms specific to the company or the product
Make the glossary translator-centric and provide as much context as possible
Complex terms should be listed with a definition and context
If you are creating multi-lingual glossaries, conduct an in-country review before using the glossary
Translation glossaries exist because even the best linguists may have difficulties translating key marketing concepts or catch phrases. They give a great resource and make their job easier.&lt;/p&gt;
&lt;p&gt;Things you might want to include in a glossary:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key terms:&lt;/strong&gt; A good glossary should provide a thorough list of relevant key terms that are very specific to the subject matter or the company’s culture.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Definitions:&lt;/strong&gt; These key terms should be clearly defined, so that linguists understand them clearly.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Preferred translations:&lt;/strong&gt; Add your company’s preferred translations for terms in the glossary. This will help linguists with the accuracy and consistency of word choices in the translation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Terms that should not be translated:&lt;/strong&gt; Some products, services, or proper names may need to be left in the source language. Include those, so there is no uncertainty whether or not such a term should be translated.&lt;/p&gt;
&lt;p&gt;A glossary is a living document, and you have to keep building it over time. Whenever a new key term is identified, make sure you add it to the glossary.&lt;/p&gt;
&lt;h2&gt;Translation memories&lt;/h2&gt;
&lt;p&gt;A translation memory or TM for short is a database that contains human translations. They are an integral part of the translation process as the speed up translation, maintain consistency and save cost.&lt;/p&gt;
&lt;p&gt;This database stores previously translated segments, which depending on the type of translation, can be sentences, paragraphs, single words, etc.&lt;/p&gt;
&lt;p&gt;When language service providers carry out word counts to provide you with quotes, they will search this database for previous translations similar to what you are sending them and they then adjust their charges accordingly. So if a sentence has been translated in full previously, it is a 100% match and they will only charge you a minimal fee for handling or sometimes no fee at all. If it is a partial match, then the charge may just be 75% or 50% of the normal full charge.&lt;/p&gt;
&lt;p&gt;The most common format for translation memories is .tmx. TMX stands for translation memory eXchange. It is a bilingual xml file that provides a standard method to describe translation memory data that is being exchanged amongst tools and / or translation vendors.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Localisation - The very basics]]></title><description><![CDATA[Localisation - The very basics I have worked in software localisation for a good few years now and often I find myself googling and…]]></description><link>https://www.cornelia-schulz.net/2018-05-21-localisation-the-very-basics/</link><guid isPermaLink="false">https://www.cornelia-schulz.net/2018-05-21-localisation-the-very-basics/</guid><pubDate>Mon, 21 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Localisation - The very basics&lt;/h1&gt;
&lt;p&gt;I have worked in software localisation for a good few years now and often I find myself googling and collecting information and how to’s on various topics related to localisation and I thought, rather than keeping it all hidden in my little notebook, I will summarise things I research and collate them in this blog.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Localisation&lt;/strong&gt; is often abbreviated to L10N, which simply takes the first and the last letter of the word itself, plus the count of letters of the word in between these letters.&lt;/p&gt;
&lt;p&gt;It is the provision of service for the linguistic and cultural adaption of products to the requirement of a market. What exactly does that mean? Translating is just one little part of localisation. Translation is the process of converting written text from one language to another. It requires that the full meaning of the source material be accurately rendered into the target language. Special attention needs to be paid to nuance and style.&lt;/p&gt;
&lt;p&gt;As part of localistion, time, date and number formats need to be adapted, the correct currencies and payment methods need to be used. In some cases images and colours need to be adapted as well as some colours may have different connotations in different cultures.&lt;/p&gt;
&lt;p&gt;In comparison what is &lt;strong&gt;internationalisation&lt;/strong&gt;? Internationalisation can also be abbreviated in a similar fashion: I16N. It is the process of generalising a product in such a way that it can be adapted in various languages and cultural conventions without having to redesign the product every single time you would like to publish it in another market.&lt;/p&gt;
&lt;p&gt;Another term worth mentioning is &lt;strong&gt;globalisation&lt;/strong&gt;. Globalisation addresses business issues of taking a product to a global market. In terms of websites, globalisation refers to enabling that website to deal with non-English speaking visitors, i.e. internationalising the website’s back-end, designing a multilingual architecture (e.g. ensure that your databases can deal with special characters) and localising the website’s static or dynamic content.&lt;/p&gt;</content:encoded></item></channel></rss>