<?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: Jakub Pomykała</title>
    <description>The latest articles on Forem by Jakub Pomykała (@jpomykala).</description>
    <link>https://forem.com/jpomykala</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%2F148038%2F0b92d49d-dc4d-4f19-80f0-eb022139cdc2.jpeg</url>
      <title>Forem: Jakub Pomykała</title>
      <link>https://forem.com/jpomykala</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jpomykala"/>
    <language>en</language>
    <item>
      <title>What is CORS?</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Tue, 18 Oct 2022 09:36:06 +0000</pubDate>
      <link>https://forem.com/jpomykala/what-is-cors-11kf</link>
      <guid>https://forem.com/jpomykala/what-is-cors-11kf</guid>
      <description>&lt;p&gt;In this article, I will explain what CORS and CORS errors are and why you might run into them. I will present possible solutions and explain what preflight requests, CORS headers are, and why they are important in the communication between parties. The article assumes you have some basic knowledge of web development and the HTTP protocol. I tried to write the article in a way that is easy to understand for beginners and fill it with knowledge and try to avoid too many technical nuances that are not tightly connected with the CORS topic. If you spotted any mistakes or have any suggestions, do not hesitate to contact me. In some places, I made a simplification where a service means server and vice versa.&lt;/p&gt;

&lt;h2&gt;
  
  
  What is CORS?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Cross-Origin Resource Sharing (CORS) is an HTTP-based security mechanism controlled and enforced by the client (web browser).&lt;/strong&gt; It allows a service (API) to indicate any origin other than its own from which the client can request resources. It has been designed in response to &lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy" rel="noopener noreferrer"&gt;the same-origin policy&lt;/a&gt; (SOP) that restricts how a website (HTML document or JS script) loaded by one origin can interact with a resource from another origin. CORS is used to explicitly allow some cross-origin requests while rejecting others.&lt;/p&gt;

&lt;p&gt;CORS is implemented primarily in web browsers, but it can also be used in API clients as an option. It's present in all popular web browsers like Google Chrome, Firefox, Opera, and Safari. The standard has been &lt;a href="https://en.wikipedia.org/wiki/Cross-origin_resource_sharing" rel="noopener noreferrer"&gt;accepted as a W3C Recommendation in January 2014&lt;/a&gt;. Based on that, we can assume that it is implemented in all currently available and other than listed web browsers.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it work?
&lt;/h3&gt;

&lt;p&gt;Everything starts on the client side, before sending the main request. The client sends a CORS preflight request to a service for resources with parameters in HTTP headers (CORS headers). The service responses using the same headers with different or the same values. The client decides, based on a CORS preflight response, if he can or cannot send the main request to the service. The web browser (client) will throw an error if the response does not meet the requirements of CORS preflight.&lt;/p&gt;

&lt;p&gt;CORS preflight requests are sent regardless of the used libraries or frameworks to send requests from web browser. That's why you won't need to conform CORS requirements when working with API from your backend application.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;CORS is not going to prevent users from requesting or downloading resources. You can still make a successful request&lt;br&gt;
for a resource using apps like &lt;a href="https://curl.se/" rel="noopener noreferrer"&gt;curl&lt;/a&gt;, &lt;a href="https://insomnia.rest/" rel="noopener noreferrer"&gt;Insomnia&lt;/a&gt;,&lt;br&gt;
or &lt;a href="https://www.postman.com/" rel="noopener noreferrer"&gt;Postman&lt;/a&gt;. CORS is only going to prevent the browser from accessing the resource if the&lt;br&gt;
CORS policy does not allow it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  What is a CORS preflight?
&lt;/h2&gt;

&lt;p&gt;When a browser sends a request to a server, it first sends an &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/OPTIONS" rel="noopener noreferrer"&gt;HTTP Options request&lt;/a&gt;. This is called a CORS preflight request. The server then responds with a list of allowed methods and headers. If the browser is allowed to make the actual request, it sends the actual request. If not, it shows an error and does not continue to send the main request.&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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-scheme-server-client.jpg" 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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-scheme-server-client.jpg" alt="CORS preflight: Server-Client Requests Scheme"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  CORS Headers
&lt;/h2&gt;

&lt;p&gt;CORS headers are regular HTTP headers that are used to control the CORS policy. They are used in requests where the browser sends a CORS preflight request to the server, and the server responses with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; indicates what origin can fetch resources. Use one or more origins, e.g.: &lt;code&gt;https://foo.io,http://bar.io&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Access-Control-Allow-Methods&lt;/code&gt; indicates what HTTP methods are allowed. Use one or more comma HTTP methods, e.g.: &lt;code&gt;GET,PUT,POST&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Access-Control-Allow-Headers&lt;/code&gt; indicates what request headers are allowed. Use one or more headers, e.g.: &lt;code&gt;Authorization,X-My-Token&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Access-Control-Allow-Credentials&lt;/code&gt; indicates if sending cookies is allowed. Default: &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Access-Control-Max-Age&lt;/code&gt; - indicates how long the request result should be cached, in seconds. Default: &lt;code&gt;0&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you decide to use &lt;code&gt;Access-Control-Allow-Credentials=true&lt;/code&gt;, then you need to be aware of the fact you cannot use  wildcards &lt;code&gt;*&lt;/code&gt; in &lt;code&gt;Access-Control-Allow-*&lt;/code&gt; headers. It's required to explicitly list all allowed origins, methods, and headers.&lt;/p&gt;

&lt;p&gt;See a &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#the_http_response_headers" rel="noopener noreferrer"&gt;full list of CORS headers&lt;/a&gt;.&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%2Fsimplelocalize.io%2Fblog%2Fbrowser-server-preflight-request-and-response-headers.jpg" 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%2Fsimplelocalize.io%2Fblog%2Fbrowser-server-preflight-request-and-response-headers.jpg" alt="cors request and response headers"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Why is request blocked by CORS policy?
&lt;/h2&gt;

&lt;p&gt;If you are a web developer, you have probably already seen or heard about CORS errors, and you have googled it many times to find the solution. The most common problem is that the browser blocks the request because of CORS policy. The browser will throw an error and show a log in the console:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;Access&lt;/span&gt; &lt;span class="err"&gt;to&lt;/span&gt; &lt;span class="err"&gt;XMLHttpRequest&lt;/span&gt; &lt;span class="err"&gt;at&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="py"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;//localhost:8080/' from origin&lt;/span&gt;
&lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="py"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;//localhost:3000' has been blocked by CORS policy:&lt;/span&gt;
&lt;span class="err"&gt;Response&lt;/span&gt; &lt;span class="err"&gt;to&lt;/span&gt; &lt;span class="err"&gt;preflight&lt;/span&gt; &lt;span class="err"&gt;request&lt;/span&gt; &lt;span class="err"&gt;doesn't&lt;/span&gt; &lt;span class="err"&gt;pass&lt;/span&gt; &lt;span class="err"&gt;access&lt;/span&gt; &lt;span class="err"&gt;control&lt;/span&gt;
&lt;span class="py"&gt;check&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s"&gt;No 'Access-Control-Allow-Origin' header is present&lt;/span&gt;
&lt;span class="err"&gt;on&lt;/span&gt; &lt;span class="err"&gt;the&lt;/span&gt; &lt;span class="err"&gt;requested&lt;/span&gt; &lt;span class="err"&gt;resource.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CORS error above notifies a user that the browser couldn't access a resource (&lt;code&gt;https://localhost:8080&lt;/code&gt;) from an origin (&lt;code&gt;https://localhost:3000&lt;/code&gt;) because the server didn't allow it. It happened because the server didn't respond with &lt;code&gt;Access-Control-Allow-Origin&lt;/code&gt; header with the origin or with a wildcard &lt;code&gt;*&lt;/code&gt; in the CORS preflight response.&lt;/p&gt;

&lt;p&gt;A request may be blocked by CORS policy not only because of the incorrect origin, but also incorrect HTTP header, HTTP method or Cookie header.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to fix CORS error?
&lt;/h2&gt;

&lt;p&gt;The fundamental idea of "fixing CORS" is to respond to "OPTIONS" requests sent from a client with proper headers. There are many ways to start responding with the proper CORS. You can use a proxy server, or you can use middleware in your server.&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%2Fsimplelocalize.io%2Fblog%2Fresponse-preflight-request-doesnt-pass-access-control-check.jpg" 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%2Fsimplelocalize.io%2Fblog%2Fresponse-preflight-request-doesnt-pass-access-control-check.jpg" alt="Response to preflight request doesn't pass access control check"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Remember that &lt;code&gt;Access-Control-*&lt;/code&gt; headers are cached in a web browser according to the value set in &lt;code&gt;Access-Control-Max-Age&lt;/code&gt; header. Please make sure that you clear the cache before testing the changes. You can also &lt;a href="https://stackoverflow.com/questions/5690269/disabling-chrome-cache-for-website-development" rel="noopener noreferrer"&gt;disable caching in your browser&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Configure your server
&lt;/h3&gt;

&lt;p&gt;By default, if you are a server owner, you need to configure CORS responses in your server and this is the only way to address the issue properly. You can achieve this in multiple ways and on multiple layers of your app. The most common way is to use reverse-proxy, API gateway, or any other routing service that offers to add headers to the responses. There are many services that you can use to do this, some of them are: HAProxy, Linkerd, Istio, Kong, nginx, Apache, Traefik. If your infrastructure contains only an application without any additional layers, then you can simply add CORS support in the application code.&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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-requests-in-firefox-developer-console.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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-requests-in-firefox-developer-console.png" alt="successful CORS preflight requests in Firefox Developer console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here are some popular examples of enabling CORS:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://enable-cors.org/server_apache.html" rel="noopener noreferrer"&gt;Apache: modify .htaccess file&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://enable-cors.org/server_nginx.html" rel="noopener noreferrer"&gt;Nginx: modify configuration file&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://doc.traefik.io/traefik/middlewares/http/headers/#cors-headers" rel="noopener noreferrer"&gt;Traefik: use middlewares&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/jpomykala/spring-higher-order-components" rel="noopener noreferrer"&gt;Spring Boot: use &lt;code&gt;@EnableCORS&lt;/code&gt; annotation&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://expressjs.com/en/resources/middleware/cors.html" rel="noopener noreferrer"&gt;ExpressJS: use &lt;code&gt;app.use(cors())&lt;/code&gt;&lt;/a&gt;,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nextjs.org/docs/api-routes/api-middlewares#cors-support" rel="noopener noreferrer"&gt;NextJS: use request helpers&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here you can find more examples of enabling CORS in different frameworks and languages: &lt;a href="https://enable-cors.org/" rel="noopener noreferrer"&gt;enable-cors.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you cannot enable CORS in the service, but you still want to make request to it, then you need to use one of the following solutions described below.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Install a browser extension
&lt;/h3&gt;

