mirror of
https://github.com/elyby/accounts-frontend.git
synced 2025-05-31 14:11:58 +05:30
Basic functionality for locale change. Draft implementation of tools for working with i18n
This commit is contained in:
@@ -8,10 +8,11 @@
|
|||||||
"license": "UNLICENSED",
|
"license": "UNLICENSED",
|
||||||
"repository": "git@bitbucket.org:ErickSkrauch/ely.by-account.git",
|
"repository": "git@bitbucket.org:ErickSkrauch/ely.by-account.git",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "webpack-dev-server --progress --colors",
|
"start": "rm -rf dist/ && webpack-dev-server --progress --colors",
|
||||||
"up": "npm install",
|
"up": "npm install",
|
||||||
"test": "karma start ./karma.conf.js",
|
"test": "karma start ./karma.conf.js",
|
||||||
"lint": "eslint ./src",
|
"lint": "eslint ./src",
|
||||||
|
"i18n": "cd ./scripts && ./node_modules/.bin/babel-node i18n-collect.js",
|
||||||
"build": "rm -rf dist/ && webpack --progress --colors -p"
|
"build": "rm -rf dist/ && webpack --progress --colors -p"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -44,6 +45,7 @@
|
|||||||
"babel-preset-react-hmre": "^1.0.1",
|
"babel-preset-react-hmre": "^1.0.1",
|
||||||
"babel-preset-stage-0": "^6.3.13",
|
"babel-preset-stage-0": "^6.3.13",
|
||||||
"babel-runtime": "^5.6.15",
|
"babel-runtime": "^5.6.15",
|
||||||
|
"bundle-loader": "^0.5.4",
|
||||||
"chai": "^3.0.0",
|
"chai": "^3.0.0",
|
||||||
"chokidar": "^1.2.0",
|
"chokidar": "^1.2.0",
|
||||||
"css-loader": "^0.23.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 { Input } from 'components/ui/form';
|
||||||
|
|
||||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
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';
|
import messages from './Login.messages';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
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 BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
import styles from './password.scss';
|
import styles from './password.scss';
|
||||||
import messages from './Password.messages';
|
import messages from './Password.intl.json';
|
||||||
|
|
||||||
class Body extends BaseAuthBody {
|
class Body extends BaseAuthBody {
|
||||||
static displayName = 'PasswordBody';
|
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 { Input, Checkbox } from 'components/ui/form';
|
||||||
|
|
||||||
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
import BaseAuthBody from 'components/auth/BaseAuthBody';
|
||||||
|
import passwordMessages from 'components/auth/password/Password.intl.json';
|
||||||
import activationMessages from 'components/auth/activation/Activation.messages';
|
import activationMessages from 'components/auth/activation/Activation.messages';
|
||||||
import messages from './Register.messages';
|
import messages from './Register.messages';
|
||||||
|
|
||||||
@@ -44,7 +45,7 @@ class Body extends BaseAuthBody {
|
|||||||
color="blue"
|
color="blue"
|
||||||
type="password"
|
type="password"
|
||||||
required
|
required
|
||||||
placeholder={messages.accountPassword}
|
placeholder={passwordMessages.accountPassword}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input {...this.bindField('rePassword')}
|
<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 { Input, Button, Checkbox, Form, FormModel } from 'components/ui/form';
|
||||||
|
|
||||||
import styles from 'components/profile/profileForm.scss';
|
import styles from 'components/profile/profileForm.scss';
|
||||||
import messages from './ChangePassword.messages';
|
import messages from './ChangePassword.intl.json';
|
||||||
|
|
||||||
export default class ChangePassword extends Component {
|
export default class ChangePassword extends Component {
|
||||||
static displayName = 'ChangePassword';
|
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: '',
|
username: '',
|
||||||
email: '',
|
email: '',
|
||||||
avatar: '',
|
avatar: '',
|
||||||
|
lang: '',
|
||||||
goal: null, // the goal with wich user entered site
|
goal: null, // the goal with wich user entered site
|
||||||
isGuest: true,
|
isGuest: true,
|
||||||
isActive: 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"
|
||||||
|
}
|
44
src/index.js
44
src/index.js
@@ -15,7 +15,9 @@ import thunk from 'redux-thunk';
|
|||||||
import { Router, browserHistory } from 'react-router';
|
import { Router, browserHistory } from 'react-router';
|
||||||
import { syncHistory, routeReducer } from 'react-router-redux';
|
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 reducers from 'reducers';
|
||||||
import routesFactory from 'routes';
|
import routesFactory from 'routes';
|
||||||
@@ -32,14 +34,32 @@ const store = applyMiddleware(
|
|||||||
thunk
|
thunk
|
||||||
)(createStore)(reducer);
|
)(createStore)(reducer);
|
||||||
|
|
||||||
if (process.env.NODE_ENV !== 'production') {
|
addLocaleData(enLocaleData);
|
||||||
// some shortcuts for testing on localhost
|
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(
|
function detectLanguage(userLanguages, availableLanguages, defaultLanguage) {
|
||||||
<IntlProvider locale="en" messages={{}}>
|
return (userLanguages || [])
|
||||||
|
.concat(defaultLanguage)
|
||||||
|
.map((lang) => lang.split('-').shift().toLowerCase())
|
||||||
|
.find((lang) => availableLanguages.indexOf(lang) !== -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
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}>
|
<ReduxProvider store={store}>
|
||||||
<Router history={browserHistory}>
|
<Router history={browserHistory}>
|
||||||
{routesFactory(store)}
|
{routesFactory(store)}
|
||||||
@@ -47,8 +67,14 @@ ReactDOM.render(
|
|||||||
</ReduxProvider>
|
</ReduxProvider>
|
||||||
</IntlProvider>,
|
</IntlProvider>,
|
||||||
document.getElementById('app')
|
document.getElementById('app')
|
||||||
);
|
);
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
document.getElementById('loader').classList.remove('is-active');
|
document.getElementById('loader').classList.remove('is-active');
|
||||||
}, 50);
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
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$/,
|
test: /\.json$/,
|
||||||
|
exclude: /intl\.json/,
|
||||||
loader: 'json'
|
loader: 'json'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
test: /\.html$/,
|
test: /\.html$/,
|
||||||
loader: 'html'
|
loader: 'html'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.intl\.json$/,
|
||||||
|
loader: 'babel!intl-loader!json'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
resolveLoader: {
|
||||||
|
alias: {
|
||||||
|
'intl-loader': path.resolve('./webpack/intl-loader')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
sassLoader: {
|
sassLoader: {
|
||||||
importer: iconfontImporter({
|
importer: iconfontImporter({
|
||||||
test: /\.font.(js|json)$/,
|
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 + ')';
|
||||||
|
};
|
Reference in New Issue
Block a user