<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Daniel Charvát</title>
    <description>The latest articles on Forem by Daniel Charvát (@elisiondan).</description>
    <link>https://forem.com/elisiondan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F468762%2F13be37f6-aa04-499e-a04d-1108c35373d2.jpeg</url>
      <title>Forem: Daniel Charvát</title>
      <link>https://forem.com/elisiondan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/elisiondan"/>
    <language>en</language>
    <item>
      <title>V-model support without requiring value prop</title>
      <dc:creator>Daniel Charvát</dc:creator>
      <pubDate>Fri, 22 Jan 2021 09:08:17 +0000</pubDate>
      <link>https://forem.com/localazy/v-model-support-without-requiring-value-prop-2jcg</link>
      <guid>https://forem.com/localazy/v-model-support-without-requiring-value-prop-2jcg</guid>
      <description>&lt;p&gt;Have you ever wished to create a component that supports &lt;code&gt;v-model&lt;/code&gt; directive, but works without it as well? First things first. If you've tried Vue.js you've probably learned that you can bind variables on inputs. This creates a two-way data binding which syncs the variable and the input's state. All you need to do is to use the v-model directive.&lt;/p&gt;

&lt;p&gt;You may also have learned that you can use this directive with any custom component since &lt;code&gt;v-model&lt;/code&gt; is just a syntax sugar to cover both ways of the data binding.  You can learn more about this &lt;a href="https://vuejs.org/v2/guide/components.html#Using-v-model-on-Components"&gt;here&lt;/a&gt;. Hence&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"searchText"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;turns into&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt;
  &lt;span class="na"&gt;v-bind:value=&lt;/span&gt;&lt;span class="s"&gt;"searchText"&lt;/span&gt;
  &lt;span class="na"&gt;v-on:input=&lt;/span&gt;&lt;span class="s"&gt;"searchText = $event.target.value"&lt;/span&gt;
&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, in order to implement the support, you have to declare a prop variable called &lt;em&gt;value&lt;/em&gt; and emit an event labeled &lt;em&gt;input&lt;/em&gt;. And that's it.&lt;/p&gt;

&lt;p&gt;However, you will quickly find out that at this point the component indeed supports the &lt;code&gt;v-model&lt;/code&gt; directive, but it doesn't work at all without it. That's often undesirable. For instance, imagine you'd like to create a custom search component that includes a text input. Since it's a mere extension of a text input, it's reasonable that it should support &lt;code&gt;v-model&lt;/code&gt;. But it is also reasonable that you'd like to be able to use it without it since the input inside would normally work straight away had it been a plain HTML element. Let's tackle this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Optional v-model support
&lt;/h2&gt;

&lt;p&gt;Let's start by creating a simple search component that will accept &lt;code&gt;value&lt;/code&gt; as prop. If the user doesn't provide it, it's initiated to an empty value.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;  props: {
    value: {
      type: String,
      default: "",
    },
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, we can't use this prop directly in the input since that would mutate it which is not recommended. To circumvent this problem we'll create a clever computed value that will use the value prop if passed from the parent, or a custom local value otherwise. We'll make use of the extended computed property syntax where one can declare different functions for setter and getter of the computed function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;  data() {
    return {
      localValue: this.value,
    };
  },
  computed: {
    searchValue: {
      get() {
        return this.isValuePropSet() ? this.value : this.localValue;
      },
      set(value) {
        this.$emit("input", value);
        this.localValue = value;
      },
    },
  },
  methods: {
    isValuePropSet() {
      return (
        !!this.$options.propsData &lt;span class="err"&gt;&amp;amp;&amp;amp;&lt;/span&gt; this.$options.propsData.value !== undefined
      );
    },
  },
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's first take a look at the getter. When retrieving the value, the &lt;code&gt;isValuePropSet()&lt;/code&gt; method is invoked. This method returns true when the &lt;code&gt;value&lt;/code&gt; prop was set by the parent, not initialized to empty string by the default property. So when it was set from the outside, we'll just return the &lt;em&gt;value&lt;/em&gt; property and the component works as if it was implemented as a regular component with &lt;code&gt;v-model&lt;/code&gt; support. However, when the value was not set, then the getter returns &lt;code&gt;localValue&lt;/code&gt; instead. In the setter the current value is both emitted as an input event and stored in the &lt;code&gt;localValue&lt;/code&gt;. &lt;/p&gt;

&lt;p&gt;With this pattern, we can bind the clever &lt;code&gt;searchValue&lt;/code&gt; computed property to the input as usual&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;input&lt;/span&gt; &lt;span class="na"&gt;v-model=&lt;/span&gt;&lt;span class="s"&gt;"searchValue"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And that's it. The search component works with &lt;code&gt;v-model&lt;/code&gt; attached as well as without it. Check out the example &lt;a href="https://codesandbox.io/s/optional-v-model-component-q3g4p"&gt;sandbox&lt;/a&gt; to see it wholly in action.&lt;/p&gt;

</description>
      <category>vue</category>
      <category>tip</category>
    </item>
    <item>
      <title>Automated Localization: GitLab CI/CD ❤ Localazy</title>
      <dc:creator>Daniel Charvát</dc:creator>
      <pubDate>Sat, 09 Jan 2021 10:09:59 +0000</pubDate>
      <link>https://forem.com/localazy/automated-localization-gitlab-ci-cd-localazy-jn0</link>
      <guid>https://forem.com/localazy/automated-localization-gitlab-ci-cd-localazy-jn0</guid>
      <description>&lt;p&gt;Setup fully automated localization for your project once and forget about all the hassle forever. It’s fun with GitLab's CI/CD!&lt;/p&gt;

