mirror of
https://github.com/elyby/accounts-frontend.git
synced 2024-12-27 15:30:37 +05:30
Basic functionality for locale change. Draft implementation of tools for working with i18n
This commit is contained in:
parent
8db3c36261
commit
4f5f18d787
@ -8,10 +8,11 @@
|
||||
"license": "UNLICENSED",
|
||||
"repository": "git@bitbucket.org:ErickSkrauch/ely.by-account.git",
|
||||
"scripts": {
|
||||
"start": "webpack-dev-server --progress --colors",
|
||||
"start": "rm -rf dist/ && webpack-dev-server --progress --colors",
|
||||
"up": "npm install",
|
||||
"test": "karma start ./karma.conf.js",
|
||||
"lint": "eslint ./src",
|
||||
"i18n": "cd ./scripts && ./node_modules/.bin/babel-node i18n-collect.js",
|
||||
"build": "rm -rf dist/ && webpack --progress --colors -p"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -44,6 +45,7 @@
|
||||
"babel-preset-react-hmre": "^1.0.1",
|
||||
"babel-preset-stage-0": "^6.3.13",
|
||||
"babel-runtime": "^5.6.15",
|
||||
"bundle-loader": "^0.5.4",
|
||||
"chai": "^3.0.0",
|
||||
"chokidar": "^1.2.0",
|
||||
"css-loader": "^0.23.0",
|
||||
|
3
scripts/.babelrc
Normal file
3
scripts/.babelrc
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"breakConfig": true
|
||||
}
|
147
scripts/i18n-collect.js
Normal file
147
scripts/i18n-collect.js
Normal file
@ -0,0 +1,147 @@
|
||||
import fs from 'fs';
|
||||
import {sync as globSync} from 'glob';
|
||||
import {sync as mkdirpSync} from 'mkdirp';
|
||||
import chalk from 'chalk';
|
||||
import prompt from 'prompt';
|
||||
|
||||
const MESSAGES_PATTERN = `../dist/messages/**/*.json`;
|
||||
const LANG_DIR = `../src/i18n`;
|
||||
const DEFAULT_LOCALE = 'en';
|
||||
const SUPPORTED_LANGS = [DEFAULT_LOCALE].concat('ru');
|
||||
|
||||
/**
|
||||
* Aggregates the default messages that were extracted from the app's
|
||||
* React components via the React Intl Babel plugin. An error will be thrown if
|
||||
* there are messages in different components that use the same `id`. The result
|
||||
* is a flat collection of `id: message` pairs for the app's default locale.
|
||||
*/
|
||||
let idToFileMap = {};
|
||||
let duplicateIds = [];
|
||||
let defaultMessages = globSync(MESSAGES_PATTERN)
|
||||
.map((filename) => [filename, JSON.parse(fs.readFileSync(filename, 'utf8'))])
|
||||
.reduce((collection, [file, descriptors]) => {
|
||||
descriptors.forEach(({id, defaultMessage}) => {
|
||||
if (collection.hasOwnProperty(id)) {
|
||||
duplicateIds.push(id);
|
||||
}
|
||||
|
||||
collection[id] = defaultMessage;
|
||||
idToFileMap[id] = (idToFileMap[id] || []).concat(file);
|
||||
});
|
||||
|
||||
return collection;
|
||||
}, {});
|
||||
|
||||
if (duplicateIds.length) {
|
||||
console.log('\nFound duplicated ids:');
|
||||
duplicateIds.forEach((id) => console.log(`${chalk.yellow(id)}:\n - ${idToFileMap[id].join('\n - ')}\n`));
|
||||
console.log(chalk.red('Please correct the errors above to proceed further!'));
|
||||
return;
|
||||
}
|
||||
|
||||
duplicateIds = null;
|
||||
idToFileMap = null;
|
||||
|
||||
/**
|
||||
* Making a diff with the previous DEFAULT_LOCALE version
|
||||
*/
|
||||
const defaultMessagesPath = `${LANG_DIR}/${DEFAULT_LOCALE}.json`;
|
||||
let keysToUpdate = [];
|
||||
let keysToAdd = [];
|
||||
let keysToRemove = [];
|
||||
const isNotMarked = (value) => value.slice(0, 2) !== '--';
|
||||
try {
|
||||
const prevMessages = JSON.parse(fs.readFileSync(defaultMessagesPath, 'utf8'));
|
||||
keysToAdd = Object.keys(defaultMessages).filter((key) => !prevMessages[key]);
|
||||
keysToRemove = Object.keys(prevMessages).filter((key) => !defaultMessages[key]).filter(isNotMarked);
|
||||
keysToUpdate = Object.entries(prevMessages).reduce((acc, [key, message]) =>
|
||||
acc.concat(defaultMessages[key] && defaultMessages[key] !== message ? key : [])
|
||||
, []);
|
||||
} catch(e) {
|
||||
console.log(chalk.yellow(`Can not read ${defaultMessagesPath}. The new file will be created.`), e);
|
||||
}
|
||||
|
||||
if (!keysToAdd.length && !keysToRemove.length && !keysToUpdate.length) {
|
||||
return console.log(chalk.green('Everything is up to date!'));
|
||||
}
|
||||
|
||||
console.log(chalk.magenta(`The diff relative to default locale (${DEFAULT_LOCALE}) is:`));
|
||||
|
||||
if (keysToRemove.length) {
|
||||
console.log('The following keys will be removed:');
|
||||
console.log(chalk.red('\n - ') + keysToRemove.join(chalk.red('\n - ')) + '\n');
|
||||
}
|
||||
|
||||
if (keysToAdd.length) {
|
||||
console.log('The following keys will be added:');
|
||||
console.log(chalk.green('\n + ') + keysToAdd.join(chalk.green('\n + ')) + '\n');
|
||||
}
|
||||
|
||||
if (keysToUpdate.length) {
|
||||
console.log('The following keys will be updated:');
|
||||
console.log(chalk.yellow('\n @ ') + keysToUpdate.join(chalk.yellow('\n @ ')) + '\n');
|
||||
}
|
||||
|
||||
prompt.start();
|
||||
prompt.get({
|
||||
properties: {
|
||||
apply: {
|
||||
description: 'Apply changes? [Y/n]',
|
||||
pattern: /^y|n$/i,
|
||||
message: 'Please enter "y" or "n"',
|
||||
default: 'y',
|
||||
before: (value) => value.toLowerCase() === 'y'
|
||||
}
|
||||
}
|
||||
}, (err, resp) => {
|
||||
console.log('\n');
|
||||
|
||||
if (err || !resp.apply) {
|
||||
return console.log(chalk.red('Aborted'));
|
||||
}
|
||||
|
||||
buildLocales();
|
||||
|
||||
console.log(chalk.green('All locales was successfuly built'));
|
||||
});
|
||||
|
||||
|
||||
function buildLocales() {
|
||||
mkdirpSync(LANG_DIR);
|
||||
|
||||
SUPPORTED_LANGS.map((lang) => {
|
||||
const destPath = `${LANG_DIR}/${lang}.json`;
|
||||
|
||||
let newMessages = {};
|
||||
try {
|
||||
newMessages = JSON.parse(fs.readFileSync(defaultMessagesPath, 'utf8'));
|
||||
} catch (e) {
|
||||
console.log(chalk.yellow(`Can not read ${defaultMessagesPath}. The new file will be created.`), e);
|
||||
}
|
||||
|
||||
keysToRemove.forEach((key) => {
|
||||
delete newMessages[key];
|
||||
});
|
||||
keysToUpdate.forEach((key) => {
|
||||
newMessages[`--${key}`] = newMessages[key];
|
||||
});
|
||||
keysToAdd.concat(keysToUpdate).forEach((key) => {
|
||||
newMessages[key] = defaultMessages[key];
|
||||
});
|
||||
|
||||
const sortedKeys = Object.keys(newMessages).sort((a, b) => {
|
||||
a = a.replace(/^\-+/, '');
|
||||
b = b.replace(/^\-+/, '');
|
||||
|
||||
return a < b || !isNotMarked(a) ? -1 : 1;
|
||||
});
|
||||
|
||||
const sortedNewMessages = sortedKeys.reduce((acc, key) => {
|
||||
acc[key] = newMessages[key];
|
||||
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
fs.writeFileSync(destPath, JSON.stringify(sortedNewMessages, null, 4) + '\n');
|
||||
});
|
||||
}
|
15
scripts/package.json
Normal file
15
scripts/package.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "scripts",
|
||||
"version": "1.0.0",
|
||||
"description": "",
|
||||
"main": "i18n-build.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"chalk": "^1.1.3"
|
||||
}
|
||||
}
|
@ -8,7 +8,7 @@ import buttons from 'components/ui/buttons.scss';
|
||||
import { Input } from 'components/ui/form';
|
||||
|
||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||
import passwordMessages from 'components/auth/password/Password.messages';
|
||||
import passwordMessages from 'components/auth/password/Password.intl.json';
|
||||
import messages from './Login.messages';
|
||||
|
||||
class Body extends BaseAuthBody {
|
||||
|
10
src/components/auth/password/Password.intl.json
Normal file
10
src/components/auth/password/Password.intl.json
Normal file
@ -0,0 +1,10 @@
|
||||
{
|
||||
"passwordTitle": "Enter password",
|
||||
"signInButton": "Sign in",
|
||||
"invalidPassword": "You entered wrong account password.",
|
||||
"suggestResetPassword": "Are you have {link}?",
|
||||
"forgotYourPassword": "forgot your password",
|
||||
"forgotPassword": "Forgot password",
|
||||
"accountPassword": "Account password",
|
||||
"rememberMe": "Remember me on this device"
|
||||
}
|
@ -10,7 +10,7 @@ import { Input, Checkbox } from 'components/ui/form';
|
||||
|
||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||
import styles from './password.scss';
|
||||
import messages from './Password.messages';
|
||||
import messages from './Password.intl.json';
|
||||
|
||||
class Body extends BaseAuthBody {
|
||||
static displayName = 'PasswordBody';
|
||||
|
@ -1,43 +0,0 @@
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
export default defineMessages({
|
||||
passwordTitle: {
|
||||
id: 'passwordTitle',
|
||||
defaultMessage: 'Enter password'
|
||||
},
|
||||
|
||||
signInButton: {
|
||||
id: 'signInButton',
|
||||
defaultMessage: 'Sign in'
|
||||
},
|
||||
|
||||
invalidPassword: {
|
||||
id: 'invalidPassword',
|
||||
defaultMessage: 'You entered wrong account password.'
|
||||
},
|
||||
|
||||
suggestResetPassword: {
|
||||
id: 'suggestResetPassword',
|
||||
defaultMessage: 'Are you have {link}?'
|
||||
},
|
||||
|
||||
forgotYourPassword: {
|
||||
id: 'forgotYourPassword',
|
||||
defaultMessage: 'forgot your password'
|
||||
},
|
||||
|
||||
forgotPassword: {
|
||||
id: 'forgotPassword',
|
||||
defaultMessage: 'Forgot password'
|
||||
},
|
||||
|
||||
accountPassword: {
|
||||
id: 'accountPassword',
|
||||
defaultMessage: 'Account password'
|
||||
},
|
||||
|
||||
rememberMe: {
|
||||
id: 'rememberMe',
|
||||
defaultMessage: 'Remember me on this device'
|
||||
}
|
||||
});
|
@ -7,6 +7,7 @@ import buttons from 'components/ui/buttons.scss';
|
||||
import { Input, Checkbox } from 'components/ui/form';
|
||||
|
||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||
import passwordMessages from 'components/auth/password/Password.intl.json';
|
||||
import activationMessages from 'components/auth/activation/Activation.messages';
|
||||
import messages from './Register.messages';
|
||||
|
||||
@ -44,7 +45,7 @@ class Body extends BaseAuthBody {
|
||||
color="blue"
|
||||
type="password"
|
||||
required
|
||||
placeholder={messages.accountPassword}
|
||||
placeholder={passwordMessages.accountPassword}
|
||||
/>
|
||||
|
||||
<Input {...this.bindField('rePassword')}
|
||||
|
@ -0,0 +1,10 @@
|
||||
{
|
||||
"changePasswordTitle": "Change password",
|
||||
"changePasswordDescription": "Please take a password, that will be different from your passwords on the other sites and will not be the same you are using to enter Minecraft game servers you are playing.",
|
||||
"achievementLossWarning": "Are you cherish your game achievements, right?",
|
||||
"passwordRequirements": "Password must contain at least 8 characters. It can be any symbols — do not limit yourself, create an unpredictable password!",
|
||||
"changePasswordButton": "Change password",
|
||||
"newPasswordLabel": "New password:",
|
||||
"repeatNewPasswordLabel": "Repeat the password:",
|
||||
"logoutOnAllDevices": "Logout on all devices"
|
||||
}
|
@ -7,7 +7,7 @@ import Helmet from 'react-helmet';
|
||||
import { Input, Button, Checkbox, Form, FormModel } from 'components/ui/form';
|
||||
|
||||
import styles from 'components/profile/profileForm.scss';
|
||||
import messages from './ChangePassword.messages';
|
||||
import messages from './ChangePassword.intl.json';
|
||||
|
||||
export default class ChangePassword extends Component {
|
||||
static displayName = 'ChangePassword';
|
||||
|
@ -1,43 +0,0 @@
|
||||
import { defineMessages } from 'react-intl';
|
||||
|
||||
export default defineMessages({
|
||||
changePasswordTitle: {
|
||||
id: 'changePasswordTitle',
|
||||
defaultMessage: 'Change password'
|
||||
// defaultMessage: 'Смена пароля'
|
||||
},
|
||||
changePasswordDescription: {
|
||||
id: 'changePasswordDescription',
|
||||
defaultMessage: 'Please take a password, that will be different from your passwords on the other sites and will not be the same you are using to enter Minecraft game servers you are playing.'
|
||||
// defaultMessage: 'Придумайте пароль, который будет отличаться от ваших паролей на других сайтах и не будет совпадаеть с тем паролем, который вы используете для входа на различные игровые сервера Minecraft.'
|
||||
},
|
||||
achievementLossWarning: {
|
||||
id: 'achievementLossWarning',
|
||||
defaultMessage: 'Are you cherish your game achievements, right?'
|
||||
// defaultMessage: 'Вы ведь дорожите своими игровыми достижениями?'
|
||||
},
|
||||
passwordRequirements: {
|
||||
id: 'passwordRequirements',
|
||||
defaultMessage: 'Password must contain at least 8 characters. It can be any symbols — do not limit yourself, create an unpredictable password!'
|
||||
// defaultMessage: 'Пароль должен содержать не менее 8 символов. Это могут быть любым символы — не ограничивайте себя, придумайте непредсказуемый пароль!'
|
||||
},
|
||||
changePasswordButton: {
|
||||
id: 'changePasswordButton',
|
||||
defaultMessage: 'Change password'
|
||||
// defaultMessage: 'Сменить пароль'
|
||||
},
|
||||
newPasswordLabel: {
|
||||
id: 'newPasswordLabel',
|
||||
defaultMessage: 'New password:'
|
||||
// defaultMessage: 'Новый пароль:'
|
||||
},
|
||||
repeatNewPasswordLabel: {
|
||||
id: 'repeatNewPasswordLabel',
|
||||
defaultMessage: 'Repeat the password:'
|
||||
// defaultMessage: 'Повторите указанный пароль:'
|
||||
},
|
||||
logoutOnAllDevices: {
|
||||
id: 'logoutOnAllDevices',
|
||||
defaultMessage: 'Logout on all devices'
|
||||
}
|
||||
});
|
@ -22,6 +22,7 @@ export default class User {
|
||||
username: '',
|
||||
email: '',
|
||||
avatar: '',
|
||||
lang: '',
|
||||
goal: null, // the goal with wich user entered site
|
||||
isGuest: true,
|
||||
isActive: true,
|
||||
|
111
src/i18n/en.json
Normal file
111
src/i18n/en.json
Normal file
@ -0,0 +1,111 @@
|
||||
{
|
||||
"acceptRules": "I agree with {link}",
|
||||
"accountActivationTitle": "Account activation",
|
||||
"accountDescription": "Ely.by account allows you to get access to many Minecraft resources. Please, take care of your account safety. Use secure password and change it regularly.",
|
||||
"accountEmail": "Enter account E-mail",
|
||||
"accountPassword": "Account password",
|
||||
"accountPreferencesTitle": "Ely.by account preferences",
|
||||
"activationMailWasSent": "Please check {email} for the message with the last registration step",
|
||||
"alreadyReceivedCode": "Already received code",
|
||||
"approve": "Approve",
|
||||
"authForAppFailed": "Authorization for {appName} was failed",
|
||||
"authForAppSuccessful": "Authorization for {appName} was successfully completed",
|
||||
"change": "Change",
|
||||
"changeEmailButton": "Change E-mail",
|
||||
"changeEmailDescription": "To change current account E-mail you must first verify that you own the current address and then confirm the new one.",
|
||||
"changeEmailTitle": "Change E-mail",
|
||||
"changePasswordTitle": "Change password",
|
||||
"changeUsernameButton": "Change nickname",
|
||||
"changeUsernameDescription": "You can change your nickname to any arbitrary value. Remember that it is not recommended to take a nickname of already existing Mojang account.",
|
||||
"changeUsernameTitle": "Change nickname",
|
||||
"changeUsernameWarning": "Be careful: if you playing on the server with nickname binding, then after changing nickname you may lose all your progress.",
|
||||
"changedAt": "Changed {at}",
|
||||
"codePlaceholder": "Paste the code here",
|
||||
"components.auth.password.accountPassword": "Account password",
|
||||
"components.auth.password.forgotPassword": "Forgot password",
|
||||
"components.auth.password.forgotYourPassword": "forgot your password",
|
||||
"components.auth.password.invalidPassword": "You entered wrong account password.",
|
||||
"components.auth.password.passwordTitle": "Enter password",
|
||||
"components.auth.password.rememberMe": "Remember me on this device",
|
||||
"components.auth.password.signInButton": "Sign in",
|
||||
"components.auth.password.suggestResetPassword": "Are you have {link}?",
|
||||
"components.profile.changePassword.achievementLossWarning": "Are you cherish your game achievements, right?",
|
||||
"components.profile.changePassword.changePasswordButton": "Change password",
|
||||
"components.profile.changePassword.changePasswordDescription": "Please take a password, that will be different from your passwords on the other sites and will not be the same you are using to enter Minecraft game servers you are playing.",
|
||||
"components.profile.changePassword.changePasswordTitle": "Change password",
|
||||
"components.profile.changePassword.logoutOnAllDevices": "Logout on all devices",
|
||||
"components.profile.changePassword.newPasswordLabel": "New password:",
|
||||
"components.profile.changePassword.passwordRequirements": "Password must contain at least 8 characters. It can be any symbols — do not limit yourself, create an unpredictable password!",
|
||||
"components.profile.changePassword.repeatNewPasswordLabel": "Repeat the password:",
|
||||
"confirmEmail": "Confirm E-mail",
|
||||
"contactSupport": "Contact support",
|
||||
"copy": "Copy",
|
||||
"currentAccountEmail": "Current account E-mail address:",
|
||||
"currentPassword": "Enter current password",
|
||||
"decline": "Decline",
|
||||
"didNotReceivedEmail": "Did not received E-mail?",
|
||||
"disabled": "Disabled",
|
||||
"emailInvalid": "Email is invalid",
|
||||
"emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"emailNotAvailable": "This email is already registered.",
|
||||
"emailOrUsername": "E-mail or username",
|
||||
"emailRequired": "Email is required",
|
||||
"enterFinalizationCode": "The E-mail change confirmation code was sent to {email}. Please enter the code received into the field below:",
|
||||
"enterInitializationCode": "The E-mail with an initialization code for E-mail change procedure was sent to {email}. Please enter the code into the field below:",
|
||||
"enterNewEmail": "Then provide your new E-mail address, that you want to use with this account. You will be mailed with confirmation code.",
|
||||
"enterTheCode": "Enter the code from E-mail here",
|
||||
"forgotPasswordMessage": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"forgotPasswordTitle": "Forgot password",
|
||||
"forgotYourPassword": "forgot your password",
|
||||
"goToAuth": "Go to auth",
|
||||
"invalidPassword": "You have entered wrong account password.",
|
||||
"keyNotExists": "The key is incorrect",
|
||||
"keyRequired": "Please, enter an activation key",
|
||||
"loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"loginRequired": "Please enter email or username",
|
||||
"loginTitle": "Sign in",
|
||||
"logout": "Logout",
|
||||
"mojangPriorityWarning": "A Mojang account with the same nickname was found. According to project rules, account owner has the right to demand the restoration of control over nickname.",
|
||||
"newEmailPlaceholder": "Enter new E-mail",
|
||||
"newPassword": "Enter new password",
|
||||
"newPasswordRequired": "Please enter new password",
|
||||
"newRePassword": "Repeat new password",
|
||||
"newRePasswordRequired": "Please repeat new password",
|
||||
"next": "Next",
|
||||
"nickname": "Nickname",
|
||||
"oldHashingAlgoWarning": "Your was hashed with an old hashing algorithm.<br />Please, change password.",
|
||||
"passCodeToApp": "To complete authorization process, please, provide the following code to {appName}",
|
||||
"password": "Password",
|
||||
"passwordChangeMessage": "To enhance the security of your account, please change your password.",
|
||||
"passwordRequired": "Please enter password",
|
||||
"passwordTooShort": "Your password is too short",
|
||||
"passwordsDoesNotMatch": "The passwords does not match",
|
||||
"permissionsTitle": "Application permissions",
|
||||
"personalData": "Personal data",
|
||||
"pleaseEnterPassword": "Please, enter your current password",
|
||||
"preferencesDescription": "Here you can change the key preferences of your account. Please note that all actions must be confirmed by entering a password.",
|
||||
"pressButtonToStart": "Press the button below to send a message with the code for E-mail change initialization.",
|
||||
"rePasswordRequired": "Please retype your password",
|
||||
"register": "Join",
|
||||
"registerTitle": "Sign Up",
|
||||
"repeatPassword": "Repeat password",
|
||||
"rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"scope_minecraft_server_session": "Authorization data for minecraft server",
|
||||
"scope_offline_access": "Access to your profile data, when you offline",
|
||||
"sendEmailButton": "Send E-mail",
|
||||
"sendMail": "Send mail",
|
||||
"signUpButton": "Register",
|
||||
"skipThisStep": "Skip password changing",
|
||||
"suggestResetPassword": "Are you have {link}?",
|
||||
"termsOfService": "Terms of service",
|
||||
"theAppNeedsAccess1": "This application needs access",
|
||||
"theAppNeedsAccess2": "to your data",
|
||||
"title": "Confirm your action",
|
||||
"twoFactorAuth": "Two factor auth",
|
||||
"usernameRequired": "Username is required",
|
||||
"usernameUnavailable": "This username is already taken",
|
||||
"waitAppReaction": "Please, wait till your application response",
|
||||
"youAuthorizedAs": "You authorized as:",
|
||||
"yourEmail": "Your E-mail",
|
||||
"yourNickname": "Your nickname"
|
||||
}
|
111
src/i18n/ru.json
Normal file
111
src/i18n/ru.json
Normal file
@ -0,0 +1,111 @@
|
||||
{
|
||||
"acceptRules": "I agree with {link}",
|
||||
"accountActivationTitle": "Account activation",
|
||||
"accountDescription": "Ely.by account allows you to get access to many Minecraft resources. Please, take care of your account safety. Use secure password and change it regularly.",
|
||||
"accountEmail": "Enter account E-mail",
|
||||
"accountPassword": "Account password",
|
||||
"accountPreferencesTitle": "Ely.by account preferences",
|
||||
"activationMailWasSent": "Please check {email} for the message with the last registration step",
|
||||
"alreadyReceivedCode": "Already received code",
|
||||
"approve": "Approve",
|
||||
"authForAppFailed": "Authorization for {appName} was failed",
|
||||
"authForAppSuccessful": "Authorization for {appName} was successfully completed",
|
||||
"change": "Change",
|
||||
"changeEmailButton": "Change E-mail",
|
||||
"changeEmailDescription": "To change current account E-mail you must first verify that you own the current address and then confirm the new one.",
|
||||
"changeEmailTitle": "Change E-mail",
|
||||
"changePasswordTitle": "Change password",
|
||||
"changeUsernameButton": "Change nickname",
|
||||
"changeUsernameDescription": "You can change your nickname to any arbitrary value. Remember that it is not recommended to take a nickname of already existing Mojang account.",
|
||||
"changeUsernameTitle": "Change nickname",
|
||||
"changeUsernameWarning": "Be careful: if you playing on the server with nickname binding, then after changing nickname you may lose all your progress.",
|
||||
"changedAt": "Changed {at}",
|
||||
"codePlaceholder": "Paste the code here",
|
||||
"components.auth.password.accountPassword": "Account password",
|
||||
"components.auth.password.forgotPassword": "Forgot password",
|
||||
"components.auth.password.forgotYourPassword": "forgot your password",
|
||||
"components.auth.password.invalidPassword": "You entered wrong account password.",
|
||||
"components.auth.password.passwordTitle": "Enter password",
|
||||
"components.auth.password.rememberMe": "Remember me on this device",
|
||||
"components.auth.password.signInButton": "Sign in",
|
||||
"components.auth.password.suggestResetPassword": "Are you have {link}?",
|
||||
"components.profile.changePassword.achievementLossWarning": "Вы ведь дорожите своими игровыми достижениями?",
|
||||
"components.profile.changePassword.changePasswordButton": "Сменить пароль",
|
||||
"components.profile.changePassword.changePasswordDescription": "Придумайте пароль, который будет отличаться от ваших паролей на других сайтах и не будет совпадаеть с тем паролем, который вы используете для входа на различные игровые сервера Minecraft.",
|
||||
"components.profile.changePassword.changePasswordTitle": "Смена пароля",
|
||||
"components.profile.changePassword.logoutOnAllDevices": "Вылогиниться на всех устройствах",
|
||||
"components.profile.changePassword.newPasswordLabel": "Новый пароль:",
|
||||
"components.profile.changePassword.passwordRequirements": "Пароль должен содержать не менее 8 символов. Это могут быть любым символы — не ограничивайте себя, придумайте непредсказуемый пароль!",
|
||||
"components.profile.changePassword.repeatNewPasswordLabel": "Повторите указанный пароль:",
|
||||
"confirmEmail": "Confirm E-mail",
|
||||
"contactSupport": "Contact support",
|
||||
"copy": "Copy",
|
||||
"currentAccountEmail": "Current account E-mail address:",
|
||||
"currentPassword": "Enter current password",
|
||||
"decline": "Decline",
|
||||
"didNotReceivedEmail": "Did not received E-mail?",
|
||||
"disabled": "Disabled",
|
||||
"emailInvalid": "Email is invalid",
|
||||
"emailIsTempmail": "Tempmail E-mail addresses is not allowed",
|
||||
"emailNotAvailable": "This email is already registered.",
|
||||
"emailOrUsername": "E-mail or username",
|
||||
"emailRequired": "Email is required",
|
||||
"enterFinalizationCode": "The E-mail change confirmation code was sent to {email}. Please enter the code received into the field below:",
|
||||
"enterInitializationCode": "The E-mail with an initialization code for E-mail change procedure was sent to {email}. Please enter the code into the field below:",
|
||||
"enterNewEmail": "Then provide your new E-mail address, that you want to use with this account. You will be mailed with confirmation code.",
|
||||
"enterTheCode": "Enter the code from E-mail here",
|
||||
"forgotPasswordMessage": "Specify the registration E-mail address for your account and we will send an email with instructions for further password recovery.",
|
||||
"forgotPasswordTitle": "Forgot password",
|
||||
"forgotYourPassword": "forgot your password",
|
||||
"goToAuth": "Go to auth",
|
||||
"invalidPassword": "You have entered wrong account password.",
|
||||
"keyNotExists": "The key is incorrect",
|
||||
"keyRequired": "Please, enter an activation key",
|
||||
"loginNotExist": "Sorry, Ely doesn't recognise your login.",
|
||||
"loginRequired": "Please enter email or username",
|
||||
"loginTitle": "Sign in",
|
||||
"logout": "Logout",
|
||||
"mojangPriorityWarning": "A Mojang account with the same nickname was found. According to project rules, account owner has the right to demand the restoration of control over nickname.",
|
||||
"newEmailPlaceholder": "Enter new E-mail",
|
||||
"newPassword": "Enter new password",
|
||||
"newPasswordRequired": "Please enter new password",
|
||||
"newRePassword": "Repeat new password",
|
||||
"newRePasswordRequired": "Please repeat new password",
|
||||
"next": "Next",
|
||||
"nickname": "Nickname",
|
||||
"oldHashingAlgoWarning": "Your was hashed with an old hashing algorithm.<br />Please, change password.",
|
||||
"passCodeToApp": "To complete authorization process, please, provide the following code to {appName}",
|
||||
"password": "Password",
|
||||
"passwordChangeMessage": "To enhance the security of your account, please change your password.",
|
||||
"passwordRequired": "Please enter password",
|
||||
"passwordTooShort": "Your password is too short",
|
||||
"passwordsDoesNotMatch": "The passwords does not match",
|
||||
"permissionsTitle": "Application permissions",
|
||||
"personalData": "Personal data",
|
||||
"pleaseEnterPassword": "Please, enter your current password",
|
||||
"preferencesDescription": "Here you can change the key preferences of your account. Please note that all actions must be confirmed by entering a password.",
|
||||
"pressButtonToStart": "Press the button below to send a message with the code for E-mail change initialization.",
|
||||
"rePasswordRequired": "Please retype your password",
|
||||
"register": "Join",
|
||||
"registerTitle": "Sign Up",
|
||||
"repeatPassword": "Repeat password",
|
||||
"rulesAgreementRequired": "You must accept rules in order to create an account",
|
||||
"scope_minecraft_server_session": "Authorization data for minecraft server",
|
||||
"scope_offline_access": "Access to your profile data, when you offline",
|
||||
"sendEmailButton": "Send E-mail",
|
||||
"sendMail": "Send mail",
|
||||
"signUpButton": "Register",
|
||||
"skipThisStep": "Skip password changing",
|
||||
"suggestResetPassword": "Are you have {link}?",
|
||||
"termsOfService": "Terms of service",
|
||||
"theAppNeedsAccess1": "This application needs access",
|
||||
"theAppNeedsAccess2": "to your data",
|
||||
"title": "Confirm your action",
|
||||
"twoFactorAuth": "Two factor auth",
|
||||
"usernameRequired": "Username is required",
|
||||
"usernameUnavailable": "This username is already taken",
|
||||
"waitAppReaction": "Please, wait till your application response",
|
||||
"youAuthorizedAs": "You authorized as:",
|
||||
"yourEmail": "Your E-mail",
|
||||
"yourNickname": "Your nickname"
|
||||
}
|
60
src/index.js
60
src/index.js
@ -15,7 +15,9 @@ import thunk from 'redux-thunk';
|
||||
import { Router, browserHistory } from 'react-router';
|
||||
import { syncHistory, routeReducer } from 'react-router-redux';
|
||||
|
||||
import { IntlProvider } from 'react-intl';
|
||||
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||
import enLocaleData from 'react-intl/locale-data/en';
|
||||
import ruLocaleData from 'react-intl/locale-data/ru';
|
||||
|
||||
import reducers from 'reducers';
|
||||
import routesFactory from 'routes';
|
||||
@ -32,23 +34,47 @@ const store = applyMiddleware(
|
||||
thunk
|
||||
)(createStore)(reducer);
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// some shortcuts for testing on localhost
|
||||
addLocaleData(enLocaleData);
|
||||
addLocaleData(ruLocaleData);
|
||||
|
||||
window.testOAuth = () => location.href = '/oauth?client_id=ely&redirect_uri=http%3A%2F%2Fely.by&response_type=code&scope=minecraft_server_session';
|
||||
// TODO: bind with user state
|
||||
const SUPPORTED_LANGUAGES = ['ru', 'en'];
|
||||
const DEFAULT_LANGUAGE = 'en';
|
||||
const state = store.getState();
|
||||
function getUserLanguages() {
|
||||
return [].concat(state.user.lang || [])
|
||||
.concat(navigator.languages || [])
|
||||
.concat(navigator.language || []);
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<IntlProvider locale="en" messages={{}}>
|
||||
<ReduxProvider store={store}>
|
||||
<Router history={browserHistory}>
|
||||
{routesFactory(store)}
|
||||
</Router>
|
||||
</ReduxProvider>
|
||||
</IntlProvider>,
|
||||
document.getElementById('app')
|
||||
);
|
||||
function detectLanguage(userLanguages, availableLanguages, defaultLanguage) {
|
||||
return (userLanguages || [])
|
||||
.concat(defaultLanguage)
|
||||
.map((lang) => lang.split('-').shift().toLowerCase())
|
||||
.find((lang) => availableLanguages.indexOf(lang) !== -1);
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
document.getElementById('loader').classList.remove('is-active');
|
||||
}, 50);
|
||||
const locale = detectLanguage(getUserLanguages(), SUPPORTED_LANGUAGES, DEFAULT_LANGUAGE);
|
||||
|
||||
new Promise(require(`bundle!i18n/${locale}.json`))
|
||||
.then((messages) => {
|
||||
ReactDOM.render(
|
||||
<IntlProvider locale={locale} messages={messages}>
|
||||
<ReduxProvider store={store}>
|
||||
<Router history={browserHistory}>
|
||||
{routesFactory(store)}
|
||||
</Router>
|
||||
</ReduxProvider>
|
||||
</IntlProvider>,
|
||||
document.getElementById('app')
|
||||
);
|
||||
|
||||
document.getElementById('loader').classList.remove('is-active');
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
// some shortcuts for testing on localhost
|
||||
window.testOAuth = () => location.href = '/oauth?client_id=ely&redirect_uri=http%3A%2F%2Fely.by&response_type=code&scope=minecraft_server_session';
|
||||
}
|
||||
|
@ -156,15 +156,26 @@ var webpackConfig = {
|
||||
},
|
||||
{
|
||||
test: /\.json$/,
|
||||
exclude: /intl\.json/,
|
||||
loader: 'json'
|
||||
},
|
||||
{
|
||||
test: /\.html$/,
|
||||
loader: 'html'
|
||||
},
|
||||
{
|
||||
test: /\.intl\.json$/,
|
||||
loader: 'babel!intl-loader!json'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
resolveLoader: {
|
||||
alias: {
|
||||
'intl-loader': path.resolve('./webpack/intl-loader')
|
||||
}
|
||||
},
|
||||
|
||||
sassLoader: {
|
||||
importer: iconfontImporter({
|
||||
test: /\.font.(js|json)$/,
|
||||
|
21
webpack/intl-loader.js
Normal file
21
webpack/intl-loader.js
Normal file
@ -0,0 +1,21 @@
|
||||
module.exports = function() {
|
||||
this.cacheable && this.cacheable();
|
||||
|
||||
var moduleId = this.context
|
||||
.replace(this.options.resolve.root, '')
|
||||
.replace(/^\/|\/$/g, '')
|
||||
.replace(/\//g, '.');
|
||||
|
||||
var content = this.inputValue[0];
|
||||
content = JSON.stringify(Object.keys(content).reduce(function(translations, key) {
|
||||
translations[key] = {
|
||||
id: moduleId + '.' + key,
|
||||
defaultMessage: content[key]
|
||||
};
|
||||
|
||||
return translations;
|
||||
}, {}));
|
||||
|
||||
return 'import { defineMessages } from \'react-intl\';'
|
||||
+ 'export default defineMessages(' + content + ')';
|
||||
};
|
Loading…
Reference in New Issue
Block a user