<?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>DEV Community: Vlatko Vlahek</title>
    <description>The latest articles on DEV Community by Vlatko Vlahek (@vlaja).</description>
    <link>https://dev.to/vlaja</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%2F228260%2F3671ad19-5250-47e6-aff7-7bb5c88c1b92.jpeg</url>
      <title>DEV Community: Vlatko Vlahek</title>
      <link>https://dev.to/vlaja</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/vlaja"/>
    <language>en</language>
    <item>
      <title>Multi-language routing in React</title>
      <dc:creator>Vlatko Vlahek</dc:creator>
      <pubDate>Wed, 30 Oct 2019 12:55:46 +0000</pubDate>
      <link>https://dev.to/prototyp/multi-language-routing-in-react-k9l</link>
      <guid>https://dev.to/prototyp/multi-language-routing-in-react-k9l</guid>
      <description>&lt;h1&gt;
  
  
  Multi-language routing in React
&lt;/h1&gt;

&lt;p&gt;One of the great things around routing in React is that its ecosystem has allowed for great and very declarative routing syntax. You can define your routing as a set of components, write an object structure from which you will render the routing logic, etc.&lt;/p&gt;

&lt;p&gt;And it’s constantly improving and getting better and better:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://reacttraining.com/blog/react-router-v5-1/"&gt;react-router v5.1 is out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://reach.tech/router"&gt;reach&lt;/a&gt; router is also getting big traction, check it out.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, what if you want to support a true multi-language routing, which will support route names in multiple languages and redirect your users to correct routes when you change languages?&lt;/p&gt;

&lt;h3&gt;
  
  
  Is that really a big deal?
&lt;/h3&gt;

&lt;p&gt;Well, it is definitively possible to go on without such a feature and have a fully usable website. There are a lot of websites that have English-only routing, but multi-language content.&lt;/p&gt;

&lt;p&gt;From a &lt;em&gt;development&lt;/em&gt; perspective, the reasons for this vary:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A framework that doesn’t support it is used.&lt;/li&gt;
&lt;li&gt;It’s a big effort to implement.&lt;/li&gt;
&lt;li&gt;It’s not always easy to maintain.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, having a multi-language route localization can give you and your &lt;em&gt;end-users&lt;/em&gt; the following benefits:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;multi-language SEO&lt;/li&gt;
&lt;li&gt;users get the additional context of the page hierarchy in their own language&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A solution written in React is relatively simple to implement and maintain, and this article will outline the packages and methods that will guide you to a solution.&lt;/p&gt;

&lt;p&gt;The example is written with &lt;em&gt;TypeScript&lt;/em&gt;, latest &lt;em&gt;react-router-dom&lt;/em&gt;, and &lt;em&gt;react-hooks&lt;/em&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add a Router package
&lt;/h2&gt;

&lt;p&gt;In case you aren’t using a router package, try &lt;a href="https://www.npmjs.com/package/react-router-dom"&gt;react-router-dom&lt;/a&gt; out.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;yarn add react-router-dom
yarn add @types/react-router-dom &lt;span class="nt"&gt;--dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;After adding a router, we should define a few routes and components that will be used on our website.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&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;FC&lt;/span&gt; &lt;span class="o"&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="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;BrowserRouter&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;AppLayout&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;Switch&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;Route&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Home&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="nt"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Home&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;Route&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;Route&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Summary&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="nt"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Summary&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;Route&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;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&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="nt"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GeneralError&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;Route&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;Switch&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;AppLayout&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;BrowserRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the latest react-router-dom version, component and render props were scrapped for children prop which is much more flexible. The only downside is that the v4 version was more concise and readable in most scenarios. Please note that the old way of doing things through component/render props is still available at this moment, but it will become deprecated soon.&lt;/p&gt;

&lt;p&gt;We also added an &lt;strong&gt;&lt;em&gt;AppLayout&lt;/em&gt;&lt;/strong&gt; component which allows us to have a global header, navigation, and footer, and renders the routes inside the main tag as partial views.&lt;/p&gt;

&lt;p&gt;There is also a fallback route here that renders the error component so our users know that they ended up on the error page in case they try to access a route that doesn’t exist.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add an i18n package
&lt;/h2&gt;

&lt;p&gt;First, we need to add a package that will allow us to internationalize things in our app. There are a lot of good examples, but one of the best packages around is &lt;a href="https://github.com/formatjs/react-intl"&gt;react-intl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It is a project by &lt;a href="https://formatjs.io/"&gt;FormatJS&lt;/a&gt; (Yahoo! Inc) which has impressive support for localizing almost everything, including currencies, dates, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;    yarn add react-intl
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This package was written in Typescript so it has its own types included.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding a base locale
&lt;/h3&gt;