&lt;h1&gt;
  
  
  Why integrate Localazy into the build process?
&lt;/h1&gt;

&lt;p&gt;Localization can be challenging on its own and having to regularly remind developers (or yourself) to include the latest localization version before the release is not going to end up well at one point. With GitLab's powerful &lt;a href="https://docs.gitlab.com/ee/ci/" rel="noopener noreferrer"&gt;CI/CD&lt;/a&gt;, you need only to configure it properly once. Afterward, you can peacefully take this off your mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrate your app with Localazy
&lt;/h2&gt;

&lt;p&gt;Let's suppose that your mobile, desktop, or web app is ready for localization, and strings in the source language are stored in JSON, YAML, iOS' strings, Flutter's ARB, or some other common format. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://localazy.com" rel="noopener noreferrer"&gt;Sign up to Localazy&lt;/a&gt;, create a new app, &lt;a href="https://localazy.com/docs/cli/installation" rel="noopener noreferrer"&gt;install the CLI tool&lt;/a&gt;, and then create and test your &lt;code&gt;localazy.json&lt;/code&gt; &lt;a href="https://localazy.com/docs/cli/the-basics" rel="noopener noreferrer"&gt;configuration&lt;/a&gt;. You should be able to upload the source language files and download the localized ones. &lt;/p&gt;

&lt;p&gt;The basic configuration could look like this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"readKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-read-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"writeKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-write-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"upload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
    &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"locales/en.json"&lt;/span&gt;&lt;span class="w"&gt;         
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

  &lt;/span&gt;&lt;span class="nl"&gt;"download"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"locales/${lang}.json"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that you've filled in your &lt;em&gt;readKey&lt;/em&gt; and &lt;em&gt;writeKey&lt;/em&gt;, you are already able to manually upload and download strings between your app and Localazy. Let's move on to automating this process.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setup Secrets
&lt;/h2&gt;

&lt;p&gt;Oftentimes it is desirable to hide secrets away from the repository and Localazy keys are no different. We'll use GitLab's variables for this.  In your GitLab project, go to  &lt;strong&gt;Settings -&amp;gt; CI / CD - &amp;gt; Variables&lt;/strong&gt; and create two variables called &lt;strong&gt;LOCALAZY_WRITE_KEY&lt;/strong&gt; and &lt;strong&gt;LOCALAZY_READ_KEY&lt;/strong&gt;. The result should look like this.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fgitlab-secrets.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fgitlab-secrets.png" alt="https://directus.localazy.com/_/assets/gitlab-secrets.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated upload
&lt;/h2&gt;

&lt;p&gt;The GitLab CI/CD is a powerful automation tool with tons of options. If you only need to automate the upload part without any special configuration (such as triggering it only on certain branches or for pull requests), you don't need to know much about it. However, if you're aiming to create complex automation rules, you should check out their &lt;a href="https://docs.gitlab.com/ee/ci/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In the root of your project, create a file called &lt;code&gt;gitlab-ci.yml&lt;/code&gt; and paste in the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This is a base template for Gitlab CI / CD &lt;/span&gt;
&lt;span class="c1"&gt;# that integrates Localazy upload process into your workflow&lt;/span&gt;
&lt;span class="c1"&gt;# For available upload options https://localazy.com/docs/cli/command-line-options&lt;/span&gt;

&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localazy/cli:latest&lt;/span&gt;

&lt;span class="c1"&gt;# There three ways how to authorize the operations (https://localazy.com/docs/cli/authorization)&lt;/span&gt;
&lt;span class="c1"&gt;# - authorization keys in the configuration file (localazy.json)&lt;/span&gt;
&lt;span class="c1"&gt;# - authorization keys in a separate file (localazy.keys.json)&lt;/span&gt;
&lt;span class="c1"&gt;# - authorization keys provided as command-line arguments&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# If you wish to keep the writeKey and readKey as secrets, we recommend opting for the third option.&lt;/span&gt;
&lt;span class="c1"&gt;# - In Gitlab, define new environment variables (In project: Settings -&amp;gt; CI / CD - &amp;gt; Variables) &lt;/span&gt;
&lt;span class="c1"&gt;#   called LOCALAZY_WRITE_KEY and LOCALAZY_READ_KEY.&lt;/span&gt;
&lt;span class="c1"&gt;# - Type in your writeKey and readKey respectively&lt;/span&gt;

&lt;span class="na"&gt;localazy-upload&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# For additional CLI options, see https://localazy.com/docs/cli/command-line-options&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
        &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;localazy upload&lt;/span&gt;
          &lt;span class="s"&gt;-w $LOCALAZY_WRITE_KEY&lt;/span&gt;
          &lt;span class="s"&gt;-r $LOCALAZY_READ_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This file will be automatically picked up by GitLab and will trigger a single job called &lt;code&gt;localazy-upload&lt;/code&gt;. As you can see, we use &lt;code&gt;-w $LOCALAZY_WRITE_KEY&lt;/code&gt; and &lt;code&gt;-r $LOCALAZY_READ_KEY&lt;/code&gt; arguments for authorization. With each push to the repository (regardless of the target branch), the upload operation to Localazy will be triggered.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated download
&lt;/h2&gt;

&lt;p&gt;The download example here is a bit artificial as normally this would be only one of the jobs that would trigger during the build process of your app. However, it is a good starting point nonetheless.&lt;/p&gt;