&lt;p&gt;Using a browser extension might be a quick and easy way to solve your problems with CORS in your developer environment. The biggest advantage of using a browser extension is that you don't need to change your code or configuration. On the other hand, you need to install an extension on every web browser that you use for testing your web application.&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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-browser-extension-solution.jpg" 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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-browser-extension-solution.jpg" alt="Use browser extension to overcome CORS error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Browser extensions alter incoming preflight request by adding the necessary headers to trick the browser. It's a handy solution to work locally with the production API that accepts requests only from the production domain.&lt;/p&gt;

&lt;p&gt;You can find extensions in &lt;a href="https://chrome.google.com/webstore/search/cors?hl=en-US" rel="noopener noreferrer"&gt;Google Web Store&lt;/a&gt; or in &lt;a href="https://addons.mozilla.org/en-US/firefox/search/?q=cors" rel="noopener noreferrer"&gt;Mozilla Add-ons Library&lt;/a&gt;. In some cases, the default extension configuration might not be enough; make sure that the installed extension is configured properly. You should also be aware of that leaving the extension turned on indefinitely may cause problems on some websites. It's recommended to use them only for development purposes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Disable browser CORS checks
&lt;/h3&gt;

&lt;p&gt;You can disable CORS checks in your browser completely. To disable CORS checks in Google Chrome, you need to close the browser and start it with the &lt;code&gt;--disable-web-security&lt;/code&gt; and &lt;code&gt;--user-data-dir&lt;/code&gt; flags. By doing that, Google Chrome will not send CORS preflight requests and will not validate CORS headers.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Windows&lt;/span&gt;
chrome.exe &lt;span class="nt"&gt;--user-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"C://chrome-dev-disabled-security"&lt;/span&gt; &lt;span class="nt"&gt;--disable-web-security&lt;/span&gt; &lt;span class="nt"&gt;--disable-site-isolation-trials&lt;/span&gt;

&lt;span class="c"&gt;# macOS&lt;/span&gt;
open /Applications/Google&lt;span class="se"&gt;\ &lt;/span&gt;Chrome.app &lt;span class="nt"&gt;--args&lt;/span&gt; &lt;span class="nt"&gt;--user-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/var/tmp/chrome-dev-disabled-security"&lt;/span&gt; &lt;span class="nt"&gt;--disable-web-security&lt;/span&gt; &lt;span class="nt"&gt;--disable-site-isolation-trials&lt;/span&gt;

&lt;span class="c"&gt;# Linux&lt;/span&gt;
google-chrome &lt;span class="nt"&gt;--user-data-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"~/chrome-dev-disabled-security"&lt;/span&gt; &lt;span class="nt"&gt;--disable-web-security&lt;/span&gt; &lt;span class="nt"&gt;--disable-site-isolation-trials&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of those commands above start Google Chrome in an isolated sandbox. They will not affect your main Chrome profile.&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%2Fsimplelocalize.io%2Fblog%2Fdisabled-cors-preflight-in-web-browser.jpg" 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%2Fsimplelocalize.io%2Fblog%2Fdisabled-cors-preflight-in-web-browser.jpg" alt="Disable security in Google Chrome to overcome CORS error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;See list of all &lt;a href="https://peter.sh/experiments/chromium-command-line-switches/" rel="noopener noreferrer"&gt;available flags for Google Chrome&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  4. Set up a proxy server
&lt;/h3&gt;

&lt;p&gt;If you are looking for a solution that doesn't require you to change the browser settings, then you should look at the proxy server solution. This option helps you to overcome CORS errors without changing anything in the browser itself. The idea of using a proxy server is to send all requests to your server, and then the server will send the request to the actual service you want to use. You can build a proxy server on your own in a language and framework of your choice. You will need to configure CORS and implement a functionality to pass requests received requests to another service.&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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-proxy-server-solution.jpg" 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%2Fsimplelocalize.io%2Fblog%2Fcors-preflight-proxy-server-solution.jpg" alt="Use proxy server to overcome CORS error"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Proxy server is a good solution if you don't have access to the service you intend to use. There are ready to use and open-source proxy server services, but you should always ensure that they are not trying to intercept your requests with authorization headers and pass them to any 3rd party service. Such security breaches could be catastrophic failure for you and potential users of the service.&lt;/p&gt;

&lt;p&gt;List of open-source CORS services that you can find on the internet:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/Freeboard/thingproxy" rel="noopener noreferrer"&gt;https://github.com/Freeboard/thingproxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/bulletmark/corsproxy" rel="noopener noreferrer"&gt;https://github.com/bulletmark/corsproxy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/Rob--W/cors-anywhere" rel="noopener noreferrer"&gt;https://github.com/Rob--W/cors-anywhere&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Please review the code of the newest version before using any of those services.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to test CORS?
&lt;/h2&gt;

&lt;p&gt;Using a browser to test your CORS configuration might be a tedious task. You can use a tool like &lt;a href="https://cors-test.codehappy.dev" rel="noopener noreferrer"&gt;CORS Tester&lt;/a&gt;, &lt;a href="https://www.test-cors.org/" rel="noopener noreferrer"&gt;test-cors.org&lt;/a&gt;, or, if you are familiar with the command line, you can use &lt;a href="https://curl.se/" rel="noopener noreferrer"&gt;curl&lt;/a&gt; to test your CORS configuration.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;curl&lt;/span&gt; &lt;span class="err"&gt;-v&lt;/span&gt; &lt;span class="err"&gt;-X&lt;/span&gt; &lt;span class="err"&gt;OPTIONS&lt;/span&gt; &lt;span class="py"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s"&gt;//simplelocalize.io/api/v1/translations&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&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%2Fsimplelocalize.io%2Fblog%2Ffree-cors-tester-web-application.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%2Fsimplelocalize.io%2Fblog%2Ffree-cors-tester-web-application.png" alt="free open-source web-based CORS tester"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Beware of false CORS errors
&lt;/h2&gt;

&lt;p&gt;In some cases, when a service is behind an additional layer with rate-limiter, load balancer or authorization server, you can get a false CORS error. Blocked or rejected requests by a server should respond with error status codes. E.g.,:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;401 unauthorized,&lt;/li&gt;
&lt;li&gt;403 forbidden,&lt;/li&gt;
&lt;li&gt;429 too many requests,&lt;/li&gt;
&lt;li&gt;500 internal server error,&lt;/li&gt;
&lt;li&gt;any other than 2XX or 3XX.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You may see that the request is blocked due to failed preflight request, but in fact, a service just rejects it. You should always check the status code and response body of the response to avoid unnecessary debugging. The browser properly alerts you when a CORS preflight request fails, but the reason for the failure is not necessarily connected to the CORS configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;In this article, I tried to explain what CORS is, and what are the most common problems with it. I suggested 4 ways to fix CORS issues and explained the advantages and disadvantages of each one. I also explained how to configure CORS responses properly and how to test them. Moreover, I showed what are the most common issues with recognizing false CORS errors. I tried to put everything in simple terms and avoid technical nuances. If you have any questions, doubts, or suggestions, please do not hesitate to contact me.&lt;/p&gt;

&lt;p&gt;Happy coding!&lt;/p&gt;

&lt;h2&gt;
  
  
  Resources
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS/Errors&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy" rel="noopener noreferrer"&gt;https://developer.mozilla.org/en-US/docs/Web/Security/Same-origin_policy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://enable-cors.org/" rel="noopener noreferrer"&gt;https://enable-cors.org/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/42024918/1133169" rel="noopener noreferrer"&gt;https://stackoverflow.com/a/42024918/1133169&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>🔎 How I integrated Algolia search with NextJS and markdown files?</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Tue, 12 Apr 2022 00:00:00 +0000</pubDate>
      <link>https://forem.com/jpomykala/how-i-integrated-algolia-search-with-nextjs-and-markdown-files-4map</link>
      <guid>https://forem.com/jpomykala/how-i-integrated-algolia-search-with-nextjs-and-markdown-files-4map</guid>
      <description>&lt;p&gt;Since 2019 I’m building a &lt;a href="https://simplelocalize.io"&gt;SaaS for translation management&lt;/a&gt; as a solo developer. Since the very beginning, I needed a place where I could post code samples, and explain people how to integrate different frameworks or how to use SimpleLocalize CLI to upload and download translation files. You can see Algolia search in action on &lt;a href="https://simplelocalize.io/docs/"&gt;SimpleLocalize documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--sufbghp3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2022-04-12/example-search-results.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--sufbghp3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2022-04-12/example-search-results.png" alt="algolia nextjs markdown example" width="880" height="739"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At beginning, I started using &lt;a href="https://www.gitbook.com"&gt;GitBook&lt;/a&gt; software because it was shining and trendy at the time. It was a good move, because when you start something new you don’t want to start from scratch on every level. The main goal is to deliver good quality code and value to the customers, all other things you can (or should) buy to save time.&lt;/p&gt;

&lt;p&gt;Short story long, I wasn’t quite happy with the GitBook after couple of months, because it didn’t fit to my needs, I didn’t like the style, and I was spending too much time on adjusting and fixing links and so on. I decided to go with my custom documentation, and surprisingly everything went smoothly! The only concert was lack o good search ability which is available in all documentation solutions, or &lt;a href="https://github.com/facebook/docusaurus"&gt;open-source Docusaurus&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;

&lt;p&gt;Algolia search components and Algolia client installation&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install react-instantsearch-dom algoliasearch --save

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://github.com/jonschlinkert/gray-matter"&gt;gray-matter&lt;/a&gt; a Markdown parser and &lt;a href="https://github.com/sindresorhus/globby"&gt;globby&lt;/a&gt; for finding files&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install gray-matter globby --saveDev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Configuration
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import algoliasearch from 'algoliasearch/lite';
import {connectStateResults, Hits, InstantSearch, SearchBox} from 'react-instantsearch-dom';

