diff --git a/i18n/config.ts b/i18n/config.ts
new file mode 100644
index 0000000..150bd07
--- /dev/null
+++ b/i18n/config.ts
@@ -0,0 +1,32 @@
+import i18n from 'i18next';
+import { initReactI18next } from 'react-i18next';
+
+import translationEN from './translations/en-US.json';
+import translationPT from './translations/pt-BR.json';
+
+i18n
+ // pass the i18n instance to react-i18next.
+ .use(initReactI18next)
+ // init i18next
+ // for all options read: https://www.i18next.com/overview/configuration-options
+ .init({
+ // in case window.VEDACCIO_LANGUAGE is undefined,it will fall back to 'en-US'
+ lng: window?.__VERDACCIO_BASENAME_UI_OPTIONS?.language,
+ fallbackLng: 'en-US',
+ whitelist: ['en-US', 'pt-BR'],
+ load: 'currentOnly',
+ resources: {
+ 'en-US': {
+ translation: translationEN,
+ },
+ 'pt-BR': {
+ translation: translationPT,
+ },
+ },
+ debug: false,
+ interpolation: {
+ escapeValue: false, // react already safes from xss
+ },
+ });
+
+export default i18n;
diff --git a/i18n/translations/en-US.json b/i18n/translations/en-US.json
new file mode 100644
index 0000000..4720cc3
--- /dev/null
+++ b/i18n/translations/en-US.json
@@ -0,0 +1,138 @@
+{
+ "copy-to-clipboard": "Copy to clipboard",
+ "author-anonymous": "Anonymous",
+ "action-bar-action": {
+ "visit-home-page": "Visit homepage",
+ "open-an-issue": "Open an issue",
+ "download-tarball": "Download tarball"
+ },
+ "dialog": {
+ "registry-info": {
+ "title": "Register Info"
+ }
+ },
+ "header": {
+ "documentation": "Documentation",
+ "registry-info": "Registry Information",
+ "greetings": "Hi "
+ },
+ "search": {
+ "packages": "Search Packages"
+ },
+ "auto-complete": {
+ "loading": "Loading...",
+ "no-results-found": "No results found."
+ },
+ "tab": {
+ "uplinks": "Uplinks",
+ "versions": "Versions",
+ "dependencies": "Dependencies",
+ "readme": "Readme"
+ },
+ "uplinks": {
+ "title": "Uplinks",
+ "no-items": "{{name}} has no uplinks."
+ },
+ "versions": {
+ "current-tags": "Current Tags",
+ "version-history": "Version history",
+ "not-available": "Not available"
+ },
+ "package": {
+ "published-on": "Published on {{time}} •",
+ "version": "v{{version}}",
+ "visit-home-page": "Visit homepage",
+ "homepage": "Homepage",
+ "open-an-issue": "Open an issue",
+ "bugs": "Bugs",
+ "download": "Download {{what}}",
+ "the-tar-file": "the tar file",
+ "tarball": "Tarball"
+ },
+ "dependencies": {
+ "has-no-dependencies": "{{package}} has no dependencies.",
+ "dependency-block": "{{package}}@{{version}}"
+ },
+ "form": {
+ "username": "Username",
+ "password": "Password"
+ },
+ "form-placeholder": {
+ "username": "Your username",
+ "password": "Your strong password"
+ },
+ "form-validation": {
+ "required-field": "This field is required",
+ "required-min-length": "This field required the min length of {{length}}",
+ "unable-to-sign-in": "Unable to sign in",
+ "username-or-password-cant-be-empty": "Username or password can't be empty!"
+ },
+ "help": {
+ "title": "No Package Published Yet.",
+ "sub-title": "To publish your first package just:",
+ "first-step": "1. Login",
+ "first-step-command-line": "npm adduser --registry {{registryUrl}}",
+ "second-step": "2. Publish",
+ "second-step-command-line": "npm publish --registry {{registryUrl}}",
+ "third-step": "3. Refresh this page."
+ },
+ "sidebar": {
+ "detail": {
+ "latest-version": "Latest v{{version}}",
+ "version": "v{{version}}"
+ },
+ "installation": {
+ "title": "Installation",
+ "install-using-yarn": "Install using yarn",
+ "install-using-yarn-command": "yarn add {{packageName}}",
+ "install-using-npm": "Install using npm",
+ "install-using-npm-command": "npm install {{packageName}}",
+ "install-using-pnpm": "Install using pnpm",
+ "install-using-pnpm-command": "pnpm install {{packageName}}"
+ },
+ "repository": {
+ "title": "Repository"
+ },
+ "author": {
+ "title": "Author"
+ },
+ "distribution": {
+ "title": "Latest Distribution",
+ "license": "License",
+ "size": "Size",
+ "file-count": "file count"
+ },
+ "maintainers": {
+ "title": "Maintainers"
+ },
+ "contributors": {
+ "title": "Contributors"
+ },
+ "engines": {
+ "npm-version": "NPM Version",
+ "node-js": "NODE JS"
+ }
+ },
+ "footer": {
+ "powered-by": "Powered by",
+ "made-with-love-on": "Made with <0>♥0> on"
+ },
+ "button": {
+ "close": "Close",
+ "cancel": "Cancel",
+ "login": "Login",
+ "logout": "Logout",
+ "go-to-the-home-page": "Go to the home page",
+ "learn-more": "Learn More",
+ "fund-this-package": "<0>Fund0> this package"
+ },
+ "error": {
+ "unspecific": "Something went wrong.",
+ "404": {
+ "page-not-found": "404 - Page not found",
+ "sorry-we-could-not-find-it": "Sorry, we couldn't find it..."
+ },
+ "app-context-not-correct-used": "The app context was not correct used",
+ "package-meta-is-required-at-detail-context": "packageMeta is required at DetailContext"
+ }
+}
\ No newline at end of file
diff --git a/i18n/translations/pt-BR.json b/i18n/translations/pt-BR.json
new file mode 100644
index 0000000..8434f1c
--- /dev/null
+++ b/i18n/translations/pt-BR.json
@@ -0,0 +1,138 @@
+{
+ "copy-to-clipboard": "Copiar para área de transferência",
+ "author-anonymous": "Anônimo(a)",
+ "action-bar-action": {
+ "visit-home-page": "Visitar a página inicial",
+ "open-an-issue": "Criar um incidente",
+ "download-tarball": "Baixar Tarball"
+ },
+ "dialog": {
+ "registry-info": {
+ "title": "Informações do Registro"
+ }
+ },
+ "header": {
+ "documentation": "Documentação",
+ "registry-info": "Informações do Registro",
+ "greetings": "Oi "
+ },
+ "search": {
+ "packages": "Pesquisar Pacotes"
+ },
+ "auto-complete": {
+ "loading": "Carregando...",
+ "no-results-found": "Nenhum resultado encontrado."
+ },
+ "tab": {
+ "uplinks": "Uplinks",
+ "versions": "Versões",
+ "dependencies": "Dependências",
+ "readme": "Leia-me"
+ },
+ "uplinks": {
+ "title": "Uplinks",
+ "no-items": "{{name}} não tem uplinks."
+ },
+ "versions": {
+ "current-tags": "Tags atuais",
+ "version-history": "Histórico de versões",
+ "not-available": "Não disponível"
+ },
+ "package": {
+ "published-on": "Publicado em {{time}} •",
+ "version": "v{{version}}",
+ "visit-home-page": "Visitar a página inicial",
+ "homepage": "Página inicial",
+ "open-an-issue": "Criar um incidente",
+ "bugs": "Erros",
+ "download": "Baixar {{what}}",
+ "the-tar-file": "o arquivo tar",
+ "tarball": "Tarball"
+ },
+ "dependencies": {
+ "has-no-dependencies": "{{package}} não tem dependências.",
+ "dependency-block": "{{package}}@{{version}}"
+ },
+ "form": {
+ "username": "Nome do usuário",
+ "password": "Senha"
+ },
+ "form-placeholder": {
+ "username": "O seu nome",
+ "password": "A sua senha forte"
+ },
+ "form-validation": {
+ "required-field": "Este campo é obrigatório",
+ "required-min-length": "Este campo requer o mínimo de {{length}} caracteres",
+ "unable-to-sign-in": "Não foi possível fazer login",
+ "username-or-password-cant-be-empty": "Nome de usuário ou senha não podem estar vazios!"
+ },
+ "help": {
+ "title": "Nenhum pacote publicado ainda.",
+ "sub-title": "Para publicar seu primeiro pacote apenas:",
+ "first-step": "1. Faça login",
+ "first-step-command-line": "npm adduser --registry {{registryUrl}}",
+ "second-step": "2. Publique",
+ "second-step-command-line": "npm publish --registry {{registryUrl}}",
+ "third-step": "3. Atualize esta página."
+ },
+ "sidebar": {
+ "detail": {
+ "latest-version": "Última versão: v{{version}}",
+ "version": "v{{version}}"
+ },
+ "installation": {
+ "title": "Instalação",
+ "install-using-yarn": "Instale usando yarn",
+ "install-using-yarn-command": "yarn add {{packageName}}",
+ "install-using-npm": "Instale usando npm",
+ "install-using-npm-command": "npm install {{packageName}}",
+ "install-using-pnpm": "Instale usando pnpm",
+ "install-using-pnpm-command": "pnpm install {{packageName}}"
+ },
+ "repository": {
+ "title": "Repositório"
+ },
+ "author": {
+ "title": "Autor(a)"
+ },
+ "distribution": {
+ "title": "Distribuição mais recente",
+ "license": "Licença",
+ "size": "Tamanho",
+ "file-count": "Contagem de arquivos"
+ },
+ "maintainers": {
+ "title": "Mantenedores(as)"
+ },
+ "contributors": {
+ "title": "Contribuidores(as)"
+ },
+ "engines": {
+ "npm-version": "Versão NPM",
+ "node-js": "NODE JS"
+ }
+ },
+ "footer": {
+ "powered-by": "Distribuído por",
+ "made-with-love-on": "Feito com amor <0>♥0> no(a)"
+ },
+ "button": {
+ "close": "Fechar",
+ "cancel": "Cancelar",
+ "login": "Conectar",
+ "logout": "Desconectar",
+ "go-to-the-home-page": "Ir para a página inicial",
+ "learn-more": "Leia mais",
+ "fund-this-package": "<0>Financie0> este pacote"
+ },
+ "error": {
+ "unspecific": "Algo deu errado.",
+ "404": {
+ "page-not-found": "404 - Página não encontrada",
+ "sorry-we-could-not-find-it": "Desculpe, não conseguimos encontrar..."
+ },
+ "app-context-not-correct-used": "O contexto do aplicativo não foi usado corretamente",
+ "package-meta-is-required-at-detail-context": "packageMeta é requerido em DetailContext"
+ }
+}
\ No newline at end of file
diff --git a/package.json b/package.json
index 4185e80..a275fe8 100644
--- a/package.json
+++ b/package.json
@@ -71,6 +71,7 @@
"github-markdown-css": "3.0.1",
"html-webpack-plugin": "3.2.0",
"husky": "3.1.0",
+ "i18next": "19.1.0",
"identity-obj-proxy": "3.0.0",
"in-publish": "2.0.0",
"jest": "24.9.0",
@@ -99,6 +100,7 @@
"react-dom": "16.13.0",
"react-hook-form": "3.29.4",
"react-hot-loader": "4.12.18",
+ "react-i18next": "11.3.1",
"react-router-dom": "5.1.2",
"request": "2.88.0",
"resolve-url-loader": "3.1.1",
@@ -138,7 +140,7 @@
"bundlesize": [
{
"path": "./static/vendors.*.js",
- "maxSize": "185 kB"
+ "maxSize": "200 kB"
},
{
"path": "./static/main.*.js",
diff --git a/partials/storage/jquery/package.json b/partials/storage/jquery/package.json
index e01aea4..9293c80 100644
--- a/partials/storage/jquery/package.json
+++ b/partials/storage/jquery/package.json
@@ -4976,8 +4976,12 @@
"_attachments": {
"jquery-1.5.1.tgz": {
"shasum": "2ae2d661e906c1a01e044a71bb5b2743942183e5"
+ },
+ "jquery-3.3.1.tgz": {
+ "shasum": "958ce29e81c9790f31be7792df5d4d95fc57fbca"
}
},
- "_rev": "60-fed4915c27b9c1e6",
- "readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```"
-}
+ "_rev": "61-e6be890a78963127",
+ "readme": "# jQuery\n\n> jQuery is a fast, small, and feature-rich JavaScript library.\n\nFor information on how to get started and how to use jQuery, please see [jQuery's documentation](http://api.jquery.com/).\nFor source files and issues, please visit the [jQuery repo](https://github.com/jquery/jquery).\n\nIf upgrading, please see the [blog post for 3.3.1](https://blog.jquery.com/2017/03/20/jquery-3.3.1-now-available/). This includes notable differences from the previous version and a more readable changelog.\n\n## Including jQuery\n\nBelow are some of the most common ways to include jQuery.\n\n### Browser\n\n#### Script tag\n\n```html\n\n```\n\n#### Babel\n\n[Babel](http://babeljs.io/) is a next generation JavaScript compiler. One of the features is the ability to use ES6/ES2015 modules now, even though browsers do not yet support this feature natively.\n\n```js\nimport $ from \"jquery\";\n```\n\n#### Browserify/Webpack\n\nThere are several ways to use [Browserify](http://browserify.org/) and [Webpack](https://webpack.github.io/). For more information on using these tools, please refer to the corresponding project's documention. In the script, including jQuery will usually look like this...\n\n```js\nvar $ = require(\"jquery\");\n```\n\n#### AMD (Asynchronous Module Definition)\n\nAMD is a module format built for the browser. For more information, we recommend [require.js' documentation](http://requirejs.org/docs/whyamd.html).\n\n```js\ndefine([\"jquery\"], function($) {\n\n});\n```\n\n### Node\n\nTo include jQuery in [Node](nodejs.org), first install with npm.\n\n```sh\nnpm install jquery\n```\n\nFor jQuery to work in Node, a window with a document is required. Since no such window exists natively in Node, one can be mocked by tools such as [jsdom](https://github.com/tmpvar/jsdom). This can be useful for testing purposes.\n\n```js\nrequire(\"jsdom\").env(\"\", function(err, window) {\n\tif (err) {\n\t\tconsole.error(err);\n\t\treturn;\n\t}\n\n\tvar $ = require(\"jquery\")(window);\n});\n```",
+ "_id": "jquery"
+}
\ No newline at end of file
diff --git a/src/App/App.tsx b/src/App/App.tsx
index c2ba219..2b21059 100644
--- a/src/App/App.tsx
+++ b/src/App/App.tsx
@@ -1,18 +1,22 @@
-import React, { useState, useEffect } from 'react';
+/* eslint-disable react/jsx-max-depth */
+import React, { useState, useEffect, Suspense } from 'react';
import styled from '@emotion/styled';
import isNil from 'lodash/isNil';
import { Router } from 'react-router-dom';
+import '../../i18n/config';
import storage from '../utils/storage';
import { isTokenExpire } from '../utils/login';
import Header from '../components/Header';
import Footer from '../components/Footer';
+import Loading from '../components/Loading';
import Box from '../muiComponents/Box';
import StyleBaseline from '../design-tokens/StyleBaseline';
import { Theme } from '../design-tokens/theme';
import AppContextProvider from './AppContextProvider';
import AppRoute, { history } from './AppRoute';
+import loadDayJSLocale from './load-dayjs-locale';
const StyledBox = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
backgroundColor: theme && theme.palette.white,
@@ -31,7 +35,6 @@ const StyledBoxContent = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
/* eslint-disable react-hooks/exhaustive-deps */
const App: React.FC = () => {
const [user, setUser] = useState();
-
/**
* Logout user
* Required by:
@@ -57,10 +60,11 @@ const App: React.FC = () => {
useEffect(() => {
checkUserAlreadyLoggedIn();
+ loadDayJSLocale();
}, []);
return (
- <>
+ }>
<>
@@ -68,7 +72,6 @@ const App: React.FC = () => {
- {/* eslint-disable-next-line react/jsx-max-depth */}
@@ -76,7 +79,7 @@ const App: React.FC = () => {
>
- >
+
);
};
diff --git a/src/App/AppRoute.tsx b/src/App/AppRoute.tsx
index 0fce9f0..8535cec 100644
--- a/src/App/AppRoute.tsx
+++ b/src/App/AppRoute.tsx
@@ -1,8 +1,7 @@
-import React, { lazy, useContext, Suspense } from 'react';
+import React, { lazy, useContext } from 'react';
import { Route as ReactRouterDomRoute, Switch, Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
-
-import Loading from '../components/Loading';
+import { useTranslation } from 'react-i18next';
import AppContext from './AppContext';
@@ -25,9 +24,10 @@ export const history = createBrowserHistory({
const AppRoute: React.FC = () => {
const appContext = useContext(AppContext);
+ const { t } = useTranslation();
if (!appContext) {
- throw Error('The app Context was not correct used');
+ throw Error(t('app-context-not-correct-used'));
}
const { user } = appContext;
@@ -36,36 +36,34 @@ const AppRoute: React.FC = () => {
return (
- }>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
);
};
diff --git a/src/App/__snapshots__/App.test.tsx.snap b/src/App/__snapshots__/App.test.tsx.snap
index ae9c1dd..057a7c3 100644
--- a/src/App/__snapshots__/App.test.tsx.snap
+++ b/src/App/__snapshots__/App.test.tsx.snap
@@ -152,53 +152,6 @@ exports[` should display the Header component 1`] = `
}
}
-.emotion-34 {
- -webkit-transform: translate(-50%,-50%);
- -ms-transform: translate(-50%,-50%);
- transform: translate(-50%,-50%);
- top: 50%;
- left: 50%;
- position: absolute;
-}
-
-.emotion-28 {
- margin: 0 0 30px 0;
- border-radius: 25px;
- box-shadow: 0 10px 20px 0 rgba(69,58,100,0.2);
- background: #f7f8f6;
-}
-
-.emotion-26 {
- display: inline-block;
- vertical-align: middle;
- box-sizing: border-box;
- background-position: center;
- background-size: contain;
- background-image: url([object Object]);
- background-repeat: no-repeat;
- width: 90px;
- height: 90px;
-}
-
-.emotion-32 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -webkit-justify-content: center;
- -ms-flex-pack: center;
- justify-content: center;
-}
-
-.emotion-30 {
- color: #4b5e40;
-}
-
.emotion-76 {
background: #f9f9f9;
border-top: 1px solid #e3e3e3;
@@ -356,6 +309,53 @@ exports[` should display the Header component 1`] = `
height: auto;
}
+.emotion-34 {
+ -webkit-transform: translate(-50%,-50%);
+ -ms-transform: translate(-50%,-50%);
+ transform: translate(-50%,-50%);
+ top: 50%;
+ left: 50%;
+ position: absolute;
+}
+
+.emotion-28 {
+ margin: 0 0 30px 0;
+ border-radius: 25px;
+ box-shadow: 0 10px 20px 0 rgba(69,58,100,0.2);
+ background: #f7f8f6;
+}
+
+.emotion-26 {
+ display: inline-block;
+ vertical-align: middle;
+ box-sizing: border-box;
+ background-position: center;
+ background-size: contain;
+ background-image: url([object Object]);
+ background-repeat: no-repeat;
+ width: 90px;
+ height: 90px;
+}
+
+.emotion-32 {
+ display: -webkit-box;
+ display: -webkit-flex;
+ display: -ms-flexbox;
+ display: flex;
+ -webkit-align-items: center;
+ -webkit-box-align: center;
+ -ms-flex-align: center;
+ align-items: center;
+ -webkit-box-pack: center;
+ -webkit-justify-content: center;
+ -ms-flex-pack: center;
+ justify-content: center;
+}
+
+.emotion-30 {
+ color: #4b5e40;
+}
+
@@ -545,6 +545,7 @@ exports[`
should display the Header component 1`] = `
>
should display the Header component 1`] = `
- Made with
+ Made with
♥
- on
+ on
@@ -700,7 +701,7 @@ exports[` should display the Header component 1`] = `
`;
exports[` should display the Loading component at the beginning 1`] = `
-.emotion-78 {
+.emotion-68 {
background-color: #fff;
}
@@ -843,7 +844,7 @@ exports[` should display the Loading component at the beginning 1`] = `
}
@media screen and (min-width:1240px) {
- .emotion-36 {
+ .emotion-26 {
max-width: 1240px;
width: 100%;
margin-left: auto;
@@ -851,54 +852,7 @@ exports[` should display the Loading component at the beginning 1`] = `
}
}
-.emotion-34 {
- -webkit-transform: translate(-50%,-50%);
- -ms-transform: translate(-50%,-50%);
- transform: translate(-50%,-50%);
- top: 50%;
- left: 50%;
- position: absolute;
-}
-
-.emotion-28 {
- margin: 0 0 30px 0;
- border-radius: 25px;
- box-shadow: 0 10px 20px 0 rgba(69,58,100,0.2);
- background: #f7f8f6;
-}
-
-.emotion-26 {
- display: inline-block;
- vertical-align: middle;
- box-sizing: border-box;
- background-position: center;
- background-size: contain;
- background-image: url([object Object]);
- background-repeat: no-repeat;
- width: 90px;
- height: 90px;
-}
-
-.emotion-32 {
- display: -webkit-box;
- display: -webkit-flex;
- display: -ms-flexbox;
- display: flex;
- -webkit-align-items: center;
- -webkit-box-align: center;
- -ms-flex-align: center;
- align-items: center;
- -webkit-box-pack: center;
- -webkit-justify-content: center;
- -ms-flex-pack: center;
- justify-content: center;
-}
-
-.emotion-30 {
- color: #4b5e40;
-}
-
-.emotion-76 {
+.emotion-66 {
background: #f9f9f9;
border-top: 1px solid #e3e3e3;
color: #999999;
@@ -906,7 +860,7 @@ exports[` should display the Loading component at the beginning 1`] = `
padding: 20px;
}
-.emotion-74 {
+.emotion-64 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@@ -923,7 +877,7 @@ exports[` should display the Loading component at the beginning 1`] = `
}
@media (min-width:768px) {
- .emotion-74 {
+ .emotion-64 {
min-width: 400px;
max-width: 800px;
margin: auto;
@@ -935,12 +889,12 @@ exports[` should display the Loading component at the beginning 1`] = `
}
@media (min-width:1024px) {
- .emotion-74 {
+ .emotion-64 {
max-width: 1240px;
}
}
-.emotion-65 {
+.emotion-55 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
@@ -949,7 +903,7 @@ exports[` should display the Loading component at the beginning 1`] = `
}
@media (min-width:768px) {
- .emotion-65 {
+ .emotion-55 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@@ -957,21 +911,21 @@ exports[` should display the Loading component at the beginning 1`] = `
}
}
-.emotion-38 {
+.emotion-28 {
color: #e25555;
padding: 0 5px;
}
-.emotion-63 {
+.emotion-53 {
position: relative;
height: 18px;
}
-.emotion-63:hover .emotion-62 {
+.emotion-53:hover .emotion-52 {
visibility: visible;
}
-.emotion-41 {
+.emotion-31 {
box-sizing: initial;
display: inline-block;
cursor: default;
@@ -980,7 +934,7 @@ exports[` should display the Loading component at the beginning 1`] = `
padding: 0 10px;
}
-.emotion-61 {
+.emotion-51 {
position: absolute;
background: #d3dddd;
padding: 1px 4px;
@@ -998,7 +952,7 @@ exports[` should display the Loading component at the beginning 1`] = `
top: -2px;
}
-.emotion-61:before {
+.emotion-51:before {
content: '';
position: absolute;
top: 29%;
@@ -1011,7 +965,7 @@ exports[` should display the Loading component at the beginning 1`] = `
transform: rotate(90deg);
}
-.emotion-44 {
+.emotion-34 {
box-sizing: initial;
display: inline-block;
cursor: default;
@@ -1020,7 +974,7 @@ exports[` should display the Loading component at the beginning 1`] = `
padding: 0 5px;
}
-.emotion-72 {
+.emotion-62 {
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
@@ -1033,7 +987,7 @@ exports[` should display the Loading component at the beginning 1`] = `
}
@media (min-width:768px) {
- .emotion-72 {
+ .emotion-62 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
@@ -1041,7 +995,7 @@ exports[` should display the Loading component at the beginning 1`] = `
}
}
-.emotion-70 {
+.emotion-60 {
box-sizing: initial;
display: inline-block;
cursor: pointer;
@@ -1050,13 +1004,14 @@ exports[` should display the Loading component at the beginning 1`] = `
padding: 0 5px;
}
-.emotion-67 {
+.emotion-57 {
width: 100%;
height: auto;
}
should display the Loading component at the beginning 1`] = `
+ class="MuiBox-root MuiBox-root-195 emotion-26 emotion-27"
+ />
- Made with
+ Made with
♥
- on
+ on
Powered by
diff --git a/src/App/load-dayjs-locale.ts b/src/App/load-dayjs-locale.ts
new file mode 100644
index 0000000..3a20136
--- /dev/null
+++ b/src/App/load-dayjs-locale.ts
@@ -0,0 +1,40 @@
+import dayjs from 'dayjs';
+import i18n from 'i18next';
+
+function getFallFackLanguage(): string | undefined {
+ const fallbackLanguage = i18n.options.fallbackLng;
+
+ if (Array.isArray(fallbackLanguage)) {
+ return fallbackLanguage[0];
+ }
+
+ if (typeof fallbackLanguage === 'string') {
+ return fallbackLanguage;
+ }
+
+ return undefined;
+}
+
+function loadDayJSLocale() {
+ const fallbackLanguage = getFallFackLanguage();
+ const locale = i18n.language || fallbackLanguage;
+
+ // dayjs loades en-US by default
+ if (!locale || locale === 'en-US') {
+ return;
+ }
+
+ switch (locale.toLowerCase()) {
+ // At the moment we only support pt-BR, please see: i18n/translations/*
+ case 'pt-br':
+ {
+ require('dayjs/locale/pt-br');
+ dayjs.locale('pt-br');
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+export default loadDayJSLocale;
diff --git a/src/components/ActionBar/ActionBarAction.tsx b/src/components/ActionBar/ActionBarAction.tsx
index 1192f16..6f46b63 100644
--- a/src/components/ActionBar/ActionBarAction.tsx
+++ b/src/components/ActionBar/ActionBarAction.tsx
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
import BugReportIcon from '@material-ui/icons/BugReport';
import DownloadIcon from '@material-ui/icons/CloudDownload';
import HomeIcon from '@material-ui/icons/Home';
+import { useTranslation } from 'react-i18next';
import Tooltip from '../../muiComponents/Tooltip';
import Link from '../Link';
@@ -26,10 +27,11 @@ export interface ActionBarActionProps {
/* eslint-disable react/jsx-no-bind */
const ActionBarAction: React.FC
= ({ type, link }) => {
+ const { t } = useTranslation();
switch (type) {
case 'VISIT_HOMEPAGE':
return (
-
+
@@ -39,7 +41,7 @@ const ActionBarAction: React.FC = ({ type, link }) => {
);
case 'OPEN_AN_ISSUE':
return (
-
+
@@ -49,7 +51,7 @@ const ActionBarAction: React.FC = ({ type, link }) => {
);
case 'DOWNLOAD_TARBALL':
return (
-
+
diff --git a/src/components/Author/Author.tsx b/src/components/Author/Author.tsx
index 103be62..ef6b0bb 100644
--- a/src/components/Author/Author.tsx
+++ b/src/components/Author/Author.tsx
@@ -1,14 +1,17 @@
import React, { FC, useContext } from 'react';
+import { useTranslation } from 'react-i18next';
import { DetailContext } from '../../pages/Version';
import { isEmail } from '../../utils/url';
import Avatar from '../../muiComponents/Avatar';
import List from '../../muiComponents/List';
+import { getAuthorName } from '../../utils/package';
import { StyledText, AuthorListItem, AuthorListItemText } from './styles';
const Author: FC = () => {
const { packageMeta } = useContext(DetailContext);
+ const { t } = useTranslation();
if (!packageMeta) {
return null;
@@ -25,7 +28,7 @@ const Author: FC = () => {
const avatarComponent = ;
return (
- {'Author'}}>
+ {t('sidebar.author.title')}}>
{!email || !isEmail(email) ? (
avatarComponent
@@ -34,8 +37,7 @@ const Author: FC = () => {
{avatarComponent}
)}
-
-
+ {name && }
);
diff --git a/src/components/Author/__snapshots__/Author.test.tsx.snap b/src/components/Author/__snapshots__/Author.test.tsx.snap
index 25a3e0f..f061be7 100644
--- a/src/components/Author/__snapshots__/Author.test.tsx.snap
+++ b/src/components/Author/__snapshots__/Author.test.tsx.snap
@@ -1,5 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` component should render the component in default state 1`] = `""`;
+exports[` component should render the component in default state 1`] = `""`;
-exports[` component should render the component when there is no author email 1`] = `""`;
+exports[` component should render the component when there is no author email 1`] = `""`;
diff --git a/src/components/Author/styles.ts b/src/components/Author/styles.ts
index 40a8cae..de8b118 100644
--- a/src/components/Author/styles.ts
+++ b/src/components/Author/styles.ts
@@ -7,7 +7,6 @@ import { Theme } from '../../design-tokens/theme';
export const StyledText = styled(Text)<{ theme?: Theme }>(props => ({
fontWeight: props.theme && props.theme.fontWeight.bold,
- textTransform: 'capitalize',
}));
export const AuthorListItem = styled(ListItem)({
diff --git a/src/components/AutoComplete/AutoComplete.tsx b/src/components/AutoComplete/AutoComplete.tsx
index 977cc91..5414e8c 100644
--- a/src/components/AutoComplete/AutoComplete.tsx
+++ b/src/components/AutoComplete/AutoComplete.tsx
@@ -3,6 +3,7 @@ import styled from '@emotion/styled';
import Autosuggest, { SuggestionSelectedEventData, InputProps, ChangeEvent } from 'react-autosuggest';
import match from 'autosuggest-highlight/match';
import parse from 'autosuggest-highlight/parse';
+import { useTranslation } from 'react-i18next';
import MenuItem from '../../muiComponents/MenuItem';
import { Theme } from '../../design-tokens/theme';
@@ -83,12 +84,6 @@ const renderMessage = (message): JSX.Element => {
);
};
-const SUGGESTIONS_RESPONSE = {
- LOADING: 'Loading...',
- FAILURE: 'Something went wrong.',
- NO_RESULT: 'No results found.',
-};
-
const AutoComplete = memo(
({
suggestions,
@@ -106,6 +101,8 @@ const AutoComplete = memo(
suggestionsLoaded = false,
suggestionsError = false,
}: Props) => {
+ const { t } = useTranslation();
+
const autosuggestProps = {
renderInputComponent,
suggestions,
@@ -130,9 +127,9 @@ const AutoComplete = memo(
function renderSuggestionsContainer({ containerProps, children, query }): JSX.Element {
return (
- {suggestionsLoaded && children === null && query && renderMessage(SUGGESTIONS_RESPONSE.NO_RESULT)}
- {suggestionsLoading && query && renderMessage(SUGGESTIONS_RESPONSE.LOADING)}
- {suggestionsError && renderMessage(SUGGESTIONS_RESPONSE.FAILURE)}
+ {suggestionsLoaded && children === null && query && renderMessage(t('auto-complete.no-results-found'))}
+ {suggestionsLoading && query && renderMessage(t('auto-complete.loading'))}
+ {suggestionsError && renderMessage(t('error.unspecific'))}
{children}
);
diff --git a/src/components/CopyToClipBoard/CopyToClipBoard.tsx b/src/components/CopyToClipBoard/CopyToClipBoard.tsx
index cf8b95a..100dcfd 100644
--- a/src/components/CopyToClipBoard/CopyToClipBoard.tsx
+++ b/src/components/CopyToClipBoard/CopyToClipBoard.tsx
@@ -1,8 +1,8 @@
import FileCopy from '@material-ui/icons/FileCopy';
import React from 'react';
+import { useTranslation } from 'react-i18next';
import { copyToClipBoardUtility } from '../../utils/cli-utils';
-import { TEXT } from '../../utils/constants';
import Tooltip from '../../muiComponents/Tooltip';
import { ClipBoardCopy, ClipBoardCopyText, CopyIcon } from './styles';
@@ -20,19 +20,16 @@ const renderText = (text: string, children: React.ReactNode): JSX.Element => {
return {text};
};
-const renderToolTipFileCopy = (text: string): React.ReactElement => (
-
-
-
-
-
-);
-
const CopyToClipBoard: React.FC = ({ text, children }) => {
+ const { t } = useTranslation();
return (
{renderText(text, children)}
- {renderToolTipFileCopy(text)}
+
+
+
+
+
);
};
diff --git a/src/components/CopyToClipBoard/__snapshots__/CopyToClipBoard.test.tsx.snap b/src/components/CopyToClipBoard/__snapshots__/CopyToClipBoard.test.tsx.snap
index bbcb88c..331c216 100644
--- a/src/components/CopyToClipBoard/__snapshots__/CopyToClipBoard.test.tsx.snap
+++ b/src/components/CopyToClipBoard/__snapshots__/CopyToClipBoard.test.tsx.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` component should load the component in default state 1`] = `""`;
+exports[` component should load the component in default state 1`] = `""`;
diff --git a/src/components/Dependencies/Dependencies.tsx b/src/components/Dependencies/Dependencies.tsx
index 7e3481b..798b5c3 100644
--- a/src/components/Dependencies/Dependencies.tsx
+++ b/src/components/Dependencies/Dependencies.tsx
@@ -1,5 +1,6 @@
import React, { useContext } from 'react';
import { useHistory } from 'react-router-dom';
+import { useTranslation } from 'react-i18next';
import CardContent from '../../muiComponents/CardContent';
import { PackageDependencies } from '../../../types/packageMeta';
@@ -16,6 +17,7 @@ interface DependencyBlockProps {
const DependencyBlock: React.FC = ({ title, dependencies }) => {
const { enableLoading } = useContext(DetailContext);
const history = useHistory();
+ const { t } = useTranslation();
const deps = Object.entries(dependencies);
@@ -31,8 +33,14 @@ const DependencyBlock: React.FC = ({ title, dependencies }
{`${title} (${deps.length})`}
{deps.map(([name, version]) => (
- // eslint-disable-next-line
- handleClick(name)} />
+ handleClick(name)}
+ />
))}
@@ -46,9 +54,10 @@ function hasKeys(object?: { [key: string]: any }): boolean {
const Dependencies: React.FC<{}> = () => {
const { packageMeta } = useContext(DetailContext);
+ const { t } = useTranslation();
if (!packageMeta) {
- throw new Error('packageMeta is required at DetailContext');
+ throw new Error(t('error.package-meta-is-required-at-detail-context'));
}
const { latest } = packageMeta;
@@ -72,7 +81,7 @@ const Dependencies: React.FC<{}> = () => {
);
}
- return ;
+ return ;
};
export default Dependencies;
diff --git a/src/components/DetailContainer/DetailContainer.tsx b/src/components/DetailContainer/DetailContainer.tsx
index fe586e0..0faff5d 100644
--- a/src/components/DetailContainer/DetailContainer.tsx
+++ b/src/components/DetailContainer/DetailContainer.tsx
@@ -1,4 +1,4 @@
-import React, { useCallback, useState, ChangeEvent, useContext } from 'react';
+import React, { useState, useContext } from 'react';
import { DetailContext } from '../../pages/Version';
import Box from '../../muiComponents/Box';
@@ -8,24 +8,19 @@ import DetailContainerContent from './DetailContainerContent';
import { TabPosition } from './tabs';
const DetailContainer: React.FC = () => {
- const [tabPosition, setTabPosition] = useState(TabPosition.README);
+ const tabs = Object.values(TabPosition);
+ const [tabPosition, setTabPosition] = useState(0);
const detailContext = useContext(DetailContext);
const { readMe } = detailContext;
- const handleChangeTabPosition = useCallback(
- (event: ChangeEvent<{}>) => {
- event.preventDefault();
- const eventTarget = event.target as HTMLSpanElement;
- const chosentab = eventTarget.innerText as TabPosition;
- setTabPosition(TabPosition[chosentab]);
- },
- [setTabPosition]
- );
+ const handleChange = (event, newValue) => {
+ setTabPosition(newValue);
+ };
return (
-
-
+
+
);
};
diff --git a/src/components/DetailContainer/DetailContainerTabs.tsx b/src/components/DetailContainer/DetailContainerTabs.tsx
index fdaa009..097136c 100644
--- a/src/components/DetailContainer/DetailContainerTabs.tsx
+++ b/src/components/DetailContainer/DetailContainerTabs.tsx
@@ -1,44 +1,35 @@
-import React, { ChangeEvent, useState, useEffect } from 'react';
+import React from 'react';
import styled from '@emotion/styled';
+import { useTranslation } from 'react-i18next';
import { default as MuiTabs } from '../../muiComponents/Tabs';
import Tab from '../../muiComponents/Tab';
-import { TabPosition } from './tabs';
-
interface Props {
- tabPosition: TabPosition;
- onChangeTabPosition: (event: ChangeEvent<{}>) => void;
+ onChange: (event, newValue) => void;
+ tabPosition: number;
}
-const Tabs = styled(MuiTabs)({
- marginBottom: 16,
-});
-
-const getTabIndex = (tabPosition: TabPosition): number =>
- Object.keys(TabPosition).findIndex(position => position === String(tabPosition).toUpperCase());
-
-const DetailContainerTabs: React.FC = ({ tabPosition, onChangeTabPosition }) => {
- const [tabPositionIndex, setTabPositionIndex] = useState(0);
-
- useEffect(() => {
- const tabIndex = getTabIndex(tabPosition);
- setTabPositionIndex(tabIndex);
- }, [tabPosition]);
+const DetailContainerTabs: React.FC = ({ tabPosition, onChange }) => {
+ const { t } = useTranslation();
return (
-
-
-
-
+
+
+
+
);
};
export default DetailContainerTabs;
+
+const Tabs = styled(MuiTabs)({
+ marginBottom: 16,
+});
diff --git a/src/components/DetailContainer/tabs.ts b/src/components/DetailContainer/tabs.ts
index 26470f8..565f1c6 100644
--- a/src/components/DetailContainer/tabs.ts
+++ b/src/components/DetailContainer/tabs.ts
@@ -1,6 +1,6 @@
export enum TabPosition {
- README = 'Readme',
- DEPENDENCIES = 'Dependencies',
- VERSIONS = 'Versions',
- UPLINKS = 'Uplinks',
+ README = 'readme',
+ DEPENDENCIES = 'dependencies',
+ VERSIONS = 'versions',
+ UPLINKS = 'uplinks',
}
diff --git a/src/components/DetailSidebar/DetailSidebarFundButton.tsx b/src/components/DetailSidebar/DetailSidebarFundButton.tsx
index 9e343aa..fb1e87f 100644
--- a/src/components/DetailSidebar/DetailSidebarFundButton.tsx
+++ b/src/components/DetailSidebar/DetailSidebarFundButton.tsx
@@ -1,6 +1,7 @@
import React, { useContext } from 'react';
import styled from '@emotion/styled';
import Favorite from '@material-ui/icons/Favorite';
+import { Trans } from 'react-i18next';
import Button from '../../muiComponents/Button';
import Link from '../Link';
@@ -38,8 +39,7 @@ const DetailSidebarFundButton: React.FC = () => {
return (
} variant="outlined">
- {'Fund'}
- {'this package'}
+ ]} i18nKey="button.fund-this-package" />
);
diff --git a/src/components/DetailSidebar/DetailSidebarTitle.tsx b/src/components/DetailSidebar/DetailSidebarTitle.tsx
index dd5a816..f04569a 100644
--- a/src/components/DetailSidebar/DetailSidebarTitle.tsx
+++ b/src/components/DetailSidebar/DetailSidebarTitle.tsx
@@ -1,5 +1,6 @@
import React from 'react';
import styled from '@emotion/styled';
+import { useTranslation } from 'react-i18next';
import Box from '../../muiComponents/Box';
import Heading from '../../muiComponents/Heading';
@@ -21,12 +22,17 @@ const StyledBoxVersion = styled(Box)<{ theme?: Theme }>(({ theme }) => ({
color: theme && theme.palette.text.secondary,
}));
-const DetailSidebarTitle: React.FC = ({ description, packageName, version, isLatest }) => (
-
- {packageName}
- {description && {description}
}
- {`${isLatest ? 'Latest v' : 'v'}${version}`}
-
-);
+const DetailSidebarTitle: React.FC = ({ description, packageName, version, isLatest }) => {
+ const { t } = useTranslation();
+ return (
+
+ {packageName}
+ {description && {description}
}
+
+ {isLatest ? t('sidebar.detail.latest-version', { version }) : t('sidebar.detail.version', { version })}
+
+
+ );
+};
export default DetailSidebarTitle;
diff --git a/src/components/Developers/Developers.test.tsx b/src/components/Developers/Developers.test.tsx
index 8913ebc..509ce55 100644
--- a/src/components/Developers/Developers.test.tsx
+++ b/src/components/Developers/Developers.test.tsx
@@ -3,7 +3,8 @@ import React from 'react';
import { mount } from '../../utils/test-enzyme';
import { DetailContextProvider } from '../../pages/Version';
-import Developers, { DeveloperType, Fab } from './Developers';
+import Developers, { Fab } from './Developers';
+import { DeveloperType } from './types';
describe('test Developers', () => {
const packageMeta = {
diff --git a/src/components/Developers/Developers.tsx b/src/components/Developers/Developers.tsx
index 3e69462..b09899a 100644
--- a/src/components/Developers/Developers.tsx
+++ b/src/components/Developers/Developers.tsx
@@ -1,38 +1,29 @@
import React, { useState, useCallback, useContext, useEffect, useMemo } from 'react';
import Add from '@material-ui/icons/Add';
import styled from '@emotion/styled';
+import { useTranslation } from 'react-i18next';
import { DetailContext } from '../../pages/Version';
import Tooltip from '../../muiComponents/Tooltip';
import Avatar from '../../muiComponents/Avatar';
import Box from '../../muiComponents/Box';
-import Text from '../../muiComponents/Text';
import FloatingActionButton from '../../muiComponents/FloatingActionButton';
import { Theme } from '../../design-tokens/theme';
import getUniqueDeveloperValues from './get-unique-developer-values';
+import DevelopersTitle from './DevelopersTitle';
+import { DeveloperType } from './types';
export const Fab = styled(FloatingActionButton)<{ theme?: Theme }>(props => ({
backgroundColor: props.theme && props.theme.palette.primary.main,
color: props.theme && props.theme.palette.white,
}));
-export enum DeveloperType {
- CONTRIBUTORS = 'contributors',
- MAINTAINERS = 'maintainers',
-}
-
interface Props {
type: DeveloperType;
visibleMax?: number;
}
-export const StyledText = styled(Text)<{ theme?: Theme }>(({ theme }) => ({
- fontWeight: theme && theme.fontWeight.bold,
- marginBottom: '10px',
- textTransform: 'capitalize',
-}));
-
const StyledBox = styled(Box)({
'> *': {
margin: 5,
@@ -43,9 +34,10 @@ export const VISIBLE_MAX = 6;
const Developers: React.FC = ({ type, visibleMax = VISIBLE_MAX }) => {
const detailContext = useContext(DetailContext);
+ const { t } = useTranslation();
if (!detailContext) {
- throw Error("The app's detail Context was not correct used");
+ throw Error(t('app-context-not-correct-used'));
}
const developers = useMemo(() => getUniqueDeveloperValues(detailContext.packageMeta?.latest[type]), [
@@ -69,7 +61,7 @@ const Developers: React.FC = ({ type, visibleMax = VISIBLE_MAX }) => {
return (
<>
- {type}
+
{visibleDevelopers.map(visibleDeveloper => (
diff --git a/src/components/Developers/DevelopersTitle.tsx b/src/components/Developers/DevelopersTitle.tsx
new file mode 100644
index 0000000..0eb9c39
--- /dev/null
+++ b/src/components/Developers/DevelopersTitle.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import styled from '@emotion/styled';
+import { useTranslation } from 'react-i18next';
+
+import Text from '../../muiComponents/Text';
+import { Theme } from '../../design-tokens/theme';
+
+import { DeveloperType } from './types';
+
+interface Props {
+ type: DeveloperType;
+}
+
+const DevelopersTitle: React.FC = ({ type }) => {
+ const { t } = useTranslation();
+ switch (type) {
+ case DeveloperType.CONTRIBUTORS:
+ return {t('sidebar.contributors.title')};
+ case DeveloperType.MAINTAINERS:
+ return {t('sidebar.maintainers.title')};
+ return null;
+ }
+};
+
+export default DevelopersTitle;
+
+const StyledText = styled(Text)<{ theme?: Theme }>(({ theme }) => ({
+ fontWeight: theme && theme.fontWeight.bold,
+ marginBottom: '10px',
+}));
diff --git a/src/components/Developers/__snapshots__/Developers.test.tsx.snap b/src/components/Developers/__snapshots__/Developers.test.tsx.snap
index 94e907d..88f7976 100644
--- a/src/components/Developers/__snapshots__/Developers.test.tsx.snap
+++ b/src/components/Developers/__snapshots__/Developers.test.tsx.snap
@@ -4,7 +4,6 @@ exports[`test Developers should render the component for contributors with items
.emotion-0 {
font-weight: 700;
margin-bottom: 10px;
- text-transform: capitalize;
}
.emotion-8 > * {
@@ -14,64 +13,68 @@ exports[`test Developers should render the component for contributors with items
-
-
-
-
-
- contributors
-
-
-
-
-
+
+ sidebar.contributors.title
+
+
+
+
+
+
* {
@@ -437,64 +439,68 @@ exports[`test Developers should render the component for maintainers with items
-
-
-
-
-
- maintainers
-
-
-
-
-
+
+ sidebar.maintainers.title
+
+
+
+
+
+
= ({ name, children }) =>
const Dist: FC = () => {
const { packageMeta } = useContext(DetailContext);
+ const { t } = useTranslation();
if (!packageMeta) {
return null;
@@ -30,11 +32,11 @@ const Dist: FC = () => {
const { dist, license } = packageMeta && packageMeta.latest;
return (
- {'Latest Distribution'}}>
+ {t('sidebar.distribution.title')}}>
- {dist.fileCount}
- {dist.unpackedSize && fileSizeSI(dist.unpackedSize)}
- {formatLicense(license)}
+ {dist.fileCount}
+ {dist.unpackedSize && fileSizeSI(dist.unpackedSize)}
+ {formatLicense(license)}
);
diff --git a/src/components/Dist/__snapshots__/Dist.test.tsx.snap b/src/components/Dist/__snapshots__/Dist.test.tsx.snap
index d2b3ab2..8792608 100644
--- a/src/components/Dist/__snapshots__/Dist.test.tsx.snap
+++ b/src/components/Dist/__snapshots__/Dist.test.tsx.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` component should render the component in default state 1`] = `""`;
+exports[` component should render the component in default state 1`] = `""`;
-exports[` component should render the component with license as object 1`] = `""`;
+exports[` component should render the component with license as object 1`] = `"sidebar.distribution.title
"`;
-exports[` component should render the component with license as string 1`] = `""`;
+exports[` component should render the component with license as string 1`] = `"sidebar.distribution.title
"`;
diff --git a/src/components/Engines/Engines.tsx b/src/components/Engines/Engines.tsx
index 5e8ea9a..b6d0ab7 100644
--- a/src/components/Engines/Engines.tsx
+++ b/src/components/Engines/Engines.tsx
@@ -1,4 +1,5 @@
import React, { useContext } from 'react';
+import { useTranslation } from 'react-i18next';
import { DetailContext } from '../../pages/Version';
import Avatar from '../../muiComponents/Avatar';
@@ -12,6 +13,7 @@ import node from './img/node.png';
const Engine: React.FC = () => {
const { packageMeta } = useContext(DetailContext);
+ const { t } = useTranslation();
const engines = packageMeta?.latest?.engines;
@@ -23,7 +25,7 @@ const Engine: React.FC = () => {
{engines.node && (
- {'node JS'}}>
+ {t('sidebar.engines.node-js')}}>
@@ -34,7 +36,7 @@ const Engine: React.FC = () => {
{engines.npm && (
- {'NPM version'}}>
+ {t('sidebar.engines.npm-version')}}>
diff --git a/src/components/Engines/__snapshots__/Engines.test.tsx.snap b/src/components/Engines/__snapshots__/Engines.test.tsx.snap
index 28ee25d..a496c67 100644
--- a/src/components/Engines/__snapshots__/Engines.test.tsx.snap
+++ b/src/components/Engines/__snapshots__/Engines.test.tsx.snap
@@ -1,3 +1,3 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[` component should render the component in default state 1`] = `""`;
+exports[` component should render the component in default state 1`] = `"sidebar.engines.npm-version
"`;
diff --git a/src/components/Footer/Footer.tsx b/src/components/Footer/Footer.tsx
index da3b58e..e53ac21 100644
--- a/src/components/Footer/Footer.tsx
+++ b/src/components/Footer/Footer.tsx
@@ -1,53 +1,38 @@
import React from 'react';
+import { useTranslation, Trans } from 'react-i18next';
import { goToVerdaccioWebsite } from '../../utils/windows';
import { Wrapper, Left, Right, Earth, Flags, Love, Flag, Logo, Inner, ToolTip } from './styles';
-const renderTooltip = (): JSX.Element => (
-
-
-
-
-
-
-
-
-
-
-
-);
-const POWERED_LABEL = 'Powered by';
-const MADEWITH_LABEL = ' Made with';
-const ON_LABEL = 'on';
-const HEARTH_EMOJI = '♥';
-
-const renderRight = (version = window.VERDACCIO_VERSION): JSX.Element => {
+/* eslint-disable react/jsx-key */
+const Footer: React.FC = () => {
+ const { t } = useTranslation();
return (
-
- {POWERED_LABEL}
-
- {`/ ${version}`}
-
+
+
+
+ ]} i18nKey="footer.made-with-love-on" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {t('footer.powered-by')}
+
+ {`/ ${window.VERDACCIO_VERSION}`}
+
+
+
);
};
-const renderLeft = (): JSX.Element => (
-
- {MADEWITH_LABEL}
- {HEARTH_EMOJI}
- {ON_LABEL}
- {renderTooltip()}
-
-);
-
-const Footer: React.FC = () => (
-
-
- {renderLeft()}
- {renderRight()}
-
-
-);
-
export default Footer;
diff --git a/src/components/Footer/__snapshots__/Footer.test.tsx.snap b/src/components/Footer/__snapshots__/Footer.test.tsx.snap
index 4583d1a..101bbcd 100644
--- a/src/components/Footer/__snapshots__/Footer.test.tsx.snap
+++ b/src/components/Footer/__snapshots__/Footer.test.tsx.snap
@@ -167,13 +167,13 @@ exports[` component should load the initial state of Footer component
- Made with
+ Made with
♥
- on
+ on
diff --git a/src/components/Header/Header.test.tsx b/src/components/Header/Header.test.tsx
index aeed01f..8869dcf 100644
--- a/src/components/Header/Header.test.tsx
+++ b/src/components/Header/Header.test.tsx
@@ -3,6 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom';
import { render, fireEvent, waitForElement, waitForElementToBeRemoved } from '../../utils/test-react-testing-library';
import { AppContextProvider } from '../../App';
+import translationEN from '../../../i18n/translations/en-US.json';
import Header from './Header';
@@ -44,7 +45,7 @@ describe(' component with logged in state', () => {
});
test('should open login dialog', async () => {
- const { getByText } = render(
+ const { getByTestId } = render(
@@ -52,9 +53,9 @@ describe(' component with logged in state', () => {
);
- const loginBtn = getByText('Login');
+ const loginBtn = getByTestId('header--button-login');
fireEvent.click(loginBtn);
- const loginDialog = await waitForElement(() => getByText('Sign in'));
+ const loginDialog = await waitForElement(() => getByTestId('login--dialog'));
expect(loginDialog).toBeTruthy();
});
@@ -119,7 +120,7 @@ describe(' component with logged in state', () => {
fireEvent.click(infoBtn);
// wait for Close's button of registrationInfo modal appearance and return the element
- const closeBtn = await waitForElement(() => getByText('CLOSE'));
+ const closeBtn = await waitForElement(() => getByText(translationEN.button.close));
fireEvent.click(closeBtn);
const hasRegistrationInfoModalBeenRemoved = await waitForElementToBeRemoved(() =>
diff --git a/src/components/Header/Header.tsx b/src/components/Header/Header.tsx
index 4d68cd1..5cab99e 100644
--- a/src/components/Header/Header.tsx
+++ b/src/components/Header/Header.tsx
@@ -1,4 +1,5 @@
import React, { useState, useContext } from 'react';
+import { useTranslation } from 'react-i18next';
import storage from '../../utils/storage';
import { getRegistryURL } from '../../utils/url';
@@ -18,13 +19,14 @@ interface Props {
/* eslint-disable react/jsx-no-bind*/
const Header: React.FC = ({ withoutSearch }) => {
+ const { t } = useTranslation();
const appContext = useContext(AppContext);
const [isInfoDialogOpen, setOpenInfoDialog] = useState();
const [showMobileNavBar, setShowMobileNavBar] = useState();
const [showLoginModal, setShowLoginModal] = useState(false);
if (!appContext) {
- throw Error('The app Context was not correct used');
+ throw Error(t('app-context-not-correct-used'));
}
const { user, scope, setUser } = appContext;
@@ -67,7 +69,7 @@ const Header: React.FC = ({ withoutSearch }) => {
)}
diff --git a/src/components/Header/HeaderGreetings.tsx b/src/components/Header/HeaderGreetings.tsx
index 74c865f..8c69fc9 100644
--- a/src/components/Header/HeaderGreetings.tsx
+++ b/src/components/Header/HeaderGreetings.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import { useTranslation } from 'react-i18next';
import Label from '../Label';
@@ -8,11 +9,14 @@ interface Props {
username: string;
}
-const HeaderGreetings: React.FC = ({ username }) => (
- <>
- {'Hi,'}
-
- >
-);
+const HeaderGreetings: React.FC = ({ username }) => {
+ const { t } = useTranslation();
+ return (
+ <>
+ {t('header.greetings')}
+
+ >
+ );
+};
export default HeaderGreetings;
diff --git a/src/components/Header/HeaderMenu.tsx b/src/components/Header/HeaderMenu.tsx
index d5d6ae1..7d1d190 100644
--- a/src/components/Header/HeaderMenu.tsx
+++ b/src/components/Header/HeaderMenu.tsx
@@ -1,4 +1,5 @@
import React, { MouseEvent } from 'react';
+import { useTranslation } from 'react-i18next';
import AccountCircle from '@material-ui/icons/AccountCircle';
import IconButton from '../../muiComponents/IconButton';
@@ -23,35 +24,38 @@ const HeaderMenu: React.FC = ({
anchorEl,
onLoggedInMenu,
onLoggedInMenuClose,
-}) => (
- <>
-
-
- >
-);
+}) => {
+ const { t } = useTranslation();
+ return (
+ <>
+
+
+ >
+ );
+};
export default HeaderMenu;
diff --git a/src/components/Header/HeaderRight.tsx b/src/components/Header/HeaderRight.tsx
index 4643645..64f3b23 100644
--- a/src/components/Header/HeaderRight.tsx
+++ b/src/components/Header/HeaderRight.tsx
@@ -1,4 +1,5 @@
import React, { useState, useEffect, MouseEvent } from 'react';
+import { useTranslation } from 'react-i18next';
import Button from '../../muiComponents/Button';
@@ -25,6 +26,7 @@ const HeaderRight: React.FC = ({
}) => {
const [anchorEl, setAnchorEl] = useState();
const [isMenuOpen, setIsMenuOpen] = useState();
+ const { t } = useTranslation();
useEffect(() => {
setIsMenuOpen(Boolean(anchorEl));
@@ -55,10 +57,10 @@ const HeaderRight: React.FC = ({
return (
{!withoutSearch && (
-
+
)}
-
-
+
+
{username ? (
= ({
/>
) : (
)}
diff --git a/src/components/Help/Help.tsx b/src/components/Help/Help.tsx
index 0923dfa..9e2ad3c 100644
--- a/src/components/Help/Help.tsx
+++ b/src/components/Help/Help.tsx
@@ -1,4 +1,5 @@
import React, { Fragment } from 'react';
+import { useTranslation } from 'react-i18next';
import { getRegistryURL } from '../../utils/url';
import CopyToClipBoard from '../CopyToClipBoard';
@@ -24,23 +25,24 @@ function renderHeadingClipboardSegments(title: string, text: string): React.Reac
const Help: React.FC = () => {
const registryUrl = getRegistryURL();
+ const { t } = useTranslation();
return (
- {HELP_TITLE}
+ {t('help.title')}
- {'To publish your first package just:'}
+ {t('help.sub-title')}
- {renderHeadingClipboardSegments('1. Login', `npm adduser --registry ${registryUrl}`)}
- {renderHeadingClipboardSegments('2. Publish', `npm publish --registry ${registryUrl}`)}
- {'3. Refresh this page.'}
+ {renderHeadingClipboardSegments(t('help.first-step'), t('help.first-step-command-line', { registryUrl }))}
+ {renderHeadingClipboardSegments(t('help.second-step'), t('help.second-step-command-line', { registryUrl }))}
+ {t('help.third-step')}
diff --git a/src/components/Help/__snapshots__/Help.test.tsx.snap b/src/components/Help/__snapshots__/Help.test.tsx.snap
index 830e33a..20562f0 100644
--- a/src/components/Help/__snapshots__/Help.test.tsx.snap
+++ b/src/components/Help/__snapshots__/Help.test.tsx.snap
@@ -68,7 +68,7 @@ exports[` component should load the component in default state 1`] = `