&lt;p&gt;The configuration is going to be very similar to the upload example. You can naturally put these two jobs into the same &lt;code&gt;gitlab-ci.yml&lt;/code&gt; file if you will.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="c1"&gt;# This is a base template for Gitlab CI / CD &lt;/span&gt;
&lt;span class="c1"&gt;# that integrates Localazy download process into your workflow&lt;/span&gt;
&lt;span class="c1"&gt;# For available download options https://localazy.com/docs/cli/command-line-options&lt;/span&gt;

&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;localazy/cli:latest&lt;/span&gt;

&lt;span class="c1"&gt;# There three ways how to authorize the operations (https://localazy.com/docs/cli/authorization)&lt;/span&gt;
&lt;span class="c1"&gt;# - authorization keys in the configuration file (localazy.json)&lt;/span&gt;
&lt;span class="c1"&gt;# - authorization keys in a separate file (localazy.keys.json)&lt;/span&gt;
&lt;span class="c1"&gt;# - authorization keys provided as command-line arguments&lt;/span&gt;
&lt;span class="c1"&gt;#&lt;/span&gt;
&lt;span class="c1"&gt;# If you wish to keep the writeKey and readKey as secrets, we recommend opting for the third option.&lt;/span&gt;
&lt;span class="c1"&gt;# - In Gitlab, define new environment variables (In project: Settings -&amp;gt; CI / CD - &amp;gt; Variables) &lt;/span&gt;
&lt;span class="c1"&gt;#   called LOCALAZY_WRITE_KEY and LOCALAZY_READ_KEY.&lt;/span&gt;
&lt;span class="c1"&gt;# - Type in your writeKey and readKey respectively&lt;/span&gt;

&lt;span class="na"&gt;localazy-download&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="c1"&gt;# For additional CLI options, see https://localazy.com/docs/cli/command-line-options&lt;/span&gt;
    &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; 
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;localazy download&lt;/span&gt;
        &lt;span class="s"&gt;-w $LOCALAZY_WRITE_KEY&lt;/span&gt;
        &lt;span class="s"&gt;-r $LOCALAZY_READ_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see, this job is identical except it triggers &lt;strong&gt;download&lt;/strong&gt; operation instead of upload.&lt;br&gt;
Of course, this example effectively does nothing as files are only downloaded during the CI/CD pipeline, and if we don't use them to produce the release build, they are lost once the pipeline is finished and cleared. The exact build configuration strongly depends on your requirements.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing Words
&lt;/h2&gt;

&lt;p&gt;This is only a starter template for GitLab CI/CD. It's quite likely that you do not wish to fire this automation with each push to each branch, but rather only with accepted pull requests to your staging or production branch. If that is the case, see the documentation about &lt;a href="https://docs.gitlab.com/ee/ci/yaml/#onlyexcept-basic" rel="noopener noreferrer"&gt;only/except&lt;/a&gt;. Nonetheless, this is a perfect basic configuration on which you can build further.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fgitlab-cicd-success.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fgitlab-cicd-success.png" alt="https://directus.localazy.com/_/assets/gitlab-cicd-success.png"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>gitlabcicd</category>
      <category>automation</category>
      <category>localazy</category>
    </item>
    <item>
      <title>How to localize React app with react-i18next and Localazy</title>
      <dc:creator>Daniel Charvát</dc:creator>
      <pubDate>Mon, 30 Nov 2020 17:59:38 +0000</pubDate>
      <link>https://forem.com/localazy/how-to-localize-react-app-with-react-i18next-and-localazy-eoe</link>
      <guid>https://forem.com/localazy/how-to-localize-react-app-with-react-i18next-and-localazy-eoe</guid>
      <description>&lt;p&gt;Localization is hardly the most favorite part of development for anyone. Regardless of whether it is a web, mobile, or desktop app, it is time-consuming and error-prone. This article will show you that there is a quick and seamless way to integrate localization that does not slow down development. We'll use Localazy and react-i18next.&lt;/p&gt;

&lt;p&gt;Localazy is a universal localization management platform that supports a wide variety of frameworks and an even wider range of formats through its CLI. Localazy's most prominent features are a pro-active review process, highly accurate translation memory supported by community-shared translations and non-disturbing, and crystal clear UI which is not bloated with rarely used options. And as I'll show shortly, it works seamlessly with react-i18next. Thanks to that, managing translation strings, even with open-source projects where anybody can contribute (with varying quality), is a piece of cake 🍰.&lt;/p&gt;

&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;sign up for &lt;a href="https://localazy.com/register" rel="noopener noreferrer"&gt;Localazy&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://localazy.com/my/create" rel="noopener noreferrer"&gt;create an app&lt;/a&gt; with English as source language and &lt;em&gt;Use community translations (ShareTM)&lt;/em&gt; option enabled,&lt;/li&gt;
&lt;li&gt;select &lt;em&gt;React&lt;/em&gt; integration option and install Localazy &lt;a href="https://testing.localazy.com/docs/cli/installation" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;install and configure &lt;a href="https://react.i18next.com/" rel="noopener noreferrer"&gt;react-18next&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;create &lt;code&gt;localazy.json&lt;/code&gt; in root and paste in and modify the &lt;a href="https://localazy.com/docs/cli/quick-start-json" rel="noopener noreferrer"&gt;configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;create &lt;code&gt;locales&lt;/code&gt; folder and in it create &lt;code&gt;en.json&lt;/code&gt;.  Add any translation key-value pair,&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;localazy upload&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;in Localazy, add any language. Then review it and accept the suggested phrases,&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;localazy download&lt;/code&gt; and check locales folder for the new locale,&lt;/li&gt;
&lt;li&gt; run the app &lt;code&gt;npm run start&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sign up and app creation
&lt;/h2&gt;