const searchClient = algoliasearch(
  'APP_ID',
  'SEARCH_API_KEY'
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Results component
&lt;/h3&gt;

&lt;p&gt;By default, Algolia &lt;code&gt;&amp;lt;Hits/&amp;gt;&lt;/code&gt; component shows all results when search query is empty. I adjusted the code to show results only if there are any results and data are loaded.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const Results = connectStateResults(({searchState, searchResults, searching}) =&amp;gt; {
  const hasQuery = searchState &amp;amp;&amp;amp; searchState.query;
  const hasResults = (searchResults?.hits ?? []).length &amp;gt; 0;
  const isSearching = searching;
  if (hasQuery &amp;amp;&amp;amp; hasResults) {
    return &amp;lt;Hits hitComponent={Hit}/&amp;gt;;
  }
  if (hasQuery &amp;amp;&amp;amp; !hasResults &amp;amp;&amp;amp; !isSearching) {
    return &amp;lt;div&amp;gt;No results 😔&amp;lt;/div&amp;gt;
  }
  return null;
}
);

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Hit component
&lt;/h3&gt;

&lt;p&gt;Hit component is nothing else as just a one search result. I stripped my styling to make it easier to copy-paste. 😄&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import React from "react";

function Hit(props: any) {
  const content = props?.hit?.content ?? "";
  const words = content.split(" ").length;
  return (&amp;lt;a href={props.hit.slug}&amp;gt;
    &amp;lt;div&amp;gt;
      &amp;lt;h3&amp;gt;{props?.hit?.frontmatter?.title ?? "no title"}&amp;lt;/h3&amp;gt;
    &amp;lt;/div&amp;gt;
    &amp;lt;p&amp;gt;{props?.hit?.frontmatter?.excerpt ?? ""}&amp;lt;/p&amp;gt;
  &amp;lt;/a&amp;gt;)
}

export default Hit;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Search component
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;InstantSearch&lt;/code&gt; component and search client which you configured in the previous step, put your index name, and use Algolia &lt;code&gt;SearchBox&lt;/code&gt; component and our custom &lt;code&gt;Results&lt;/code&gt; component with changed empty state behaviour which we created previously.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;InstantSearch indexName="simplelocalize-docs" searchClient={searchClient}&amp;gt;
    &amp;lt;SearchBox/&amp;gt;
    &amp;lt;Results/&amp;gt;
&amp;lt;/InstantSearch&amp;gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I didn’t want to make it more complex that it needs to be, I overwrite some CSS properties in my stylesheets to hide a search button and reset button. I also added Bootstrap styling to the search box using SCSS &lt;code&gt;@extend&lt;/code&gt; property. Simple and it does the job.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.ais-SearchBox-input {
  @extend .form-control;
}

.ais-SearchBox-submit {
  display: none;
}

.ais-SearchBox-reset {
  display: none;
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Get markdown files to index
&lt;/h2&gt;

&lt;p&gt;Now, it’s time to get all files which should be indexed and visible in the search results. I created a new &lt;code&gt;index-docs.js&lt;/code&gt; file which I will be executed after every successful build on CI/CD server. All my documentation pages are in &lt;code&gt;/docs/&lt;/code&gt; directory. So I needed to write a script for converting it into an array of objects to populate Algolia search index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import {globby} from 'globby';
import fs from "fs";
import matter from "gray-matter";
import algoliasearch from 'algoliasearch';

const pages = await globby([
  'docs/',
]);

const objects = pages.map(page =&amp;gt; {
  const fileContents = fs.readFileSync(page, 'utf8')
  const {data, content} = matter(fileContents)
  const path = page.replace('.md', '');
  let slug = path === 'docs/index' ? 'docs' : path;
  slug = "/" + slug + "/"
  return {
    slug,
    content,
    frontmatter: {
      ...data
    }
  }
})

//algolia update index code

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;I’m getting all markdown files from &lt;code&gt;/docs/&lt;/code&gt; directory with &lt;code&gt;globby&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;reading content of the files with &lt;code&gt;fs&lt;/code&gt;,&lt;/li&gt;
&lt;li&gt;parsing files with &lt;code&gt;gray-matter&lt;/code&gt; for markdown,&lt;/li&gt;
&lt;li&gt;and doing some magic tricks to convert file path to slugs which are used.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In my case, slugs are the just file paths, where the file path looks like this &lt;code&gt;/docs/{category}/{title}.md&lt;/code&gt;, for example:&lt;code&gt;/docs/integrations/next-translate.md&lt;/code&gt;, so slug will look like this: &lt;code&gt;/docs/integrations/next-translate/&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the end I’m getting an array of objects which looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[
    {
      "slug": "/docs/integrations/next-translate/",
      "content": "My article content for indexing",
      "frontmatter": {
        "category": "Integrations",
        "date": "2022-01-20",
        "some-other-properties": "properties"
      }
    }
]

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Update Algolia index
&lt;/h3&gt;

&lt;p&gt;Algolia provides a really simple and easy to use JavaScript client, so there no magic here. We are acquiring our index, and saving objects which we created in previous step.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const client = algoliasearch(
  'APP_ID',
  'ADMIN_API_KEY'
);
const index = client.initIndex("simplelocalize-docs")
index.saveObjects(objects, {
  autoGenerateObjectIDIfNotExist: true
});

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Include index update in package.json
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
  "name": "simplelocalize-docs",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build &amp;amp;&amp;amp; next export -o build/ &amp;amp;&amp;amp; i18n:download &amp;amp;&amp;amp; index:docs",
    "index:docs": "npx ts-node --skip-project index-docs.mjs",
    "i18n:upload": "simplelocalize upload",
    "i18n:download": "simplelocalize download"
  }
}

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can execute the script manually by running &lt;code&gt;npm run index:docs&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aLJk8_1e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2022-04-12/algolia-docs-search-index-overview.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aLJk8_1e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2022-04-12/algolia-docs-search-index-overview.png" alt="algolia search index overview" width="880" height="633"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it? That’s it! See the search in action on SimpleLocalize &lt;a href="https://simplelocalize.io/docs"&gt;documentation page&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>nextjs</category>
      <category>devlog</category>
    </item>
    <item>
      <title>Number formatting in JavaScript</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Thu, 02 Dec 2021 12:30:43 +0000</pubDate>
      <link>https://forem.com/jpomykala/number-formatting-in-javascript-1mc</link>
      <guid>https://forem.com/jpomykala/number-formatting-in-javascript-1mc</guid>
      <description>&lt;p&gt;Discover the power of &lt;code&gt;toLocaleString()&lt;/code&gt; function in JavaScript. Format numbers, currencies, and units without any 3rd party localization library.&lt;br&gt;
In simple words, the &lt;code&gt;toLocaleString()&lt;/code&gt; method converts a number into a string, using locale format. By default, it uses locale from web browser language but you can specify it manually.   &lt;/p&gt;
&lt;h2&gt;
  
  
  Syntax
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;locale&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;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  Parameters
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;locale&lt;/code&gt; (optional) - if not provided, then the method will use the host environment's current locale (e.g.: default browser language)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;options&lt;/code&gt; (optional) - object with formatting options
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="nx"&gt;exampleNumber&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;123456.789&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nx"&gt;exampleNumber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl-PL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// output: 123.456,789&lt;/span&gt;

&lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ar-EG&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// output: ١٢٣٤٥٦٫٧٨٩&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Limit to two significant digits
&lt;/h3&gt;


&lt;div class="highlight js-code-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;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;123456.789&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&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-IN&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="na"&gt;maximumSignificantDigits&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="c1"&gt;// output: 1,23,000&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Use default locale and custom number formatting
&lt;/h3&gt;

&lt;p&gt;Put &lt;code&gt;undefined&lt;/code&gt; as first parameter, to use default locale set in browser.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;30000.65&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
  &lt;span class="na"&gt;minimumFractionDigits&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;maximumFractionDigits&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="c1"&gt;// English output: 30,000.65&lt;/span&gt;
&lt;span class="c1"&gt;// German output: 30.000,65&lt;/span&gt;
&lt;span class="c1"&gt;// French output: 30 000,65&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Change formatting style
&lt;/h3&gt;

&lt;p&gt;Style property can have 3 different values:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;decimal&lt;/code&gt; (default)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;currency&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;percent&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;unit&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this article, we go through every style.&lt;/p&gt;

&lt;h2&gt;
  
  
  Style: Currencies
&lt;/h2&gt;

&lt;p&gt;Use &lt;code&gt;style&lt;/code&gt; property in options object with value &lt;code&gt;currency&lt;/code&gt; to format number into a string.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;123456.789&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&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-DE&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 123.456,79 €&lt;/span&gt;

&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja-JP&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JPY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: ￥123,457&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can adjust &lt;code&gt;currencyDisplay&lt;/code&gt; property to change currency formatting. Possible values are: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;symbol&lt;/code&gt; (default)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;code&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;name&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-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;price&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;123456.789&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&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-DE&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;currencyDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;code&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;EUR&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 123.456,79 EUR&lt;/span&gt;

&lt;span class="nx"&gt;price&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ja-JP&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;currency&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;currencyDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;name&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
  &lt;span class="na"&gt;currency&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;JPY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 123,457円&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Style: Percentages
&lt;/h2&gt;

&lt;p&gt;Percentage localization is a non-trivial task in some languages. &lt;br&gt;
Not in every language, percentage sign comes after a number. &lt;br&gt;
For example, in Arabic languages.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;0.767&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl-PL&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;percent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 77%&lt;/span&gt;

&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;ar-SA&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;percent&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output:؜ ٧٣٪ ؜&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Style: Units
&lt;/h2&gt;

&lt;p&gt;Units style is the one of the most understated JavaScript locale features. It allows you format &lt;br&gt;
number into any popular units with proper formatting for given locale.&lt;/p&gt;
&lt;h3&gt;
  
  
  Example with &lt;code&gt;liter&lt;/code&gt; unit
&lt;/h3&gt;

&lt;p&gt;Use &lt;code&gt;unit&lt;/code&gt; property in options object to set a desired unit.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl-PL&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;liter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 3 l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You might also want to adjust &lt;code&gt;unitDisplay&lt;/code&gt; property to show full word instead just one letter.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl-PL&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;liter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;unitDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;long&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 3 litry&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The shortest version you will get with &lt;code&gt;narrow&lt;/code&gt; value in &lt;code&gt;unitDisplay&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl-PL&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;liter&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;unitDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;narrow&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 3l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  List of JavaScript number locale units
&lt;/h3&gt;

&lt;p&gt;Below, you can check all possible values for &lt;code&gt;unit&lt;/code&gt; property.&lt;/p&gt;

