Repository: lingui/js-lingui
Pull request #760 (2020-10-15 09:21:25)

fix: trailing whitespace
Fixes https://github.com/lingui/js-lingui/issues/747

This line `.replace(keepSpaceRe, " ")` is creating the whitespace, probably that regex could be reimplemented to don't do that change on this cases, but with the new regex this issue is fixed


Patch:
diff --git a/docs/misc/showroom.rst b/docs/misc/showroom.rst
index 1ce6402d..7cbb350e 100644
--- a/docs/misc/showroom.rst
+++ b/docs/misc/showroom.rst
@@ -14,4 +14,3 @@ Feel free to `send a PR <https://github.com/lingui/js-lingui/issues/new>`__ to l
 - `LocalEthereum <https://localethereum.com/>`__
 - `Upcount <https://github.com/madisvain/upcount>`__
 - `Symbolovník <http://www.symbolovnik.cz>`__
-- `Notos <https://www.notos.co>`__
diff --git a/docs/ref/react.rst b/docs/ref/react.rst
index 6f9b9f06..20debc5f 100644
--- a/docs/ref/react.rst
+++ b/docs/ref/react.rst
@@ -295,7 +295,6 @@ I18nProvider
    :prop object catalogs: Message catalogs
    :prop React.Element|React.Class|string defaultRender: Default element to render translation
    :prop string|Function missing: Custom message to be returned when translation is missing
-   :prop boolean forceRenderOnLocaleChange: Force re-render when locale changes (default: true)
 
 ``defaultRender`` has the same meaning as ``render`` in other i18n
 components. :ref:`Rendering of translations <rendering-translations>` is explained
@@ -346,15 +345,6 @@ for debugging:
      [messageId: string]: string | Function
    }
 
-``forceRenderOnLocaleChange`` is true by default and it ensures that:
-
-  - Children of ``I18nProvider`` aren't rendered before locales are loaded.
-  - When locale changes, the whole element tree below ``I18nProvider`` is
-    re-rendered.
-
-Disable ``forceRenderOnLocaleChange`` when you have specific needs to handle
-initial state before locales are loaded and when locale changes.
-
 This component should live above all i18n components. A good place is as a
 top-level application component. However, if the ``language`` is stored in a
 ``redux`` store, this component should be inserted below ``react-redux/Provider``:
diff --git a/docs/releases/migration-3.rst b/docs/releases/migration-3.rst
index b0087bc8..0a53645a 100644
--- a/docs/releases/migration-3.rst
+++ b/docs/releases/migration-3.rst
@@ -14,7 +14,8 @@ Minimal required versions are:
 @lingui/react
 -------------
 
-- ``<I18n>`` render-prop component was removed in favor of :js:func:`useLingui` hook.
+- ``<I18n>`` render-prop component and ``withI18n`` high-order component were
+  removed in favor of :js:func:`useLingui` hook.
 
 - In :component:`Trans`, ``defaults`` prop was renamed to ``message`` and
   ``description`` to ``comment``.
diff --git a/docs/tutorials/react.rst b/docs/tutorials/react.rst
index c5c8f9b6..36e723cb 100644
--- a/docs/tutorials/react.rst
+++ b/docs/tutorials/react.rst
@@ -4,7 +4,7 @@
 Tutorial - Internationalization of React apps
 *********************************************
 
-Through this tutorial, we'll learn how to add internationalization (i18n)
+Through this tutorial, we'll learn how to add internationalization
 to an existing application in React JS.
 
 Let's Start
@@ -70,11 +70,10 @@ Setup
 We will directly start translating the ``Inbox`` component, but we need
 to complete one more step to setup our application.
 
-Components needs to read information about current language and message catalogs from ``i18n`` instance. 
-Initially, you can use the one created and exported from ``@lingui/core`` and later you can replace with
-your one if such need arise.
-
-In order to pass ``i18n`` around the I18nProvider wraps around React Context.
+Components needs to be aware of their active language. All LinguiJS_ components
+read translations and language settings from the React context. In order to get this
+information into the context, we need to wrap our application in
+:component:`I18nProvider` component.
 
 Let's add all required imports and wrap our app inside :component:`I18nProvider`:
 
@@ -83,13 +82,13 @@ Let's add all required imports and wrap our app inside :component:`I18nProvider`
    // index.js
    import React from 'react'
    import { render } from 'react-dom'
+   import Inbox from './Inbox.js'
 
-   import { i18n } from '@lingui/core'
    import { I18nProvider } from '@lingui/react'
-   import { messages } from './locales/en/messages.js'
-   import Inbox from './Inbox.js'
+   import { setupI18n } from '@lingui/core'
 