&lt;p&gt;First of all, let's &lt;a href="https://localazy.com/register" rel="noopener noreferrer"&gt;set up a new account&lt;/a&gt; on Localazy and create a &lt;a href="https://localazy.com/my/create" rel="noopener noreferrer"&gt;new application&lt;/a&gt;. In this article, we'll use English as the source language, but you can generally choose any other. Make sure that the &lt;em&gt;Use community translations (ShareTM)&lt;/em&gt; option is enabled. &lt;a href="https://localazy.com/docs/general/what-is-localazy-sharetm" rel="noopener noreferrer"&gt;ShareTM&lt;/a&gt; is the highly accurate translation memory I mentioned. Thanks to it, most of the new applications have as much as 50 % of their strings automatically available for translation into 80+ languages.&lt;/p&gt;

&lt;p&gt;Proceed to create the app. Afterward, select &lt;em&gt;React&lt;/em&gt; on the integration screen. We'll use the powerful CLI tool to manage the upload and download of phrases. &lt;a href="https://testing.localazy.com/docs/cli/installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt; is available for Linux, MacOS and Windows. Note the read and write keys in step 2. We'll need it shortly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up React app
&lt;/h2&gt;

&lt;p&gt;If you don't want to follow the step-by-step guide here, you can take a look at the &lt;a href="https://github.com/localazy/react-i18next-example" rel="noopener noreferrer"&gt;finished repo&lt;/a&gt;. Otherwise, stay awhile and listen.&lt;/p&gt;

&lt;p&gt;Create a new React project with &lt;code&gt;npx create-react-app react-i18next-example&lt;/code&gt;.  Once everything is installed, add &lt;em&gt;react-i18next&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;react-i18next i18next &lt;span class="nt"&gt;--save&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to add integration with Localazy. Create &lt;code&gt;localazy.json&lt;/code&gt; in the root folder and paste the following configuration. Use the write and read keys from the step 2 of the integration guide page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"writeKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-write-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"readKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-read-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"upload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/assets/locales/en.json"&lt;/span&gt;&lt;span class="w"&gt;         
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"download"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/assets/locales/${lang}.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, create &lt;code&gt;src/assets/locales&lt;/code&gt; folder and &lt;code&gt;en.json&lt;/code&gt; file inside. Since we've set English to be the source language, this file will contain the source phrases for our application. You can fill in any key-value pair you like. I'll add this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"translation"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, my friend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"stay_awhile_and_listen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stay awhile and listen"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the application is ready to have localization managed by Localazy. Before we upload the first bunch of strings, let's prepare a test scenario with react-18next to get it off our plates. &lt;/p&gt;

&lt;p&gt;First, create &lt;code&gt;i18n.js&lt;/code&gt; in src folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initReactI18next&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./assets/locales/en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;en&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;i18n&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initReactI18next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;interpolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;escapeValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then modify &lt;code&gt;index.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;ReactDOM&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-dom&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./index.css&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;reportWebVitals&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./reportWebVitals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;ReactDOM&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;StrictMode&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/React.StrictMode&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;,
&lt;/span&gt;  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getElementById&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;root&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then &lt;code&gt;App.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;useTranslation&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;App&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;useTranslation&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="k"&gt;return &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"App"&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h1&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nf"&gt;t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stay_awhile_and_listen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;h2&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run &lt;code&gt;npm run start&lt;/code&gt;, you should see the two English phrases. Nothing fancy so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading and downloading phrases
&lt;/h2&gt;

&lt;p&gt;Let's upload the English file to Localazy. From the root folder, run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localazy upload &lt;span class="nt"&gt;-s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; argument stands for simulate. It is a good practice to test out the configuration without uploading anything to assure that nothing unexpected happens (such as some of the key-value pairs are incorrectly matched and override each other). The output should be something along these lines,  depending on the CLI version.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Localazy CLI, v1.1.9
Advanced file uploader/downloader for the Localazy translation platform.

Read more information at https://localazy.com/docs/cli

Uploading...
  - deprecate missing: false
  - import as new: false
  - app version: 0
  - groups: (default only)
  - folder: .

Processing files...

./src/assets/locales/en.json
  (file=file.json, lang=inherited, type=json)

Verifying...

Validating...

Done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything worked out well and our English file was matched. This time let's let upload it for real.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localazy upload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refresh your app page and you should see the English language on the list. Open the &lt;em&gt;Add languages&lt;/em&gt; tab and there you find a couple of languages with info about the percentage of automated translations. It is possible that you will see either 50 % or 100 %. The automated matching with ShareTM improves all the time and it's likely that thanks to this article you would have all the phrases automatically translated. How cool is that? 🙂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fadd_language_screen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fadd_language_screen.png" title="ShareTM suggestions" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One way or another, look up Spanish and add it to your app. You'll see there is a review button. Every time ShareTM provides a translation suggestion it will have candidate status. This means that it will be ready for review and any reviewer can either approve it or decline. Go ahead and approve the suggested phrase(s). &lt;/p&gt;

&lt;p&gt;In case that the ShareTM did not translate 100 % of phrases, come back to the languages list and notice that the review button now reads translate. Localazy recognizes that there is nothing to review but still something to translate, so it offers you the next most likely action in one click. Translate the other phrase (you may use a suggested phrase on the translation page). This time you do not need to go through the review process since you are a trusted translator as owner by default, so the translation is immediately approved.&lt;/p&gt;

