mirror of
https://github.com/elyby/emails-renderer.git
synced 2024-12-22 13:19:45 +05:30
Support of styling and i18n
This commit is contained in:
parent
bfcf4971f6
commit
f64539d6f3
@ -188,7 +188,7 @@
|
|||||||
"react/jsx-max-props-per-line": ["warn", {"maximum": 3}],
|
"react/jsx-max-props-per-line": ["warn", {"maximum": 3}],
|
||||||
"react/jsx-no-bind": "warn",
|
"react/jsx-no-bind": "warn",
|
||||||
"react/jsx-no-duplicate-props": "warn",
|
"react/jsx-no-duplicate-props": "warn",
|
||||||
"react/jsx-no-literals": "warn",
|
"react/jsx-no-literals": "off",
|
||||||
"react/jsx-no-undef": "warn",
|
"react/jsx-no-undef": "warn",
|
||||||
"react/jsx-pascal-case": "warn",
|
"react/jsx-pascal-case": "warn",
|
||||||
"react/jsx-uses-react": "warn",
|
"react/jsx-uses-react": "warn",
|
||||||
@ -206,7 +206,7 @@
|
|||||||
"react/no-unknown-property": "warn",
|
"react/no-unknown-property": "warn",
|
||||||
"react/prefer-es6-class": "warn",
|
"react/prefer-es6-class": "warn",
|
||||||
"react/prop-types": "warn",
|
"react/prop-types": "warn",
|
||||||
"react/react-in-jsx-scope": "warn",
|
"react/react-in-jsx-scope": "off",
|
||||||
"react/self-closing-comp": "warn",
|
"react/self-closing-comp": "warn",
|
||||||
"react/sort-comp": ["warn", {"order": ["lifecycle", "render", "everything-else"]}]
|
"react/sort-comp": ["warn", {"order": ["lifecycle", "render", "everything-else"]}]
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
"up": "npm update",
|
"up": "npm update",
|
||||||
"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",
|
"i18n": "cd ./scripts && ../node_modules/.bin/babel-node i18n-collect.js",
|
||||||
"build": "rm -rf dist/ && NODE_ENV=production webpack --progress --colors",
|
"build": "rm -rf dist/ && NODE_ENV=production webpack --progress --colors",
|
||||||
"render": ""
|
"render": ""
|
||||||
},
|
},
|
||||||
|
@ -52,38 +52,35 @@ let keysToAdd = [];
|
|||||||
let keysToRemove = [];
|
let keysToRemove = [];
|
||||||
const keysToRename = [];
|
const keysToRename = [];
|
||||||
const isNotMarked = (value) => value.slice(0, 2) !== '--';
|
const isNotMarked = (value) => value.slice(0, 2) !== '--';
|
||||||
try {
|
|
||||||
const prevMessages = JSON.parse(fs.readFileSync(defaultMessagesPath, 'utf8'));
|
|
||||||
const prevMessagesMap = Object.entries(prevMessages).reduce((acc, [key, value]) => {
|
|
||||||
if (acc[value]) {
|
|
||||||
acc[value].push(key);
|
|
||||||
} else {
|
|
||||||
acc[value] = [key];
|
|
||||||
}
|
|
||||||
|
|
||||||
return acc;
|
const prevMessages = readJSON(defaultMessagesPath);
|
||||||
}, {});
|
const prevMessagesMap = Object.entries(prevMessages).reduce((acc, [key, value]) => {
|
||||||
keysToAdd = Object.keys(collectedMessages).filter((key) => !prevMessages[key]);
|
if (acc[value]) {
|
||||||
keysToRemove = Object.keys(prevMessages).filter((key) => !collectedMessages[key]).filter(isNotMarked);
|
acc[value].push(key);
|
||||||
keysToUpdate = Object.entries(prevMessages).reduce((acc, [key, message]) =>
|
} else {
|
||||||
acc.concat(collectedMessages[key] && collectedMessages[key] !== message ? key : [])
|
acc[value] = [key];
|
||||||
, []);
|
}
|
||||||
|
|
||||||
// detect keys to rename, mutating keysToAdd and keysToRemove
|
return acc;
|
||||||
[].concat(keysToAdd).forEach((toKey) => {
|
}, {});
|
||||||
const keys = prevMessagesMap[collectedMessages[toKey]] || [];
|
keysToAdd = Object.keys(collectedMessages).filter((key) => !prevMessages[key]);
|
||||||
const fromKey = keys.find((fromKey) => keysToRemove.indexOf(fromKey) > -1);
|
keysToRemove = Object.keys(prevMessages).filter((key) => !collectedMessages[key]).filter(isNotMarked);
|
||||||
|
keysToUpdate = Object.entries(prevMessages).reduce((acc, [key, message]) =>
|
||||||
|
acc.concat(collectedMessages[key] && collectedMessages[key] !== message ? key : [])
|
||||||
|
, []);
|
||||||
|
|
||||||
if (fromKey) {
|
// detect keys to rename, mutating keysToAdd and keysToRemove
|
||||||
keysToRename.push([fromKey, toKey]);
|
[].concat(keysToAdd).forEach((toKey) => {
|
||||||
|
const keys = prevMessagesMap[collectedMessages[toKey]] || [];
|
||||||
|
const fromKey = keys.find((fromKey) => keysToRemove.indexOf(fromKey) > -1);
|
||||||
|
|
||||||
keysToRemove.splice(keysToRemove.indexOf(fromKey), 1);
|
if (fromKey) {
|
||||||
keysToAdd.splice(keysToAdd.indexOf(toKey), 1);
|
keysToRename.push([fromKey, toKey]);
|
||||||
}
|
|
||||||
});
|
keysToRemove.splice(keysToRemove.indexOf(fromKey), 1);
|
||||||
} catch (err) {
|
keysToAdd.splice(keysToAdd.indexOf(toKey), 1);
|
||||||
console.log(chalk.yellow(`Can not read ${defaultMessagesPath}. The new file will be created.`), err);
|
}
|
||||||
}
|
});
|
||||||
|
|
||||||
if (!keysToAdd.length && !keysToRemove.length && !keysToUpdate.length && !keysToRename.length) {
|
if (!keysToAdd.length && !keysToRemove.length && !keysToUpdate.length && !keysToRename.length) {
|
||||||
return console.log(chalk.green('Everything is up to date!'));
|
return console.log(chalk.green('Everything is up to date!'));
|
||||||
@ -142,13 +139,7 @@ function buildLocales() {
|
|||||||
|
|
||||||
SUPPORTED_LANGS.map((lang) => {
|
SUPPORTED_LANGS.map((lang) => {
|
||||||
const destPath = `${LANG_DIR}/${lang}.json`;
|
const destPath = `${LANG_DIR}/${lang}.json`;
|
||||||
|
const newMessages = readJSON(destPath);
|
||||||
let newMessages = {};
|
|
||||||
try {
|
|
||||||
newMessages = JSON.parse(fs.readFileSync(destPath, 'utf8'));
|
|
||||||
} catch (err) {
|
|
||||||
console.log(chalk.yellow(`Can not read ${destPath}. The new file will be created.`), err);
|
|
||||||
}
|
|
||||||
|
|
||||||
keysToRename.forEach(([fromKey, toKey]) => {
|
keysToRename.forEach(([fromKey, toKey]) => {
|
||||||
newMessages[toKey] = newMessages[fromKey];
|
newMessages[toKey] = newMessages[fromKey];
|
||||||
@ -181,3 +172,13 @@ function buildLocales() {
|
|||||||
fs.writeFileSync(destPath, JSON.stringify(sortedNewMessages, null, 4) + '\n');
|
fs.writeFileSync(destPath, JSON.stringify(sortedNewMessages, null, 4) + '\n');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readJSON(destPath) {
|
||||||
|
try {
|
||||||
|
return JSON.parse(fs.readFileSync(destPath, 'utf8'));
|
||||||
|
} catch (err) {
|
||||||
|
console.log(chalk.yellow(`Can not read ${destPath}. The new file will be created.`), `(${err.message})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
51
src/App.jsx
Normal file
51
src/App.jsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { PropTypes } from 'react';
|
||||||
|
|
||||||
|
import { IntlProvider, addLocaleData } from 'react-intl';
|
||||||
|
|
||||||
|
import enLocaleData from 'react-intl/locale-data/en';
|
||||||
|
import ruLocaleData from 'react-intl/locale-data/ru';
|
||||||
|
import beLocaleData from 'react-intl/locale-data/be';
|
||||||
|
import ukLocaleData from 'react-intl/locale-data/uk';
|
||||||
|
|
||||||
|
// till we have not so many locales, we can require their data at once
|
||||||
|
addLocaleData(enLocaleData);
|
||||||
|
addLocaleData(ruLocaleData);
|
||||||
|
addLocaleData(beLocaleData);
|
||||||
|
addLocaleData(ukLocaleData);
|
||||||
|
|
||||||
|
const SUPPORTED_LANGUAGES = ['ru', 'en', 'be', 'uk'];
|
||||||
|
const DEFAULT_LANGUAGE = 'en';
|
||||||
|
|
||||||
|
export default function App({type, payload = {}, debug = false}) {
|
||||||
|
let {locale} = payload;
|
||||||
|
|
||||||
|
if (!locale || SUPPORTED_LANGUAGES.indexOf(locale) === -1) {
|
||||||
|
locale = DEFAULT_LANGUAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
const messages = require(`i18n/${locale}.json`);
|
||||||
|
const Email = require(`emails/${type}/index`).default;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<IntlProvider locale={locale} messages={messages}>
|
||||||
|
{debug
|
||||||
|
? (
|
||||||
|
<div>
|
||||||
|
Hello world
|
||||||
|
<Email {...payload} />
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Email {...payload} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</IntlProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
App.propTypes = {
|
||||||
|
type: PropTypes.string.isRequired,
|
||||||
|
payload: PropTypes.shape({
|
||||||
|
locale: PropTypes.string
|
||||||
|
}),
|
||||||
|
debug: PropTypes.bool
|
||||||
|
};
|
@ -1,7 +1,18 @@
|
|||||||
|
import { PropTypes } from 'react';
|
||||||
|
|
||||||
|
import { FormattedMessage as Message } from 'react-intl';
|
||||||
|
|
||||||
|
import styles from './styles';
|
||||||
|
import messages from './messages.intl.json';
|
||||||
|
|
||||||
export default function Register({username}) {
|
export default function Register({username}) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div style={styles.container}>
|
||||||
You Have Been Registered, {username}!
|
<Message {...messages.you_registered_as} values={{username}} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Register.propTypes = {
|
||||||
|
username: PropTypes.string
|
||||||
|
};
|
||||||
|
3
src/emails/register/messages.intl.json
Normal file
3
src/emails/register/messages.intl.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"you_registered_as": "You have been registered as {username}"
|
||||||
|
}
|
8
src/emails/register/styles.js
Normal file
8
src/emails/register/styles.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
export default {
|
||||||
|
container: {
|
||||||
|
padding: '10px',
|
||||||
|
margin: '10px',
|
||||||
|
background: '#f7f7f7',
|
||||||
|
border: '1px #ddd solid',
|
||||||
|
}
|
||||||
|
};
|
3
src/i18n/be.json
Normal file
3
src/i18n/be.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"emails.register.you_registered_as": "Вы былі зарэгістраваныя як {username}"
|
||||||
|
}
|
3
src/i18n/en.json
Normal file
3
src/i18n/en.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"emails.register.you_registered_as": "You have been registered as {username}"
|
||||||
|
}
|
3
src/i18n/ru.json
Normal file
3
src/i18n/ru.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"emails.register.you_registered_as": "Вы были зарегистрированы как {username}"
|
||||||
|
}
|
3
src/i18n/uk.json
Normal file
3
src/i18n/uk.json
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"emails.register.you_registered_as": "Ви були зареєстровані як {username}"
|
||||||
|
}
|
25
src/index.js
25
src/index.js
@ -1,35 +1,20 @@
|
|||||||
import 'babel-polyfill';
|
import 'babel-polyfill';
|
||||||
|
|
||||||
import React from 'react';
|
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import ReactDOMServer from 'react-dom/server';
|
import ReactDOMServer from 'react-dom/server';
|
||||||
|
|
||||||
import { IntlProvider } from 'react-intl';
|
import App from 'App';
|
||||||
|
|
||||||
import Register from 'emails/register';
|
|
||||||
|
|
||||||
const isCli = typeof window === 'undefined';
|
const isCli = typeof window === 'undefined';
|
||||||
|
|
||||||
const App = ({type, payload = {}}) => (
|
|
||||||
<IntlProvider locale="en" messages={{}}>
|
|
||||||
{isCli
|
|
||||||
? (
|
|
||||||
<Register {...payload} />
|
|
||||||
) : (
|
|
||||||
<div>
|
|
||||||
Hello world
|
|
||||||
<Register {...payload} />
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
</IntlProvider>
|
|
||||||
);
|
|
||||||
|
|
||||||
if (isCli) {
|
if (isCli) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
default: (props) =>
|
default: (props) =>
|
||||||
ReactDOMServer.renderToStaticMarkup(<App {...props} />)
|
ReactDOMServer.renderToStaticMarkup(<App {...props} />)
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
ReactDOM.render(<App />, document.getElementById('app'));
|
ReactDOM.render(
|
||||||
|
<App type="register" payload={{locale: 'ru'}} debug />,
|
||||||
|
document.getElementById('app')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user