&lt;p&gt;It’s always easiest to start with a language that will be the primary language for the website as a baseline. You can always add more languages easily later on.&lt;/p&gt;

&lt;p&gt;Let’s first add an enum which will be a collection of all languages used inside our app. For start, we will only add the base language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;AppLanguage&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;English&lt;/span&gt; &lt;span class="o"&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="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The value of each enum property should match a two-letter country code ISO locale.&lt;/p&gt;

&lt;p&gt;After adding a language, we should also add some language strings for that language, which we will use to localize our routes and other content.&lt;/p&gt;

&lt;p&gt;Create an intl folder somewhere in the app, and a file for your base language.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;baseStrings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/** Routes */&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;routes.home&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;/&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;routes.summary&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;/summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

  &lt;span class="p"&gt;...&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="nx"&gt;LanguageStrings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;baseStrings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;en&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;baseStrings&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The exported type will be used as an equality enforcer which all other languages need to support, meaning that any localization added to &lt;em&gt;baseStrings&lt;/em&gt; will need to be added to other files in order to enforce some safety. It also works vice-versa.&lt;/p&gt;

&lt;p&gt;If you try to add a string to a specific language which doesn’t exist in the base strings file, you will get a compilation error. This will enforce that all of the used languages have all strings at least set, if not translated, and save you from runtime errors.&lt;/p&gt;

&lt;p&gt;We are also exporting the &lt;em&gt;baseStrings&lt;/em&gt; as a matching iso variable for the language at hand.&lt;/p&gt;

&lt;p&gt;Now let’s add a matching enum (or frozen object in plain JS) which we can use to reference the routes to avoid any typos.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kr"&gt;enum&lt;/span&gt; &lt;span class="nx"&gt;AppRoute&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nx"&gt;Home&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;routes.home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;Summary&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;routes.summary&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Localized Switch component
&lt;/h3&gt;

&lt;p&gt;In order to simplify the process of translating the route paths, we will create a custom &lt;strong&gt;LocalizedSwitch&lt;/strong&gt; component that handles this logic.&lt;/p&gt;

&lt;p&gt;It is also possible to do this on the route component level, however, swapping out the Switch component allows you to support this with the least amount of changes, as it is easier to update the parent then every route to a LocalizedRoute variant. Changing the route component is probably a more flexible solution though.&lt;/p&gt;

&lt;p&gt;The intended suggestion for the LocalisedSwitch component is imagined as a drop-in replacement for the normal Switch one, and it is designed to work with Route components from the &lt;strong&gt;react-router-dom&lt;/strong&gt; package.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LocalizedSwitch&lt;/span&gt;&lt;span class="p"&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;FC&lt;/span&gt; &lt;span class="o"&gt;=&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="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/**
   * inject params and formatMessage through hooks, so we can localize the route
   */&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;formatMessage&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useIntl&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   * Apply localization to all routes
   * Also checks if all children elements are &amp;lt;Route /&amp;gt; components
   */&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;Switch&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;React&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="nx"&gt;map&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="nx"&gt;child&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;isValidElement&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;RouteProps&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
          &lt;span class="p"&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;cloneElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&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="nx"&gt;child&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="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;localizeRoutePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;child&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;path&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="nx"&gt;child&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="nc"&gt;Switch&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="cm"&gt;/**
   *
   * @param path can be string, undefined or string array
   * @returns Localized string path or path array
   */&lt;/span&gt;
  &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;localizeRoutePath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;switch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;typeof&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;undefined&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;undefined&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;object&lt;/span&gt;&lt;span class="dl"&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;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="p"&gt;}));&lt;/span&gt;
      &lt;span class="nl"&gt;default&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;isFallbackRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;*&lt;/span&gt;&lt;span class="dl"&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;isFallbackRoute&lt;/span&gt;
          &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt;
          &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;locale&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h3&gt;
  
  
  Wiring it all up
&lt;/h3&gt;