&lt;p&gt;It's time to go back to the React project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localazy download
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this command, you'll download all the newly accepted phrases and newly added languages. In the &lt;em&gt;locales&lt;/em&gt; folder, we can see there is newly &lt;code&gt;es.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The last thing to be done is to update &lt;code&gt;i18n.js&lt;/code&gt;, add the Spanish locale resource file and switch the app's language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;initReactI18next&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react-i18next&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./assets/locales/en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;es&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./assets/locales/es.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;resources&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;es&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;i18n&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;initReactI18next&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="nx"&gt;resources&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;lng&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;es&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;interpolation&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;escapeValue&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// not needed for react as it escapes by default&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;


&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you run the app again, you'll see that the phrases were correctly translated to Spanish.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;I hope you've enjoyed this short intro into Localazy with react-i18next. If you'd like to get closer to us, join us on &lt;a href="https://discord.gg/CAVhHrh" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://https:/localazy.com/blog/how-to-localize-react-app-with-react-i18next-and-localazy" rel="noopener noreferrer"&gt;Localazy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>reacti18next</category>
      <category>localazy</category>
      <category>localization</category>
    </item>
    <item>
      <title>How to localize Vue.js app with vue-i18n and Localazy</title>
      <dc:creator>Daniel Charvát</dc:creator>
      <pubDate>Tue, 27 Oct 2020 15:41:42 +0000</pubDate>
      <link>https://forem.com/localazy/how-to-localize-vue-js-app-with-vue-i18n-and-localazy-50p7</link>
      <guid>https://forem.com/localazy/how-to-localize-vue-js-app-with-vue-i18n-and-localazy-50p7</guid>
      <description>&lt;p&gt;Localization of any type of application, be it a web, mobile or desktop app, can be tedious and irritating. In this article, I'll show you how can you handle that easily with Localazy and vue-18n in a way that you'll spend your time effectively and actually enjoy the localization process.&lt;/p&gt;

&lt;p&gt;Localazy is a universal localization management platform that supports a wide variety of frameworks and an even wider range of formats through its CLI. Localazy's most prominent features are a pro-active review process, highly accurate translation memory supported by community-shared translations and non-disturbing, and crystal clear UI which is not bloated with rarely used options. And as I'll show shortly, it works seamlessly with vue-i18n. Thanks to that, managing translation strings, even with open-source projects where anybody can contribute (with varying quality), is a piece of cake 🍰.&lt;/p&gt;

&lt;h2&gt;
  
  
  tldr;
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;sign up for &lt;a href="https://localazy.com/register" rel="noopener noreferrer"&gt;Localazy&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://localazy.com/my/create" rel="noopener noreferrer"&gt;create an app&lt;/a&gt; with English as source language and &lt;em&gt;Use community translations (ShareTM)&lt;/em&gt; option enabled,&lt;/li&gt;
&lt;li&gt;select &lt;em&gt;Vue.js&lt;/em&gt; integration option and install Localazy &lt;a href="https://localazy.com/docs/cli/installation" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;install and configure &lt;a href="https://kazupon.github.io/vue-i18n/" rel="noopener noreferrer"&gt;vue-i18n&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;create &lt;code&gt;localazy.json&lt;/code&gt; in root and paste in and modify the &lt;a href="https://localazy.com/docs/cli/quick-start-json" rel="noopener noreferrer"&gt;configuration&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;create &lt;code&gt;locales&lt;/code&gt; folder and in it create &lt;code&gt;en.json&lt;/code&gt;.  Add any translation key-value pair&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;localazy upload&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;in Localazy, add any language. Then review it and accept the suggested phrases,&lt;/li&gt;
&lt;li&gt;run &lt;code&gt;localazy download&lt;/code&gt; and check locales folder for the new locale,&lt;/li&gt;
&lt;li&gt; run the app &lt;code&gt;npm run serve&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Sign up and app creation
&lt;/h2&gt;

&lt;p&gt;First of all, let's &lt;a href="https://localazy.com/register" rel="noopener noreferrer"&gt;set up a new account&lt;/a&gt; on Localazy and create a &lt;a href="https://localazy.com/my/create" rel="noopener noreferrer"&gt;new application&lt;/a&gt;. In this article, we'll use English as the source language, but you can generally choose any other. Make sure that the &lt;em&gt;Use community translations (ShareTM)&lt;/em&gt; option is enabled. &lt;a href="https://localazy.com/docs/general/what-is-localazy-sharetm" rel="noopener noreferrer"&gt;ShareTM&lt;/a&gt; is the highly accurate translation memory I mentioned. Thanks to it, most of the new applications have as much as 50 % of their strings automatically available for translation into 80+ languages.&lt;/p&gt;

&lt;p&gt;Proceed to create the app. Afterward, select &lt;em&gt;Vue.js&lt;/em&gt; on the integration screen. We'll use the powerful CLI tool to manage the upload and download of phrases. &lt;a href="https://localazy.com/docs/cli/installation" rel="noopener noreferrer"&gt;Installation&lt;/a&gt; is available for Linux, MacOS and Windows. Note the read and write keys in step 2. We'll need it shortly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Set up Vue project
&lt;/h2&gt;

&lt;p&gt;If you don't want to follow the step-by-step guide here, you can take a look at the &lt;a href="https://github.com/localazy/vue-18n-example" rel="noopener noreferrer"&gt;finished repo&lt;/a&gt;. Otherwise, stay awhile and listen.&lt;/p&gt;