&lt;p&gt;acre&lt;br&gt;
bit&lt;br&gt;
byte&lt;br&gt;
celsius&lt;br&gt;
centimeter&lt;br&gt;
day&lt;br&gt;
degree&lt;br&gt;
fahrenheit&lt;br&gt;
fluid-ounce&lt;br&gt;
foot&lt;br&gt;
gallon&lt;br&gt;
gigabit&lt;br&gt;
gigabyte&lt;br&gt;
gram&lt;br&gt;
hectare&lt;br&gt;
hour&lt;br&gt;
inch&lt;br&gt;
kilobit&lt;br&gt;
kilobyte&lt;br&gt;
kilogram&lt;br&gt;
kilometer&lt;br&gt;
liter&lt;br&gt;
megabit&lt;br&gt;
megabyte&lt;br&gt;
meter&lt;br&gt;
mile&lt;br&gt;
mile-scandinavian&lt;br&gt;
milliliter&lt;br&gt;
millimeter&lt;br&gt;
millisecond&lt;br&gt;
minute&lt;br&gt;
month&lt;br&gt;
ounce&lt;br&gt;
percent&lt;br&gt;
petabyte&lt;br&gt;
pound&lt;br&gt;
second&lt;br&gt;
stone&lt;br&gt;
terabit&lt;br&gt;
terabyte&lt;br&gt;
week&lt;br&gt;
yard&lt;br&gt;
year&lt;/p&gt;
&lt;h3&gt;
  
  
  Kilometer per hour
&lt;/h3&gt;

&lt;p&gt;You can combine two values using &lt;code&gt;per&lt;/code&gt; keyword, like &lt;code&gt;X-per-Y&lt;/code&gt;. For example &lt;code&gt;kilometer-per-hour&lt;/code&gt;.&lt;br&gt;
JavaScript will choose the best-fit localized pattern to format this compound unit.&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;speed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;50.2137&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;speed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pt-PT&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;kilometer-per-hour&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 50,214 km/h&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Terabyte per gram
&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;unit&lt;/code&gt; property doesn't have to make sense, it accepts any combination. 😊&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mf"&gt;50.2137&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="nx"&gt;value&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;toLocaleString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pl-PL&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="na"&gt;style&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;unit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;unit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;terabyte-per-gram&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;unitDisplay&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;long&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="c1"&gt;// output: 50,214 terabajta na gram&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Resources:
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://tc39.es/ecma402" rel="noopener noreferrer"&gt;tc39.es/ecma402&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.to/blog/posts/the-most-popular-react-localization-libraries/"&gt;React Localization libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://simplelocalize.io" rel="noopener noreferrer"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fsimplelocalize.io%2Fassets%2Fcta.jpg" alt="react localization"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>About Core Web Tools</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Mon, 08 Nov 2021 00:00:00 +0000</pubDate>
      <link>https://forem.com/jpomykala/about-core-web-tools-397l</link>
      <guid>https://forem.com/jpomykala/about-core-web-tools-397l</guid>
      <description>&lt;p&gt;&lt;a href="https://corewebtool.com"&gt;Core Web Tools&lt;/a&gt; is a directory with web tools for internet users. It’s created with minimal server usage for near to zero-carbon emission in mind.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why?
&lt;/h2&gt;

&lt;p&gt;There are a lot of great small utility apps on the web, and I think they are not getting enough attention. I wanted to make the app easy to use, that’s why there is no signup or tons of unnecessary stuff, just a list of links with small preview.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--NJha5X5_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-11-08/core-web-tools.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NJha5X5_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-11-08/core-web-tools.png" alt="Core Web Tools" width="880" height="636"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;List of tools, apps or services,&lt;/li&gt;
&lt;li&gt;Option to save them for later.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Submission Rules
&lt;/h2&gt;

&lt;p&gt;To be honest there are no restrictions in that matter. You can submit anything, but not everything will be added right away. You can add your small and clunky side-project, or big paid service. It’s hard to decide at this moment what tools should be listed.&lt;/p&gt;

&lt;p&gt;For now the priority are small web apps that solve some problem using just a JavaScript in your web browser, no servers and so on; or apps which don’t have any fancy landing page to get visibility.&lt;/p&gt;

&lt;p&gt;However, I added a few services which have paid options because they are actually used in this project, so I think they deserve being listed.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kwK8KEMC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-11-08/submit-core-web-tool.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kwK8KEMC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-11-08/submit-core-web-tool.png" alt="Core Web Tools Submission" width="880" height="729"&gt;&lt;/a&gt;&lt;a href="https://tally.so/r/wzQp83"&gt;Fill submission form&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Technology Stack
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fq5npheg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-11-08/core-web-tools-deployment.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fq5npheg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-11-08/core-web-tools-deployment.png" alt="Core Web Tools Stack" width="880" height="689"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Database: &lt;a href="https://www.json.org/json-en.html"&gt;JSON&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Framework: &lt;a href="https://nextjs.org"&gt;NextJS&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Hosting: &lt;a href="https://vercel.com"&gt;Vercel&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Cover: &lt;a href="https://bannerly.io"&gt;Bannerly&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;i18n: &lt;a href="https://simplelocalize.io"&gt;SimpleLocalize&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Developer: &lt;a href="https://twitter.com/jakub_pomykala"&gt;@jakub_pomykala&lt;/a&gt; 😄&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What’s next?
&lt;/h2&gt;

&lt;p&gt;If the project will be used by more people than myself, I would like to review listed tools and posts them every week or month as collection of ‘My favourites’, ‘Designer Tools’ or ‘Web Developer 2021’.&lt;/p&gt;

</description>
      <category>tools</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>react</category>
    </item>
    <item>
      <title>Top 12 libraries for NextJS, React apps and React Native apps for i18n and react localization</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Sat, 13 Feb 2021 16:17:09 +0000</pubDate>
      <link>https://forem.com/jpomykala/top-12-libraries-for-nextjs-react-apps-and-react-native-apps-for-i18n-and-react-localization-5fi8</link>
      <guid>https://forem.com/jpomykala/top-12-libraries-for-nextjs-react-apps-and-react-native-apps-for-i18n-and-react-localization-5fi8</guid>
      <description>&lt;h2&gt;
  
  
  Update 2021-02-22
&lt;/h2&gt;

&lt;p&gt;Hey! If you want to read the most recent version of this post, then checkout the &lt;a href="https://simplelocalize.io/blog/posts/the-most-popular-react-localization-libraries/" rel="noopener noreferrer"&gt;original post on my blog&lt;/a&gt;. I update it regularly! 🌱&lt;/p&gt;

&lt;h2&gt;
  
  
  Star &lt;a href="https://github.com/jpomykala/awesome-i18n" rel="noopener noreferrer"&gt;awesome-i18n&lt;/a&gt; repository
&lt;/h2&gt;

&lt;p&gt;A full &lt;a href="https://github.com/jpomykala/awesome-i18n" rel="noopener noreferrer"&gt;list of localization libraries and tools on Github&lt;/a&gt; can be found on GitHub. Feel free to add your resources there. 🤙&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚛️ Libraries list for React localization
&lt;/h2&gt;

&lt;p&gt;Checkout my list of the best React libraries wich I gathered. I focus mainly on ReactJS, React Native and Expo libraries.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. &lt;a href="https://github.com/zoontek/react-native-localize" rel="noopener noreferrer"&gt;react-native-localize&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A toolbox for your React Native app localization&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu9clovbbygyynepbpdnu.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fu9clovbbygyynepbpdnu.png" alt="Screenshot 2021-02-13 at 16.48.01"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. &lt;a href="https://formatjs.io" rel="noopener noreferrer"&gt;FormatJS&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Internationalize your web apps with react-intl library. Check also FormatJS CLI for message extraction below!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvuixvedahnulx42ip99l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fvuixvedahnulx42ip99l.png" alt="Screenshot 2021-02-13 at 16.48.42"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. &lt;a href="https://formatjs.io/docs/tooling/cli/" rel="noopener noreferrer"&gt;FormatJS CLI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Extract messages from project with FormatJS library&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp3gu7b64mfg6bpa4s7md.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fp3gu7b64mfg6bpa4s7md.png" alt="Screenshot 2021-02-13 at 16.49.23"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. &lt;a href="https://github.com/sealninja/react-i18nify" rel="noopener noreferrer"&gt;react-i18nify&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Simple i18n translation and localization components and helpers for React&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5aboslv2dpx5z3pz444r.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F5aboslv2dpx5z3pz444r.png" alt="Screenshot 2021-02-13 at 16.50.24"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. &lt;a href="https://github.com/evandhq/react-persian" rel="noopener noreferrer"&gt;react-persian&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;react-persian is a set of react components for Persian localization&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx7rs5zd63u3nutegejf1.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fx7rs5zd63u3nutegejf1.png" alt="Screenshot 2021-02-13 at 17.03.13"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. &lt;a href="https://react.i18next.com/" rel="noopener noreferrer"&gt;react-i18next&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Internationalization framework for React / React Native which is based on i18next. The i18next-community created integrations for frontend-frameworks such as React, AngularJS, Vue.js and many more.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqdsd0kq701mjhad55txl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fqdsd0kq701mjhad55txl.png" alt="react localization"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  8. &lt;a href="https://github.com/bloodyowl/react-translate" rel="noopener noreferrer"&gt;bloodyowl/react-translate&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Internationalization for react&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0vleumn4cn3owrx85z4l.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0vleumn4cn3owrx85z4l.png" alt="Screenshot 2021-02-13 at 17.02.54"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  9. &lt;a href="https://github.com/vinissimus/next-translate" rel="noopener noreferrer"&gt;next-translate&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;Easy i18n for Next.js +10&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Futqt31b1lfjqhee1sqjl.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Futqt31b1lfjqhee1sqjl.png" alt="Screenshot 2021-02-13 at 17.01.53"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  10. &lt;a href="https://github.com/amsul/react-translated" rel="noopener noreferrer"&gt;react-translated&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;A dead simple way to add complex translations in a React project&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff7j04hewvzd5p7uqtutx.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ff7j04hewvzd5p7uqtutx.png" alt="Screenshot 2021-02-13 at 17.02.13"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  11. &lt;a href="https://github.com/CreateThrive/react-intl-hooks" rel="noopener noreferrer"&gt;React-intl hooks&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;React-intl-hooks is a small and fast library that you can use to replace Format.js components. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0eo7vujvx4zab2fmu9xc.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F0eo7vujvx4zab2fmu9xc.png" alt="Screenshot 2021-02-13 at 17.02.32"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  12. &lt;a href="https://simplelocalize.io/docs/api/get-started/" rel="noopener noreferrer"&gt;SimpleLocalize CLI&lt;/a&gt;
&lt;/h3&gt;