&lt;p&gt;To wire it all together, we need to add the &lt;strong&gt;IntlProvider&lt;/strong&gt; component from the &lt;a href="https://github.com/formatjs/react-intl"&gt;react-intl&lt;/a&gt; package, connect it to the data we defined, and add our own LocalizedSwitch component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;App&lt;/span&gt;&lt;span class="p"&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;FC&lt;/span&gt; &lt;span class="o"&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="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;LocalizedRouter&lt;/span&gt;
    &lt;span class="na"&gt;RouterComponent&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;BrowserRouter&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppLanguage&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
    &lt;span class="na"&gt;appStrings&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;appStrings&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;AppLayout&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;LocalizedSwitch&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;Route&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Home&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="nt"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Home&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;Route&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;Route&lt;/span&gt; &lt;span class="na"&gt;exact&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Summary&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="nt"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Summary&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;Route&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;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&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="nt"&gt;views&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;GeneralError&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;Route&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;LocalizedSwitch&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;AppLayout&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;LocalizedRouter&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Supporting multiple languages
&lt;/h2&gt;

&lt;p&gt;Now that we have covered the basics of setting up the logic that allows us to internationalize our application and localize the application routes, we need to add support for other languages and add their route definitions.&lt;/p&gt;

&lt;p&gt;For the purpose of this example, let’s add support for &lt;em&gt;Deutch&lt;/em&gt;, &lt;em&gt;French&lt;/em&gt; and &lt;em&gt;Croatian&lt;/em&gt; languages, all inside the intl folder that we already have.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer:&lt;/strong&gt; I don’t personally speak Deutch or French, so if the translations are not perfect, I do apologize for mangling your language, but please blame Google Translate :)&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Adding translations for a new language
&lt;/h3&gt;

&lt;p&gt;Just add a new language file inside the intl folder:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;de&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;LanguageStrings&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="cm"&gt;/** Routes */&lt;/span&gt;
  &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;routes.home&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;/&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;routes.summary&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;/zusammenfassung&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

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



&lt;p&gt;If you are wondering why this was done in &lt;strong&gt;.ts&lt;/strong&gt; file in this scenario, and not another format like JSON, the sole purpose is to enforce safety that comes with using TypeScript.&lt;/p&gt;

&lt;p&gt;You can, of course, write these in JSON, JS or another preferred format in case you don’t want or need the type-safety.&lt;/p&gt;

&lt;p&gt;For every language file you add, extend the &lt;strong&gt;AppLanguage&lt;/strong&gt; enum.&lt;/p&gt;

&lt;h3&gt;
  
  
  Updating the router
&lt;/h3&gt;

&lt;p&gt;We first need to update the router to support redirecting to other languages, reading the current language from the pathname, and setting the locale accordingly.&lt;/p&gt;

