From 8868ed2173a68018bb1d6eb5f5233bfd7e5a1fe7 Mon Sep 17 00:00:00 2001 From: oruburos Date: Wed, 12 Aug 2020 12:47:28 +0100 Subject: [PATCH 1/6] Translations From REduxFormUtils --- client/components/Nav.jsx | 6 +- translations/locales/en-US/translations.json | 67 ++++++++++++---- translations/locales/es-419/translations.json | 79 +++++++++++++------ 3 files changed, 111 insertions(+), 41 deletions(-) diff --git a/client/components/Nav.jsx b/client/components/Nav.jsx index 1661711291..4f315bb33a 100644 --- a/client/components/Nav.jsx +++ b/client/components/Nav.jsx @@ -608,13 +608,13 @@ class Nav extends React.PureComponent { diff --git a/translations/locales/en-US/translations.json b/translations/locales/en-US/translations.json index d08685805b..09c4e559eb 100644 --- a/translations/locales/en-US/translations.json +++ b/translations/locales/en-US/translations.json @@ -33,18 +33,9 @@ "Lang": "Language", "BackEditor": "Back to Editor", "WarningUnsavedChanges": "Are you sure you want to leave this page? You have unsaved changes.", - "Login": { - "Login": "Log in", - "LoginOr": "or", - "SignUp": "Sign up", - "Email": "email", - "Username": "username", - "LoginGithub": "Login with Github", - "LoginGoogle": "Login with Google", - "DontHaveAccount": "Don't have an account?", - "ForgotPassword": "Forgot your password?", - "ResetPassword": "Reset your password" - }, + "Login": "Log in", + "LoginOr": "or", + "SignUp": "Sign up", "Auth": { "Welcome": "Welcome", "Hello": "Hello", @@ -57,6 +48,29 @@ "LogOut": "Log Out" } }, + "LoginForm": { + "UsernameOrEmail": "Email or Username", + "UsernameOrEmailARIA": "Email or Username", + "Password": "Password", + "PasswordARIA": "Password", + "Submit": "Log In" + }, + "LoginView": { + "Title": "p5.js Web Editor | Login", + "Login": "Log In", + "LoginOr": "or", + "SignUp": "Sign Up", + "Email": "email", + "Username": "username", + "DontHaveAccount": "Don't have an account? ", + "ForgotPassword": "Forgot your password? ", + "ResetPassword": "Reset your password" + }, + "SocialAuthButton": { + "Github": "Login with Github", + "LogoARIA": "{{serviceauth}} logo", + "Google": "Login with Google" + }, "About": { "Title": "About", "TitleHelmet": "p5.js Web Editor | About", @@ -169,21 +183,20 @@ "Error": "Error", "Save": "Save", "p5logoARIA": "p5.js Logo" - }, "IDEView": { "SubmitFeedback": "Submit Feedback" }, "NewFileModal": { "Title": "Create File", - "CloseButtonARIA": "Close New File Modal", + "CloseButtonARIA": "Close New File Modal", "EnterName": "Please enter a name", "InvalidType": "Invalid file type. Valid extensions are .js, .css, .json, .txt, .csv, .tsv, .frag, and .vert." }, "NewFileForm": { - "AddFileSubmit": "Add File", + "AddFileSubmit": "Add File", "Placeholder": "Name" -}, + }, "NewFolderModal": { "Title": "Create Folder", "CloseButtonARIA": "Close New Folder Modal", @@ -194,5 +207,27 @@ "NewFolderForm": { "AddFolderSubmit": "Add Folder", "Placeholder": "Name" + }, + "ResetPasswordForm": { + "Email": "Email used for registration", + "EmailARIA": "email", + "Submit": "Send Password Reset Email" + }, + "ResetPasswordView": { + "Title": "p5.js Web Editor | Reset Password", + "Reset": "Reset Your Password", + "Submitted": "Your password reset email should arrive shortly. If you don't see it, check\n in your spam folder as sometimes it can end up there." + }, + "ReduxFormUtils": { + "errorInvalidEmail": "Please enter a valid email address", + "errorEmptyEmail": "Please enter an email", + "errorPasswordMismatch": "Passwords must match", + "errorEmptyPassword": "Please enter a password", + "errorShortPassword": "Password must be at least 6 characters", + "errorConfirmPassword": "Please enter a password confirmation", + "errorNewPassword": "Please enter a new password or leave the current password empty.", + "errorEmptyUsername": "Please enter a username.", + "errorLongUsername": "Username must be less than 20 characters.", + "errorValidUsername": "Username must only consist of numbers, letters, periods, dashes, and underscores." } } diff --git a/translations/locales/es-419/translations.json b/translations/locales/es-419/translations.json index 398da8dcb3..ef279fc0f8 100644 --- a/translations/locales/es-419/translations.json +++ b/translations/locales/es-419/translations.json @@ -33,18 +33,9 @@ "Lang": "Lenguaje", "BackEditor": "Regresa al editor", "WarningUnsavedChanges": "¿Realmente quieres salir de la página? Tienes cambios sin guardar.", - "Login": { - "Login": "Ingresa", - "LoginOr": "o", - "SignUp": "registráte", - "Email": "correo electrónico", - "Username": "Identificación", - "LoginGithub": "Ingresa con Github", - "LoginGoogle": "Ingresa con Google", - "DontHaveAccount": "¿No tienes cuenta?", - "ForgotPassword": "¿Olvidaste tu contraseña?", - "ResetPassword": "Regenera tu contraseña" - }, + "Login": "Ingresa", + "LoginOr": "o", + "SignUp": "Registráte", "Auth": { "Welcome": "Hola", "Hello": "Hola", @@ -57,6 +48,29 @@ "LogOut": "Cerrar sesión" } }, + "LoginForm": { + "UsernameOrEmail": "Correo o Identificación", + "UsernameOrEmailARIA": "Introduce Correo o Identificación", + "Password": "Contraseña", + "PasswordARIA": "Contraseña", + "Submit": "Ingresa" + }, + "LoginView": { + "Title": " Editor Web p5.js | Ingreso", + "Login": "Ingresa", + "LoginOr": "o", + "SignUp": "Registráte", + "Email": "correo electrónico", + "Username": "Identificación", + "DontHaveAccount": "¿No tienes cuenta? ", + "ForgotPassword": "¿Olvidaste tu contraseña? ", + "ResetPassword": "Regenera tu contraseña" + }, + "SocialAuthButton": { + "Github": "Ingresa con Github", + "LogoARIA": "Logo de {{serviceauth}}", + "Google": "Ingresa con Google" + }, "About": { "Title": "Acerca de", "TitleHelmet": "Editor Web p5.js | Acerca de", @@ -174,8 +188,8 @@ "SubmitFeedback": "Enviar retroalimentación" }, "NewFileModal": { - "Title": "Crear Archivo", - "CloseButtonARIA": "Cerrar diálogo de crear archivo", + "Title": "Crear Archivo", + "CloseButtonARIA": "Cerrar diálogo de crear archivo", "EnterName": "Por favor introduce un nombre", "InvalidType": "Tipo de archivo inválido. Las extensiones válidas son .js, .css, .json, .txt, .csv, .tsv, .frag y .vert." }, @@ -184,18 +198,39 @@ "Placeholder": "Nombre" }, "NewFolderModal": { - "Title": "Crear Directorio", - "CloseButtonARIA": "Cerrar Diálogo de Nuevo Directorio", - "EnterName": "Por favor introduce un nombre", - "EmptyName": " El nombre del directorio no debe contener solo espacios vacíos", - "InvalidExtension": "El nombre del directorio no debe contener una extensión" -}, + "Title": "Crear Directorio", + "CloseButtonARIA": "Cerrar Diálogo de Nuevo Directorio", + "EnterName": "Por favor introduce un nombre", + "EmptyName": " El nombre del directorio no debe contener solo espacios vacíos", + "InvalidExtension": "El nombre del directorio no debe contener una extensión" + }, "NewFolderForm": { "AddFolderSubmit": "Agregar Directorio", "Placeholder": "Nombre" + }, + "ResetPasswordForm": { + "Email": "Correo electrónico usado al registrarse", + "EmailARIA": "correo electrónico", + "Submit": "Enviar correo para regenerar contraseña" + }, + "ResetPasswordView": { + "Title": "Editor Web p5.js | Regenerar Contraseña", + "Reset": "Regenerar Contraseña", + "Submitted": "Your password reset email should arrive shortly. If you don't see it, check\n in your spam folder as sometimes it can end up there." + }, + "ReduxFormUtils": { + "errorInvalidEmail": "Por favor introduce un correo electrónico válido", + "errorEmptyEmail": "Por favor introduce un correo electrónico", + "errorPasswordMismatch": "Las contraseñas deben coincidir", + "errorEmptyPassword": "Por favor introduce una contraseña", + "errorShortPassword": "La contraseña debe tener al menos 6 caracteres", + "errorConfirmPassword": "Por favor confirma una contraseña", + "errorNewPassword": "Por favor introduce una nueva contraseña o deja la actual contraseña vacía", + "errorEmptyUsername": "Por favor introduce tu identificación", + "errorLongUsername": "La identificación debe ser menor a 20 caracteres.", + "errorValidUsername": "La identificación debe consistir solamente de números, letras, puntos, guiones y guiones bajos." + } } - - From 6fca524e691d899b682ec337350f04c6a12225b2 Mon Sep 17 00:00:00 2001 From: oruburos Date: Wed, 12 Aug 2020 18:03:53 +0100 Subject: [PATCH 2/6] Translations for Account, AiKey and New Password --- client/modules/User/components/APIKeyForm.jsx | 31 ++++++------- client/modules/User/components/APIKeyList.jsx | 15 +++--- .../modules/User/components/AccountForm.jsx | 31 +++++++------ client/modules/User/pages/AccountView.jsx | 22 +++++---- client/modules/User/pages/NewPasswordView.jsx | 10 ++-- client/utils/reduxFormUtils.js | 31 +++++++------ translations/locales/en-US/translations.json | 46 +++++++++++++++++++ translations/locales/es-419/translations.json | 46 +++++++++++++++++++ 8 files changed, 167 insertions(+), 65 deletions(-) diff --git a/client/modules/User/components/APIKeyForm.jsx b/client/modules/User/components/APIKeyForm.jsx index cb99dcde38..371053b876 100644 --- a/client/modules/User/components/APIKeyForm.jsx +++ b/client/modules/User/components/APIKeyForm.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; - +import i18next from 'i18next'; import Button from '../../../common/Button'; import { PlusIcon } from '../../../common/icons'; import CopyableInput from '../../IDE/components/CopyableInput'; @@ -12,7 +12,7 @@ export const APIKeyPropType = PropTypes.shape({ token: PropTypes.object, label: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired, - lastUsedAt: PropTypes.string, + lastUsedAt: PropTypes.string }); class APIKeyForm extends React.Component { @@ -39,7 +39,8 @@ class APIKeyForm extends React.Component { } removeKey(key) { - const message = `Are you sure you want to delete "${key.label}"?`; + // const message = `Are you sure you want to delete "${}"?`; + const message = i18next.t('APIKeyForm.ConfirmDelete', { key_label: key.label }); if (window.confirm(message)) { this.props.removeApiKey(key.id); @@ -51,10 +52,10 @@ class APIKeyForm extends React.Component { if (hasApiKeys) { return ( - + ); } - return

You have no exsiting tokens.

; + return

{this.props.t('APIKeyForm.NoTokens')}

; } render() { @@ -63,20 +64,18 @@ class APIKeyForm extends React.Component { return (

- Personal Access Tokens act like your password to allow automated - scripts to access the Editor API. Create a token for each script - that needs access. + {this.props.t('APIKeyForm.Summary')}

-

Create new token

+

{this.props.t('APIKeyForm.CreateToken')}

- + { this.setState({ keyLabel: event.target.value }); }} - placeholder="What is this token for? e.g. Example import script" + placeholder={this.props.t('APIKeyForm.TokenPlaceholder')} type="text" value={this.state.keyLabel} /> @@ -86,17 +85,16 @@ class APIKeyForm extends React.Component { label="Create new key" type="submit" > - Create + {this.props.t('APIKeyForm.CreateTokenSubmit')}
{ keyWithToken && (
-

Your new access token

+

{this.props.t('APIKeyForm.NewTokenTitle')}

- Make sure to copy your new personal access token now. - You won’t be able to see it again! + {this.props.t('APIKeyForm.NewTokenInfo')}

@@ -105,7 +103,7 @@ class APIKeyForm extends React.Component {
-

Existing tokens

+

{this.props.t('APIKeyForm.ExistingTokensTitle')}

{this.renderApiKeys()}
@@ -117,6 +115,7 @@ APIKeyForm.propTypes = { apiKeys: PropTypes.arrayOf(PropTypes.shape(APIKeyPropType)).isRequired, createApiKey: PropTypes.func.isRequired, removeApiKey: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; export default APIKeyForm; diff --git a/client/modules/User/components/APIKeyList.jsx b/client/modules/User/components/APIKeyList.jsx index 9201aa4b6d..2c2e39ac71 100644 --- a/client/modules/User/components/APIKeyList.jsx +++ b/client/modules/User/components/APIKeyList.jsx @@ -8,22 +8,22 @@ import { APIKeyPropType } from './APIKeyForm'; import TrashCanIcon from '../../../images/trash-can.svg'; -function APIKeyList({ apiKeys, onRemove }) { +function APIKeyList({ apiKeys, onRemove, t }) { return ( - - - - + + + + {orderBy(apiKeys, ['createdAt'], ['desc']).map((key) => { const lastUsed = key.lastUsedAt ? distanceInWordsToNow(new Date(key.lastUsedAt), { addSuffix: true }) : - 'Never'; + t('APIKeyList.Never'); return ( @@ -34,7 +34,7 @@ function APIKeyList({ apiKeys, onRemove }) { @@ -50,6 +50,7 @@ function APIKeyList({ apiKeys, onRemove }) { APIKeyList.propTypes = { apiKeys: PropTypes.arrayOf(PropTypes.shape(APIKeyPropType)).isRequired, onRemove: PropTypes.func.isRequired, + t: PropTypes.func.isRequired }; export default APIKeyList; diff --git a/client/modules/User/components/AccountForm.jsx b/client/modules/User/components/AccountForm.jsx index e032448bc0..829beb0ded 100644 --- a/client/modules/User/components/AccountForm.jsx +++ b/client/modules/User/components/AccountForm.jsx @@ -1,5 +1,6 @@ import PropTypes from 'prop-types'; import React from 'react'; +import { withTranslation } from 'react-i18next'; import { domOnlyProps } from '../../../utils/reduxFormUtils'; import Button from '../../../common/Button'; @@ -13,7 +14,8 @@ function AccountForm(props) { initiateVerification, submitting, invalid, - pristine + pristine, + t } = props; const handleInitiateVerification = (evt) => { @@ -24,10 +26,10 @@ function AccountForm(props) { return (

- + - Unconfirmed. + {t('AccountForm.Unconfirmed')} { user.emailVerificationInitiate === true ? ( - Confirmation sent, check your email. + {t('AccountForm.EmailSent')} ) : ( ) } @@ -55,10 +57,10 @@ function AccountForm(props) { ) }

- + {username.error}}

- +

- + Save All Settings + >{t('AccountForm.SubmitSaveAllSettings')} ); @@ -118,6 +120,7 @@ AccountForm.propTypes = { submitting: PropTypes.bool, invalid: PropTypes.bool, pristine: PropTypes.bool, + t: PropTypes.func.isRequired }; AccountForm.defaultProps = { @@ -126,4 +129,4 @@ AccountForm.defaultProps = { invalid: false }; -export default AccountForm; +export default withTranslation()(AccountForm); diff --git a/client/modules/User/pages/AccountView.jsx b/client/modules/User/pages/AccountView.jsx index fff8d3318a..f9f46cc8f6 100644 --- a/client/modules/User/pages/AccountView.jsx +++ b/client/modules/User/pages/AccountView.jsx @@ -4,6 +4,7 @@ import { reduxForm } from 'redux-form'; import { bindActionCreators } from 'redux'; import { Tab, Tabs, TabList, TabPanel } from 'react-tabs'; import { Helmet } from 'react-helmet'; +import { withTranslation } from 'react-i18next'; import { updateSettings, initiateVerification, createApiKey, removeApiKey } from '../actions'; import AccountForm from '../components/AccountForm'; import apiClient from '../../../utils/apiClient'; @@ -16,9 +17,11 @@ function SocialLoginPanel(props) { return ( -

Social Login

+ {/* eslint-disable-next-line react/prop-types */} +

{props.t('AccountView.SocialLogin')}

- Use your GitHub or Google account to log into the p5.js Web Editor. + {/* eslint-disable-next-line react/prop-types */} + {props.t('AccountView.SocialLoginDescription')}

@@ -39,21 +42,21 @@ class AccountView extends React.Component { return (
- p5.js Web Editor | Account Settings + {this.props.t('AccountView.Title')}
NameCreated onLast usedActions{t('APIKeyList.Name')}{t('APIKeyList.Created')}{t('APIKeyList.LastUsed')}{t('APIKeyList.Actions')}