&lt;p&gt;SimpleLocalize CLI allows you to upload and manage translation keys in cloud for free! &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feanmx4cmk8mthzbo2vr6.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feanmx4cmk8mthzbo2vr6.png" alt="Screenshot 2021-02-13 at 17.10.21"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  1.Upload translation in JSON files and manage them in translation editor.
&lt;/h4&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft2ehjetlw3tkuifl7izi.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft2ehjetlw3tkuifl7izi.gif" alt="upload"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Manage them in translation editor
&lt;/h4&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frxm1q0vgfm428x13eftz.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Frxm1q0vgfm428x13eftz.gif" alt="change-translation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  3. Download ready to use JSON files
&lt;/h4&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Firpa9scrovwlkni18slt.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Firpa9scrovwlkni18slt.gif" alt="download"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;👋 Thanks for reading! &lt;a href="https://twitter.com/jakub_pomykala" rel="noopener noreferrer"&gt;Follow me on Twitter&lt;/a&gt;&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>react</category>
      <category>typescript</category>
    </item>
    <item>
      <title>💼️ Why it's a good idea to keep e-mail registration in 2021</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Fri, 12 Feb 2021 13:01:43 +0000</pubDate>
      <link>https://forem.com/jpomykala/why-it-s-a-good-idea-to-keep-e-mail-registration-in-2021-8ll</link>
      <guid>https://forem.com/jpomykala/why-it-s-a-good-idea-to-keep-e-mail-registration-in-2021-8ll</guid>
      <description>&lt;p&gt;When I started working on &lt;a href="https://simplelocalize.io"&gt;my app for translation management&lt;/a&gt; in 2018, I knew it would be good to support single sign in option (SSO) with GitHub.&lt;/p&gt;

&lt;p&gt;The service was created with intention that it will be used by developers, and developers have GitHub accounts! I even&lt;br&gt;
advertised it as "Localization for Software Developers" or "developer-friendly localization". Although, it didn't get too much &lt;a href="https://news.ycombinator.com/item?id=19823169"&gt;attention on Hacker News&lt;/a&gt;, &lt;br&gt;
but hey! Now I can put Hacker News logo on my landing page and say "Featured on". 👌&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6SRlef-Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/hacker-news.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6SRlef-Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/hacker-news.png" alt="simplelocalize featured on hackernews"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As the time goes I implemented good old e-mail registration because I had ready to use code and &lt;a href="https://github.com/jpomykala/spring-higher-order-components"&gt;open-source library for&lt;br&gt;
Java Spring Boot&lt;/a&gt; to send e-mails. The most of the work was done.&lt;/p&gt;

&lt;p&gt;Thanks to OAuth library for Spring Boot, I also added Google account login with ease. I only needed to add a few more lines in configuration file and voilà! &lt;br&gt;
Visitors are able to create accounts by Google Profile. I couldn't add LinkedIn due to some problems, so I just left what I got in config and gave up. 😅&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7DxRCtqM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/spring-oauth.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7DxRCtqM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/spring-oauth.png" alt="simplelocalize sso option"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Eventually, I launched SimpleLocalize in late 2018. I started posting this project everywhere, ProductHunt, Reddit, dev.to, Medium and more.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uq4r1uBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/first-simplelocalize-draft.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uq4r1uBe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/first-simplelocalize-draft.png" alt="simplelocalize sketch draft"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After 2 years of application existence I gathered over 800 users and surprisingly most of them used Google to register.&lt;br&gt;
It's about 550 accounts which used Google to create their accounts. It was a surprise for me. Only 20 people chosen GitHub (including me 😄),&lt;br&gt;
and the rest used e-mail, or their accounts has been created by project admins.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;SimpleLocalize offers project sharing where you can add team member by e-mail and then account is automatically created for them.&lt;br&gt;
Their accounts are always created using 'e-mail' method. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CeIPe4ml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/pie-chart.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CeIPe4ml--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/pie-chart.png" alt="top selected register options"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I noticed that every person who used GitHub or Google to register, after trying the service wanted &lt;br&gt;
to move its account to business e-mail. The second option was that they were creating a new account with company e-mail, &lt;br&gt;
and asking me to move their projects to the new account. This is something what should interest every bootstrapper. &lt;strong&gt;Don't kick out &lt;br&gt;
the e-mail registration, people still use it to create accounts using business e-mails instead personal accounts!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In conclusion, my project is now targeted to more professional organizations and small/medium agile team. &lt;br&gt;
I needed to change my plans, to make sure I can provide support fast enough. 💪&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2z2Hzfa2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/plans.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2z2Hzfa2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-02-12/plans.png" alt="simplelocalize plans"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I also plan to add Microsoft login in the near feature.&lt;br&gt;
Many corporate employees use Outlook and Microsoft ecosystem. &lt;br&gt;
They will more encouraged to create an account in the system and try it out. &lt;br&gt;
They will not have to remember a password to e-mail accounts and use their personal accounts. &lt;br&gt;
In the further feature it would be great to add more corporate solutions like OpenID. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://twitter.com/jakub_pomykala"&gt;Follow me on Twitter 👋&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Post was originally posted on &lt;a href="https://jpomykala.com"&gt;https://jpomykala.com&lt;/a&gt;&lt;/p&gt;

</description>
      <category>saas</category>
      <category>startup</category>
      <category>marketing</category>
    </item>
    <item>
      <title>Easy Localization: 7 tips to make your work faster</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Tue, 12 Jan 2021 11:31:23 +0000</pubDate>
      <link>https://forem.com/jpomykala/easy-localization-7-tips-to-make-your-work-faster-4ae1</link>
      <guid>https://forem.com/jpomykala/easy-localization-7-tips-to-make-your-work-faster-4ae1</guid>
      <description>&lt;p&gt;Did you find out a smart way to handle i18n, and it didn't work again? Checkout our 7 tips how to make your localization better and easy to maintain. We worked for over 4 years with many companies on their i18n localization systems. Now we are sharing our experience with the audience! &lt;/p&gt;

&lt;h2&gt;
  
  
  Use unique translation keys
&lt;/h2&gt;

&lt;p&gt;For each translation use separate translation key. do not try to cheat the system. This may result with changing translation  in multiple places which may not fit in all places. It's hard to discover such problems later. Try to keep &lt;strong&gt;one i18n key per translation&lt;/strong&gt;. This will allow you to precisely edit content in place where you want.&lt;/p&gt;

&lt;h2&gt;
  
  
  Don’t capitalize with CSS
&lt;/h2&gt;

&lt;p&gt;When you try to cheat the system using one key in multiple places you will notice that in some places you need capitalized translation and somewhere you don’t want to use this. Solution is to use unique translation keys for every&lt;br&gt;
place, and capitalize it properly. Remember that different languages have different grammar rules. Not in every language we capitalize the days of week. Many &lt;strong&gt;users will easily notice the grammar issues&lt;/strong&gt;, and this can cause they won't stick with your application for a long.&lt;/p&gt;
&lt;h2&gt;
  
  
  Use same translation keys in buttons
&lt;/h2&gt;

&lt;p&gt;If some action in your service does the same thing, then you should use the same translation key every button. This is the one of a few places where you should use the same translation key. Thanks to that you will always keep the context. Same wording will help you users to understand what they are doing. Be consistent, users will thank you and more easily understand the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jZd3WlBx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/easy-localization/localization-progress.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jZd3WlBx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/easy-localization/localization-progress.jpg" alt="localization progress" width="880" height="483"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Don’t nest translations
&lt;/h2&gt;

&lt;p&gt;How many times did you tried to create fancy directory structure to get everything clean and tidy? Probably many. After a few days you end up with the same mess which you had, because instead of searching the correct directory you just put files to ‘temporary’ directory. It looks like the same with the translations.&lt;/p&gt;

&lt;p&gt;In many i18n libraries it’s a common approach to use &lt;strong&gt;nested translations&lt;/strong&gt; like following:&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;"nav"&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;"buttons"&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;"get-started"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get Started"&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;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;Don’t do this, this tidiness is artificial, and it won’t help. Imagine that your app will evolve because &lt;a href="https://medium.com/skiplist-publication/software-principle-11-the-only-constant-is-change-5c3be83c9ec5"&gt;the only constant in software development is change&lt;/a&gt;. Moving translations around will be a nightmare. After some time translation key may not belong anymore to some parent node. &lt;br&gt;
Then you will have to choose which key should go to another nested group.&lt;/p&gt;
&lt;h2&gt;
  
  
  Keep flat structure
&lt;/h2&gt;

&lt;p&gt;If you think that keeping translation in 'groups' is a good idea then consider using prefixes. In some scenarios it is a good idea, for example for navigation keys, or buttons. You can use category for each translation keys like following&lt;br&gt;
&lt;code&gt;nav-product-solution&lt;/code&gt;&lt;br&gt;
or&lt;br&gt;
&lt;code&gt;nav.product-solution&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;It makes sens because you will exactly know which translation will be changed.&lt;/p&gt;
&lt;h2&gt;
  
  
  Consider i18n management
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://simplelocalize.io/tag/i18n-management"&gt;Translation management&lt;/a&gt; is being more and more important topic when your project grows. Many i18n libraries uses JSON files to keep translation files. The structure varies but in general all of them looks similar. &lt;strong&gt;The biggest i18n problem is that it’s very hard to handle without a proper tools.&lt;/strong&gt; Image that every of translations are packed into separate json file named: "en.json", "de.json", "fr.json", "it.json" and every file contain structure 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;"sign-in"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sign In"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"get-started"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Get Started"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"register"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Register"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"logout"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Logout"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"close"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Close"&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;&lt;strong&gt;Adding a translation to many files can be frustrating and slow down the development process.&lt;/strong&gt; Now you need to send it to translator or translate it on your own using &lt;a href="https://www.deepl.com/home"&gt;DeepL&lt;/a&gt;, &lt;a href="https://translate.google.pl/"&gt;Google Translate&lt;/a&gt; or &lt;a href="https://www.microsoft.com/translator/"&gt;Microsoft Translate&lt;/a&gt;. &lt;br&gt;
Creating localized apps or games can be really annoying in such conditions. That is why we created SimpleLocalize. &lt;a href="https://simplelocalize.io"&gt;Clean, simple, and user-friendly system for handling i18n&lt;/a&gt;. We provide many i18n library integrations including &lt;a href="https://simplelocalize.io/docs/integrations/i18next/"&gt;i18next&lt;/a&gt;, &lt;a href="https://simplelocalize.io/docs/integrations/format-js/"&gt;FormatJS&lt;/a&gt;, Android and iOS. &lt;a href="https://simplelocalize.io/docs/cli/get-started/"&gt;Translation keys can be easily extracted&lt;/a&gt; from the projects, uploaded to &lt;a href="https://simplelocalize.io/translation-editor/"&gt;translation editor&lt;/a&gt; and &lt;a href="https://simplelocalize.io/docs/general/export/"&gt;downloaded back on local disk&lt;/a&gt;. Our localization command-line tool can simplify this process. &lt;a href="//mailto:contact@simplelocalize.io"&gt;Book a demo with me&lt;/a&gt; to see how your life can be easier with the SimpleLocalize!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ku5cyMEv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/easy-localization/localization-progress-bonjour.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ku5cyMEv--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/easy-localization/localization-progress-bonjour.jpg" alt="easy localization progress" width="880" height="494"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finding unused translation keys
&lt;/h2&gt;