&lt;p&gt;Expected behaviour:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/summary -&amp;gt; Redirect to base language
/en/summary -&amp;gt; English language summary page
/de/zusammenfassung -&amp;gt; German language summary page
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We will swap out the default router component with the one that supports pathname detection and returns react-intl provider.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="kr"&gt;interface&lt;/span&gt; &lt;span class="nx"&gt;Props&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;RouterComponent&lt;/span&gt;&lt;span class="p"&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;ComponentClass&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;any&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;languages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;k&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;number&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nl"&gt;appStrings&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="na"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;]:&lt;/span&gt; &lt;span class="nx"&gt;LanguageStrings&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
  &lt;span class="nx"&gt;defaultLanguage&lt;/span&gt;&lt;span class="p"&gt;?:&lt;/span&gt; &lt;span class="nx"&gt;AppLanguage&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LocalizedRouter&lt;/span&gt;&lt;span class="p"&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;FC&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Props&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;=&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="nx"&gt;RouterComponent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;appStrings&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;defaultLanguage&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;RouterComponent&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;Route&lt;/span&gt; &lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"/:lang([a-z]{2})"&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;({&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;location&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="cm"&gt;/**
         * Get current language
         * Set default locale to en if base path is used without a language
         */&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt; &lt;span class="p"&gt;?&lt;/span&gt; &lt;span class="nx"&gt;match&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;params&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;lang&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;defaultLanguage&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nx"&gt;AppLanguage&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;English&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="cm"&gt;/**
         * If language is not in route path, redirect to language root
         */&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;pathname&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;includes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lang&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="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;Redirect&lt;/span&gt; &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="s2"&gt;`/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;}&lt;/span&gt;

        &lt;span class="cm"&gt;/**
         * Return Intl provider with default language set
         */&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;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="nx"&gt;lang&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="nx"&gt;appStrings&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;children&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;);&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="nc"&gt;Route&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;RouterComponent&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Wrapping everything in a route, allows us to use regex to determine the language from the pathname, and use that match to inject the current language into the provider.&lt;/p&gt;

&lt;p&gt;Also, our new router component will enforce that a language is always a part of the pathname.&lt;/p&gt;

&lt;p&gt;The regex used in this example will only support lowercase language, but you can modify it to &lt;strong&gt;[a-zA-z]{2}&lt;/strong&gt; and use &lt;strong&gt;String.toLowercase()&lt;/strong&gt; method when pathname matching if you want to support uppercase routes as well.&lt;/p&gt;

&lt;h3&gt;
  
  
  Language switcher
&lt;/h3&gt;

&lt;p&gt;We also need to add a language switcher component that will allow us to change the active language and show the currently activated language based on the pathname.&lt;/p&gt;

&lt;p&gt;Apart from the styling, we need a helper function that checks for matching route inside the strings object for other languages if we want to support navigating to the same page in another language directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;LanguageSwitcher&lt;/span&gt;&lt;span class="p"&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;FC&lt;/span&gt; &lt;span class="o"&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="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;pathname&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useLocation&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;locale&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;=&lt;/span&gt; &lt;span class="nx"&gt;useIntl&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;ul&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppLanguage&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;lang&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;lang&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&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;NavLink&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;activeClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;getMatchingRoute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppLanguage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;AppLanguage&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;lang&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="nc"&gt;NavLink&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;li&lt;/span&gt;&lt;span class="p"&gt;&amp;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;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;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;getMatchingRoute&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="nx"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cm"&gt;/**
     * Get the key of the route the user is currently on
     */&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;route&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;pathname&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;split&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;routeKey&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;route&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Find the matching route for the new language
     */&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;matchingRoute&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;appStrings&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;routeKey&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="cm"&gt;/**
     * Return localized route
     */&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&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="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;matchingRoute&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Navigation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The last thing to do is updating the &lt;strong&gt;Navigation&lt;/strong&gt; component itself, to also support switching to other routes in all languages.&lt;/p&gt;

&lt;p&gt;We simply use the &lt;strong&gt;formatMessage&lt;/strong&gt; function from the react-intl hook for this purpose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Navigation&lt;/span&gt;&lt;span class="p"&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;FC&lt;/span&gt; &lt;span class="o"&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="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;formatMessage&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="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useIntl&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;ul&lt;/span&gt; &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&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="si"&gt;{&lt;/span&gt;&lt;span class="nb"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;keys&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="na"&gt;key&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;elem&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;list&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;item&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;NavLink&lt;/span&gt;
            &lt;span class="na"&gt;exact&lt;/span&gt;
            &lt;span class="na"&gt;className&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;primary&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;activeClassName&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;css&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;link&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;active&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
            &lt;span class="na"&gt;to&lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;localizeRouteKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;elem&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="si"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;AppRouteTitles&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;elem&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="dl"&gt;''&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;
          &lt;span class="p"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nc"&gt;NavLink&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;li&lt;/span&gt;&lt;span class="p"&gt;&amp;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;ul&lt;/span&gt;&lt;span class="p"&gt;&amp;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;localizeRouteKey&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="na"&gt;path&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;string&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="s2"&gt;`/&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="s2"&gt;`&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;formatMessage&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;id&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In order to allow for easier route name resolution, since TS enums don’t allow for reverse mapping on string enums, you can create an ES6 map.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;AppRouteTitles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nb"&gt;Map&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
  &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;AppRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Home&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;home.title&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;AppRoute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Summary&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;summary.title&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;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;As you can see, localizing the routes of the website is not a hard task in React. It requires a few components and little thinking on the side of the project architecture, so you don’t overcomplicate things. The result is easy to understand the solution that will easily scale regardless of the language count that you might add later on.&lt;/p&gt;

&lt;p&gt;A fully working example can be found on:&lt;br&gt;
&lt;a href="https://github.com/vlaja/multilanguage-routing-react"&gt;&lt;strong&gt;vlaja/multilanguage-routing-react&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>react</category>
      <category>routing</category>
      <category>webdev</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Avoiding the messy git history</title>
      <dc:creator>Vlatko Vlahek</dc:creator>
      <pubDate>Tue, 17 Sep 2019 08:56:25 +0000</pubDate>
      <link>https://dev.to/prototyp/avoiding-the-messy-git-history-470d</link>
      <guid>https://dev.to/prototyp/avoiding-the-messy-git-history-470d</guid>
      <description>&lt;h1&gt;
  
  
  Avoiding the messy git history
&lt;/h1&gt;

&lt;p&gt;If we try to name the things that have clearly defined modern software development, source control would most certainly be very high on the list, especially git which is probably the most widely used version control system today.&lt;/p&gt;

&lt;p&gt;Days of having our code versioned in different folders locally, often prone to corruption are long gone. However, a lot of developers use git just as a means to store the source files somewhere remotely, without actually utilising some of its more advanced features that allow us to have a great, easily readable git history.&lt;/p&gt;

&lt;p&gt;This article will cover one of the git-flow approaches, heavily based on git rebase, that will allow you to have a more streamlined git experience, especially when working inside a team. It’s a strict approach and takes a while to get used to.&lt;/p&gt;

&lt;p&gt;The experience stems from working on bigger projects, based on the in-house practices that we have at &lt;a href="https://prototyp.digital/"&gt;PROTOTYP&lt;/a&gt;. We put a strong emphasis on code review and easy readability of all changes that happen inside our codebase.&lt;/p&gt;

&lt;p&gt;Main goals of the approach are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;cleaner git history&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fewer merge conflicts&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;enforcing code review&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;increasing branch stability&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All examples in the article are done via command line, but there will be links and references on how to achieve some parts of the process in the git provider dashboards.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initialising git flow
&lt;/h2&gt;

&lt;p&gt;The first step of the journey is definitively initialising Git flow over your repository.&lt;/p&gt;

&lt;p&gt;More thorough documentation on the matter by its original author can be found &lt;a href="https://nvie.com/posts/a-successful-git-branching-model/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In short, it’s a branching model that scaled really well for us in the past and is widely adopted.&lt;/p&gt;

&lt;p&gt;In order to use this from the command line, you will most probably need to install git-flow. GUI solutions such as Tower or Sourcetree usually have it integrated.&lt;/p&gt;

&lt;p&gt;You can check the installation instructions &lt;a href="https://danielkummer.github.io/git-flow-cheatsheet/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// initialises git on your repository
git init

// initialises git flow on your git repo
git flow init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After initialising git flow on your repository, you will be asked for default branch names. We use the default values internally, only prefixing tags with letter &lt;strong&gt;“v”&lt;/strong&gt;, so our versions are v1.0.0, v1.0.1 etc.&lt;/p&gt;

&lt;p&gt;Feel free to use the versioning system for releases that has the most sense for your team and your product. However, semantic versioning or &lt;a href="https://semver.org/"&gt;semver&lt;/a&gt; has been our weapon of choice for some time now, and while it could be an overkill for smaller one-off projects, it has proven great for releasing new features for SaaS products or mobile apps inside our company.&lt;/p&gt;

&lt;p&gt;Each of the branches git flow introduces has its own place in the ecosystem, and understanding when to use each one is a must!&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// New features
Feature branches? [feature/]

// Tags a version and merges develop to master. 
// A short lived branch. Versions bumps are ok inside it.
Release branches? [release/]

// A branch done from master directly, for fast hotfix push
// We use bugfix/ name for a bugfix branch that is branched from  
// develop
Hotfix branches? [hotfix/]

// Need to add some client specific code ? Use a support branch
Support branches? [support/]

// Tag for release branches
Version tag prefix? [v]
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;Remember, git is not some sort of a magic wand that makes all of your issues go away just by itself, nor does it have any sense in having multiple branches if you don’t know what to do with them in the first place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Locking down develop and master branches
&lt;/h2&gt;

&lt;p&gt;This one is maybe a tad controversial for people not used to this approach, but I would definitively note this as one of the most important steps in the process.&lt;/p&gt;

&lt;p&gt;Protecting &lt;em&gt;**develop&lt;/em&gt;* and &lt;strong&gt;&lt;em&gt;master&lt;/em&gt;&lt;/strong&gt; branches will require your team to merge code to them exclusively via merge requests, and through a code review process, which are both strongly encouraged practices.&lt;/p&gt;

&lt;p&gt;It will also save you from a lot of potential “instability” troubles that tend to happen when people push a &lt;strong&gt;&lt;em&gt;“small and insignificant fix that can’t break anything”&lt;/em&gt;&lt;/strong&gt; directly to one of these branches. This creates a lot of frustration when things go wrong, which happens, sooner or later.&lt;/p&gt;

&lt;p&gt;How to do it, differs from provider to provider, but here is the outline for more popular ones:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bitbucket:&lt;/strong&gt; &lt;a href="https://blog.bitbucket.org/2016/12/05/protect-your-master-branch-with-merge-checks/"&gt;https://blog.bitbucket.org/2016/12/05/protect-your-master-branch-with-merge-checks/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://help.github.com/articles/configuring-protected-branches/"&gt;https://help.github.com/articles/configuring-protected-branches/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitLab:&lt;/strong&gt; &lt;a href="https://docs.gitlab.com/ee/user/project/protected_branches.html"&gt;https://docs.gitlab.com/ee/user/project/protected_branches.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would suggest enabling some merge checks along, such as at least one code review and approval from another developer before merging any code to them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding new code through feature branches
&lt;/h2&gt;

&lt;p&gt;Considering that no code can be directly pushed to develop or master branches, it’s required that you create a new feature branch to add a new functionality to your app.&lt;/p&gt;

&lt;p&gt;You can either do it from the command line or use integrated functionality in tools such as &lt;a href="https://www.sourcetreeapp.com/"&gt;Sourcetree&lt;/a&gt; or &lt;a href="https://www.git-tower.com/mac"&gt;Tower&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source branch:&lt;/strong&gt; develop&lt;br&gt;
&lt;strong&gt;Naming:&lt;/strong&gt; feature/feature-name&lt;/p&gt;

&lt;p&gt;Example:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout develop
git branch feature/my-new-feature
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After you have successfully created your feature branch, feel free to push the code to it, until you are ready to get your feature reviewed as merged by another member of your team.&lt;/p&gt;

&lt;h2&gt;
  
  
  Merging your code
&lt;/h2&gt;

&lt;p&gt;In order to merge the code via this approach, after you have finished your feature, you will first need to rebase it. This is a multi-step process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebase by developer
&lt;/h3&gt;

&lt;p&gt;As a developer who created a feature, you generally want to pull the latest changes from the develop branch that happened in the meantime and test whether your feature is still working.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout develop
git pull
git checkout feature/your-feature-name

// This line will return a hash of commit where your branch diverged // from develop
git merge-base develop feature/your-feature-name

// {hash} is the result from the previous step
git rebase --onto develop {hash}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will start the rebase process where changes from develop are integrated to your own feature branch, &lt;strong&gt;commit by commit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once you understand the steps that happen with rebase, there are also shorter alternatives such as:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout feature/your-feature-name
git pull --rebase origin develop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can check the complete rebase documentation &lt;a href="https://git-scm.com/docs/git-rebase"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Why not simply use merge?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;A valid point. You can, of course, merge the develop to your own feature branch and get similar results. However, there are a few key differences, why we prefer to rebase the branch over merge in this scenario.&lt;/p&gt;

&lt;p&gt;Rebase:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Integrates changes commit by commit.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Conflicts also come in commit by commit, and it’s easy to ask your colleague what was the change to resolve the conflict more efficiently together.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Rebase can easily be aborted and started over, reverting all changes that you made if you are unsure if you messed up somewhere.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// After you stage files, you can continue to next commit
git rebase --continue

// Skips the current commit entirely
git rebase --skip

// Reverts all rebase changes that you did
// Returns the branch to pre-rebase state
git rebase --abort
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have more flexibility when rebasing as you can rename incoming commits or completely skip them, if you think they are unnecessary or superseded by your changes.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;It doesn’t create unnecessary merge commits if you integrate changes to your feature branches often.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;If you don’t have any conflicts, it will just pass through all commits and the process will be a breeze as it is with git merge.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Merge chaos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AnDSxyzH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AJzp7pSDzzJI5sTvGzucoQQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AnDSxyzH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AJzp7pSDzzJI5sTvGzucoQQ.gif" alt="Merge chaos"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Merge glues all changes together leading to a huge amount of potentially conflicting files, and resolving the differences is often quite a chore. Also, it makes it much harder to understand who and for what reason changed a file if a conflict occurs.&lt;/p&gt;

&lt;p&gt;However, regardless of your choice, the burden of testing the feature before creating a Pull Request is definitely on the developer, and shouldn’t be skipped.&lt;/p&gt;

&lt;h3&gt;
  
  
  Creating a pull request (merge request in some providers)
&lt;/h3&gt;

&lt;p&gt;Create a pull request from your feature branch to develop (or branch from which you branched off) inside the interface of your git provider.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Bitbucket:&lt;/strong&gt; &lt;a href="https://confluence.atlassian.com/bitbucket/create-a-pull-request-to-merge-your-change-774243413.html"&gt;https://confluence.atlassian.com/bitbucket/create-a-pull-request-to-merge-your-change-774243413.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitHub&lt;/strong&gt;: &lt;a href="https://help.github.com/en/articles/creating-a-pull-request"&gt;https://help.github.com/en/articles/creating-a-pull-request&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GitLab:&lt;/strong&gt; &lt;a href="https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html"&gt;https://docs.gitlab.com/ee/gitlab-basics/add-merge-request.html&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Gitlab offers automatic rebase option inside their interface, a feature that I really like, and would be hyped to see it in BitBucket, for example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Rebase by reviewer
&lt;/h3&gt;

&lt;p&gt;This step is the main trick to have a readable and streamlined git history.&lt;/p&gt;

&lt;p&gt;Unlike the developer rebase, which is used for resolving potential conflicts and testing your feature with the latest changes, this one is primarily for readability reasons, although it can also catch issues if they do happen.&lt;/p&gt;

&lt;p&gt;We think it’s a critical step in the process because after you create a PR, you don’t know how long it will take for somebody to review and merge it.&lt;/p&gt;

&lt;p&gt;More often than not, before this happens, there are new features merged to your development branch, which means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;new features might have introduced conflicts which need to be resolved&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;git history has changed from the moment you first rebased&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the reviewer does another rebase, it should improve the testing of the feature, minimise the potential of the feature not working after being merged, and provide you with a very clean and linear git history.&lt;/p&gt;

&lt;h2&gt;
  
  
  How does it look in practice
&lt;/h2&gt;

&lt;p&gt;Here is a little screenshot from Sourcetree, showing features merged via this method, and mutual relationships between &lt;em&gt;develop&lt;/em&gt;, &lt;em&gt;master&lt;/em&gt; and &lt;em&gt;other branches&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--aeZNPoik--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3100/1%2AbrfzRnafwUrh3sEpSJNDjA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--aeZNPoik--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3100/1%2AbrfzRnafwUrh3sEpSJNDjA.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;it’s very readable&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;release point with the tag from develop to master can be found quickly&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;you can easily see in which order your features or bug fixes were merged.&lt;br&gt;
This can help a lot if you are unsure which feature broke something else in your project. It even makes using &lt;a href="https://git-scm.com/docs/git-bisect"&gt;*git bisect&lt;/a&gt;* much easier if things come to that.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Squash or no squash&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The example shown here uses &lt;em&gt;squash&lt;/em&gt; which is given as a feature by GitLab automatically, although you can squash commits locally if required, like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout feature/my-new-feature // If you are not on it
git rebase -i HEAD~1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This would squash your whole branch to one commit. A word of advice, &lt;strong&gt;discuss internally if this is what you want.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;From our perspective, as long as you follow the rebase flow, squash will not significantly impact the readability of your git graph, unless your features have 100+ commits.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;In that scenario, maybe you bundled too much inside a single feature :).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I prefer squashing commits in a branch before doing a PR because it forces you to go for a new &lt;em&gt;bugfix/&lt;/em&gt; or &lt;em&gt;hotfix/&lt;/em&gt; branch if you messed something up. Also, regardless of whether your developers do atomic commits or huge beasts of commits, it will not matter.&lt;/p&gt;

&lt;p&gt;However, it’s not mandatory to squash all to one single commit. If it’s a bigger feature, you can manually squash your branch to a few important commits via interactive rebase.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout feature/your-feature-name
git merge-base develop feature/your-feature-name // returns {hash}
git rebase -i {hash}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You will get a screen like this:&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;pick be8606b Added localisation package and settings
pick 48e6aec Fixed an issue with payload not being propagated
squash 6085ce3 Added connected intl
squash 60ec657 Fixed connected intl
squash ba09d22 Modified tasks from package.json
pick 0bea497 Build android
pick 52c67b9 Updated packages
pick 21aa18c rm package lock
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Simply change &lt;em&gt;pick&lt;/em&gt; to &lt;em&gt;squash&lt;/em&gt; to merge a commit with the commit that preceded it.&lt;/p&gt;

&lt;p&gt;This is usually used to squash commit duplicates or commits with stupid names such as &lt;em&gt;removed console.log&lt;/em&gt; in order to maintain a git history that is relevant and informative.&lt;/p&gt;

&lt;h2&gt;
  
  
  Not convinced that this is a way to go?
&lt;/h2&gt;

&lt;p&gt;If you haven’t used git in this fashion it’s very understandable. At least try it out, and try to make an opinion of it after you use it for a few days or a single project.&lt;/p&gt;

&lt;p&gt;It did allow us to improve our git usage at &lt;a href="http://prototyp.digital"&gt;PROTOTYP&lt;/a&gt;, and to achieve better git readability with far fewer conflicts. And when they do happen, they are resolved quickly, allowing us to be more efficient and focus on features, and not pulling our hair out.&lt;/p&gt;

&lt;p&gt;The process of switching to the flow on all projects was not easy and took some time. After a while though, everybody is satisfied with the results that it has brought to our team.&lt;/p&gt;

&lt;p&gt;Here are a few final things about the process.&lt;/p&gt;

&lt;h3&gt;
  
  
  A few words about Git rebase
&lt;/h3&gt;

&lt;p&gt;Oh boy. Not rebase, right?&lt;/p&gt;

&lt;p&gt;For us, &lt;strong&gt;git rebase&lt;/strong&gt; is one of the most powerful features that comes with git. Think of it as a swiss-tool for managing your git history.&lt;/p&gt;

&lt;p&gt;However, opinions for this functionality are often highly opinionated and this can lead to a few misconceptions.&lt;/p&gt;

&lt;p&gt;Here are a few:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don’t use rebase, it’s a destructive operation!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This has some merit. Rebase rewrites git history, and can lead to disastrous results, &lt;strong&gt;if not used properly!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;However, a lot of things with git are potentially destructive. This doesn’t mean they shouldn’t be used, just that you need to understand &lt;strong&gt;how&lt;/strong&gt; and &lt;strong&gt;when&lt;/strong&gt; to use them, and how to mitigate the issues if they do happen.&lt;/p&gt;

&lt;p&gt;Be mindful of using this approach on public repositories and open-source projects where a lot of different people are pushing code, and not everybody is using the same principle. It requires the whole team to be disciplined.&lt;/p&gt;

&lt;p&gt;Also, if several people are working on the same feature, only rebase &lt;strong&gt;before the pull request&lt;/strong&gt; or &lt;strong&gt;if you are completely sure everybody commited their changes.&lt;/strong&gt; Rebase does rewrite the history of your own branch, so it could lead to a lot of force pulling and pushing on the branch then, which can create a frustration of its own.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This flow only makes the git graph nicer, it doesn’t bring in any value.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I strongly disagree with this one, for multiple reasons.&lt;/p&gt;

&lt;p&gt;First off, you can write nice code and ugly spaghetti code, but both can be functional. However, do ask yourself which is faster to understand and refactor and less prone to issues?&lt;/p&gt;

&lt;p&gt;The same logic applies here. Added brevity is rarely a bad thing.&lt;/p&gt;

&lt;p&gt;Also, the whole point of enforcing rebase is to minimise issues with conflicts, as they happen to be much much easier to resolve via this approach. The nice graph is only a great side effect of the whole process.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;What if using rebase messes my branch and project up?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To be honest, it’s very very hard to completely mess a project or a branch up, especially if multiple people are working on it, and have their own local versions which are ok. They can always force push the change to reset your state.&lt;/p&gt;

&lt;p&gt;You can also mess a branch up if you use merge and commit these changes, but you haven’t resolved issues properly.&lt;/p&gt;

&lt;p&gt;However, if you do manage to do to the unthinkable, resolving these issues is often a very easy thing to do.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Git reflog&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Behold, the magic eraser pen of all the bad things that we do to our repository.&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git reflog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Hitting that command will show hashes of all states in which your branch was, up to 90 days. You can simply check out or reset the branch to a state before the merge or rebase, and start over, by finding the last hash before you did any destructive operation.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Something is strange here. Sometimes I need to rebase, sometimes not. What’s the catch?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If your branch is &lt;strong&gt;ahead&lt;/strong&gt; of the tip of develop, you don’t need to do it. In the following scenario, ensure that you have pulled all changes from develop, and if you are still ahead of it, just do a Pull request.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QuBGy_eW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2620/1%2AQb5X8sEsfN3wfnMCVWRXjg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QuBGy_eW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2620/1%2AQb5X8sEsfN3wfnMCVWRXjg.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If your branch is &lt;strong&gt;behind&lt;/strong&gt; the tip of develop, you will need to rebase. Observe how the &lt;em&gt;feature/other-feature&lt;/em&gt; is not connected to the foremost point of develop, but a point behind its tip.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jWpwYhxA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AgGFdRS_FtAE1QONsEB4OXw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jWpwYhxA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AgGFdRS_FtAE1QONsEB4OXw.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

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

&lt;p&gt;We hope that this article outlined both the process and its pros and cons, based on our experiences.&lt;/p&gt;

&lt;p&gt;If you are looking for a new process that could bring in improvements to readability and stability of your git process, making you and your team more efficient in the process, give it a shot. It could go a long way!&lt;/p&gt;

&lt;p&gt;If you have a similar or different workflow which works for your team, we would like to hear about it and see how it compares.&lt;/p&gt;

</description>
      <category>git</category>
    </item>
  </channel>
</rss>