-   i18n.load('en', messages)
+   const i18n = setupI18n()
+   i18n.load('en', catalogEn)
    i18n.activate('en')
 
    const App = () => (
@@ -184,9 +183,21 @@ We're going to use `CLI` again. Run :cli:`extract` command to extract messages::
 
    No locales defined!
 
-   Add 'locales' to your configuration. See https://lingui.js.org/ref/conf.html#locales
+   (use "lingui add-locale <language>" to add one)
+
+Oops! Seems we forgot something. First we need to tell the CLI what locales we're
+going to use in our app. Let's start with two locales: ``en`` for English and ``cs``
+for Czech::
 
-After fixing configuration, let's run :cli:`extract` command again
+   $ lingui add-locale en cs
+
+   Added locale en.
+   Added locale cs.
+
+   (use "lingui extract" to extract messages)
+
+Everything went well and CLI guides us what to do next. Let's run :cli:`extract` command
+again::
 
    $ lingui extract
 
@@ -198,6 +209,7 @@ After fixing configuration, let's run :cli:`extract` command again
    │ en       │      1      │    1    │
    └──────────┴─────────────┴─────────┘
 
+   (use "lingui add-locale <language>" to add more locales)
    (use "lingui extract" to update catalogs with new messages)
    (use "lingui compile" to compile catalogs for production)
 
@@ -232,6 +244,7 @@ If we run :cli:`extract` command again, we'll see that all Czech messages are tr
    │ en       │      1      │    1    │
    └──────────┴─────────────┴─────────┘
 
+   (use "lingui add-locale <language>" to add more locales)
    (use "lingui extract" to update catalogs with new messages)
    (use "lingui compile" to compile catalogs for production)
 
@@ -245,7 +258,8 @@ to compile them. As you see in the help in command output, we use :cli:`compile`
    Done!
 
 What just happened? If you look inside ``locales`` directory, you'll see there's a
-new file for each locale: ``<locale>.js``. This file contains compiled message catalog.
+new file for each locale: ``messages.js``. This file contains compiled message catalogs
+but also any locale specific data like plurals.
 
 Let's load this file into our app and set active language to ``cs``:
 
@@ -256,14 +270,15 @@ Let's load this file into our app and set active language to ``cs``:
    import React from 'react'
    import { render } from 'react-dom'
    import Inbox from './Inbox.js'
+   import catalogCs from './locales/cs/messages.js'
 
-   import { I18nProvider } from '@lingui/react'
-   import { i18n } from '@lingui/core'
+   import { setupI18n, I18nProvider } from '@lingui/react'
 
-   import catalogCs from './locales/cs.js'
-   i18n.load('cs', catalogCs.messages)
+   const i18n = setupI18n()
+   i18n.load('cs', catalogCs)
    i18n.activate('cs')
 
+   const catalogs = { cs: catalogCs };
    const App = () => (
      <I18nProvider i18n={i18n}>
        <Inbox />
@@ -692,11 +707,9 @@ After all modifications, the final component with i18n looks like this:
 
    // Inbox.js
    import React from 'react'
-   import { Trans, Plural } from '@lingui/macro'
-   import { useLingui } from '@lingui/react'
+   import { Trans, Plural, date } from '@lingui/macro'
 
    const Inbox = ({ messages, markAsRead, user }) => {
-     const { i18n } = useLingui()
      const messagesCount = messages.length
      const { name, lastLogin } = user
 
@@ -720,7 +733,7 @@ After all modifications, the final component with i18n looks like this:
            </p>
 
            <footer>
-             <Trans>Last login on {i18n.date(lastLogin)} />.</Trans>
+             <Trans>Last login on {date(lastLogin)} />.</Trans>
            </footer>
          </div>
        )
diff --git a/docs/tutorials/setup-cra.rst b/docs/tutorials/setup-cra.rst
index 9d8ca170..38613936 100644
--- a/docs/tutorials/setup-cra.rst
+++ b/docs/tutorials/setup-cra.rst
@@ -34,32 +34,41 @@ Install
    .. code-block:: json
 
       {
-         "locales": ["en", "cs", "fr"],
-         "sourceLocale": "en",
-         "catalogs": [{
-            "path": "src/locales/{locale}",
-            "include": ["src"]
-         }],
-         "format": "po"
+         "localeDir": "src/locales/",
+         "srcPathDirs": ["src/"],
+         "format": "po",
+         "sourceLocale": "en"
       }
 
    This configuration will extract messages from source files inside ``src`` directory
    and write them into message catalogs in ``src/locales`` (English catalog would be
-   in e.g: ``src/locales/en.po``). Finally, PO format is recommended. See
+   in e.g: ``src/locales/en/messages.po``). Finally, PO format is recommended. See
    :conf:`format` documentation for other available formats.
 
-4. Optionally, add following scripts to your ``package.json`` for conveniece:
+4. Add following scripts to your ``package.json``:
 
    .. code-block:: json
 
       {
          "scripts": {
+            "add-locale": "lingui add-locale",
             "extract": "lingui extract",
             "compile": "lingui compile"
          }
       }
 
-5. Check the installation by running extract command:
+5. Run ``npm run add-locale`` (or ``yarn add-locale``) with
+   `locale codes <https://www.iana.org/assignments/language-subtag-registry/language-subtag-registry>`_
+   you would like to use in your app:
+
+   .. code-block:: shell
+
+      npm run add-locale en es fr  # Add English, Spanish and French locale
+
+      # or using Yarn
+      yarn add-locale en es fr
+
+6. Check the installation by running ``npm run extract`` (or ``yarn extract``):
 
    .. code-block:: shell
 
@@ -68,7 +77,24 @@ Install
       # or using Yarn
       yarn extract
 
-   There should be no error and you can find extracted messages in src/locales.
+   There should be no error and you should see output similar following:
+
+   .. code-block:: none
+
+      > npm run extract
+
+      Catalog statistics:
+      ┌──────────┬─────────────┬─────────┐
+      │ Language │ Total count │ Missing │
+      ├──────────┼─────────────┼─────────┤
+      │ cs       │     0       │   0     │
+      │ en       │     0       │   0     │
+      │ fr       │     0       │   0     │
+      └──────────┴─────────────┴─────────┘
+
+      (use "lingui add-locale <language>" to add more locales)
+      (use "lingui extract" to update catalogs with new messages)
+      (use "lingui compile" to compile catalogs for production)
 
 Congratulations! You've sucessfully set up project with LinguiJS.
 Now it's good time to follow :doc:`React tutorial </tutorials/react>`
diff --git a/examples/next-js/pages/_app.tsx b/examples/next-js/pages/_app.tsx
index 98b54fa4..b4b640c3 100644
--- a/examples/next-js/pages/_app.tsx
+++ b/examples/next-js/pages/_app.tsx
@@ -1,6 +1,6 @@
-import { useEffect } from "react"
+import { Fragment, useEffect } from "react"
 
-import { I18nProvider } from "@lingui/react"
+import { I18nProvider, useLingui } from "@lingui/react"
 import { i18n } from "@lingui/core"
 
 import { activate } from "lingui-example/i18n"
@@ -14,7 +14,25 @@ export default function Page({ Component, pageProps }) {
 
   return (
     <I18nProvider i18n={i18n}>
-      <Component {...pageProps} />
+      <I18nWatchLocale>
+        <Component {...pageProps} />
+      </I18nWatchLocale>
     </I18nProvider>
   )
 }
+
+/**
+ * Watch for locale changes and force re-render. Otherwise string
+ * translations (e.g. using t`Macro`) won't be updated.
+ * <Trans>Components</Trans> have access to Lingui context and
+ * re-render automatically.
+ */
+function I18nWatchLocale({ children }) {
+  const { i18n } = useLingui()
+
+  // Skip render when locale isn't loaded
+  if (!i18n.locale) return null
+
+  // Force re-render by using active locale as an element key.
+  return <Fragment key={i18n.locale}>{children}</Fragment>
+}
diff --git a/examples/next-js/yarn.lock b/examples/next-js/yarn.lock
index 5e32d541..a1f4596a 100644
--- a/examples/next-js/yarn.lock
+++ b/examples/next-js/yarn.lock
@@ -291,7 +291,7 @@
 
 "@babel/helper-validator-identifier@^7.10.4":
   version "7.10.4"
-  resolved "http://0.0.0.0:4873/@babel%2fhelper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2"
   integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==
 
 "@babel/helper-wrap-function@^7.10.4":
@@ -315,7 +315,7 @@
 
 "@babel/highlight@^7.10.4":
   version "7.10.4"
-  resolved "http://0.0.0.0:4873/@babel%2fhighlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.10.4.tgz#7d1bdfd65753538fabe6c38596cdb76d9ac60143"
   integrity sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==
   dependencies:
     "@babel/helper-validator-identifier" "^7.10.4"
@@ -967,7 +967,7 @@
 
 "@babel/runtime@7.11.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4":
   version "7.11.2"
-  resolved "http://0.0.0.0:4873/@babel%2fruntime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.11.2.tgz#f549c13c754cc40b87644b9fa9f09a6a95fe0736"
   integrity sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==
   dependencies:
     regenerator-runtime "^0.13.4"
@@ -1045,28 +1045,28 @@
     "@types/yargs" "^15.0.0"
     chalk "^4.0.0"
 
-"@lingui/babel-plugin-extract-messages@3.0.0-16":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2fbabel-plugin-extract-messages/-/babel-plugin-extract-messages-3.0.0-16.tgz#c332030e535853c574c5dfbb0d486ed4173ea5e6"
-  integrity sha512-Mi3OHZJvokSBiUSlp+CY4qIhX/fTTv9ZSXqmbI5RuoHHZDlvHpk2i9TRw5lrYLq63wjCPiyqB6DdWUMjJfFQdw==
+"@lingui/babel-plugin-extract-messages@3.0.0-15":
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2fbabel-plugin-extract-messages/-/babel-plugin-extract-messages-3.0.0-15.tgz#a4ffd45df58d4d159aaf8121b3b8ef968325f0a4"
+  integrity sha512-k2C1kvKzTc/4BM9ZPT4/D4s+swF6ZMotdgJD7XJzNLO+uesvLIidhYgwsNv7zdhdkpLSqRNvCibYMc8KVe+p+w==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.0.0-16"
+    "@lingui/conf" "3.0.0-15"
     mkdirp "^1.0.4"
 
-"@lingui/cli@3.0.0-16", "@lingui/cli@^3.0.0-15":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2fcli/-/cli-3.0.0-16.tgz#48a8dc326effed83a291eb21181c46e8b6b996e1"
-  integrity sha512-l8O0p7lIPqwM7wtOlu66Oz4QYoA0zeWNKYDYuE4CiMgO7LknQmh6hItVlDRhqoS8uyQIcalt635O82oIOjZerg==
+"@lingui/cli@3.0.0-15", "@lingui/cli@^3.0.0-15":
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2fcli/-/cli-3.0.0-15.tgz#06d33dfe74a6409b65acb14df00329ad9d979654"
+  integrity sha512-/MNXhXLqCE+0K0CU3KP/9W1moI/lzyVdJKn+5VNVhYD84QEbPGnBq2XqfpY6oPZ2f7qZ3Z3bRQaX8Vw0r0I4wg==
   dependencies:
     "@babel/generator" "^7.11.6"
     "@babel/parser" "^7.11.5"
     "@babel/plugin-syntax-jsx" "^7.10.4"
     "@babel/runtime" "^7.11.2"
     "@babel/types" "^7.11.5"
-    "@lingui/babel-plugin-extract-messages" "3.0.0-16"
-    "@lingui/conf" "3.0.0-16"
+    "@lingui/babel-plugin-extract-messages" "3.0.0-15"
+    "@lingui/conf" "3.0.0-15"
     babel-plugin-macros "^2.8.0"
     bcp-47 "^1.0.7"
     chalk "^4.1.0"
@@ -1088,52 +1088,52 @@
     pseudolocale "^1.1.0"
     ramda "^0.27.1"
 
-"@lingui/conf@3.0.0-16":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2fconf/-/conf-3.0.0-16.tgz#8e6f5e3e44dd2b5423fded53cc2620b7e55aefe9"
-  integrity sha512-esh3KXvMhcHRm2KX2bpI/aOxOQOoxlLQJ/vkdfd4jjmz1Iz378BoAqyZXo9j3MaVEOm8aglt884KbDhM8NBknQ==
+"@lingui/conf@3.0.0-15":
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2fconf/-/conf-3.0.0-15.tgz#810b4398a609ca3eb463b09b65f3eb349a00462b"
+  integrity sha512-ZrRGHhzlTTVyBEcOEoM/T9OARX3xXlK8kXW6s2kyiJ1p70P7tVrW98f3aiJoVAMjaXEiW/mM3JSmeRXXHTduDw==
   dependencies:
     "@babel/runtime" "^7.11.2"
     chalk "^4.1.0"
     cosmiconfig "^7.0.0"
     jest-validate "^26.5.2"
 
-"@lingui/core@3.0.0-16", "@lingui/core@^3.0.0-14":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2fcore/-/core-3.0.0-16.tgz#352f3a090baeeaee63b07f8ee569cf5f2bbdc2de"
-  integrity sha512-iVzEuYfrVoDOsnphhC8tQneHoCwp6QAgBncMjUKjAAutQ2M/yI+ahFOj+xD+aqqu/NwJaU7djeZ4r68SI+A1uw==
+"@lingui/core@3.0.0-15", "@lingui/core@^3.0.0-14":
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2fcore/-/core-3.0.0-15.tgz#4403d04ef58f4f2a82fbffd87c6e2cdfb8726477"
+  integrity sha512-Y+qk9d+6kYNRXwLo25QWqbvA4SqqYlfUQORYKhdnWv4H2R4D4zlePnp/8XjdWEt7+b5ZKnbAdgeZ53oONqtaHA==
   dependencies:
     "@babel/runtime" "^7.11.2"
     make-plural "^6.2.2"
     messageformat-parser "^4.1.3"
 
 "@lingui/loader@^3.0.0-15":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2floader/-/loader-3.0.0-16.tgz#14fad6d521f958cf5f357c6307838a58fca53326"
-  integrity sha512-Mzp8bNx+0pVNB5YEXgAYf6ne4D9qPuaHd6C/p6fcFB5IUqMF3Fpvd5nl3Wx+IMghpW3JndtF7c/CrFOQftcU/g==
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2floader/-/loader-3.0.0-15.tgz#cc18150b4fa62b7b5ec2f9399281e2cf447f8e2e"
+  integrity sha512-BI6Oun5HhGmbWagNUNwIYU43QZo0MgflyGNqfGvx8Gcg1Nw8x1p+h+ffX95fobgQY9zlJnp/T2RHYH1lGB+Blw==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/cli" "3.0.0-16"
-    "@lingui/conf" "3.0.0-16"
+    "@lingui/cli" "3.0.0-15"
+    "@lingui/conf" "3.0.0-15"
     loader-utils "^2.0.0"
     ramda "^0.27.1"
 
 "@lingui/macro@^3.0.0-15":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2fmacro/-/macro-3.0.0-16.tgz#f3510f008233928938f4a2afc543c6a7e063c70e"
-  integrity sha512-D/xms04q8LoaKDeYBiD7go6fx1lMHUp2G8pWrwTcozgawJ1sXi+YhW+8l0VqXXrk4O/6TYcC2mjYKkURgzy/4Q==
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2fmacro/-/macro-3.0.0-15.tgz#f295ebb83b3b11a96d241cf43838dcb39bb8b2d2"
+  integrity sha512-YCXHTYihN+CzEWOCdU75Zr6FZNviw2rpzOTd48Wjk/33r+oz3sFNzeOqI///8xdULxqBsWFLWlhGOPfg4zfIZA==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/conf" "3.0.0-16"
+    "@lingui/conf" "3.0.0-15"
     ramda "^0.27.1"
 
 "@lingui/react@^3.0.0-14":
-  version "3.0.0-16"
-  resolved "http://0.0.0.0:4873/@lingui%2freact/-/react-3.0.0-16.tgz#e0871d11aead6cf30e09ad8e53752ec6959d363d"
-  integrity sha512-xDBo+gOPAV9nWcFoPytnW8vdke+MGqO7YUanpI4xQPz0A57GJRVcHAHrxjvHMb2yazeXOaEoL3oian21VZ6z3Q==
+  version "3.0.0-15"
+  resolved "http://0.0.0.0:4873/@lingui%2freact/-/react-3.0.0-15.tgz#773307ca9daefab70c6b2bf08063e948f84b07f6"
+  integrity sha512-mxb9tHUeGhsZWhL2ww8acqL6NA3RXjJlKXq6TSluBYY9ru/Ft41+Dfuf0BvTC0KCCOlNbiro6ImawtBIX8YpXA==
   dependencies:
     "@babel/runtime" "^7.11.2"
-    "@lingui/core" "3.0.0-16"
+    "@lingui/core" "3.0.0-15"
 
 "@next/env@9.5.5":
   version "9.5.5"
@@ -1204,7 +1204,7 @@
 
 "@types/parse-json@^4.0.0":
   version "4.0.0"
-  resolved "http://0.0.0.0:4873/@types%2fparse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
+  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
   integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
 
 "@types/yargs-parser@*":
@@ -1454,19 +1454,19 @@ ansi-escapes@^4.2.1:
 
 ansi-regex@^5.0.0:
   version "5.0.0"
-  resolved "http://0.0.0.0:4873/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75"
   integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==
 
 ansi-styles@^3.2.1:
   version "3.2.1"
-  resolved "http://0.0.0.0:4873/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
   integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
   dependencies:
     color-convert "^1.9.0"
 
 ansi-styles@^4.0.0, ansi-styles@^4.1.0:
   version "4.3.0"
-  resolved "http://0.0.0.0:4873/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
   integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
   dependencies:
     color-convert "^2.0.1"
@@ -1603,7 +1603,7 @@ babel-plugin-transform-react-remove-prop-types@0.4.24:
 
 balanced-match@^1.0.0:
   version "1.0.0"
-  resolved "http://0.0.0.0:4873/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
   integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
 
 base64-js@^1.0.2:
@@ -1635,7 +1635,7 @@ bcp-47@^1.0.7:
 
 big.js@^5.2.2:
   version "5.2.2"
-  resolved "http://0.0.0.0:4873/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
   integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
 
 binary-extensions@^1.0.0:
@@ -1672,7 +1672,7 @@ bn.js@^5.1.1:
 
 brace-expansion@^1.1.7:
   version "1.1.11"
-  resolved "http://0.0.0.0:4873/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
   integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
   dependencies:
     balanced-match "^1.0.0"
@@ -1880,7 +1880,7 @@ cache-base@^1.0.1:
 
 callsites@^3.0.0:
   version "3.1.0"
-  resolved "http://0.0.0.0:4873/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
   integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
 
 camelcase@5.0.0:
@@ -1895,7 +1895,7 @@ camelcase@5.3.1:
 
 camelcase@^6.0.0:
   version "6.0.0"
-  resolved "http://0.0.0.0:4873/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.0.0.tgz#5259f7c30e35e278f1bdc2a4d91230b37cad981e"
   integrity sha512-8KMDF1Vz2gzOq54ONPJS65IvTUaB1cHJ2DMM7MbPmLZljDH1qpzzLsWdiN9pHh6qvkRVDTi/07+eNGch/oLU4w==
 
 caniuse-lite@^1.0.30001093, caniuse-lite@^1.0.30001113, caniuse-lite@^1.0.30001135:
@@ -2051,26 +2051,26 @@ collection-visit@^1.0.0:
 
 color-convert@^1.9.0:
   version "1.9.3"
-  resolved "http://0.0.0.0:4873/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
   integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
   dependencies:
     color-name "1.1.3"
 
 color-convert@^2.0.1:
   version "2.0.1"
-  resolved "http://0.0.0.0:4873/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
   integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
   dependencies:
     color-name "~1.1.4"
 
 color-name@1.1.3:
   version "1.1.3"
-  resolved "http://0.0.0.0:4873/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
   integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
 
 color-name@~1.1.4:
   version "1.1.4"
-  resolved "http://0.0.0.0:4873/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
   integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
 
 colors@1.0.3:
@@ -2107,7 +2107,7 @@ compose-function@3.0.3:
 
 concat-map@0.0.1:
   version "0.0.1"
-  resolved "http://0.0.0.0:4873/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
   integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
 
 concat-stream@^1.5.0:
@@ -2530,7 +2530,7 @@ emojis-list@^2.0.0:
 
 emojis-list@^3.0.0:
   version "3.0.0"
-  resolved "http://0.0.0.0:4873/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
   integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
 
 end-of-stream@^1.0.0, end-of-stream@^1.1.0:
@@ -2645,7 +2645,7 @@ escalade@^3.0.1, escalade@^3.1.0:
 
 escape-string-regexp@^1.0.5:
   version "1.0.5"
-  resolved "http://0.0.0.0:4873/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
+  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
   integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
 
 eslint-scope@^4.0.3:
@@ -2793,7 +2793,7 @@ fill-range@^4.0.0:
 
 fill-range@^7.0.1:
   version "7.0.1"
-  resolved "http://0.0.0.0:4873/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
   integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
   dependencies:
     to-regex-range "^5.0.1"
@@ -2888,7 +2888,7 @@ fs-write-stream-atomic@^1.0.8:
 
 fs.realpath@^1.0.0:
   version "1.0.0"
-  resolved "http://0.0.0.0:4873/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
   integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
 
 fsevents@^1.2.7:
@@ -2963,12 +2963,12 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
 
 has-flag@^3.0.0:
   version "3.0.0"
-  resolved "http://0.0.0.0:4873/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
   integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
 
 has-flag@^4.0.0:
   version "4.0.0"
-  resolved "http://0.0.0.0:4873/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
   integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
 
 has-symbols@^1.0.1:
@@ -3122,7 +3122,7 @@ infer-owner@^1.0.3, infer-owner@^1.0.4:
 
 inflight@^1.0.4:
   version "1.0.6"
-  resolved "http://0.0.0.0:4873/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
   integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
   dependencies:
     once "^1.3.0"
@@ -3322,7 +3322,7 @@ is-number@^3.0.0:
 
 is-number@^7.0.0:
   version "7.0.0"
-  resolved "http://0.0.0.0:4873/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
   integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
 
 is-plain-object@^2.0.3, is-plain-object@^2.0.4:
@@ -3405,7 +3405,7 @@ jest-worker@24.9.0:
 
 jsesc@^2.5.1:
   version "2.5.2"
-  resolved "http://0.0.0.0:4873/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
   integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
 
 jsesc@~0.5.0:
@@ -3420,7 +3420,7 @@ json-parse-better-errors@^1.0.2:
 
 json-parse-even-better-errors@^2.3.0:
   version "2.3.1"
-  resolved "http://0.0.0.0:4873/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
+  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
   integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
 
 json-schema-traverse@^0.4.1:
@@ -3482,7 +3482,7 @@ klona@^2.0.3:
 
 leven@^3.1.0:
   version "3.1.0"
-  resolved "http://0.0.0.0:4873/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
+  resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2"
   integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==
 
 levenary@^1.1.1:
@@ -3494,7 +3494,7 @@ levenary@^1.1.1:
 
 lines-and-columns@^1.1.6:
   version "1.1.6"
-  resolved "http://0.0.0.0:4873/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
+  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00"
   integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=
 
 loader-runner@^2.4.0:
@@ -3701,7 +3701,7 @@ minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
 
 minimatch@^3.0.4:
   version "3.0.4"
-  resolved "http://0.0.0.0:4873/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
   integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
   dependencies:
     brace-expansion "^1.1.7"
@@ -4140,7 +4140,7 @@ parallel-transform@^1.1.0:
 
 parent-module@^1.0.0:
   version "1.0.1"
-  resolved "http://0.0.0.0:4873/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
   integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
   dependencies:
     callsites "^3.0.0"
@@ -4158,7 +4158,7 @@ parse-asn1@^5.0.0, parse-asn1@^5.1.5:
 
 parse-json@^5.0.0:
   version "5.1.0"
-  resolved "http://0.0.0.0:4873/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.1.0.tgz#f96088cdf24a8faa9aea9a009f2d9d942c999646"
   integrity sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==
   dependencies:
     "@babel/code-frame" "^7.0.0"
@@ -4198,7 +4198,7 @@ path-exists@^4.0.0:
 
 path-is-absolute@^1.0.0:
   version "1.0.1"
-  resolved "http://0.0.0.0:4873/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
+  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
   integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
 
 path-parse@^1.0.6:
@@ -4208,7 +4208,7 @@ path-parse@^1.0.6:
 
 path-type@^4.0.0:
   version "4.0.0"
-  resolved "http://0.0.0.0:4873/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
   integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
 
 pbkdf2@^3.0.3:
@@ -4623,7 +4623,7 @@ repeat-string@^1.6.1:
 
 resolve-from@^4.0.0:
   version "4.0.0"
-  resolved "http://0.0.0.0:4873/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
   integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
 
 resolve-url-loader@3.1.1:
@@ -5082,7 +5082,7 @@ stylis@3.5.4:
 
 supports-color@^5.3.0:
   version "5.5.0"
-  resolved "http://0.0.0.0:4873/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
   integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
   dependencies:
     has-flag "^3.0.0"
@@ -5096,7 +5096,7 @@ supports-color@^6.1.0:
 
 supports-color@^7.1.0:
   version "7.2.0"
-  resolved "http://0.0.0.0:4873/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
   integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
   dependencies:
     has-flag "^4.0.0"
@@ -5176,7 +5176,7 @@ to-arraybuffer@^1.0.0:
 
 to-fast-properties@^2.0.0:
   version "2.0.0"
-  resolved "http://0.0.0.0:4873/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
   integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
 
 to-object-path@^0.3.0:
@@ -5196,7 +5196,7 @@ to-regex-range@^2.1.0:
 
 to-regex-range@^5.0.1:
   version "5.0.1"
-  resolved "http://0.0.0.0:4873/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
   integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
   dependencies:
     is-number "^7.0.0"
@@ -5230,7 +5230,7 @@ ts-pnp@^1.1.6:
 
 tslib@^1.9.0:
   version "1.14.1"
-  resolved "http://0.0.0.0:4873/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
   integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
 
 tty-browserify@0.0.0:
@@ -5487,7 +5487,7 @@ worker-farm@^1.7.0:
 
 wrappy@1:
   version "1.0.2"
-  resolved "http://0.0.0.0:4873/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
   integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
 
 xtend@^4.0.0, xtend@~4.0.1:
diff --git a/package.json b/package.json
index 3155ffac..bb2f4058 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "private": true,
-  "version": "3.0.0-18",
+  "version": "3.0.0-13",
   "author": {
     "name": "Tomáš Ehrlich",
     "email": "tomas.ehrlich@gmail.com"
diff --git a/packages/macro/src/macroJsx.ts b/packages/macro/src/macroJsx.ts
index 59549ab5..1c008bb8 100644
--- a/packages/macro/src/macroJsx.ts
+++ b/packages/macro/src/macroJsx.ts
@@ -37,6 +37,8 @@ function normalizeWhitespace(text) {
       // keep escaped newlines
       .replace(/\\n/g, "\n")
       .replace(/\\s/g, " ")
+      // we remove trailing whitespace inside Plural
+      .replace(/(\s+})/gm, "}")
       .trim()
   )
 }