&lt;p&gt;Create a new Vue project with &lt;code&gt;vue create vue-i18n-example&lt;/code&gt; (if you don't have Vue CLI installed, run &lt;code&gt;npm install -g @vue/cli&lt;/code&gt;) and use &lt;em&gt;Vue 2&lt;/em&gt; preset.  Once everything is installed, add vue-i18n.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install &lt;/span&gt;vue-i18n
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now it's time to add integration with Localazy. Create &lt;code&gt;localazy.json&lt;/code&gt; in the root folder and paste the following configuration. Use the write and read keys from the step 2 of the integration guide page.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"writeKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-write-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"readKey"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-read-key"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"upload"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;  
      &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/assets/locales/en.json"&lt;/span&gt;&lt;span class="w"&gt;         
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"download"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"files"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"src/assets/locales/${lang}.json"&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Additionally, create &lt;code&gt;src/assets/locales&lt;/code&gt; folder and &lt;code&gt;en.json&lt;/code&gt; file inside. Since we've set English to be the source language, this file will contain the source phrases for our application. You can fill in any key-value pair you like. I'll add this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hello"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Hello, my friend"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"stay_awhile_and_listen"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Stay awhile and listen"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, the application is ready to have localization managed by Localazy. Before we upload the first bunch of strings, let's prepare a test scenario with vue-i18n to get it off our plates. &lt;/p&gt;

&lt;p&gt;First modify &lt;code&gt;main.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;VueI18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue-i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/assets/locales/en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;VueI18n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VueI18n&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;en&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productionTip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;$mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And then &lt;code&gt;App.vue&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight vue"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;div&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"app"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt;&lt;span class="nf"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;hello&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;h2&amp;gt;&lt;/span&gt;&lt;span class="si"&gt;{{&lt;/span&gt;&lt;span class="nf"&gt;$t&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;stay_awhile_and_listen&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}}&lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/h2&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/div&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;template&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;App&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;script&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="nt"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nf"&gt;#app&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;font-family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Avenir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Helvetica&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;sans-serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-webkit-font-smoothing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;antialiased&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;-moz-osx-font-smoothing&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;grayscale&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;text-align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#2c3e50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;margin-top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;60px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="k"&gt;style&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you run &lt;code&gt;npm run serve&lt;/code&gt;, you should see the two English phrases. Nothing fancy so far.&lt;/p&gt;

&lt;h2&gt;
  
  
  Uploading and downloading phrases
&lt;/h2&gt;

&lt;p&gt;Let's upload the English file to Localazy. From the root folder, run the following command&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localazy upload &lt;span class="nt"&gt;-s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;-s&lt;/code&gt; argument stands for simulate. It is a good practice to test out the configuration without uploading anything to assure that nothing unexpected happens (such as some of the key-value pairs are incorrectly matched and override each other). The output should be something along these lines,  depending on the CLI version&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Localazy CLI, v1.1.9
Advanced file uploader/downloader for the Localazy translation platform.

Read more information at https://localazy.com/docs/cli

Uploading...
  - deprecate missing: false
  - import as new: false
  - app version: 0
  - groups: (default only)
  - folder: .

Processing files...

./src/assets/locales/en.json
  (file=file.json, lang=inherited, type=json)

Verifying...

Validating...

Done.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything worked out well and our English file was matched. This time let's let upload it for real.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localazy upload
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Refresh your app page and you should see the English language on the list. Open the &lt;em&gt;Add languages&lt;/em&gt; tab and there you find a couple of languages with info about the percentage of automated translations. It is possible that you will see either 50 % or 100 %. The automated matching with ShareTM improves all the time and it's likely that thanks to this article you would have all the phrases automatically translated. How cool is that? 🙂&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fadd_language_screen.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Fadd_language_screen.png" title="ShareTM suggestions" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One way or another, look up German and add it to your app. You'll see there is a review button. Every time ShareTM provides a translation suggestion it will have candidate status. This means that it will be ready for review and any reviewer can either approve it or decline. Go ahead and approve the suggested phrase(s). &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Freview_for_sharetm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdirectus.localazy.com%2F_%2Fassets%2Freview_for_sharetm.png" title="Review phrases by ShareTM" alt="alt text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In case that the ShareTM did not translate 100 % of phrases, come back to the languages list and notice that the review button now reads translate. Localazy recognizes that there is nothing to review but still something to translate, so it offers you the next most likely action in one click. Translate the other phrase (you may use a suggested phrase on the translation page). This time you do not need to go through the review process since you are a trusted translator as owner by default, so the translation is immediately approved.&lt;/p&gt;

&lt;p&gt;It's time to go back to the Vue project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;localazy download
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this command, you'll download all the newly accepted phrases and newly added languages. In the &lt;em&gt;locales&lt;/em&gt; folder, we can see there is newly &lt;code&gt;de.json&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The last thing to be done is to update &lt;code&gt;main.js&lt;/code&gt; and add the German locale resource file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Vue&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./App.vue&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;VueI18n&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;vue-i18n&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/assets/locales/en.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;../src/assets/locales/de.json&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;


&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;en&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;de&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;use&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;VueI18n&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;i18n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;VueI18n&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;de&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;messages&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;


&lt;span class="nx"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;productionTip&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;

&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Vue&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="nx"&gt;i18n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;render&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;h&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;h&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;$mount&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;#app&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you run the app again, you'll see that the phrases were correctly translated to German.&lt;/p&gt;

&lt;h2&gt;
  
  
  Closing words
&lt;/h2&gt;

&lt;p&gt;I hope you've enjoyed this short intro into Localazy with vue-i18n. If you'd like to get closer to us, join us on &lt;a href="https://discord.gg/CAVhHrh" rel="noopener noreferrer"&gt;Discord&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;This article was originally published on &lt;a href="https://https:/localazy.com/blog/how-to-localize-Vue-js-app-with-vue-i18n-and-localazy" rel="noopener noreferrer"&gt;Localazy&lt;/a&gt;&lt;/p&gt;

</description>
      <category>vue</category>
      <category>vuei18n</category>
      <category>localazy</category>
      <category>localization</category>
    </item>
    <item>
      <title>How to pass function to Web Workers</title>
      <dc:creator>Daniel Charvát</dc:creator>
      <pubDate>Sun, 11 Oct 2020 08:22:45 +0000</pubDate>
      <link>https://forem.com/localazy/how-to-pass-function-to-web-workers-4ee1</link>
      <guid>https://forem.com/localazy/how-to-pass-function-to-web-workers-4ee1</guid>
      <description>&lt;p&gt;Web Workers allow for something similar to multithread operations that are common in languages such as Java or C++. In front end world, they are tool which is yet to be more frequently used. &lt;br&gt;
That's, in my opinion, mainly due to lack of knowledge about their use cases, misjudgment that most people have fast PCs and modern browsers, and force of habit of sticking to what one knows (I second that). Additionally, there some limitations to their usage, such as the inability to pass functions into them.&lt;/p&gt;
&lt;h2&gt;
  
  
  Why to use Web Workers
&lt;/h2&gt;

&lt;p&gt;Web worker is a mere script that runs in the background, in another thread, which means that any calculation, however expensive, will not block the UI's thread. That's huge. People hate when websites become slow or even worse, non-responsive. With  Web Workers, you can do the heavy lifting in the background while showing the user a loading indicator and letting him or her do whatever else in the meantime. &lt;/p&gt;

&lt;p&gt;You may ask when this is useful. We've put this into good use when we worked with a recursive tree structure. We were processing the whole tree with thousands of nodes each time the user interacted with the tree. That included loads of calculations and had we had done all of that in the main thread + render the result at the end, even the most beastly pc sets would have growled about it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Limitations of Web Workers
&lt;/h2&gt;

&lt;p&gt;Since the Web Workers run in another thread, there are limitations to what it can and cannot do.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It cannot access the DOM directly and you lose direct access to &lt;em&gt;window&lt;/em&gt; object.&lt;/li&gt;
&lt;li&gt;you cannot rely on a global state within them.&lt;/li&gt;
&lt;li&gt;you cannot send in data that cannot be handled by &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Guide/DOM/The_structured_clone_algorithm"&gt;structured clone&lt;/a&gt; algorithm&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last has turned out to be the most painful for me. You see, when you have an instance of a Web Worker, you may send in data through &lt;code&gt;postMessage&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;string&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;array&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[],&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Those value types above can be handled by the structured cloning. However, you cannot send in functions because they can be neither cloned nor &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/Transferable"&gt;transferred&lt;/a&gt;. That was a problem, because we wanted to send in an evaluator for each of the nodes (e.g. whether its name matches a search term), for which we needed a function inside of the worker.&lt;/p&gt;

&lt;h2&gt;
  
  
  Overcoming the no-functions limitation
&lt;/h2&gt;

&lt;p&gt;There is a simple trick on how to solve this. As any other object or value, and in javascript especially since functions here are First-class citizens, we may define functions within objects and stringify them through &lt;code&gt;JSON.stringify&lt;/code&gt;. This transforms the function declaration a bit, so parsing them back requires a bit of effort. Luckily, there's &lt;a href="https://github.com/vkiryukhin/jsonfn"&gt;JSONfn&lt;/a&gt; plugin that handles it well both ways.&lt;/p&gt;

&lt;p&gt;And that's that is required. Now you can declare and object which includes functions for the Web Worker, stringified with JSONfn:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// From main thread&lt;/span&gt;
&lt;span class="nx"&gt;worker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;postMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;JSONfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;arg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt; &lt;span class="c1"&gt;// any kind of data, let the function decide whether it's useful&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And reconstructed inside of the Web Worker's script&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// inside of worker&lt;/span&gt;
&lt;span class="nb"&gt;self&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;message&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// `e.data` contains data sent from main thread&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;myFunction&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSONfn&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nx"&gt;myFunction&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// reconstructed and callable&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As you can see, if we have several functions which need different arguments, we have to be careful. This is similar to an observer pattern in the way commonly implemented in C# for instance, where several observers subscribe to the dispatcher, and when they receive data, the observers have to handle the payload and decide whether they can use that message. Here it is the same. The most scalable option I've found is to have two stable parameters, one for functions and one for their arguments a simply send it both in arrays. Then when the event occurs, send all the arguments to all the functions and let them handle it. &lt;/p&gt;

&lt;h3&gt;
  
  
  A side note about classes
&lt;/h3&gt;

&lt;p&gt;Be aware that the above-described approach will not work if you use classes. Although from the maintainability and readability perspective it would have made a perfect sense to use classes and typescript interfaces, it is not possible. The stringify method can turn to a string only those values it has access to directly. However, when you define something as a class method, it is attached merely to the object's prototype. It does not directly exist on the object itself.&lt;/p&gt;




&lt;p&gt;This article has been originally published on &lt;a href="https://localazy.com/blog/how-to-pass-function-to-web-workers"&gt;localazy.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>webworkers</category>
    </item>
    <item>
      <title>Sharing asynchronous data between Nuxt.js modules</title>
      <dc:creator>Daniel Charvát</dc:creator>
      <pubDate>Wed, 16 Sep 2020 08:07:57 +0000</pubDate>
      <link>https://forem.com/localazy/sharing-asynchronous-data-between-nuxt-js-modules-591d</link>
      <guid>https://forem.com/localazy/sharing-asynchronous-data-between-nuxt-js-modules-591d</guid>
      <description>&lt;p&gt;If you’ve developed some sites in Nuxt.js, there’s a decent chance that you’ve had to asynchronously fetch data during the generation. However, there are often times when several modules such as the internal route module, sitemap module, or the RSS feed module require the same data from the database. Alas, there is no easy way to share the fetched data between the modules as they run in an isolated synchronous order. Or is there?&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the Localazy scenes
&lt;/h2&gt;

&lt;p&gt;We've found ourselves in a spot where we generate dozens of dynamic routes and that kind of data has to be used for dynamic routes, sitemap generation and the RSS feed for our blog posts. In truth, it's already quite challenging to generate all the dynamic routes with each website update itself. Since the Nuxt v2.13 there is a &lt;a href="https://nuxtjs.org/api/configuration-generate/#crawler"&gt;crawler&lt;/a&gt; option that enables detection of all the reachable dynamic routes by crawling through the statically generated content. However, I've had mixed success with it and doing it manually still seems like a safer option.&lt;/p&gt;

&lt;p&gt;I will not go into much detail on how to fetch the data and generate all the dynamic routes. If you would like to know more, join us on &lt;a href="https://discord.gg/CAVhHrh"&gt;Discord&lt;/a&gt; and reach out to me. Anyways, once you have the data, the trick to share them lies in having access to the filesystem through &lt;a href="https://github.com/jprichardson/node-fs-extra"&gt;fse-extra&lt;/a&gt; within the Nuxt modules. So once you fetch the data, you can store them as a JSON file in the distribution folder.&lt;/p&gt;

&lt;h2&gt;
  
  
  Preparing the data
&lt;/h2&gt;

&lt;p&gt;In our case, we begin in our custom module for data retreival and route generation. One of the final parts of it looks as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;generateRoutes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tablesToRoutes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
  &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;entries&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;tablesToRoutes&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="nx"&gt;entry&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;route&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;table&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;table&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;payload&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;payload&lt;/span&gt;
      &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;});&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Essentially, for each entry we resolve the proper route path, not important. The crucial part is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;payload: route.payload
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We're storing the whole object that we've fetched under payload property. The &lt;code&gt;route.payload&lt;/code&gt; is manufactured in one of the previous steps.&lt;/p&gt;