&lt;p&gt;One of the biggest problems in agile teams is that system changes and evolving fast! That causes problem with the translations which must keep up with a product evolving. It’s easy to add a new translation in code and ping translators. But what happens when your product now contains 10x times more translations keys than the beginning? Many of them are still useful but not used, the key has been changed, but the meaning is still valid, so it’s hard to say if we can remove it or no. The solution is SimpleLocalize system which will help you in finding out which translation keys is not used in the code. Integrate your project with our translation management service and sort translation keys by last occurrence! To extract translation keys from the project files you can use our &lt;a href="https://simplelocalize.io/docs/cli/get-started/"&gt;Localization CLI Tool&lt;/a&gt;. &lt;a href="https://github.com/simplelocalize/simplelocalize-cli"&gt;It’s open source&lt;/a&gt;, so it can be used in enterprise project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://simplelocalize.io/tag/react-localization/"&gt;App localization&lt;/a&gt; is not the easy topic. Many people tried to find out the new smart way of handling it, many of them failed due to over-engineering stuff. How about keeping everything simple, and clean? Try to always follow the KISS rule, every professional software developer will tell you that! &lt;/p&gt;

&lt;p&gt;This post has been originally posted on &lt;strong&gt;SimpleLocalize Blog&lt;/strong&gt;. Link: &lt;a href="https://simplelocalize.io/blog/posts/easy-localization/"&gt;https://simplelocalize.io/blog/posts/easy-localization/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>i18n</category>
      <category>i18next</category>
      <category>javascript</category>
      <category>typescript</category>
    </item>
    <item>
      <title>📢 Startup advertising: Stick with the bubble</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Mon, 11 Jan 2021 14:57:45 +0000</pubDate>
      <link>https://forem.com/jpomykala/startup-advertising-stick-with-the-bubble-13f0</link>
      <guid>https://forem.com/jpomykala/startup-advertising-stick-with-the-bubble-13f0</guid>
      <description>&lt;p&gt;&lt;a href="https://twitter.com/jakub_pomykala"&gt;I work as a software developer for more than 7 years now&lt;/a&gt;. For that time I spent many years in companies which were struggling with &lt;br&gt;
getting traction and more customers. &lt;/p&gt;

&lt;p&gt;Eventually, at some point every manager wanted to invest some time in online marketing when the &lt;a href="https://en.wikipedia.org/wiki/Lead_generation"&gt;lead generation&lt;/a&gt; by networking was not enough.&lt;br&gt;
Obvious and easy way? &lt;strong&gt;Pay for ads and get more customers. It never worked.&lt;/strong&gt; I also tried to buy ads for my projects. &lt;br&gt;
In most cases it's useless, I was getting more views and clicks. I never get an e-mail or customer&lt;/p&gt;

&lt;h2&gt;
  
  
  👺 Don't buy ads
&lt;/h2&gt;

&lt;p&gt;If you ever wondered if it's worth to create a campaign on Facebook then... it's not. Consider hiring an expert for that or &lt;strong&gt;don't do it on your own.&lt;/strong&gt;&lt;br&gt;
I've never hired someone to run my campaigns, so my expirience may not be valid, but many of you probably would try to run ads on your own.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4O6ooUR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-01-04/analytics.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4O6ooUR---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-01-04/analytics.png" alt="SimpleLocalize ahrefs report" width="880" height="271"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created more than 20 different campaigns on Facebook and other social platforms, and I've never meet a customer&lt;br&gt;
who saw my ad on Facebook or Google. Recently, I read &lt;a href="https://www.forbes.com/sites/augustinefou/2021/01/02/when-big-brands-stopped-spending-on-digital-ads-nothing-happened-why/"&gt;an article about spending on digital ads at Uber&lt;/a&gt; and it made me thinking if online marketing is still a thing in 2021. &lt;br&gt;
Maybe the targeting was wrong, or maybe I should put much more money on it to make it effective. The only difference which I noticed was more page views.&lt;br&gt;
&lt;strong&gt;Follow the next steps in this post before you buy ads.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  😇 Find good backlinks
&lt;/h2&gt;

&lt;p&gt;Don't flood &lt;a href="https://reddit.com"&gt;Reddit&lt;/a&gt; or any other &lt;a href="https://www.producthunt.com"&gt;side project aggregator&lt;/a&gt; with your links. It won't improve the SEO because everybody can post there a link. &lt;br&gt;
Try to find places where not everybody can post about you and try to appear there. In 00's URL exchange was a popular way of &lt;strong&gt;getting more traffic&lt;/strong&gt; on your website. Today this is still relevant. &lt;br&gt;
&lt;strong&gt;Try to appear in places which are related to your project.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  👨‍🔧 Fix SEO first
&lt;/h2&gt;

&lt;p&gt;When I was creating landing pages, I got brief knowledge about SEO. I knew I need some links, keywords, good titles maybe and not copied content.&lt;br&gt;
After I finished death march for features in &lt;a href="https://dev.to/#projects"&gt;my projects&lt;/a&gt; in 2020, I started thinking: 'how to increase my sales'. I knew I probably need to write some tutorials, &lt;br&gt;
but then I discovered &lt;a href="https://ahrefs.com"&gt;ahrefs&lt;/a&gt;. I bought 7 days trial and started checking all the issues which I got on &lt;a href="https://simplelocalize.io"&gt;SimpleLocalize&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---5-X5qpS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-01-04/simplelocalize-ahrefs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---5-X5qpS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-01-04/simplelocalize-ahrefs.png" alt="SimpleLocalize ahrefs report" width="589" height="322"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I didn't realize how much work I need to do to fix all of these issues. Unique page title, keywords, text with good contrast, good descriptions for every page. Go through &lt;a href="https://ahrefs.com/blog/seo-checklist/"&gt;ahrefs SEO checklist&lt;/a&gt;&lt;br&gt;
to fix your issues if you don't want to buy a service yet. It's not cheap, but it's worth to subscribe. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5f4JJlBZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-01-04/impressions.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5f4JJlBZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://jpomykala.com/assets/2021-01-04/impressions.png" alt="SimpleLocalize backlinks" width="880" height="370"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All my rankings started going up after adjusting a few HTML tags. It was extremly easy thanks to &lt;a href="https://www.npmjs.org/package/react-helmet"&gt;react-helmet&lt;/a&gt;. I also moved my docs from &lt;a href="https://docs.gitbook.com/editing-content/content-structure"&gt;GitBook pages&lt;/a&gt; to &lt;a href="https://www.gatsbyjs.com"&gt;GatsbyJS&lt;/a&gt;, so this also helped a lot.&lt;/p&gt;

&lt;h2&gt;
  
  
  🛁 Join to the bubble
&lt;/h2&gt;

&lt;p&gt;This is the final advice which combines all advices from above. By fixing your SEO and using backlinks it's easy to join to the bubble. &lt;br&gt;
By bubble, I mean &lt;strong&gt;'being among all other websites which are similar'&lt;/strong&gt;. People who will need your service or something similar to your service will find you later or sooner. &lt;br&gt;
They will compare you with your competitors and choose the right option. You don't need to put $$ into adverts or flood Reddit to a get traction.&lt;/p&gt;

&lt;h2&gt;
  
  
  and happy new year! 😄
&lt;/h2&gt;

</description>
      <category>marketing</category>
      <category>saas</category>
      <category>startup</category>
      <category>seo</category>
    </item>
    <item>
      <title>ReactIntl and ReactJS interantionalization with SimpleLocalize.io</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Fri, 20 Nov 2020 00:13:31 +0000</pubDate>
      <link>https://forem.com/jpomykala/reactintl-and-reactjs-interantionalization-with-simplelocalize-io-14ph</link>
      <guid>https://forem.com/jpomykala/reactintl-and-reactjs-interantionalization-with-simplelocalize-io-14ph</guid>
      <description>&lt;h1&gt;
  
  
  Start with FormatJS library (originally react-intl)
&lt;/h1&gt;

&lt;p&gt;Today I will show you how localize React application using formatjs.io library (originally yahoo/react-intl). &lt;br&gt;
Please notice that this is not the only popular library for React app localization. Second popular library is &lt;a href="https://github.com/i18next/i18next"&gt;i18next&lt;/a&gt; which supports much more frameworks than FormatJS. &lt;br&gt;
If you are interested in i18next integration, you can &lt;a href="https://simplelocalize.io/blog/posts/i18next-reactjs-localization/"&gt;check our tutorial here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;
  
  
  Create a sample project
&lt;/h1&gt;

&lt;p&gt;I will start with something simple. I will create a new project using &lt;a href="https://github.com/facebook/create-react-app"&gt;create-react-app&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create react-app simplelocalize-react-intl-example
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Install dependencies
&lt;/h1&gt;

&lt;p&gt;Add &lt;code&gt;react-intl&lt;/code&gt; library to your newly created project.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Using NPM&lt;/span&gt;
npm i &lt;span class="nt"&gt;-S&lt;/span&gt; react react-intl

&lt;span class="c"&gt;# Using yarn&lt;/span&gt;
yarn add react react-intl
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Add Language Context
&lt;/h1&gt;

&lt;p&gt;In this project I will use &lt;code&gt;Context&lt;/code&gt; to keep translations and option to change language in realtime.&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="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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LanguageContext&lt;/span&gt; &lt;span class="o"&gt;=&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;createContext&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="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Read more about &lt;a href="https://reactjs.org/docs/context.html"&gt;React Context API&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  &lt;code&gt;react-intl&lt;/code&gt; configuration
&lt;/h1&gt;