diff --git a/packages/react/src/I18nProvider.tsx b/packages/react/src/I18nProvider.tsx
index cc4fdb88..1a8a6c84 100644
--- a/packages/react/src/I18nProvider.tsx
+++ b/packages/react/src/I18nProvider.tsx
@@ -1,4 +1,4 @@
-import React, { FunctionComponent, ComponentType } from "react"
+import React, { FunctionComponent } from "react"
 import { I18n } from "@lingui/core"
 import { TransRenderType } from "./Trans"
 
@@ -7,14 +7,12 @@ type I18nContext = {
   defaultRender?: TransRenderType
 }
 
-export type I18nProviderProps = I18nContext & {
-  forceRenderOnLocaleChange?: boolean
-}
+export type I18nProviderProps = I18nContext
 
 const LinguiContext = React.createContext<I18nContext>(null)
 
 export function useLingui(): I18nContext {
-  const context = React.useContext<I18nContext>(LinguiContext)
+  const context = React.useContext(LinguiContext)
 
   if (process.env.NODE_ENV !== "production") {
     if (context == null) {
@@ -25,47 +23,7 @@ export function useLingui(): I18nContext {
   return context
 }
 
-export function withI18n(o?: object): <P extends { i18n: I18n }>(Component: ComponentType<P>) => React.ComponentType<P> {
-  return <P extends { i18n: I18n }>(WrappedComponent: ComponentType<P>) : ComponentType<P> => {
-    return (props) => {
-      if (process.env.NODE_ENV !== "production") {
-        if (typeof o === "function" || React.isValidElement(o)) {
-          throw new Error(
-            "withI18n([options]) takes options as a first argument, " +
-              "but received React component itself. Without options, the Component " +
-              "should be wrapped as withI18n()(Component), not withI18n(Component)."
-          )
-        }
-      }
-
-      const { i18n } = useLingui();
-      return <WrappedComponent {...props} i18n={i18n} />;
-    }
-  }
-}
-
-export const I18nProvider: FunctionComponent<I18nProviderProps> = ({
-  i18n,
-  defaultRender,
-  forceRenderOnLocaleChange = true,
-  children,
-}) => {
-  /**
-   * We can't pass `i18n` object directly through context, because even when locale
-   * or messages are changed, i18n object is still the same. Context provider compares
-   * reference identity and suggested workaround is create a wrapper object every time
-   * we need to trigger re-render. See https://reactjs.org/docs/context.html#caveats.
-   *
-   * Due to this effect we also pass `defaultRender` in the same context, instead
-   * of creating a separate Provider/Consumer pair.
-   *
-   * We can't use useMemo hook either, because we want to recalculate value manually.
-   */
-  const makeContext = () => ({
-    i18n,
-    defaultRender,
-  })
-
+export const I18nProvider: FunctionComponent<I18nProviderProps> = (props) => {
   const [context, setContext] = React.useState<I18nContext>(makeContext())
 
   /**
@@ -76,16 +34,31 @@ export const I18nProvider: FunctionComponent<I18nProviderProps> = ({
    * we need to trigger re-rendering of LinguiContext.Consumers.
    */
   React.useEffect(() => {
-    const unsubscribe = i18n.on("change", () => setContext(makeContext()))
+    const unsubscribe = props.i18n.on("change", () => setContext(makeContext()))
     return () => unsubscribe()
   }, [])
 
-  const renderKey = forceRenderOnLocaleChange && i18n.locale
-  if (forceRenderOnLocaleChange && !renderKey) return null
+  /**
+   * We can't pass `i18n` object directly through context, because even when locale
+   * or messages are changed, i18n object is still the same. Context provider compares
+   * reference identity and suggested workaround is create a wrapper object every time
+   * we need to trigger re-render. See https://reactjs.org/docs/context.html#caveats.
+   *
+   * Due to this effect we also pass `defaultRender` in the same context, instead
+   * of creating a separate Provider/Consumer pair.
+   *
+   * We can't use useMemo hook either, because we want to recalculate value manually.
+   */
+  function makeContext() {
+    return {
+      i18n: props.i18n,
+      defaultRender: props.defaultRender,
+    }
+  }
 
   return (
-    <LinguiContext.Provider value={context} key={renderKey}>
-      {children}
+    <LinguiContext.Provider value={context}>
+      {props.children}
     </LinguiContext.Provider>
   )
 }
diff --git a/packages/react/src/format.ts b/packages/react/src/format.ts
index c60dedb7..2d7c3667 100644
--- a/packages/react/src/format.ts
+++ b/packages/react/src/format.ts
@@ -4,27 +4,6 @@ import React from "react"
 const tagRe = /<(\d+)>(.*?)<\/\1>|<(\d+)\/>/
 const nlRe = /(?:\r\n|\r|\n)/g
 
-// For HTML, certain tags should omit their close tag. We keep a whitelist for
-// those special-case tags.
-const voidElementTags = {
-  area: true,
-  base: true,
-  br: true,
-  col: true,
-  embed: true,
-  hr: true,
-  img: true,
-  input: true,
-  keygen: true,
-  link: true,
-  meta: true,
-  param: true,
-  source: true,
-  track: true,
-  wbr: true,
-  menuitem: true
-}
-
 /**
  * `formatElements` - parse string and return tree of react elements
  *
@@ -47,23 +26,7 @@ function formatElements(
   if (before) tree.push(before)
 
   for (const [index, children, after] of getElements(parts)) {
-    let element = elements[index]
-
-    if (!element || (voidElementTags[element.type as string] && children)) {
-      if (!element) {
-        console.error(
-          `Can use element at index '${index}' as it is not declared in the original translation`
-        )
-      } else {
-        console.error(
-          `${element.type} is a void element tag therefore it must have no children`
-        )
-      }
-
-      // ignore problematic element but push its children and elements after it
-      element = React.createElement(React.Fragment)
-    }
-
+    const element = elements[index]
     tree.push(
       React.cloneElement(
         element,


Test patch:
diff --git a/packages/macro/test/jsx-plural.ts b/packages/macro/test/jsx-plural.ts
index 7f3a72d1..739ad0c4 100644
--- a/packages/macro/test/jsx-plural.ts
+++ b/packages/macro/test/jsx-plural.ts
@@ -19,6 +19,33 @@ export default [
         }} />;
       `,
   },
+  {
+    input: `
+        import { Trans, Plural } from '@lingui/macro';
+        <Plural
+          value={count}
+          one={
+            <Trans>
+              <strong>#</strong> slot added
+            </Trans>
+          }
+          other={
+            <Trans>
+              <strong>#</strong> slots added
+            </Trans>
+          }
+        />;
+      `,
+    expected: `
+        import { Trans } from "@lingui/react";
+        <Trans id="{count, plural, one {<0>#</0> slot added} other {<1>#</1> slots added}}" values={{
+          count: count
+        }} components={{
+          0: <strong />,
+          1: <strong />
+        }} />;
+      `,
+  },
   {
     input: `
         import { Plural } from '@lingui/macro';
diff --git a/packages/react/src/I18nProvider.test.tsx b/packages/react/src/I18nProvider.test.tsx
index 18258a9e..6e9f8b83 100644
--- a/packages/react/src/I18nProvider.test.tsx
+++ b/packages/react/src/I18nProvider.test.tsx
@@ -1,39 +1,11 @@
 import * as React from "react"
-import { act, render } from "@testing-library/react"
+import { render } from "@testing-library/react"
 
-import { withI18n, I18nProvider } from "./I18nProvider"
+import { I18nProvider, useLingui } from "@lingui/react"
 import { setupI18n } from "@lingui/core"
 
-describe("I18nProvider", () => {
-
-  it("should pass i18n context to wrapped component", () => {
-    const i18n = setupI18n({
-      locale: "cs",
-    })
-
-    const WithoutHoc = (props) => {
-      return <div {...props}>{props?.i18n?.locale}</div>
-    }
-
-    const WithHoc = withI18n()(WithoutHoc)
-
-    const { getByTestId } = render(
-      <I18nProvider i18n={i18n}>
-        <WithoutHoc data-testid="not-composed" />
-        <WithHoc data-testid="composed" />
-      </I18nProvider>
-    )
-
-    act(() => {
-      i18n.load("cs", {})
-      i18n.activate("cs")
-    })
-
-    expect(getByTestId("not-composed").textContent).toEqual("")
-    expect(getByTestId("composed").textContent).toEqual("cs")
-  })
-
-  it("should subscribe for locale changes", () => {
+describe("I18nProvider", function () {
+  it("should subscribe for locale changes", function () {
     const i18n = setupI18n()
     i18n.on = jest.fn(() => jest.fn())
 
@@ -46,7 +18,7 @@ describe("I18nProvider", () => {
     expect(i18n.on).toBeCalledWith("change", expect.anything())
   })
 
-  it("should unsubscribe for locale changes on unmount", () => {
+  it("should unsubscribe for locale changes on unmount", function () {
     const unsubscribe = jest.fn()
     const i18n = setupI18n()
     i18n.on = jest.fn(() => unsubscribe)
@@ -62,38 +34,30 @@ describe("I18nProvider", () => {
   })
 
   it("should re-render on locale changes", async () => {
-    expect.assertions(3)
+    expect.assertions(2)
 
-    const i18n = setupI18n()
+    const i18n = setupI18n({
+      locale: "en",
+      messages: {},
+    })
 
-    const CurrentLocale = () => {
-      return <span>{i18n.locale}</span>
+    function RenderLocale() {
+      const { i18n } = useLingui()
+      return i18n.locale as null
     }
 
     const { container } = render(
       <I18nProvider i18n={i18n}>
-        <CurrentLocale />
+        <RenderLocale />
       </I18nProvider>
     )
-    // First render — no output, because locale isn't activated
-    expect(container.textContent).toEqual("")
+    expect(container.textContent).toEqual("en")
 
-    act(() => {
-      i18n.load("en", {})
-    })
-    // Again, no output. Catalog is loaded, but locale
-    // still isn't activated.
-    expect(container.textContent).toEqual("")
-
-    act(() => {
-      i18n.load("cs", {})
-      i18n.activate("cs")
-    })
-    // After loading and activating locale, it's finally rendered.
+    await i18n.activate("cs")
     expect(container.textContent).toEqual("cs")
   })
 
-  it("should render children", () => {
+  it("should render children", function () {
     const i18n = setupI18n({
       locale: "en",
     })
diff --git a/packages/react/src/format.test.tsx b/packages/react/src/format.test.tsx
index a38f1e3d..7e86802e 100644
--- a/packages/react/src/format.test.tsx
+++ b/packages/react/src/format.test.tsx
@@ -51,29 +51,4 @@ describe("formatElements", function () {
       'Before <a href="/about">Inside <strong>Nested</strong> Between <br> After</a>'
     )
   })
-
-  it("should ignore non existing element", function() {
-    expect(html(formatElements("<0>First</0>"))).toEqual("First")
-    expect(html(formatElements("<0>First</0>Second"))).toEqual("FirstSecond")
-    expect(html(formatElements("First<0>Second</0>Third")))
-        .toEqual("FirstSecondThird")
-    expect(html(formatElements("Fir<0/>st"))).toEqual("First")
-  })
-
-  it("should ignore incorrect tags and print them as a text", function() {
-    expect(html(formatElements("text</0>"))).toEqual("text&lt;/0&gt;")
-    expect(html(formatElements("text<0 />"))).toEqual("text&lt;0 /&gt;")
-    expect(html(formatElements("<tag>text</tag>")))
-        .toEqual("&lt;tag&gt;text&lt;/tag&gt;")
-    expect(html(formatElements("text <br/>"))).toEqual("text &lt;br/&gt;")
-  })
-
-  it("should ignore unpaired element used as paired", function() {
-    expect(html(formatElements("<0>text</0>", {0: <br />}))).toEqual("text")
-  })
-
-  it("should ignore paired element used as unpaired", function() {
-    expect(html(formatElements("text<0/>", {0: <span />})))
-        .toEqual("text<span></span>")
-  })
 })