&lt;p&gt;Once we have this gigantic array of route objects, we can step in into the final &lt;a href="https://nuxtjs.org/api/internals-generator#hooks"&gt;Nuxt's generation hook&lt;/a&gt; and store it as JSON.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fse&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs-extra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// comes with Nuxt already&lt;/span&gt;

&lt;span class="nx"&gt;moduleContainer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nuxt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;hook&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;generate:done&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;outputJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;nuxt&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/routes.json`&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;spaces&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;EOL&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The above is quite self-explanatory, perhaps except for &lt;code&gt;this.nuxt.options.generate.dir&lt;/code&gt;. When you read more about the Nuxt modules, you'll find in which context is the code executed and this is just one of the properties you have access to by default.&lt;/p&gt;

&lt;h2&gt;
  
  
  Sharing the data
&lt;/h2&gt;

&lt;p&gt;Now when you run &lt;code&gt;npm run generate&lt;/code&gt;, you'll find in your distribution folder (&lt;em&gt;dist&lt;/em&gt; by default) a file called &lt;strong&gt;routes.json&lt;/strong&gt;. The file contains an array of the data we've fetched in the module, in our case one entry may look like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;route&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;/blog/kotlin-mpp-and-http-with-wininet-api-on-windows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;payload&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;modified_on&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2020-09-09T12:57:04+00:00&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;slug&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;kotlin-mpp-and-http-with-wininet-api-on-windows&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;priority&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;0.7&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;changefreq&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;monthly&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;...&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;That's everything we need in the other modules, so there is absolutely no need to refetch anything :) Let's show how to utilize this in the commonly used &lt;a href="https://github.com/nuxt-community/sitemap-module"&gt;sitemap&lt;/a&gt; module.&lt;/p&gt;

&lt;p&gt;First, let's modify the config in &lt;code&gt;nuxt.config.js&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;  &lt;span class="nx"&gt;sitemap&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/sitemap.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;hostname&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://localazy.com&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;sitemaps&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/static.xml&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;routes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;generateSitemap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;generate&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;dir&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We'll dive into the &lt;code&gt;generateSitemap&lt;/code&gt; in a second, but notice the argument first. We'll need to know where to find the JSON file and since we're not creating a module, but only a function to generate routes for the sitemap module, we will not have access to &lt;strong&gt;nuxt.options&lt;/strong&gt; as before. But we have access to it still within &lt;code&gt;nuxt.config.js&lt;/code&gt;, so let's just pass the path to the generated folder.&lt;/p&gt;

&lt;p&gt;The definition of &lt;code&gt;generateSitemap&lt;/code&gt; would vary for everyone, but the important bit are the first lines&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;fse&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;fs-extra&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;sitemapRoutes&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;generateDir&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routesJson&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;fse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readJson&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;generateDir&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/routes.json`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;As we know path to the JSON file, it's enough to read it's content. This grants us access to all the data we've prepared in the previously executed module and there is no need to re-fetch anything. This makes the generation considerably faster and puts less load on your database.&lt;/p&gt;

&lt;p&gt;Obviously we could repeat this pattern for any other Nuxt module. Needless to say that with every additional module that would require such data, the benefits become even more obvious.&lt;/p&gt;




&lt;p&gt;This article has been originally published on &lt;a href="https://localazy.com/blog/sharing-asynchronous-data-between-nuxtjs-modules"&gt;localazy.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>nuxt</category>
    </item>
  </channel>
</rss>