&lt;p&gt;Let's create main configuration&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="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="s2"&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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;IntlProvider&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-intl&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;LanguageContext&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;./LanguageContext&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nx"&gt;SimpleLocalize&lt;/span&gt; &lt;span class="kd"&gt;extends&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;Component&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="kd"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;props&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;state&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="na"&gt;language&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="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;componentDidMount&lt;/span&gt;&lt;span class="p"&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;setupLanguageMessages&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;

  &lt;span class="nx"&gt;setupLanguageMessages&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&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;projectToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5e13e3019cff4dc6abe36009445f0883&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;translationsUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://cdn.simplelocalize.io/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/_latest/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;language&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;return&lt;/span&gt; &lt;span class="nx"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;translationsUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&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="o"&gt;=&amp;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;json&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;then&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="o"&gt;=&amp;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;setState&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;language&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="p"&gt;};&lt;/span&gt;

  &lt;span class="nx"&gt;render&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="p"&gt;(&lt;/span&gt;
      &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&lt;/span&gt;
        &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="na"&gt;changeLanguage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;setupLanguageMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="p"&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;gt;&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;IntlProvider&lt;/span&gt;
          &lt;span class="na"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;language&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="na"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;state&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="si"&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;state&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="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;children&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;IntlProvider&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="nc"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Provider&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="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;SimpleLocalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This wrapper will keep translations in our &lt;code&gt;LanguageContext&lt;/code&gt; and it will also provide a function to change language in fly.&lt;/p&gt;

&lt;h1&gt;
  
  
  Project &lt;code&gt;translationsUrl&lt;/code&gt; variable
&lt;/h1&gt;

&lt;p&gt;Create a &lt;a href="https://simplelocalize.io"&gt;SimpleLocalize.io&lt;/a&gt; project to get your unique &lt;code&gt;messages&lt;/code&gt; variable. For this demo project you can use the &lt;code&gt;messages&lt;/code&gt; from the example above!&lt;/p&gt;

&lt;h1&gt;
  
  
  Activate &lt;code&gt;react-intl&lt;/code&gt; in application
&lt;/h1&gt;

&lt;p&gt;Now lets use our newly created &lt;code&gt;SimpleLocalize&lt;/code&gt; wrapper to provide translations for React application&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="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="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;SimpleLocalize&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;./SimpleLocalize&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="nx"&gt;render&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;SimpleLocalize&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="nc"&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="nc"&gt;SimpleLocalize&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;,&lt;/span&gt;
  &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&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;Done! React will now fetch translations from SimpleLocalize CDN and provide them to your app. &lt;br&gt;
Let's check how to use it in the source code.&lt;/p&gt;
&lt;h1&gt;
  
  
  Using translations in the app
&lt;/h1&gt;

&lt;p&gt;Now, let's use translations, and create very simple web page. &lt;/p&gt;
&lt;h1&gt;
  
  
  Usage
&lt;/h1&gt;

&lt;p&gt;Checkout how use it.&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="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;logo&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;./logo.svg&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;./App.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="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;FormattedMessage&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="s2"&gt;react-intl&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;LanguageContext&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;./LanguageContext&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="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="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="nc"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&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="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;header&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-header"&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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="nc"&gt;FormattedMessage&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"USE_BUTTONS_BELOW"&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;p&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Spanish&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pl&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;gt;&lt;/span&gt;Polish&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;hr&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;img&lt;/span&gt; &lt;span class="na"&gt;src&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;logo&lt;/span&gt;&lt;span class="si"&gt;}&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-logo"&lt;/span&gt; &lt;span class="na"&gt;alt&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"logo"&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;p&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="nc"&gt;FormattedMessage&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"DESCRIPTION"&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;p&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;a&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-link"&lt;/span&gt;
            &lt;span class="na"&gt;href&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"https://simplelocalize.io"&lt;/span&gt;
            &lt;span class="na"&gt;target&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"_blank"&lt;/span&gt;
            &lt;span class="na"&gt;rel&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"noopener noreferrer"&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="nc"&gt;FormattedMessage&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"LEARN_MORE"&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;a&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;header&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="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Consumer&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;h2&gt;
  
  
  Using &lt;code&gt;&amp;lt;FormattedMessage/&amp;gt;&lt;/code&gt; in application code
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;FormattedMessage/&amp;gt;&lt;/code&gt; usage is very easy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;FormattedMessage id="YOUR_TRANSLATION_KEY/&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;React will convert &lt;code&gt;FormattedMessage&lt;/code&gt; tag into &lt;code&gt;span&lt;/code&gt; tag and put concrete translation into it. You can also use &lt;code&gt;&amp;lt;FormattedHTMLMessage id="TRANSLATION_WITH_CSS"/&amp;gt;&lt;/code&gt; which will also produce message with HTML inside &lt;code&gt;span&lt;/code&gt; tag.&lt;br&gt;
Example translation key could look like following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;TRANSLATION_WITH_CSS &lt;span class="o"&gt;=&lt;/span&gt; This is my &amp;lt;strong&amp;gt;text&amp;lt;/strong&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Switching between languages
&lt;/h2&gt;

&lt;p&gt;In presented example I used &lt;code&gt;LanguageContext.Consumer&lt;/code&gt; to provide function. This function can trigger language change and fetch proper messages from the CDN.&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;context&lt;/span&gt; &lt;span class="o"&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="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;header&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-header"&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;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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="nc"&gt;FormattedMessage&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"USE_BUTTONS_BELOW"&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;p&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Spanish&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;context&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;changeLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pl&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;gt;&lt;/span&gt;Polish&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;hr&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;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;header&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="si"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;LanguageContext&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Consumer&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You need &lt;code&gt;Language.Consumer&lt;/code&gt; tag only in places where you would like to change the language. It's not needed for &lt;code&gt;&amp;lt;FormattedMessages/&amp;gt;&lt;/code&gt; tags.&lt;/p&gt;

&lt;h1&gt;
  
  
  Let's check it!
&lt;/h1&gt;

&lt;p&gt;Notice that translation is done in realtime! How cool is that? Very cool!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--d-yC80o7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fjaetss0rnkzeek6794c.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--d-yC80o7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/fjaetss0rnkzeek6794c.gif" alt="formatjs_and_react_app_localization" width="520" height="400"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://react-intl.simplelocalize.io"&gt;Checkout live version&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Project code is available on &lt;a href="https://github.com/simplelocalize/simplelocalize-react-intl"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>react</category>
      <category>i18n</category>
    </item>
    <item>
      <title>i18next and ReactJS interantionalization with SimpleLocalize.io</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Thu, 01 Oct 2020 21:44:19 +0000</pubDate>
      <link>https://forem.com/jpomykala/i18next-and-reactjs-interantionalization-with-simplelocalize-io-4c6l</link>
      <guid>https://forem.com/jpomykala/i18next-and-reactjs-interantionalization-with-simplelocalize-io-4c6l</guid>
      <description>&lt;h1&gt;
  
  
  Background
&lt;/h1&gt;

&lt;p&gt;We took original post inspiration from an awesome guy called &lt;a href="https://dev.to/aryclenio"&gt;Aryclenio Xavier Barros&lt;/a&gt;, who presented sample app for localizing app with i18next. You can &lt;a href="https://dev.to/aryclenio/internationalizing-your-react-app-with-i18next-43op"&gt;read it here&lt;/a&gt;. &lt;br&gt;
We expanded the idea by adding section about integrating i18next with translation management system. &lt;/p&gt;
&lt;h1&gt;
  
  
  How to start with i18n in ReactJS?
&lt;/h1&gt;

&lt;p&gt;Thanks to that ReactJS is super popular library we got so many options. The most popular i18n libraries are i18next and yahoo/react-intl. Today I will show you how to integrate i18next into your ReactJS application.&lt;/p&gt;
&lt;h1&gt;
  
  
  Create a sample project
&lt;/h1&gt;

&lt;p&gt;I will start with very beginning and I will create sample app in ReactJS with TypeScript&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn create react-app simplelocalize-i18next-example &lt;span class="nt"&gt;--template&lt;/span&gt; typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Install dependencies:
&lt;/h1&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; &lt;span class="nt"&gt;--save&lt;/span&gt; react-i18next i18next i18next-http-backend i18next-browser-languagedetector
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No we are ready to start!&lt;/p&gt;

&lt;h1&gt;
  
  
  Configuration
&lt;/h1&gt;

&lt;p&gt;I will create &lt;code&gt;i18n.ts&lt;/code&gt; file where I will put whole i18next configuration, after that we will import this file in &lt;code&gt;index.ts&lt;/code&gt;.&lt;br&gt;
My &lt;code&gt;i18n.ts&lt;/code&gt; looks as following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Backend&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-http-backend&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;LanguageDetector&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-browser-languagedetector&lt;/span&gt;&lt;span class="dl"&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;projectToken&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;5e13e3019cff4dc6abe36009445f0883&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;loadPath&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`https://cdn.simplelocalize.io/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;projectToken&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/_latest/i18next/{{lng}}/{{ns}}/_index`&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;Backend&lt;/span&gt;&lt;span class="p"&gt;)&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;LanguageDetector&lt;/span&gt;&lt;span class="p"&gt;)&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="c1"&gt;// default/fallback language &lt;/span&gt;
    &lt;span class="na"&gt;fallbackLng&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="na"&gt;ns&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;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="na"&gt;defaultNS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;default&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="c1"&gt;//detects and caches a cookie from the language provided&lt;/span&gt;
    &lt;span class="na"&gt;detection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;order&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="s1"&gt;queryString&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="s1"&gt;cookie&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
      &lt;span class="na"&gt;cache&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="s1"&gt;cookie&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="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="na"&gt;backend&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;loadPath&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;h1&gt;
  
  
  Project &lt;code&gt;loadPath&lt;/code&gt; variable
&lt;/h1&gt;

&lt;p&gt;Create a &lt;a href="https://simplelocalize.io" rel="noopener noreferrer"&gt;SimpleLocalize.io&lt;/a&gt; project to get your unique &lt;code&gt;loadPath&lt;/code&gt; variable. For this demo project you can use the &lt;code&gt;loadPath&lt;/code&gt; from the example above!&lt;/p&gt;

&lt;h1&gt;
  
  
  Enable &lt;code&gt;i18next&lt;/code&gt; in application
&lt;/h1&gt;

&lt;p&gt;Configuration is completed when you import &lt;code&gt;i18n.ts&lt;/code&gt; file in &lt;code&gt;index.ts&lt;/code&gt; just by adding &lt;code&gt;import './i18n';&lt;/code&gt; Whole &lt;code&gt;index.ts&lt;/code&gt; file should looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="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="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./i18n&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// import i18next configuration (!!)&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="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&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="nc"&gt;Suspense&lt;/span&gt; &lt;span class="na"&gt;fallback&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;div&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Loading...&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="si"&gt;}&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="nc"&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="nc"&gt;Suspense&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="nc"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StrictMode&lt;/span&gt;&lt;span class="p"&gt;&amp;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;We are done! i18next library is ready to use.&lt;/p&gt;

&lt;h1&gt;
  
  
  Using translations in the app
&lt;/h1&gt;

&lt;p&gt;Now, let's use translations, and create very simple web page. &lt;/p&gt;

&lt;h2&gt;
  
  
  Import &lt;code&gt;useTranslation&lt;/code&gt; hook
&lt;/h2&gt;

&lt;p&gt;To import the i18next hook we use the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="s2"&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="nx"&gt;i18n&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="c1"&gt;//...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;t&lt;/code&gt; variable is a function used to load translations for given key.&lt;/p&gt;

&lt;h2&gt;
  
  
  Using &lt;code&gt;t&lt;/code&gt; in application code
&lt;/h2&gt;

&lt;p&gt;&lt;code&gt;t&lt;/code&gt; usage is very simple and clean:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;t("USE_BUTTONS_BELOW")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;in HTML it would look like following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&gt;&lt;code&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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="s2"&gt;USE_BUTTONS_BELOW&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;p&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Switching between language
&lt;/h2&gt;

&lt;p&gt;Now it's a time to add option to switch languages. I will use simple buttons without any fancy CSS styles. :) I added 3 buttons for English, Spanish and Polish language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight tsx"&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="s2"&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="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;./App.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="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="s2"&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="nx"&gt;i18n&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="p"&gt;&amp;gt;&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;p&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="s2"&gt;USE_BUTTONS_BELOW&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;p&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeLanguage&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;English&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeLanguage&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="si"&gt;}&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;Spanish&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;button&lt;/span&gt; &lt;span class="na"&gt;onClick&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&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;i18n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;changeLanguage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pl&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;gt;&lt;/span&gt;Polish&lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nt"&gt;button&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;h1&gt;
  
  
  Let's check it!
&lt;/h1&gt;

&lt;p&gt;Notice that translation is done in realtime! Cool!&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr506c32f8xwy82o51oj1.gif" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fr506c32f8xwy82o51oj1.gif" alt="React Localization with i18next"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i18next.simplelocalize.io" rel="noopener noreferrer"&gt;Checkout live version&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Project code is available on &lt;a href="https://github.com/simplelocalize/simplelocalize-i18next" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>typescript</category>
      <category>react</category>
      <category>i18n</category>
    </item>
    <item>
      <title>Software project internationalization - quick look</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Tue, 08 Sep 2020 09:59:28 +0000</pubDate>
      <link>https://forem.com/jpomykala/start-with-software-project-localization-fl5</link>
      <guid>https://forem.com/jpomykala/start-with-software-project-localization-fl5</guid>
      <description>&lt;h1&gt;
  
  
  Localization in mobile/web applications
&lt;/h1&gt;

&lt;p&gt;The most important thing in any software translation process is localization. While introducing your mobile or web app or any other product to another market, it’s important to adjust it for the particular location. &lt;br&gt;
Localization is the process of targeting your product for specific group of users, defined by their location. In other words, the product or service you provide will be more suitable for a particular country or area thanks to the localization.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zKn-v2XP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/localization-1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zKn-v2XP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/localization-1.jpg" alt="simplelocalize localization" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Why should I focus on localization?
&lt;/h1&gt;

&lt;p&gt;Localization significantly improves user experience by making texts in your app more readable and understandable for particular group of users - they can react with the product more naturally, in the environment they know and feel good with, which brings only good results for your product. More languages you offer in your product, more users and customers you can attend.&lt;br&gt;
Translation with localization included, brings many more benefits to the final product than with a simple translation of the text. Moreover, localization gives your product a soul, like it's designed specifically for a group of users in specific location. &lt;br&gt;
Localization is in opposition to one universal product designed for everyone. It refines and adapts content for local needs which makes the product more suitable for specific recipients. As a result, you can create a unique relationship between your product or company and the person who is using it.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5PL4jtTN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/extraction-cli.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5PL4jtTN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/extraction-cli.jpg" alt="simplelocalize i18n extraction cli" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How localization works?
&lt;/h1&gt;

&lt;p&gt;Localization is based on adapting the content to the product recipient. It means that instead of using simple translation, you need to search deeper, understand the language culture of your users. It's important to notice, that a word in English translated to another language, may have more than one meaning and very often it can't be translated literally. Therefore, it's crucial to understand different cultures and language differences to localize the product successfully so it’s as familiar as possible for the users. &lt;br&gt;
Another example are symbols which may have different meaning in different languages and cultures. Furthermore, there are multiple variations of languages. As an example, Spanish is different in Madrid, in Malaga and in Buenos Aires or Bogotá. Words in the same language may have totally different meaning used in different parts of the world. That's why the localization is important - you want users to react positively to your product, accordingly to the way you designed it to be.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why localization is important?
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Improves customer satisfaction. Localization shows to your customers that they are important for you and you take care of them by providing with the product that’s adjusted for their culture, customs and needs.&lt;/li&gt;
&lt;li&gt;Helps increase customers base and expand your business.&lt;/li&gt;
&lt;li&gt;Improves your SEO.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--otU9X0RW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/key-value-banner.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--otU9X0RW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/key-value-banner.jpg" alt="simplelocalize key value translation" width="880" height="587"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Should I use localization tools?
&lt;/h1&gt;

&lt;p&gt;There are multiple tools on the Internet that will help you automatize the process of localization. See below how exactly they work:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They help you automatize the process of translation and localization and deliver product faster for specific locations&lt;/li&gt;
&lt;li&gt;You can control the whole translation and localization progress in one app&lt;/li&gt;
&lt;li&gt;Changes can be deployed with one click so they are updated immediately&lt;/li&gt;
&lt;li&gt;You can easily track all changes in translations and see previous versions&lt;/li&gt;
&lt;li&gt;They give you an option to translate for multiple languages&lt;/li&gt;
&lt;li&gt;Easy interface helps translators to focus more on the localization&lt;/li&gt;
&lt;li&gt;You can work with your team on multiple projects at the same time, online&lt;/li&gt;
&lt;li&gt;They optimize your workflow&lt;/li&gt;
&lt;li&gt;and much more!&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--p9586BiJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/advert-banner.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--p9586BiJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://simplelocalize.io/start-with-software-project-localization/advert-banner.jpg" alt="simplelocalize extract i18n" width="880" height="253"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Get your free trial account on SimpleLocalize to check all the features and test it on your product!&lt;/p&gt;

</description>
      <category>internationalization</category>
      <category>localization</category>
      <category>i18n</category>
      <category>multilanguage</category>
    </item>
    <item>
      <title>Why handling i18n in software projects is tough</title>
      <dc:creator>Jakub Pomykała</dc:creator>
      <pubDate>Fri, 04 Sep 2020 22:26:27 +0000</pubDate>
      <link>https://forem.com/jpomykala/why-handling-i18n-in-software-projects-is-tough-4emd</link>
      <guid>https://forem.com/jpomykala/why-handling-i18n-in-software-projects-is-tough-4emd</guid>
      <description>&lt;p&gt;Have you ever thinking about adding more languages to your application? Does it make sens to do it? Will you get more customers? Or will it make your existing customers happier? Or maybe you would like to look more professional than your competitors? Let's make it clear - yes, your app will look much more profesional if you will give your clients more languages to choose besides English which is language of the Internet by default. Every big tech company provides more than English language in their apps. &lt;/p&gt;

&lt;h1&gt;
  
  
  Background history
&lt;/h1&gt;

&lt;p&gt;When I was creating my first big B2C web application I knew I will need to support more languages than only English. I wanted to reach more mature people who often don't know English at all. Application initially was designed to support 5 languages: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;English, because it's by default the Internet language&lt;/li&gt;
&lt;li&gt;Polish, because I'm from Poland and I wanted to reach people like my parents who would like to use this app in their first language&lt;/li&gt;
&lt;li&gt;Spanish, because my girlfriend knows this language very well&lt;/li&gt;
&lt;li&gt;Italian, because we planned to add places from Italy&lt;/li&gt;
&lt;li&gt;French, because my girlfriend would like to learn this language 👩‍🎨&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I started working on the coding side and my girlfriend was taking care about everything else including translations. We noticed very quickly that i18n... is though... &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F68b2thkwc251ymkeqo3c.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F68b2thkwc251ymkeqo3c.jpg" alt="i18n is though"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I was using ReactJS to create &lt;a href="https://PlaceFlare.com" rel="noopener noreferrer"&gt;PlaceFlare.com&lt;/a&gt; so I decided to go with &lt;a href="https://www.npmjs.com/package/react-intl" rel="noopener noreferrer"&gt;yahoo/react-intl&lt;/a&gt; from &lt;a href="https://FormatJS.io" rel="noopener noreferrer"&gt;FormatJS.io&lt;/a&gt; as my primary i18n library. It was very easy to configure and to use. The problem was with handling i18n keys and translations for more than one language.&lt;/p&gt;

&lt;h1&gt;
  
  
  Why maintaining i18n is so hard
&lt;/h1&gt;

&lt;p&gt;Basically it was very hard to handle and maintain all i18n keys because every language translations were packed into separate JSON objects or even separate JSON files like en.json, it.json and so on.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsgmeka8xiapgm4ccwooh.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fsgmeka8xiapgm4ccwooh.png" alt="i18n translations file en.json"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Making changes was hell! When I needed to update an i18n key in code, I had to do the changes in every translation file, and in the end I needed to update the translation itself to match it.&lt;/p&gt;

&lt;h1&gt;
  
  
  How I solved problem which I created
&lt;/h1&gt;

&lt;p&gt;I came up with the simple software solution. We started keeping translations in Excel files like shown below.&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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft1f8jbdu3t5bbjdd0uzq.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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Ft1f8jbdu3t5bbjdd0uzq.png" alt="i18n app translations in Excel file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;So I provided a small Java app to convert such Excel file to format required by FormatJS library. More problems come up later, like finding i18n in application code, also i18n key changes were still a nightmare, keeping one Excel file which should be always up-to-date, more and more problems to solve.&lt;/p&gt;

&lt;h1&gt;
  
  
  How I improved my clunky solution
&lt;/h1&gt;

&lt;p&gt;Very quickly I turned everything what I learned into small simple SaaS project which I called &lt;a href="https://simplelocalize.io" rel="noopener noreferrer"&gt;SimpleLocalize.io&lt;/a&gt; I think I solved most of the problems with i18n app translations.&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%2Fsimplelocalize.io%2Fstatic%2Fui-2fee8e735b014d8baea37d93c6108a41.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%2Fsimplelocalize.io%2Fstatic%2Fui-2fee8e735b014d8baea37d93c6108a41.png" alt="simplelocalize project list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The biggest advantage of &lt;a href="https://simplelocalize.io" rel="noopener noreferrer"&gt;SimpleLocalize.io&lt;/a&gt; is that you can use any i18n library you want. &lt;a href="https://github.com/simplelocalize/simplelocalize-cli" rel="noopener noreferrer"&gt;SimpleLocalize CLI&lt;/a&gt; will extract i18n keys from application source code, push them to the cloud where you can edit it and publish to the CDN which will make it easy to fetch and use in app. &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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxiv7rhog74tcsz6pizwx.jpg" 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%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxiv7rhog74tcsz6pizwx.jpg" alt="hide the pain harold"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>i18n</category>
      <category>localization</category>
      <category>intl</category>
      <category>internationalization</category>
    </item>
  </channel>
</rss>
