Merge pull request #586 from coralproject/i18n-refactor

Refactor i18n
This commit is contained in:
Kiwi
2017-05-29 21:59:52 +07:00
committed by GitHub
122 changed files with 1499 additions and 1681 deletions
@@ -3,14 +3,16 @@ import styles from './ModerationList.css';
import {Button} from 'coral-ui';
import {menuActionsMap} from '../containers/ModerationQueue/helpers/moderationQueueActionsMap';
import t from 'coral-framework/services/i18n';
const ActionButton = ({type = '', active, ...props}) => {
const typeName = type.toLowerCase();
let text = menuActionsMap[type].text;
if (text === 'Approve' && active) {
text = 'Approved';
} else if (text === 'Reject' && active) {
text = 'Rejected';
if (text === 'approve' && active) {
text = 'approved';
} else if (text === 'reject' && active) {
text = 'rejected';
}
return (
@@ -19,7 +21,7 @@ const ActionButton = ({type = '', active, ...props}) => {
cStyle={typeName}
icon={menuActionsMap[type].icon}
onClick={type === 'APPROVE' ? props.acceptComment : props.rejectComment}
>{text}</Button>
>{t(`modqueue.${text}`)}</Button>
);
};
@@ -5,9 +5,7 @@ import cn from 'classnames';
import {findDOMNode} from 'react-dom';
import styles from './ActionsMenu.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
let count = 0;
@@ -43,7 +41,7 @@ class ActionsMenu extends React.Component {
onClick={this.syncOpenState}
icon={this.props.icon}
raised>
{lang.t('modqueue.actions')}
{t('modqueue.actions')}
<Icon
name={this.state.open ? 'keyboard_arrow_up' : 'keyboard_arrow_down'}
className={styles.arrowIcon}
@@ -2,10 +2,8 @@ import React, {PropTypes} from 'react';
import Layout from 'coral-admin/src/components/ui/Layout';
import styles from './NotFound.css';
import {Button, TextField, Alert, Success} from 'coral-ui';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations';
import t from 'coral-framework/services/i18n';
import Recaptcha from 'react-recaptcha';
const lang = new I18n(translations);
class AdminLogin extends React.Component {
@@ -37,7 +35,7 @@ class AdminLogin extends React.Component {
const {errorMessage, loginMaxExceeded, recaptchaPublic} = this.props;
const signInForm = (
<form onSubmit={this.handleSignIn}>
{errorMessage && <Alert>{lang.t(`errors.${errorMessage}`)}</Alert>}
{errorMessage && <Alert>{t(`error.${errorMessage}`)}</Alert>}
<TextField
label='Email Address'
value={this.state.email}
@@ -1,10 +1,8 @@
import React, {PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
import styles from 'coral-admin/src/containers/Dashboard/Dashboard.css';
import {Icon} from 'coral-ui';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const refreshIntervalSeconds = 60 * 5;
class CountdownTimer extends React.Component {
@@ -74,7 +72,7 @@ class CountdownTimer extends React.Component {
className={styles.autoUpdate}
onClick={this.dismissNote}>
<b>×</b>
<Icon name='timer' /> <strong>{lang.t('dashboard.next-update', this.formatTime())}</strong> {lang.t('dashboard.auto-update')}
<Icon name='timer' /> <strong>{t('dashboard.next_update', this.formatTime())}</strong> {t('dashboard.auto_update')}
</p>
);
}
@@ -1,17 +1,14 @@
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations.json';
import React, {PropTypes} from 'react';
import Modal from 'components/Modal';
import styles from './ModerationKeysModal.css';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const shortcuts = [
{
title: 'modqueue.navigation',
shortcuts: {
'j': 'modqueue.nextcomment',
'k': 'modqueue.prevcomment',
'j': 'modqueue.next_comment',
'k': 'modqueue.prev_comment',
's': 'modqueue.singleview',
'?': 'modqueue.thismenu'
}
@@ -40,29 +37,29 @@ export default class ModerationKeysModal extends React.Component {
<div>
<div className={styles.callToAction} style={{display: shortcutsNoteVisible === 'show' ? 'block' : 'none'}}>
<div onClick={hideShortcutsNote} className={styles.closeButton}>×</div>
<p className={styles.ctaHeader}>{lang.t('modqueue.mod-faster')}</p>
<p><strong>{lang.t('modqueue.try-these')}:</strong></p>
<p className={styles.ctaHeader}>{t('modqueue.mod_faster')}</p>
<p><strong>{t('modqueue.try_these')}:</strong></p>
<ul>
<li><span>{lang.t('modqueue.approve')}</span> <span className={styles.smallKey}>t</span></li>
<li><span>{lang.t('modqueue.reject')}</span> <span className={styles.smallKey}>r</span></li>
<li><span>{t('modqueue.approve')}</span> <span className={styles.smallKey}>t</span></li>
<li><span>{t('modqueue.reject')}</span> <span className={styles.smallKey}>r</span></li>
</ul>
<p><span>{lang.t('modqueue.view-more-shortcuts')}</span> <span className={styles.smallKey}>{lang.t('modqueue.shift-key')}</span> + <span className={styles.smallKey}>/</span></p>
<p><span>{t('modqueue.view_more_shortcuts')}</span> <span className={styles.smallKey}>{t('modqueue.shift_key')}</span> + <span className={styles.smallKey}>/</span></p>
</div>
<Modal open={open} onClose={onClose}>
<h3>{lang.t('modqueue.shortcuts')}</h3>
<h3>{t('modqueue.shortcuts')}</h3>
<div className={styles.container}>
{shortcuts.map((shortcut, i) => (
<table className={styles.table} key={i}>
<thead>
<tr>
<th>{lang.t(shortcut.title)}</th>
<th>{t(shortcut.title)}</th>
</tr>
</thead>
<tbody>
{Object.keys(shortcut.shortcuts).map((key) => (
<tr key={`${key}tr`}>
<td className={styles.shortcut}><span className={styles.key}>{key}</span></td>
<td>{lang.t(shortcut.shortcuts[key])}</td>
<td>{t(shortcut.shortcuts[key])}</td>
</tr>
))}
</tbody>
@@ -2,8 +2,7 @@ import React, {PropTypes} from 'react';
import {Navigation, Drawer} from 'react-mdl';
import {IndexLink, Link} from 'react-router';
import styles from './Drawer.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import {can} from 'coral-framework/services/perms';
const CoralDrawer = ({handleLogout, auth}) => (
@@ -15,7 +14,7 @@ const CoralDrawer = ({handleLogout, auth}) => (
className={styles.navLink}
to="/admin/dashboard"
activeClassName={styles.active}>
{lang.t('configure.dashboard')}
{t('configure.dashboard')}
</IndexLink>
{
can(auth.user, 'MODERATE_COMMENTS') && (
@@ -23,19 +22,19 @@ const CoralDrawer = ({handleLogout, auth}) => (
className={styles.navLink}
to="/admin/moderate"
activeClassName={styles.active}>
{lang.t('configure.moderate')}
{t('configure.moderate')}
</Link>
)
}
<Link className={styles.navLink}
to="/admin/stories"
activeClassName={styles.active}>
{lang.t('configure.stories')}
{t('configure.stories')}
</Link>
<Link className={styles.navLink}
to="/admin/community"
activeClassName={styles.active}>
{lang.t('configure.community')}
{t('configure.community')}
</Link>
{
can(auth.user, 'UPDATE_CONFIG') &&
@@ -44,7 +43,7 @@ const CoralDrawer = ({handleLogout, auth}) => (
className={styles.navLink}
to="/admin/configure"
activeClassName={styles.active}>
{lang.t('configure.configure')}
{t('configure.configure')}
</Link>
)
}
@@ -60,6 +59,4 @@ CoralDrawer.propTypes = {
restricted: PropTypes.bool // hide app elements from a logged out user
};
const lang = new I18n(translations);
export default CoralDrawer;
+8 -11
View File
@@ -2,8 +2,7 @@ import React, {PropTypes} from 'react';
import {Navigation, Header, IconButton, MenuItem, Menu} from 'react-mdl';
import {Link, IndexLink} from 'react-router';
import styles from './Header.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import {Logo} from './Logo';
import {can} from 'coral-framework/services/perms';
@@ -23,7 +22,7 @@ const CoralHeader = ({
className={styles.navLink}
to="/admin/dashboard"
activeClassName={styles.active}>
{lang.t('configure.dashboard')}
{t('configure.dashboard')}
</IndexLink>
{
can(auth.user, 'MODERATE_COMMENTS') && (
@@ -32,7 +31,7 @@ const CoralHeader = ({
className={styles.navLink}
to="/admin/moderate"
activeClassName={styles.active}>
{lang.t('configure.moderate')}
{t('configure.moderate')}
</Link>
)
}
@@ -41,14 +40,14 @@ const CoralHeader = ({
className={styles.navLink}
to="/admin/stories"
activeClassName={styles.active}>
{lang.t('configure.stories')}
{t('configure.stories')}
</Link>
<Link
id='communityNav'
className={styles.navLink}
to="/admin/community"
activeClassName={styles.active}>
{lang.t('configure.community')}
{t('configure.community')}
</Link>
{
can(auth.user, 'UPDATE_CONFIG') && (
@@ -57,7 +56,7 @@ const CoralHeader = ({
className={styles.navLink}
to="/admin/configure"
activeClassName={styles.active}>
{lang.t('configure.configure')}
{t('configure.configure')}
</Link>
)
}
@@ -71,8 +70,8 @@ const CoralHeader = ({
<div>
<IconButton name="settings" id="menu-settings"/>
<Menu target="menu-settings" align="right">
<MenuItem onClick={() => showShortcuts(true)}>{lang.t('configure.shortcuts')}</MenuItem>
<MenuItem onClick={handleLogout}>{lang.t('configure.sign-out')}</MenuItem>
<MenuItem onClick={() => showShortcuts(true)}>{t('configure.shortcuts')}</MenuItem>
<MenuItem onClick={handleLogout}>{t('configure.sign_out')}</MenuItem>
</Menu>
</div>
</li>
@@ -91,6 +90,4 @@ CoralHeader.propTypes = {
handleLogout: PropTypes.func.isRequired
};
const lang = new I18n(translations);
export default CoralHeader;
@@ -1,11 +1,7 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
import styles from './Community.css';
import Loading from './Loading';
import EmptyCard from 'coral-admin/src/components/EmptyCard';
import User from './components/User';
@@ -34,7 +30,7 @@ const FlaggedAccounts = ({...props}) => {
suspendUser={props.suspendUser}
/>;
})
: <EmptyCard>{lang.t('community.no-flagged-accounts')}</EmptyCard>
: <EmptyCard>{t('community.no_flagged_accounts')}</EmptyCard>
}
</div>
</div>
@@ -1,7 +1,9 @@
import React from 'react';
import t from 'coral-framework/services/i18n';
const Loading = () => (
<h1> Loading results </h1>
<h1> {t('loading_results')}</h1>
);
export default Loading;
@@ -1,29 +1,26 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import styles from './Community.css';
import Table from './Table';
import {Pager, Icon} from 'coral-ui';
import EmptyCard from '../../components/EmptyCard';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const tableHeaders = [
{
title: lang.t('community.username_and_email'),
title: t('community.username_and_email'),
field: 'username'
},
{
title: lang.t('community.account_creation_date'),
title: t('community.account_creation_date'),
field: 'created_at'
},
{
title: lang.t('community.status'),
title: t('community.status'),
field: 'status'
},
{
title: lang.t('community.newsroom_role'),
title: t('community.newsroom_role'),
field: 'role'
}
];
@@ -41,7 +38,7 @@ const People = ({commenters, searchValue, onSearchChange, ...props}) => {
className={styles.searchBoxInput}
value={searchValue}
onChange={onSearchChange}
placeholder={lang.t('streams.search')}
placeholder={t('streams.search')}
/>
</div>
</div>
@@ -53,7 +50,7 @@ const People = ({commenters, searchValue, onSearchChange, ...props}) => {
commenters={commenters}
onHeaderClickHandler={props.onHeaderClickHandler}
/>
: <EmptyCard>{lang.t('community.no-results')}</EmptyCard>
: <EmptyCard>{t('community.no_results')}</EmptyCard>
}
<Pager
totalPages={props.totalPages}
@@ -2,11 +2,9 @@ import React, {Component} from 'react';
import {connect} from 'react-redux';
import {SelectField, Option} from 'react-mdl-selectfield';
import styles from './Community.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations';
import {setRole, setCommenterStatus} from '../../actions/community';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
class Table extends Component {
@@ -53,21 +51,21 @@ class Table extends Component {
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.status || ''}
className={styles.selectField}
label={lang.t('community.status')}
label={t('community.status')}
onChange={(status) => this.onCommenterStatusChange(row.id, status)}>
<Option value={'ACTIVE'}>{lang.t('community.active')}</Option>
<Option value={'BANNED'}>{lang.t('community.banned')}</Option>
<Option value={'ACTIVE'}>{t('community.active')}</Option>
<Option value={'BANNED'}>{t('community.banned')}</Option>
</SelectField>
</td>
<td className="mdl-data-table__cell--non-numeric">
<SelectField label={'Select me'} value={row.roles[0] || ''}
className={styles.selectField}
label={lang.t('community.role')}
label={t('community.role')}
onChange={(role) => this.onRoleChange(row.id, role)}>
<Option value={''}>.</Option>
<Option value={'STAFF'}>{lang.t('community.staff')}</Option>
<Option value={'MODERATOR'}>{lang.t('community.moderator')}</Option>
<Option value={'ADMIN'}>{lang.t('community.admin')}</Option>
<Option value={'STAFF'}>{t('community.staff')}</Option>
<Option value={'MODERATOR'}>{t('community.moderator')}</Option>
<Option value={'ADMIN'}>{t('community.admin')}</Option>
</SelectField>
</td>
</tr>
@@ -4,6 +4,8 @@ import BanUserButton from './BanUserButton';
import {Button} from 'coral-ui';
import {menuActionsMap} from '../../../containers/ModerationQueue/helpers/moderationQueueActionsMap';
import t from 'coral-framework/services/i18n';
const ActionButton = ({type = '', user, ...props}) => {
if (type === 'BAN') {
return <BanUserButton icon='not interested' user={user} onClick={() => props.showBanUserDialog(user)} />;
@@ -17,7 +19,7 @@ const ActionButton = ({type = '', user, ...props}) => {
onClick={() => {
type === 'APPROVE' ? props.approveUser({userId: user.id}) : props.showSuspendUserDialog({user: user});
}}
>{menuActionsMap[type].text}</Button>
>{t(`modqueue.${menuActionsMap[type].text}`)}</Button>
);
};
@@ -2,9 +2,7 @@ import React, {PropTypes} from 'react';
import {Button, Icon} from 'coral-ui';
import styles from './BanUserButton.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const BanUserButton = ({user, ...props}) => (
<div className={styles.ban}>
@@ -14,7 +12,7 @@ const BanUserButton = ({user, ...props}) => (
onClick={props.onClick}
raised>
<Icon name='not_interested' />
{lang.t('comment.ban_user')}
{t('comment.ban_user')}
</Button>
</div>
);
@@ -4,10 +4,7 @@ import styles from './BanUserDialog.css';
import Button from 'coral-ui/components/Button';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
<Dialog
@@ -16,19 +13,19 @@ const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
open={open}
onClose={handleClose}
onCancel={handleClose}
title={lang.t('community.ban_user')}>
title={t('community.ban_user')}>
<span className={styles.close} onClick={handleClose}>×</span>
<div>
<div className={styles.header}>
<h2>{lang.t('community.ban_user')}</h2>
<h2>{t('community.ban_user')}</h2>
</div>
<div className={styles.separator}>
<h3>{lang.t('community.are_you_sure', user.username)}</h3>
<i>{lang.t('community.note')}</i>
<h3>{t('community.are_you_sure', user.username)}</h3>
<i>{t('community.note')}</i>
</div>
<div className={styles.buttons}>
<Button cStyle="cancel" className={styles.cancel} onClick={handleClose} raised>
{lang.t('community.cancel')}
{t('community.cancel')}
</Button>
<Button
cStyle="black" className={styles.ban}
@@ -38,7 +35,7 @@ const BanUserDialog = ({open, handleClose, handleBanUser, user}) => (
});
}}
raised>
{lang.t('community.yes_ban_user')}
{t('community.yes_ban_user')}
</Button>
</div>
</div>
@@ -1,14 +1,9 @@
import React from 'react';
import styles from './styles.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import t from 'coral-framework/services/i18n';
import {Link} from 'react-router';
const lang = new I18n(translations);
const CommunityMenu = () => {
const flaggedPath = '/admin/community/flagged';
const peoplePath = '/admin/community/people';
@@ -17,10 +12,10 @@ const CommunityMenu = () => {
<div className={`mdl-tabs__tab-bar ${styles.tabBar}`}>
<div>
<Link to={flaggedPath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
{lang.t('community.flaggedaccounts')}
{t('community.flaggedaccounts')}
</Link>
<Link to={peoplePath} className={`mdl-tabs__tab ${styles.tab}`} activeClassName={styles.active}>
{lang.t('community.people')}
{t('community.people')}
</Link>
</div>
</div>
@@ -3,10 +3,7 @@ import React, {Component, PropTypes} from 'react';
import {Dialog, Button} from 'coral-ui';
import styles from './SuspendUserDialog.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const stages = [
{
@@ -38,7 +35,7 @@ class SuspendUserDialog extends Component {
}
componentDidMount() {
this.setState({email: lang.t('suspenduser.email_message_reject'), about: lang.t('suspenduser.username')});
this.setState({email: t('suspenduser.email_message_reject'), about: t('suspenduser.username')});
}
/*
@@ -79,18 +76,18 @@ class SuspendUserDialog extends Component {
open={open}
onClose={handleClose}
onCancel={handleClose}
title={lang.t('suspenduser.suspend_user')}>
title={t('suspenduser.suspend_user')}>
<div className={styles.title}>
{lang.t(stages[stage].title, lang.t('suspenduser.username'))}
{t(stages[stage].title, t('suspenduser.username'))}
</div>
<div className={styles.container}>
<div className={styles.description}>
{lang.t(stages[stage].description, lang.t('suspenduser.username'))}
{t(stages[stage].description, t('suspenduser.username'))}
</div>
{
stage === 1 &&
<div className={styles.writeContainer}>
<div className={styles.emailMessage}>{lang.t('suspenduser.write_message')}</div>
<div className={styles.emailMessage}>{t('suspenduser.write_message')}</div>
<div className={styles.emailContainer}>
<textarea
rows={5}
@@ -103,7 +100,7 @@ class SuspendUserDialog extends Component {
<div className={styles.modalButtons}>
{Object.keys(stages[stage].options).map((key, i) => (
<Button key={i} onClick={this.onActionClick(stage, i)}>
{lang.t(stages[stage].options[key], lang.t('suspenduser.username'))}
{t(stages[stage].options[key], t('suspenduser.username'))}
</Button>
))}
</div>
@@ -3,10 +3,15 @@ import styles from '../Community.css';
import ActionButton from './ActionButton';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../../translations.json';
import t from 'coral-framework/services/i18n';
const lang = new I18n(translations);
const shortReasons = {
'This comment is offensive': t('community.offensive'),
'This looks like an ad/marketing': t('community.spam_ads'),
'This user is impersonating': t('community.impersonating'),
'I don\'t like this username': t('community.dont_like_username'),
'Other': t('community.other')
};
// Render a single user for the list
const User = (props) => {
@@ -35,11 +40,11 @@ const User = (props) => {
<div className={styles.itemBody}>
<div className={styles.body}>
<div className={styles.flaggedByCount}>
<i className="material-icons">flag</i><span className={styles.flaggedByLabel}>{lang.t('community.flags')}({ user.actions.length })</span>:
<i className="material-icons">flag</i><span className={styles.flaggedByLabel}>{t('community.flags')}({ user.actions.length })</span>:
{ user.action_summaries.map(
(action, i) => {
return <span className={styles.flaggedBy} key={i}>
{lang.t(`community.${action.reason}`)} ({action.count})
{shortReasons[action.reason]} ({action.count})
</span>;
}
)}
@@ -49,7 +54,7 @@ const User = (props) => {
(action_sum, i) => {
return <div key={i}>
<span className={styles.flaggedByLabel}>
{lang.t(`community.${action_sum.reason}`)} ({action_sum.count})
{shortReasons[action_sum.reason]} ({action_sum.count})
</span>
{user.actions.map(
@@ -10,11 +10,10 @@ import {
import {Button, List, Item, Card, Spinner} from 'coral-ui';
import styles from './Configure.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import StreamSettings from './StreamSettings';
import ModerationSettings from './ModerationSettings';
import TechSettings from './TechSettings';
import t from 'coral-framework/services/i18n';
import {can} from 'coral-framework/services/perms';
class Configure extends Component {
@@ -106,11 +105,11 @@ class Configure extends Component {
getPageTitle (section) {
switch(section) {
case 'stream':
return lang.t('configure.stream-settings');
return t('configure.stream_settings');
case 'moderation':
return lang.t('configure.moderation-settings');
return t('configure.moderation_settings');
case 'tech':
return lang.t('configure.tech-settings');
return t('configure.tech_settings');
default:
return '';
}
@@ -133,13 +132,13 @@ class Configure extends Component {
<div className={styles.leftColumn}>
<List onChange={this.changeSection} activeItem={activeSection}>
<Item itemId='stream' icon='speaker_notes'>
{lang.t('configure.stream-settings')}
{t('configure.stream_settings')}
</Item>
<Item itemId='moderation' icon='thumbs_up_down'>
{lang.t('configure.moderation-settings')}
{t('configure.moderation_settings')}
</Item>
<Item itemId='tech' icon='code'>
{lang.t('configure.tech-settings')}
{t('configure.tech_settings')}
</Item>
</List>
<div className={styles.saveBox}>
@@ -152,7 +151,7 @@ class Configure extends Component {
icon='check'
full
>
{lang.t('configure.save-changes')}
{t('configure.save_changes')}
</Button>
:
<Button
@@ -161,7 +160,7 @@ class Configure extends Component {
icon='check'
full
>
{lang.t('configure.save-changes')}
{t('configure.save_changes')}
</Button>
}
</div>
@@ -182,5 +181,3 @@ const mapStateToProps = (state) => ({
settings: state.settings.toJS()
});
export default connect(mapStateToProps)(Configure);
const lang = new I18n(translations);
@@ -2,17 +2,14 @@ import React from 'react';
import {Card} from 'coral-ui';
import styles from './Configure.css';
import TagsInput from 'react-tagsinput';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const Domainlist = ({domains, onChangeDomainlist}) => {
return (
<Card id={styles.domainlist} className={styles.configSetting}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>{lang.t('configure.domain-list-title')}</div>
<p className={styles.domainlistDesc}>{lang.t('configure.domain-list-text')}</p>
<div className={styles.settingsHeader}>{t('configure.domain_list_title')}</div>
<p className={styles.domainlistDesc}>{t('configure.domain_list_text')}</p>
<div className={styles.wrapper}>
<TagsInput
value={domains}
@@ -1,6 +1,6 @@
import React, {Component} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import styles from './Configure.css';
import {Button, Card} from 'coral-ui';
@@ -47,11 +47,11 @@ class EmbedLink extends Component {
<Card shadow="2" className={styles.configSetting}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>Embed Comment Stream</div>
<p>{lang.t('configure.copy-and-paste')}</p>
<p>{t('configure.copy_and_paste')}</p>
<textarea rows={5} type='text' className={styles.embedInput} value={embedText} readOnly={true}/>
<div className={styles.actions}>
<Button raised className={styles.copyButton} onClick={this.copyToClipBoard} cStyle="black">
{lang.t('embedlink.copy')}
{t('embedlink.copy')}
</Button>
<div className={styles.copiedText}>
{this.state.copied && 'Copied!'}
@@ -64,5 +64,3 @@ class EmbedLink extends Component {
}
export default EmbedLink;
const lang = new I18n(translations);
@@ -3,9 +3,7 @@ import styles from './Configure.css';
import {Card} from 'coral-ui';
import {Checkbox} from 'react-mdl';
import Wordlist from './Wordlist';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const updateModeration = (updateSettings, mod) => () => {
const moderation = mod === 'PRE' ? 'POST' : 'PRE';
@@ -42,9 +40,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
checked={settings.requireEmailConfirmation} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.require-email-verification')}</div>
<div className={styles.settingsHeader}>{t('configure.require_email_verification')}</div>
<p className={settings.requireEmailConfirmation ? '' : styles.disabledSettingText}>
{lang.t('configure.require-email-verification-text')}
{t('configure.require_email_verification_text')}
</p>
</div>
</Card>
@@ -55,9 +53,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
checked={settings.moderation === 'PRE'} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.enable-pre-moderation')}</div>
<div className={styles.settingsHeader}>{t('configure.enable_pre_moderation')}</div>
<p className={settings.moderation === 'PRE' ? '' : styles.disabledSettingText}>
{lang.t('configure.enable-pre-moderation-text')}
{t('configure.enable_pre_moderation_text')}
</p>
</div>
</Card>
@@ -68,9 +66,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
checked={settings.premodLinksEnable} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.enable-premod-links')}</div>
<div className={styles.settingsHeader}>{t('configure.enable_premod_links')}</div>
<p>
{lang.t('configure.enable-premod-links-text')}
{t('configure.enable_premod_links_text')}
</p>
</div>
</Card>
@@ -81,9 +79,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
{/* Edit Comment Timeframe */}
<Card className={styles.configSetting}>
<div className={styles.settingsHeader}>{lang.t('configure.edit-comment-timeframe-heading')}</div>
<div className={styles.settingsHeader}>{t('configure.edit_comment_timeframe_heading')}</div>
<p>
{lang.t('configure.edit-comment-timeframe-text-pre')}
{t('configure.edit_comment_timeframe_text_pre')}
&nbsp;
<input
style={{width: '3em'}}
@@ -96,9 +94,9 @@ const ModerationSettings = ({settings, updateSettings, onChangeWordlist}) => {
pattern='[0-9]+([\.][0-9]*)?'
/>
&nbsp;
{lang.t('configure.edit-comment-timeframe-text-post')}
{t('configure.edit_comment_timeframe_text_post')}
</p>
</Card>
</Card>
</div>
);
};
@@ -1,7 +1,6 @@
import React from 'react';
import {SelectField, Option} from 'react-mdl-selectfield';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import styles from './Configure.css';
import {Checkbox, Textfield} from 'react-mdl';
import {Card, Icon, TextArea} from 'coral-ui';
@@ -77,9 +76,9 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
checked={settings.charCountEnable} />
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>{lang.t('configure.comment-count-header')}</div>
<div className={styles.settingsHeader}>{t('configure.comment_count_header')}</div>
<p className={settings.charCountEnable ? '' : styles.disabledSettingText}>
<span>{lang.t('configure.comment-count-text-pre')}</span>
<span>{t('configure.comment_count_text_pre')}</span>
<input type='text'
className={`${styles.inlineTextfield} ${styles.charCountTexfield} ${settings.charCountEnable && styles.charCountTexfieldEnabled}`}
htmlFor='charCount'
@@ -87,13 +86,13 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
value={settings.charCount}
disabled={settings.charCountEnable ? '' : 'disabled'}
/>
<span>{lang.t('configure.comment-count-text-post')}</span>
<span>{t('configure.comment_count_text_post')}</span>
{
errors.charCount &&
<span className={styles.settingsError}>
<br/>
<Icon name="error_outline"/>
{lang.t('configure.comment-count-error')}
{t('configure.comment_count_error')}
</span>
}
</p>
@@ -107,10 +106,10 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
</div>
<div className={styles.content}>
<div className={styles.settingsHeader}>
{lang.t('configure.include-comment-stream')}
{t('configure.include_comment_stream')}
</div>
<p className={settings.infoBoxEnable ? '' : styles.disabledSettingText}>
{lang.t('configure.include-comment-stream-desc')}
{t('configure.include_comment_stream_desc')}
</p>
<div className={`${styles.configSettingInfoBox} ${settings.infoBoxEnable ? null : styles.hidden}`} >
<MarkdownEditor
@@ -123,8 +122,8 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
</Card>
<Card className={`${styles.configSetting} ${styles.configSettingInfoBox}`}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>{lang.t('configure.closed-stream-settings')}</div>
<p>{lang.t('configure.closed-comments-desc')}</p>
<div className={styles.settingsHeader}>{t('configure.closed_stream_settings')}</div>
<p>{t('configure.closed_comments_desc')}</p>
<div>
<TextArea className={styles.descriptionBox}
onChange={updateClosedMessage(updateSettings)}
@@ -140,7 +139,7 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
checked={settings.autoCloseStream} />
</div>
<div className={styles.content}>
{lang.t('configure.close-after')}
{t('configure.close_after')}
<br />
<Textfield
type='number'
@@ -148,15 +147,15 @@ const StreamSettings = ({updateSettings, settingsError, settings, errors}) => {
style={{width: 50}}
onChange={updateClosedTimeout(updateSettings, settings.closedTimeout)}
value={getTimeoutAmount(settings.closedTimeout)}
label={lang.t('configure.closed-comments-label')} />
label={t('configure.closed_comments_label')} />
<div className={styles.configTimeoutSelect}>
<SelectField
label="comments closed time window"
value={getTimeoutMeasure(settings.closedTimeout)}
onChange={updateClosedTimeout(updateSettings, settings.closedTimeout, true)}>
<Option value={'hours'}>{lang.t('configure.hours')}</Option>
<Option value={'days'}>{lang.t('configure.days')}</Option>
<Option value={'weeks'}>{lang.t('configure.weeks')}</Option>
<Option value={'hours'}>{t('configure.hours')}</Option>
<Option value={'days'}>{t('configure.days')}</Option>
<Option value={'weeks'}>{t('configure.weeks')}</Option>
</SelectField>
</div>
</div>
@@ -183,5 +182,3 @@ const getTimeoutMeasure = (ts) => {
// Dividing the amount by it's measure (hours, days, weeks) we
// obtain the amount of time
const getTimeoutAmount = (ts) => ts / TIMESTAMPS[getTimeoutMeasure(ts)];
const lang = new I18n(translations);
@@ -3,9 +3,7 @@ import {Card} from 'coral-ui';
import Domainlist from './Domainlist';
import EmbedLink from './EmbedLink';
import styles from './Configure.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const updateCustomCssUrl = (updateSettings) => (event) => {
const customCssUrl = event.target.value;
@@ -21,8 +19,8 @@ const TechSettings = ({settings, onChangeDomainlist, updateSettings}) => {
<EmbedLink />
<Card className={styles.configSetting}>
<div className={styles.wrapper}>
<div className={styles.settingsHeader}>{lang.t('configure.custom-css-url')}</div>
<p>{lang.t('configure.custom-css-url-desc')}</p>
<div className={styles.settingsHeader}>{t('configure.custom_css_url')}</div>
<p>{t('configure.custom_css_url_desc')}</p>
<input
className={styles.customCSSInput}
value={settings.customCssUrl}
@@ -1,6 +1,5 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../translations.json';
import t from 'coral-framework/services/i18n';
import TagsInput from 'react-tagsinput';
import styles from './Configure.css';
import {Card} from 'coral-ui';
@@ -8,8 +7,8 @@ import {Card} from 'coral-ui';
const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
<div>
<Card id={styles.bannedWordlist} className={styles.configSetting}>
<div className={styles.settingsHeader}>{lang.t('configure.banned-words-title')}</div>
<p className={styles.wordlistDesc}>{lang.t('configure.banned-word-text')}</p>
<div className={styles.settingsHeader}>{t('configure.banned_words_title')}</div>
<p className={styles.wordlistDesc}>{t('configure.banned_word_text')}</p>
<div className={styles.wrapper}>
<TagsInput
value={bannedWords}
@@ -21,8 +20,8 @@ const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
</div>
</Card>
<Card id={styles.suspectWordlist} className={styles.configSetting}>
<div className={styles.settingsHeader}>{lang.t('configure.suspect-words-title')}</div>
<p className={styles.wordlistDesc}>{lang.t('configure.suspect-word-text')}</p>
<div className={styles.settingsHeader}>{t('configure.suspect_word_title')}</div>
<p className={styles.wordlistDesc}>{t('configure.suspect_word_text')}</p>
<div className={styles.wrapper}>
<TagsInput
value={suspectWords}
@@ -36,5 +35,3 @@ const Wordlist = ({suspectWords, bannedWords, onChangeWordlist}) => (
);
export default Wordlist;
const lang = new I18n(translations);
@@ -1,18 +1,15 @@
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import styles from './Widget.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const ActivityWidget = ({assets}) => {
return (
<div className={styles.widget}>
<h2 className={styles.heading}>Articles with the most conversations</h2>
<h2 className={styles.heading}>{t('dashboard.most_conversations')}</h2>
<div className={styles.widgetHead}>
<p>{lang.t('streams.article')}</p>
<p>{lang.t('dashboard.comment_count')}</p>
<p>{t('streams.article')}</p>
<p>{t('dashboard.comment_count')}</p>
</div>
<div className={styles.widgetTable}>
{
@@ -29,7 +26,7 @@ const ActivityWidget = ({assets}) => {
</div>
);
})
: <div className={styles.rowLinkify}>{lang.t('dashboard.no_activity')}</div>
: <div className={styles.rowLinkify}>{t('dashboard.no_activity')}</div>
}
</div>
</div>
@@ -1,19 +1,17 @@
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import styles from './Widget.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const FlagWidget = ({assets}) => {
return (
<div className={styles.widget}>
<h2 className={styles.heading}>{lang.t('dashboard.most_flags')}</h2>
<h2 className={styles.heading}>{t('dashboard.most_flags')}</h2>
<div className={styles.widgetHead}>
<p>{lang.t('streams.article')}</p>
<p>{lang.t('dashboard.flags')}</p>
<p>{t('streams.article')}</p>
<p>{t('dashboard.flags')}</p>
</div>
<div className={styles.widgetTable}>
{
@@ -35,7 +33,7 @@ const FlagWidget = ({assets}) => {
</div>
);
})
: <div className={styles.rowLinkify}>{lang.t('dashboard.no_flags')}</div>
: <div className={styles.rowLinkify}>{t('dashboard.no_flags')}</div>
}
</div>
</div>
@@ -1,10 +1,7 @@
import React, {PropTypes} from 'react';
import {Link} from 'react-router';
import styles from './Widget.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const LikeWidget = ({assets}) => {
@@ -12,8 +9,8 @@ const LikeWidget = ({assets}) => {
<div className={styles.widget}>
<h2 className={styles.heading}>Articles with the most likes</h2>
<div className={styles.widgetHead}>
<p>{lang.t('streams.article')}</p>
<p>{lang.t('modqueue.likes')}</p>
<p>{t('streams.article')}</p>
<p>{t('modqueue.likes')}</p>
</div>
<div className={styles.widgetTable}>
{
@@ -31,7 +28,7 @@ const LikeWidget = ({assets}) => {
</div>
);
})
: <div className={styles.rowLinkify}>{lang.t('dashboard.no_likes')}</div>
: <div className={styles.rowLinkify}>{t('dashboard.no_likes')}</div>
}
</div>
</div>
@@ -1,11 +1,9 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
import ModerationQueue from 'coral-admin/src/containers/ModerationQueue/ModerationQueue';
import styles from './Widget.css';
import BanUserDialog from 'coral-admin/src/components/BanUserDialog';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const MostLikedCommentsWidget = (props) => {
const {
@@ -21,7 +19,7 @@ const MostLikedCommentsWidget = (props) => {
return (
<div className={styles.widget}>
<h2 className={styles.heading}>{lang.t('most_liked_comments')}</h2>
<h2 className={styles.heading}>{t('most_liked_comments')}</h2>
<ModerationQueue
comments={comments}
suspectWords={settings.wordlist.suspect}
@@ -2,26 +2,24 @@ import React from 'react';
import styles from './style.css';
import {TextField, Button} from 'coral-ui';
const lang = new I18n(translations);
import translations from '../../translations.json';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
const AddOrganizationName = (props) => {
const {handleSettingsChange, handleSettingsSubmit, install} = props;
return (
<div className={styles.step}>
<p>{lang.t('ADD_ORGANIZATION.DESCRIPTION')}</p>
<p>{t('install.add_organization.description')}</p>
<div className={styles.form}>
<form onSubmit={handleSettingsSubmit}>
<TextField
className={styles.TextField}
id="organizationName"
type="text"
label={lang.t('ADD_ORGANIZATION.LABEL')}
label={t('install.add_organization.label')}
onChange={handleSettingsChange}
showErrors={install.showErrors}
errorMsg={install.errors.organizationName} />
<Button type="submit" cStyle='black' full>{lang.t('ADD_ORGANIZATION.SAVE')}</Button>
<Button type="submit" cStyle='black' full>{t('install.add_organization.save')}</Button>
</form>
</div>
</div>
@@ -2,9 +2,7 @@ import React from 'react';
import styles from './style.css';
import {TextField, Button, Spinner} from 'coral-ui';
const lang = new I18n(translations);
import translations from '../../translations.json';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
const InitialStep = (props) => {
const {handleUserChange, handleUserSubmit, install} = props;
@@ -16,7 +14,7 @@ const InitialStep = (props) => {
className={styles.textField}
id="email"
type="email"
label={lang.t('CREATE.EMAIL')}
label={t('install.create.email')}
onChange={handleUserChange}
showErrors={install.showErrors}
errorMsg={install.errors.email}
@@ -27,7 +25,7 @@ const InitialStep = (props) => {
className={styles.textField}
id="username"
type="text"
label={lang.t('CREATE.USERNAME')}
label={t('install.create.username')}
onChange={handleUserChange}
showErrors={install.showErrors}
errorMsg={install.errors.username}
@@ -37,7 +35,7 @@ const InitialStep = (props) => {
className={styles.textField}
id="password"
type="password"
label={lang.t('CREATE.PASSWORD')}
label={t('install.create.password')}
onChange={handleUserChange}
showErrors={install.showErrors}
errorMsg={install.errors.password}
@@ -47,15 +45,15 @@ const InitialStep = (props) => {
className={styles.textField}
id="confirmPassword"
type="password"
label={lang.t('CREATE.CONFIRM_PASSWORD')}
label={t('install.create.confirm_password')}
onChange={handleUserChange}
showErrors={install.showErrors}
errorMsg={install.errors.confirmPassword}
errorMsg={install.errors.confirm_password}
/>
{
!props.install.isLoading ?
<Button cStyle='black' type="submit" full>{lang.t('CREATE.SAVE')}</Button>
<Button cStyle='black' type="submit" full>{t('install.create.save')}</Button>
:
<Spinner />
}
@@ -3,16 +3,14 @@ import styles from './style.css';
import {Button} from 'coral-ui';
import {Link} from 'react-router';
const lang = new I18n(translations);
import translations from '../../translations.json';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
const InitialStep = () => {
return (
<div className={`${styles.step} ${styles.finalStep}`}>
<p>{lang.t('FINAL.DESCRIPTION')}</p>
<Button raised><Link to='/admin'>{lang.t('FINAL.LAUNCH')}</Link></Button>
<Button cStyle='black' raised><a href="http://coralproject.net">{lang.t('FINAL.CLOSE')}</a></Button>
<p>{t('install.final.description')}</p>
<Button raised><Link to='/admin'>{t('install.final.launch')}</Link></Button>
<Button cStyle='black' raised><a href="http://coralproject.net">{t('install.final.close')}</a></Button>
</div>
);
};
@@ -2,16 +2,14 @@ import React from 'react';
import styles from './style.css';
import {Button} from 'coral-ui';
const lang = new I18n(translations);
import translations from '../../translations.json';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
const InitialStep = (props) => {
const {nextStep} = props;
return (
<div className={styles.step}>
<p>{lang.t('INITIAL.DESCRIPTION')}</p>
<Button cStyle='green' onClick={nextStep} raised>{lang.t('INITIAL.SUBMIT')}</Button>
<p>{t('install.initial.description')}</p>
<Button cStyle='green' onClick={nextStep} raised>{t('install.initial.submit')}</Button>
</div>
);
};
@@ -3,18 +3,16 @@ import styles from './style.css';
import {Button, Card} from 'coral-ui';
import TagsInput from 'react-tagsinput';
const lang = new I18n(translations);
import translations from '../../translations.json';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
const PermittedDomainsStep = (props) => {
const {finishInstall, install, handleDomainsChange} = props;
const domains = install.data.settings.domains.whitelist;
return (
<div className={styles.step}>
<h3>{lang.t('PERMITTED_DOMAINS.TITLE')}</h3>
<h3>{t('install.permitted_domains.title')}</h3>
<Card className={styles.card}>
<p>{lang.t('PERMITTED_DOMAINS.DESCRIPTION')}</p>
<p>{t('install.permitted_domains.description')}</p>
<TagsInput
value={domains}
inputProps={{placeholder: 'URL'}}
@@ -23,7 +21,7 @@ const PermittedDomainsStep = (props) => {
onChange={(tags) => handleDomainsChange(tags)}
/>
</Card>
<Button cStyle='green' onClick={finishInstall} raised>{lang.t('PERMITTED_DOMAINS.SUBMIT')}</Button>
<Button cStyle='green' onClick={finishInstall} raised>{t('install.permitted_domains.submit')}</Button>
</div>
);
};
@@ -1,58 +0,0 @@
{
"en": {
"INITIAL" : {
"DESCRIPTION": "Let's set up your Talk community in just a few short steps.",
"SUBMIT": "Get Started"
},
"ADD_ORGANIZATION": {
"DESCRIPTION": "Please tell us the name of your organization. This will appear in emails when inviting new team members.",
"LABEL": "Organization Name",
"SAVE": "Save"
},
"CREATE": {
"EMAIL": "Email address",
"USERNAME": "Username",
"PASSWORD": "Password",
"CONFIRM_PASSWORD": "Confirm Password",
"SAVE": "Save"
},
"PERMITTED_DOMAINS": {
"TITLE": "Permitted domains",
"DESCRIPTION": "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com).",
"SUBMIT": "Finish install"
},
"FINAL": {
"DESCRIPTION": "Thanks for installing Talk! We sent an email to verify your email address. While you finish setting up the account, you can start engaging with your readers now.",
"LAUNCH": "Launch Talk",
"CLOSE": "Close this Installer"
}
},
"es": {
"INITIAL" : {
"DESCRIPTION": "Configuremos tu comunidad de Talk en sólo algunos pasos.",
"SUBMIT": "Empezá!"
},
"ADD_ORGANIZATION": {
"DESCRIPTION": "Por favor, dinos el nombre de tu organización. Este aparecerá en los emails cuando invites nuevos miembros.",
"LABEL": "Nombre de la Organización",
"SAVE": "Guardar"
},
"CREATE": {
"EMAIL": "Dirección de E-Mail",
"USERNAME": "Usuario",
"PASSWORD": "Contraseña",
"CONFIRM_PASSWORD": "Confirmar contraseña",
"SAVE": "Guardar"
},
"PERMITTED_DOMAINS": {
"TITLE": "Dominios Permitidos",
"DESCRIPTION": "Agrega dominios permitidos a Talk, e.g. tu localhost, staging y ambientes de production (ex. localhost:3000, staging.domain.com, domain.com).",
"SUBMIT": "Finalizar instalación"
},
"FINAL": {
"DESCRIPTION": "Gracias por instalar Talk! Te enviamos un email para verificar tu identidad. Mientras se termina de configurar la cuenta, ya puedes empezar a interactuar con tus lectores",
"LAUNCH": "Lanzar Talk",
"CLOSE": "Cerrar este instalador"
}
}
}
@@ -6,8 +6,7 @@ import * as notification from 'coral-admin/src/services/notification';
import key from 'keymaster';
import isEqual from 'lodash/isEqual';
import styles from './components/styles.css';
import translations from 'coral-admin/src/translations';
import I18n from 'coral-framework/modules/i18n/i18n';
import t, {timeago} from 'coral-framework/services/i18n';
import {modQueueQuery, getQueueCounts} from '../../graphql/queries';
import {banUser, setCommentStatus, suspendUser} from '../../graphql/mutations';
@@ -36,8 +35,6 @@ import NotFoundAsset from './components/NotFoundAsset';
import ModerationKeysModal from '../../components/ModerationKeysModal';
import UserDetail from './UserDetail';
const lang = new I18n(translations);
class ModerationContainer extends Component {
state = {
selectedIndex: 0,
@@ -108,9 +105,9 @@ class ModerationContainer extends Component {
throw result.data.suspendUser.errors;
}
notification.success(
lang.t('suspenduser.notify_suspend_until',
t('suspenduser.notify_suspend_until',
this.props.moderation.suspendUserDialog.username,
lang.timeago(args.until)),
timeago(args.until)),
);
const {commentStatus, commentId} = this.props.moderation.suspendUserDialog;
if (commentStatus !== 'REJECTED') {
@@ -4,11 +4,10 @@ import Comment from './components/Comment';
import styles from './components/styles.css';
import EmptyCard from '../../components/EmptyCard';
import {actionsMap} from './helpers/moderationQueueActionsMap';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
import t from 'coral-framework/services/i18n';
import LoadMore from './components/LoadMore';
const lang = new I18n(translations);
class ModerationQueue extends React.Component {
static propTypes = {
@@ -71,7 +70,7 @@ class ModerationQueue extends React.Component {
currentUserId={this.props.currentUserId}
/>;
})
: <EmptyCard>{lang.t('modqueue.emptyqueue')}</EmptyCard>
: <EmptyCard>{t('modqueue.empty_queue')}</EmptyCard>
}
</ul>
<LoadMore
@@ -3,10 +3,7 @@ import {Dialog} from 'coral-ui';
import styles from './BanUserDialog.css';
import Button from 'coral-ui/components/Button';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../../../translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const onBanClick = (userId, commentId, commentStatus, handleBanUser, rejectComment, handleClose) => (e) => {
e.preventDefault();
@@ -22,22 +19,22 @@ const BanUserDialog = ({open, handleClose, handleBanUser, rejectComment, user, c
open={open}
onClose={handleClose}
onCancel={handleClose}
title={lang.t('bandialog.ban_user')}>
title={t('bandialog.ban_user')}>
<span className={styles.close} onClick={handleClose}>×</span>
<div>
<div className={styles.header}>
<h2>{lang.t('bandialog.ban_user')}</h2>
<h2>{t('bandialog.ban_user')}</h2>
</div>
<div className={styles.separator}>
<h3>{lang.t('bandialog.are_you_sure', user.name)}</h3>
<i>{showRejectedNote && lang.t('bandialog.note')}</i>
<h3>{t('bandialog.are_you_sure', user.name)}</h3>
<i>{showRejectedNote && t('bandialog.note')}</i>
</div>
<div className={styles.buttons}>
<Button cStyle="cancel" className={styles.cancel} onClick={handleClose} raised>
{lang.t('bandialog.cancel')}
{t('bandialog.cancel')}
</Button>
<Button cStyle="black" className={styles.ban} onClick={onBanClick(user.id, commentId, commentStatus, handleBanUser, rejectComment, handleClose)} raised>
{lang.t('bandialog.yes_ban_user')}
{t('bandialog.yes_ban_user')}
</Button>
</div>
</div>
@@ -1,5 +1,4 @@
import React, {PropTypes} from 'react';
import timeago from 'timeago.js';
import {Link} from 'react-router';
import Linkify from 'react-linkify';
@@ -16,9 +15,7 @@ import ActionsMenuItem from 'coral-admin/src/components/ActionsMenuItem';
const linkify = new Linkify();
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t, {timeago} from 'coral-framework/services/i18n';
const Comment = ({
actions = [],
@@ -62,10 +59,7 @@ const Comment = ({
{comment.user.name}
</span>
<span className={styles.created}>
{timeago().format(
comment.created_at || Date.now() - props.index * 60 * 1000,
lang.getLocale().replace('-', '_')
)}
{timeago(comment.created_at || Date.now() - props.index * 60 * 1000)}
</span>
{props.currentUserId !== comment.user.id &&
<ActionsMenu icon="not_interested">
@@ -85,7 +79,7 @@ const Comment = ({
{comment.user.status === 'banned'
? <span className={styles.banned}>
<Icon name="error_outline" />
{lang.t('comment.banned_user')}
{t('comment.banned_user')}
</span>
: null}
<Slot fill="adminCommentInfoBar" comment={comment} />
@@ -93,7 +87,7 @@ const Comment = ({
<div className={styles.moderateArticle}>
Story: {comment.asset.title}
{!props.currentAsset &&
<Link to={`/admin/moderate/${comment.asset.id}`}>Moderate </Link>}
<Link to={`/admin/moderate/${comment.asset.id}`}>{t('modqueue.moderate')}</Link>}
</div>
<div className={styles.itemBody}>
<p className={styles.body}>
@@ -107,7 +101,7 @@ const Comment = ({
href={`${comment.asset.url}#${comment.id}`}
target="_blank"
>
<Icon name="open_in_new" /> {lang.t('comment.view_context')}
<Icon name="open_in_new" /> {t('comment.view_context')}
</a>
</p>
<Slot fill="adminCommentContent" comment={comment} />
@@ -1,19 +1,18 @@
import React, {PropTypes} from 'react';
import styles from './CommentCount.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const CommentCount = ({count}) => {
let number = count;
// shorten large counts to abbreviations
if (number / 1e9 > 1) {
number = `${(number / 1e9).toFixed(1)}${lang.t('modqueue.billion')}`;
number = `${(number / 1e9).toFixed(1)}${t('modqueue.billion')}`;
} else if (number / 1e6 > 1) {
number = `${(number / 1e6).toFixed(1)}${lang.t('modqueue.million')}`;
number = `${(number / 1e6).toFixed(1)}${t('modqueue.million')}`;
} else if (number / 1e3 > 1) {
number = `${(number / 1e3).toFixed(1)}${lang.t('modqueue.thousand')}`;
number = `${(number / 1e3).toFixed(1)}${t('modqueue.thousand')}`;
}
return (
@@ -1,16 +1,14 @@
import React, {Component, PropTypes} from 'react';
import {Icon} from 'coral-ui';
import styles from './FlagBox.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const shortReasons = {
'This comment is offensive': lang.t('modqueue.offensive'),
'This looks like an ad/marketing': lang.t('modqueue.spam/ads'),
'This user is impersonating': lang.t('modqueue.impersonating'),
'I don\'t like this username': lang.t('modqueue.dont-like-username'),
'Other': lang.t('modqueue.other')
'This comment is offensive': t('modqueue.offensive'),
'This looks like an ad/marketing': t('modqueue.spam_ads'),
'This user is impersonating': t('modqueue.impersonating'),
'I don\'t like this username': t('modqueue.dont_like_username'),
'Other': t('modqueue.other')
};
class FlagBox extends Component {
@@ -42,13 +40,13 @@ class FlagBox extends Component {
<div className={styles.flagBox}>
<div className={styles.container}>
<div className={styles.header}>
<Icon name='flag'/><h3>Flags ({actionSummaries.length}):</h3>
<Icon name='flag'/><h3>{t('community.flags')} ({actionSummaries.length}):</h3>
<ul>
{actionSummaries.map((action, i) =>
<li key={i} className={styles.lessDetail}>{this.reasonMap(action.reason)} (<strong>{action.count}</strong>)</li>
<li key={i} className={styles.lessDetail}> {this.reasonMap(action.reason)} (<strong>{action.count}</strong>)</li>
)}
</ul>
<a onClick={this.toggleDetail} className={styles.moreDetail}>{showDetail ? lang.t('modqueue.less-detail') : lang.t('modqueue.more-detail')}</a>
<a onClick={this.toggleDetail} className={styles.moreDetail}>{showDetail ? t('modqueue.less_detail') : t('modqueue.more_detail')}</a>
</div>
{showDetail && (
<div className={styles.detail}>
@@ -2,6 +2,7 @@ import React from 'react';
import {Link} from 'react-router';
import {Icon} from 'coral-ui';
import styles from './styles.css';
import t from 'coral-framework/services/i18n';
const ModerationHeader = (props) => (
<div className=''>
@@ -9,7 +10,7 @@ const ModerationHeader = (props) => (
{
props.asset ?
<div className={`mdl-tabs__tab-bar ${styles.moderateAsset}`}>
<Link className="mdl-tabs__tab" to="/admin/moderate">All Streams</Link>
<Link className="mdl-tabs__tab" to="/admin/moderate">{t('modqueue.all_streams')}</Link>
<a className="mdl-tabs__tab" href={props.asset.url} target="_blank">
<span>{props.asset.title}</span>
<Icon className={styles.settingsButton} name="open_in_new"/>
@@ -19,8 +20,8 @@ const ModerationHeader = (props) => (
:
<div className={`mdl-tabs__tab-bar ${styles.moderateAsset}`}>
<a className="mdl-tabs__tab" />
<a className="mdl-tabs__tab">All Streams</a>
<Link className="mdl-tabs__tab" to="/admin/stories">Select Stream</Link>
<a className="mdl-tabs__tab">{t('modqueue.all_streams')}</a>
<Link className="mdl-tabs__tab" to="/admin/stories">{t('modqueue.select_stream')}</Link>
</div>
}
</div>
@@ -2,12 +2,10 @@ import React, {PropTypes} from 'react';
import CommentCount from './CommentCount';
import styles from './styles.css';
import {SelectField, Option} from 'react-mdl-selectfield';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations.json';
import {Icon} from 'coral-ui';
import {Link} from 'react-router';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const ModerationMenu = (
{asset, allCount, acceptedCount, premodCount, rejectedCount, flaggedCount, selectSort, sort}
@@ -26,31 +24,31 @@ const ModerationMenu = (
to={getPath('all')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='question_answer' className={styles.tabIcon} /> {lang.t('modqueue.all')} <CommentCount count={allCount} />
<Icon name='question_answer' className={styles.tabIcon} /> {t('modqueue.all')} <CommentCount count={allCount} />
</Link>
<Link
to={getPath('premod')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='access_time' className={styles.tabIcon} /> {lang.t('modqueue.premod')} <CommentCount count={premodCount} />
<Icon name='access_time' className={styles.tabIcon} /> {t('modqueue.premod')} <CommentCount count={premodCount} />
</Link>
<Link
to={getPath('flagged')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='flag' className={styles.tabIcon} /> {lang.t('modqueue.flagged')} <CommentCount count={flaggedCount} />
<Icon name='flag' className={styles.tabIcon} /> {t('modqueue.flagged')} <CommentCount count={flaggedCount} />
</Link>
<Link
to={getPath('accepted')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='check' className={styles.tabIcon} /> {lang.t('modqueue.approved')} <CommentCount count={acceptedCount} />
<Icon name='check' className={styles.tabIcon} /> {t('modqueue.approved')} <CommentCount count={acceptedCount} />
</Link>
<Link
to={getPath('rejected')}
className={`mdl-tabs__tab ${styles.tab}`}
activeClassName={styles.active}>
<Icon name='close' className={styles.tabIcon} /> {lang.t('modqueue.rejected')} <CommentCount count={rejectedCount} />
<Icon name='close' className={styles.tabIcon} /> {t('modqueue.rejected')} <CommentCount count={rejectedCount} />
</Link>
</div>
<SelectField
@@ -58,8 +56,8 @@ const ModerationMenu = (
label="Sort"
value={sort}
onChange={(sort) => selectSort(sort)}>
<Option value={'REVERSE_CHRONOLOGICAL'}>Newest First</Option>
<Option value={'CHRONOLOGICAL'}>Oldest First</Option>
<Option value={'REVERSE_CHRONOLOGICAL'}>{t('modqueue.newest_first')}</Option>
<Option value={'CHRONOLOGICAL'}>{t('modqueue.oldest_first')}</Option>
</SelectField>
</div>
</div>
@@ -5,10 +5,8 @@ import styles from './SuspendUserDialog.css';
import Button from 'coral-ui/components/Button';
import I18n from 'coral-framework/modules/i18n/i18n';
import t, {timeago} from 'coral-framework/services/i18n';
import {dateAdd} from 'coral-framework/utils';
import translations from '../../../translations';
const lang = new I18n(translations);
const initialState = {step: 0, duration: '3'};
@@ -39,11 +37,11 @@ class SuspendUserDialog extends React.Component {
goToStep1 = () => {
this.setState({
step: 1,
message: lang.t(
message: t(
'suspenduser.email_message_suspend',
this.props.username,
this.props.organizationName,
lang.timeago(durationsToDate(this.state.duration)),
timeago(durationsToDate(this.state.duration)),
),
});
}
@@ -65,13 +63,13 @@ class SuspendUserDialog extends React.Component {
return (
<section>
<h1 className={styles.header}>
{lang.t('suspenduser.title_suspend')}
{t('suspenduser.title_suspend')}
</h1>
<p className={styles.description}>
{lang.t('suspenduser.description_suspend', username)}
{t('suspenduser.description_suspend', username)}
</p>
<fieldset>
<legend className={styles.legend}>{lang.t('suspenduser.select_duration')}</legend>
<legend className={styles.legend}>{t('suspenduser.select_duration')}</legend>
<RadioGroup
name='status filter'
value={duration}
@@ -79,18 +77,18 @@ class SuspendUserDialog extends React.Component {
onChange={this.handleDurationChange}
className={styles.radioGroup}
>
<Radio value='1'>{lang.t('suspenduser.one_hour')}</Radio>
<Radio value='3'>{lang.t('suspenduser.hours', 3)}</Radio>
<Radio value='24'>{lang.t('suspenduser.hours', 24)}</Radio>
<Radio value='168'>{lang.t('suspenduser.days', 7)}</Radio>
<Radio value='1'>{t('suspenduser.one_hour')}</Radio>
<Radio value='3'>{t('suspenduser.hours', 3)}</Radio>
<Radio value='24'>{t('suspenduser.hours', 24)}</Radio>
<Radio value='168'>{t('suspenduser.days', 7)}</Radio>
</RadioGroup>
</fieldset>
<div className={styles.buttons}>
<Button cStyle="white" className={styles.cancel} onClick={onCancel} raised>
{lang.t('suspenduser.cancel')}
{t('suspenduser.cancel')}
</Button>
<Button cStyle="black" className={styles.perform} onClick={this.goToStep1} raised>
{lang.t('suspenduser.suspend_user')}
{t('suspenduser.suspend_user')}
</Button>
</div>
</section>
@@ -103,13 +101,13 @@ class SuspendUserDialog extends React.Component {
return (
<section>
<h1 className={styles.header}>
{lang.t('suspenduser.title_notify')}
{t('suspenduser.title_notify')}
</h1>
<p className={styles.description}>
{lang.t('suspenduser.description_notify', username)}
{t('suspenduser.description_notify', username)}
</p>
<fieldset>
<legend className={styles.legend}>{lang.t('suspenduser.write_message')}</legend>
<legend className={styles.legend}>{t('suspenduser.write_message')}</legend>
<textarea
rows={5}
className={styles.messageInput}
@@ -118,7 +116,7 @@ class SuspendUserDialog extends React.Component {
</fieldset>
<div className={styles.buttons}>
<Button cStyle="white" className={styles.cancel} onClick={onCancel} raised>
{lang.t('suspenduser.cancel')}
{t('suspenduser.cancel')}
</Button>
<Button
cStyle="black"
@@ -127,7 +125,7 @@ class SuspendUserDialog extends React.Component {
disabled={this.state.message.length === 0}
raised
>
{lang.t('suspenduser.send')}
{t('suspenduser.send')}
</Button>
</div>
</section>
@@ -5,10 +5,10 @@ export const actionsMap = {
};
export const menuActionsMap = {
'REJECT': {status: 'REJECTED', text: 'Reject', icon: 'close', key: 'r'},
'REJECTED': {status: 'REJECTED', text: 'Rejected', icon: 'close'},
'APPROVE': {status: 'ACCEPTED', text: 'Approve', icon: 'done', key: 't'},
'FLAGGED': {status: 'FLAGGED', text: 'Flag', icon: 'flag', filter: 'Untouched'},
'BAN': {status: 'BANNED', text: 'Ban User', icon: 'not interested'},
'REJECT': {status: 'REJECTED', text: 'reject', icon: 'close', key: 'r'},
'REJECTED': {status: 'REJECTED', text: 'rejected', icon: 'close'},
'APPROVE': {status: 'ACCEPTED', text: 'approve', icon: 'done', key: 't'},
'FLAGGED': {status: 'FLAGGED', text: 'flag', icon: 'flag', filter: 'Untouched'},
'BAN': {status: 'BANNED', text: 'ban_user', icon: 'not interested'},
'': {icon: 'done'}
};
@@ -1,9 +1,8 @@
import React, {Component} from 'react';
import styles from './Stories.css';
import {connect} from 'react-redux';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
import {fetchAssets, updateAssetState} from 'coral-admin/src/actions/assets';
import translations from 'coral-admin/src/translations.json';
import {Link} from 'react-router';
import {Pager, Icon} from 'coral-ui';
@@ -82,14 +81,14 @@ class Stories extends Component {
className={closed ? styles.statusMenuClosed : styles.statusMenuOpen}
onClick={this.onStatusClick(closed, id, statusMenuOpen)}>
{!statusMenuOpen && <Icon className={styles.statusMenuIcon} name='keyboard_arrow_down'/>}
{closed ? lang.t('streams.closed') : lang.t('streams.open')}
{closed ? t('streams.closed') : t('streams.open')}
</div>
{
statusMenuOpen &&
<div
className={!closed ? styles.statusMenuClosed : styles.statusMenuOpen}
onClick={this.onStatusClick(!closed, id, statusMenuOpen)}>
{!closed ? lang.t('streams.closed') : lang.t('streams.open')}
{!closed ? t('streams.closed') : t('streams.open')}
</div>
}
</div>;
@@ -121,10 +120,10 @@ class Stories extends Component {
value={search}
className={styles.searchBoxInput}
onChange={this.onSearchChange}
placeholder={lang.t('streams.search')}/>
placeholder={t('streams.search')}/>
</div>
<div className={styles.optionHeader}>{lang.t('streams.filter-streams')}</div>
<div className={styles.optionDetail}>{lang.t('streams.stream-status')}</div>
<div className={styles.optionHeader}>{t('streams.filter_streams')}</div>
<div className={styles.optionDetail}>{t('streams.stream_status')}</div>
<RadioGroup
name='status filter'
value={filter}
@@ -132,11 +131,11 @@ class Stories extends Component {
onChange={this.onSettingChange('filter')}
className={styles.radioGroup}
>
<Radio value='all'>{lang.t('streams.all')}</Radio>
<Radio value='open'>{lang.t('streams.open')}</Radio>
<Radio value='closed'>{lang.t('streams.closed')}</Radio>
<Radio value='all'>{t('streams.all')}</Radio>
<Radio value='open'>{t('streams.open')}</Radio>
<Radio value='closed'>{t('streams.closed')}</Radio>
</RadioGroup>
<div className={styles.optionHeader}>{lang.t('streams.sort-by')}</div>
<div className={styles.optionHeader}>{t('streams.sort_by')}</div>
<RadioGroup
name='sort by'
value={sort}
@@ -144,20 +143,20 @@ class Stories extends Component {
onChange={this.onSettingChange('sort')}
className={styles.radioGroup}
>
<Radio value='desc'>{lang.t('streams.newest')}</Radio>
<Radio value='asc'>{lang.t('streams.oldest')}</Radio>
<Radio value='desc'>{t('streams.newest')}</Radio>
<Radio value='asc'>{t('streams.oldest')}</Radio>
</RadioGroup>
</div>
{
assetsIds.length
? <div className={styles.mainContent}>
<DataTable className={styles.streamsTable} rows={assetsIds} onClick={this.goToModeration}>
<TableHeader name="title" cellFormatter={this.renderTitle}>{lang.t('streams.article')}</TableHeader>
<TableHeader name="title" cellFormatter={this.renderTitle}>{t('streams.article')}</TableHeader>
<TableHeader name="publication_date" cellFormatter={this.renderDate}>
{lang.t('streams.pubdate')}
{t('streams.pubdate')}
</TableHeader>
<TableHeader name="closedAt" cellFormatter={this.renderStatus} className={styles.status}>
{lang.t('streams.status')}
{t('streams.status')}
</TableHeader>
</DataTable>
<Pager
@@ -165,7 +164,7 @@ class Stories extends Component {
page={this.state.page}
onNewPageHandler={this.onPageClick} />
</div>
: <EmptyCard>{lang.t('streams.empty_result')}</EmptyCard>
: <EmptyCard>{t('streams.empty_result')}</EmptyCard>
}
</div>
);
@@ -188,5 +187,3 @@ const mapDispatchToProps = (dispatch) => {
};
export default connect(mapStateToProps, mapDispatchToProps)(Stories);
const lang = new I18n(translations);
@@ -1,9 +1,9 @@
import React, {Component} from 'react';
import styles from './Stories.css';
import {connect} from 'react-redux';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
import {fetchAssets, updateAssetState} from '../../actions/assets';
import translations from '../../translations.json';
import {Link} from 'react-router';
import {Pager, Icon} from 'coral-ui';
@@ -81,14 +81,14 @@ class Stories extends Component {
className={closed ? styles.statusMenuClosed : styles.statusMenuOpen}
onClick={this.onStatusClick(closed, id, statusMenuOpen)}>
{!statusMenuOpen && <Icon className={styles.statusMenuIcon} name='keyboard_arrow_down'/>}
{closed ? lang.t('streams.closed') : lang.t('streams.open')}
{closed ? t('streams.closed') : t('streams.open')}
</div>
{
statusMenuOpen &&
<div
className={!closed ? styles.statusMenuClosed : styles.statusMenuOpen}
onClick={this.onStatusClick(!closed, id, statusMenuOpen)}>
{!closed ? lang.t('streams.closed') : lang.t('streams.open')}
{!closed ? t('streams.closed') : t('streams.open')}
</div>
}
</div>;
@@ -116,10 +116,10 @@ class Stories extends Component {
value={search}
className={styles.searchBoxInput}
onChange={this.onSearchChange}
placeholder={lang.t('streams.search')}/>
placeholder={t('streams.search')}/>
</div>
<div className={styles.optionHeader}>{lang.t('streams.filter-streams')}</div>
<div className={styles.optionDetail}>{lang.t('streams.stream-status')}</div>
<div className={styles.optionHeader}>{t('streams.filter_streams')}</div>
<div className={styles.optionDetail}>{t('streams.stream_status')}</div>
<RadioGroup
name='status filter'
value={filter}
@@ -127,11 +127,11 @@ class Stories extends Component {
onChange={this.onSettingChange('filter')}
className={styles.radioGroup}
>
<Radio value='all'>{lang.t('streams.all')}</Radio>
<Radio value='open'>{lang.t('streams.open')}</Radio>
<Radio value='closed'>{lang.t('streams.closed')}</Radio>
<Radio value='all'>{t('streams.all')}</Radio>
<Radio value='open'>{t('streams.open')}</Radio>
<Radio value='closed'>{t('streams.closed')}</Radio>
</RadioGroup>
<div className={styles.optionHeader}>{lang.t('streams.sort-by')}</div>
<div className={styles.optionHeader}>{t('streams.sort_by')}</div>
<RadioGroup
name='sort by'
value={sort}
@@ -139,20 +139,20 @@ class Stories extends Component {
onChange={this.onSettingChange('sort')}
className={styles.radioGroup}
>
<Radio value='desc'>{lang.t('streams.newest')}</Radio>
<Radio value='asc'>{lang.t('streams.oldest')}</Radio>
<Radio value='desc'>{t('streams.newest')}</Radio>
<Radio value='asc'>{t('streams.oldest')}</Radio>
</RadioGroup>
</div>
{
assetsIds.length
? <div className={styles.mainContent}>
<DataTable className={styles.streamsTable} rows={assetsIds} onClick={this.goToModeration}>
<TableHeader name="title" cellFormatter={this.renderTitle}>{lang.t('streams.article')}</TableHeader>
<TableHeader name="title" cellFormatter={this.renderTitle}>{t('streams.article')}</TableHeader>
<TableHeader name="publication_date" cellFormatter={this.renderDate}>
{lang.t('streams.pubdate')}
{t('streams.pubdate')}
</TableHeader>
<TableHeader name="closedAt" cellFormatter={this.renderStatus} className={styles.status}>
{lang.t('streams.status')}
{t('streams.status')}
</TableHeader>
</DataTable>
<Pager
@@ -160,7 +160,7 @@ class Stories extends Component {
page={this.state.page}
onNewPageHandler={this.onPageClick} />
</div>
: <EmptyCard>{lang.t('streams.empty_result')}</EmptyCard>
: <EmptyCard>{t('streams.empty_result')}</EmptyCard>
}
</div>
);
@@ -183,5 +183,3 @@ const mapDispatchToProps = (dispatch) => {
};
export default connect(mapStateToProps, mapDispatchToProps)(Stories);
const lang = new I18n(translations);
+3
View File
@@ -8,6 +8,9 @@ import store from './services/store';
import App from './components/App';
import 'react-mdl/extra/material.js';
import {loadPluginsTranslations} from 'coral-framework/helpers/plugins';
loadPluginsTranslations();
render(
<ApolloProvider client={client} store={store}>
@@ -1,9 +1,6 @@
import translations from 'coral-admin/src/translations';
import I18n from 'coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
import {toast} from 'react-toastify';
const lang = new I18n(translations);
export function success(msg) {
return toast(msg, {type: 'success'});
}
@@ -21,7 +18,7 @@ export function showMutationErrors(err) {
errors.forEach((err) => {
console.error(err);
toast(
err.translation_key ? lang.t(`errors.${err.translation_key}`) : err,
err.translation_key ? t(`error.${err.translation_key}`) : err,
{type: 'error'}
);
});
-382
View File
@@ -1,382 +0,0 @@
{
"en": {
"errors": {
"NOT_AUTHORIZED": "You are not authorized to perform this action.",
"LOGIN_MAXIMUM_EXCEEDED": "You have made too many unsuccessful password attempts. Please wait."
},
"community": {
"username_and_email": "Username and Email",
"account_creation_date": "Account Creation Date",
"newsroom_role": "Newsroom Role",
"admin": "Administrator",
"moderator": "Moderator",
"staff": "Staff",
"role": "Select role...",
"no-results": "No users found with that user name or email address. They're hiding!",
"status": "Status",
"select-status": "Select status...",
"active": "Active",
"banned": "Banned",
"banned-user": "Banned User",
"loading": "Loading results",
"flags": "Flags",
"flaggedaccounts": "Flagged Usernames",
"people": "People",
"no-flagged-accounts": "The Account Flags queue is currently empty.",
"I don't like this username": "I don't like this username",
"This user is impersonating": "Impersonation",
"This looks like an ad/marketing": "Spam/Ads",
"This username is offensive": "Offensive",
"Other": "Other",
"ban_user": "Ban User?",
"are_you_sure": "Are you sure you would like to ban {0}?",
"note": "Note: Banning this user will not let them edit, comment or remove anything.",
"cancel": "Cancel",
"yes_ban_user": "Yes, Ban User"
},
"modqueue": {
"likes": "likes",
"all": "all",
"approved": "approved",
"premod": "pre-mod",
"rejected": "rejected",
"flagged": "flagged",
"account": "account flags",
"shortcuts": "Shortcuts",
"close": "Close",
"actions": "Actions",
"navigation": "Navigation",
"mod-faster": "Moderate faster with keyboard shortcuts",
"try-these": "Try these",
"view-more-shortcuts": "View more shortcuts",
"shift-key": "⇧",
"approve": "Approve comment",
"reject": "Reject comment",
"nextcomment": "Go to the next comment",
"prevcomment": "Go to the previous comment",
"singleview": "Toggle single comment edit view",
"thismenu": "Open this menu",
"emptyqueue": "No more comments to moderate! You're all caught up. Go have some ☕️",
"showshortcuts": "Show Shortcuts",
"more-detail": "More detail",
"less-detail": "Less detail",
"dont-like-username": "Don't like username",
"impersonating": "Impersonating",
"offensive": "Offensive",
"spam/ads": "Spam/Ads",
"other": "Other",
"thousand": "k",
"million": "M",
"billion": "B"
},
"comment": {
"flagged": "flagged",
"anon": "Anonymous",
"ban_user": "Ban User",
"view_context": "View context",
"banned_user": "Banned User"
},
"user": {
"user_bio": "User Bio",
"bio_flags": "flags for this bio",
"username_flags": "flags for this username"
},
"embedlink": {
"copy": "Copy to Clipboard"
},
"configure": {
"sign-out": "Sign Out",
"shortcuts": "Shortcuts",
"closed-stream-settings": "Closed Stream Message",
"open-stream-configuration": "This comment stream is currently open. By closing this comment stream, no new comments may be submitted and all previous comments will still be displayed.",
"close-stream-configuration": "This comment stream is currently closed. By opening this comment stream, new comments may be submitted and displayed",
"close-stream": "Close Stream",
"open-stream": "Open Stream",
"stream-settings": "Stream Settings",
"moderation-settings": "Moderation Settings",
"tech-settings": "Tech Settings",
"custom-css-url": "Custom CSS URL",
"custom-css-url-desc": "URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external.",
"dashboard": "Dashboard",
"enable-pre-moderation": "Enable pre-moderation",
"enable-pre-moderation-text": "Moderators must approve any comment before it is published.",
"require-email-verification": "Require Email Verification",
"require-email-verification-text": "New Users must verify their email before commenting",
"include-comment-stream": "Include Comment Stream Description for Readers",
"include-comment-stream-desc": "Write a message to be added to the top of your comment stream. Pose a topic, include community guidelines, etc.",
"include-text": "Include your text here.",
"enable-premod-links": "Pre-Moderate Comments Containing Links",
"enable-premod-links-text": "Moderators must approve any comment containing a link before its published.",
"edit-comment-timeframe-heading": "Edit Comment Timeframe",
"edit-comment-timeframe-text-pre": "Commenters will have",
"edit-comment-timeframe-text-post": "seconds to edit their comments.",
"comment-settings": "Settings",
"embed-comment-stream": "Embed Stream",
"banned-word-text": "Comments which contain these words or phrases (not case-sensitive) will be automatically removed from the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list.",
"suspect-word-text": "Comments which contain these words or phrases (not case-sensitive) will be highlighted in the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list.",
"wordlist": "Banned Words",
"banned-words-title": "Banned words list",
"suspect-words-title": "Suspect words list",
"save-changes": "Save Changes",
"copy-and-paste": "Copy and paste code below into your CMS to embed your comment box in your articles",
"moderate": "Moderate",
"configure": "Configure",
"community": "Community",
"stories": "Stories",
"closed-comments-desc": "Write a message to be displayed when when your comment stream is closed and no longer accepting comments.",
"closed-comments-label": "Write a message...",
"hours": "Hours",
"days": "Days",
"weeks": "Weeks",
"close-after": "Close comments after",
"comment-count-header": "Limit Comment Length",
"comment-count-text-pre": "Comments will be limited to ",
"comment-count-text-post": " characters",
"comment-count-error": "Please enter a valid number.",
"domain-list-title": "Permitted Domains",
"domain-list-text": "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com)."
},
"bandialog": {
"ban_user": "Ban User?",
"are_you_sure": "Are you sure you would like to ban {0}?",
"note": "Note: Banning this user will also place this comment in the Rejected queue.",
"cancel": "Cancel",
"yes_ban_user": "Yes, Ban User"
},
"suspenduser": {
"title_suspend": "Suspend User",
"description_suspend": "You are suspending {0}. This comment will go to the Rejected queue, and {0} will not be allowed to like, report, reply or post until the suspension time is complete.",
"select_duration": "Select suspension duration",
"title_reject": "We noticed you rejected a username",
"description_reject": "Would you like to temporarily ban this user because of their {0}? Doing so will temporarily hide their comments until they rewrite their {0}.",
"title_notify": "Notify the user of their temporary suspension",
"description_notify": "Suspending this user will temporarily disable their account and hide all of their comments on the site.",
"no_cancel": "No, cancel",
"yes_suspend": "Yes, suspend",
"send": "Send",
"bio": "bio",
"username": "username",
"email_subject": "Your account has been suspended",
"email_message_reject": "Another member of the community recently flagged your username for review. Because of its content your user was rejected. This means you can no longer comment, like, or flag content until you rewrite your username. Please e-mail us if you have any questions or concerns.",
"email_message_suspend": "Dear {0},\n\nIn accordance with {1}s community guidelines, your account has been temporarily suspended. During the suspension, you will be unable to comment, flag or engage with fellow commenters. Please rejoin the conversation {2}.",
"write_message": "Write a message",
"one_hour": "1 hour",
"hours": "{0} hours",
"days": "{0} days",
"suspend_user": "Suspend User",
"cancel": "Cancel",
"error_email_message_empty": "You must specify an E-Mail message.",
"notify_suspend_until": "User {0} has been temporarily suspended. This suspension will automatically end {1}."
},
"dashboard": {
"next-update": "{0} minutes until next update.",
"auto-update": "Data automatically updates every five minutes or when you Reload.",
"no_flags": "There have been no flags in the last 5 minutes! Hooray!",
"no_likes": "There have been no likes in the last 5 minutes. All quiet.",
"flags": "Flags",
"no_activity": "There haven't been any comments anywhere in the last five minutes.",
"comment_count": "comments",
"most_flags": "Articles with the most flags"
},
"streams": {
"empty_result": "No assets match this search. Maybe try widening your search?",
"search": "Search",
"filter-streams": "Filter Streams",
"stream-status": "Stream Status",
"all": "All",
"open": "Open",
"closed": "Closed",
"newest": "Newest",
"oldest": "Oldest",
"sort-by": "Sort By",
"open": "Open",
"closed": "Closed",
"article": "Story",
"pubdate": "Publication Date",
"status": "Stream Status"
}
},
"es": {
"errors": {
"NOT_AUTHORIZED": "Acción no autorizada.",
"LOGIN_MAXIMUM_EXCEEDED": "Ha realizado demasiados intentos fallidos de colocar la contraseña. Por favor espere."
},
"community": {
"username_and_email": "Usuario y E-mail",
"account_creation_date": "Fecha de creación de la cuenta",
"newsroom_role": "Rol en la redacción",
"admin": "Administradora",
"moderator": "Moderadora",
"staff": "Miembro",
"role": "Seleccionar rol...",
"no-results": "No se encontraron usuarixs con ese nombre de usuario o e-mail.",
"status": "Estado",
"select-status": "Seleccionar estado...",
"active": "Activa",
"banned": "Suspendido",
"banned-user": "Usuario Suspendido",
"loading": "Cargando resultados",
"flags": "Reporte",
"flaggedaccounts": "Nombres de Usuario Reportados",
"people": "Gente",
"no-flagged-accounts": "No hay ninguna cuenta reportada.",
"I don't like this username": "No me gusta ese nombre de usuario",
"This user is impersonating": "Suplantación",
"This looks like an ad/marketing": "Spam/Propaganda",
"This username is offensive": "Ofensivo",
"Other": "Otros",
"ban_user": "Quieres suspender al Usuario?",
"are_you_sure": "Estas segura que quieres suspender a {0}?",
"note": "Nota: Suspender a este usuario no le va a permitir (al usuario) borrar ni editar ni comentar.",
"cancel": "Cancelar",
"yes_ban_user": "Si, Suspendan el usuario"
},
"suspenduser": {
"title_suspend": "Suspender Usuario",
"title_reject": "Esta queriendo suspender un usuario?",
"description_reject": "Le gustaria suspender a esta usuaria temporarianmente por su nombre de usuario? Si lo hace sus comentarios serán escondidos temporariamente hasta que puedan reescribir su nombre de usuario.",
"title_notify": "Enviarle una nota al usuario sobre su cuenta suspendida",
"description_notify": "Si suspende a este usuario, su cuenta va a ser deshabilitada y todos sus comentarios escondidos del sitio.",
"no_cancel": "No, cancelar",
"yes_suspend": "Si, suspender",
"send": "Enviar",
"username": "nombre de usuario",
"email_subject": "Su cuenta ha sido suspendida temporariamente",
"email_message_reject": "Otra persona de la comunidad recientemente marcó su nombre de usuario para ser revisado. Por su contenido, el nombre de usuario ha sido rechazado. Esto quiere decir que no puede comentar, gustar o marcar contenido hasta que modifique su nombre de usuario. Por favor, envienos un correo a moderator@newsorg.com si tiene alguna pregunta o preocupación",
"write_message": "Escribir un mensaje",
"loading": "Cargando resultados",
"hour": "una hora",
"hours": "{0} horas",
"days": "{0} días",
"suspend_user": "Suspender",
"cancel": "Cancelar"
},
"modqueue": {
"all": "todos",
"approved": "aprobado",
"likes": "gustos",
"premod": "pre-mod",
"rejected": "rechazado",
"flagged": "marcado",
"shortcuts": "Atajos de teclado",
"mod-faster": "Moderar más rápido con atajos del teclado",
"try-these": "Intenta estos",
"view-more-shortcuts": "Ver más atajos",
"shift-key": "⇧",
"close": "Cerrar",
"emptyqueue": "No se encontro ningún usuario. Están escondidos.",
"showshortcuts": "Mostrar atajos",
"more-detail": "Mas detalle",
"less-detail": "Menos detalle",
"dont-like-username": "No me gusta ese nombre de usuario",
"impersonating": "Suplantación",
"offensive": "Ofensivo",
"spam/ads": "Spam/Propaganda",
"other": "Otros",
"thousand": "m",
"million": "M",
"billion": "B"
},
"comment": {
"flagged": "marcado",
"anon": "Anónimo",
"view_context": "Ver contexto",
"ban_user": "Suspender Usuario",
"banned_user": "Usuario Suspendido"
},
"user": {
"user_bio": "marcas para este usuario",
"bio_flags": "marcas para esta biografia",
"username_flags": "marcas para este nombre de usuario"
},
"configure": {
"sign-out": "Desconectar",
"shortcuts": "Atajos",
"closed-stream-settings": "Mensaje a enviar cuando los comentarios están cerrados en el artículo",
"open-stream-configuration": "Este hilo de comentarios esta abierto. Al cerrarlo, ningún nuevo comentario será publicado y todos los comentarios anteriores serán mostrados.",
"close-stream-configuration": "Este hilo de comentario está en este momento cerrado. Al abrirlo, nuevos comentarios serán publicaods y mostrados.",
"close-stream": "Cerrar Comentarios",
"open-stream": "Abrir Comentarios",
"stream-settings": "Configuración de Comentarios",
"moderation-settings": "Configuración de Moderación",
"tech-settings": "Configuración Técnica",
"custom-css-url": "URL CSS a medida",
"custom-css-url-desc": "URL de una hoja de estilo que va a sobrescribir los estilos por defecto del hilo de comentarios. Puede ser interna o externa.",
"dashboard": "Panel",
"enable-pre-moderation": "Habilitar pre-moderación",
"enable-pre-moderation-text": "Los moderadores deben aprobar cada comentario antes de que sea publicado.",
"require-email-verification": "Necesita confirmación de e-mail",
"require-email-verification-text": "Nuevos usuarios deben verificar sus e-mails antes de comentar",
"include-comment-stream": "Incluir la Descripción a un Hilo de Comentario para los y las Lectoras.",
"include-comment-stream-desc": "Escribir un mensaje que será agregado a la parte de arriba del tu hilo de comentarios. Por ejemplo, un tema, guias de comunidad, etc.",
"include-text": "Incluir tu texto aqui.",
"comment-settings": "Configuración de Comentarios",
"embed-comment-stream": "Colocar Hilo de Comentarios",
"enable-premod-links": "Pre-Moderar Commentarios que contienen Enlaces",
"enable-premod-links-text": "Los y las Moderadoras deben aprobar cualquier comentario que contengan links antes de su publicación.",
"edit-comment-timeframe-heading": "Editar Tiempo de Comentario",
"edit-comment-timeframe-text-pre": "Los comentaristas tendrán",
"edit-comment-timeframe-text-post": "segundos para editar sus comentarios.",
"wordlist": "Palabras Suspendidas y Sospechosas",
"banned-word-text": "Comentarios que contengan estas palabras o frases, no separadas por comas y en mayusculas o minusuculas, serán automaticamente marcadas para separar los comentarios publicados.",
"suspect-word-text": "Comentarios que contengan estas palabras o frases, considerando mayusculas y minusculas, serán automaticamente destacadas en los comentarios publicados. Escribir una palabra y apretar Enter o Tabulador para agergarla. Opcionalmente pegar una lista separada por coma.",
"banned-words-title": "Lista de palabras prohibidas",
"suspect-words-title": "Lista de palabras sospechosas",
"save-changes": "Guardar Cambios",
"copy-and-paste": "Copiar y pegar el código de más abajo en tu CMS para colocar la caja de comentarios en tus articulos",
"moderate": "Moderar",
"configure": "Configurar",
"community": "Comunidad",
"stories": "Artículos",
"closed-comments-desc": "Escribe un mensaje que será mostrado cuando los comentarios estén cerrados y no se acepten más comentarios.",
"closed-comments-label": "Escribe un mensaje...",
"never": "Nunca",
"hours": "Horas",
"days": "Días",
"weeks": "Semanas",
"close-after": "Cerrar comentarios luego de",
"comment-count-header": "Limitar el largo del comentario",
"comment-count-text-pre": "El largo de comentarios será ",
"comment-count-text-post": " caracteres",
"comment-count-error": "Por favor escribe un número válido.",
"domain-list-title": "Lista de Dominios Permitidos",
"domain-list-text": "Agrega dominios permitidos a Talk, por ejemplo tu localhost, staging y ambientes de producción (ej. localhost:3000, staging.domain.com, domain.com)."
},
"embedlink": {
"copy": "Copiar"
},
"bandialog": {
"ban_user": "¿Quieres suspender el Usuario?",
"are_you_sure": "¿Estás segura que quieres suspender a {0}?",
"note": "Nota: Suspender a este usuario también va a colocar este comentario en la cola de Rechazados.",
"cancel": "Cancelar",
"yes_ban_user": "Si, Suspendan el usuario"
},
"dashboard": {
"next-update": "{0} minutos hasta la siguiente actualización.",
"auto-update": "Los datos se actualizan automaticamente cada 5 minutos o cuando recargas.",
"no_flags": "¡Nadie ha marcado nada en los últimos 5 minutos! ¡Bravo!",
"no_likes": "A nadie le ha gustado algún comentario en los últimos 5 minutos. Todo tranquilo.",
"flags": "Marcados",
"no_activity": "No hubo comentarios en los ultimos 5 minutos",
"comment_count": "comentarios",
"most_flags": "Articulos con más reportes"
},
"streams": {
"empty_result": "No se encuentro articulo con esta busqueda. ¿Tal vez puedas extender la busqueda?",
"search": "buscar",
"filter-streams": "Filtrar Hilos de Comentarios",
"stream-status": "Estado del Hilo de Comentarios",
"all": "todxs",
"open": "abrir",
"closed": "cerrado",
"newest": "más nuevoß",
"oldest": "más viejo",
"sort-by": "ordenar por",
"article": "artículo",
"pubdate": "Fecha de Pblicación",
"status": "Estado"
}
}
}
@@ -1,25 +1,22 @@
import React from 'react';
import {Button} from 'coral-ui';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-admin/src/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
export default ({status, onClick}) => (
status === 'open' ? (
<div className="close-comments-intro-wrapper">
<p>
{lang.t('configure.open-stream-configuration')}
{t('configure.open_stream_configuration')}
</p>
<Button onClick={onClick}>{lang.t('configure.close-stream')}</Button>
<Button onClick={onClick}>{t('configure.close_stream')}</Button>
</div>
) : (
<div className="close-comments-intro-wrapper">
<p>
{lang.t('configure.close-stream-configuration')}
{t('configure.close_stream_configuration')}
</p>
<Button onClick={onClick}>{lang.t('configure.open-stream')}</Button>
<Button onClick={onClick}>{t('configure.open_stream')}</Button>
</div>
)
);
@@ -3,23 +3,21 @@ import {Button, Checkbox, TextField} from 'coral-ui';
import styles from './ConfigureCommentStream.css';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from '../translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
export default ({handleChange, handleApply, changed, ...props}) => (
<form onSubmit={handleApply}>
<div className={styles.wrapper}>
<div className={styles.container}>
<h3>{lang.t('configureCommentStream.title')}</h3>
<h3>{t('configure.title')}</h3>
<Button
type="submit"
className={styles.apply}
onChange={handleChange}
cStyle={changed ? 'green' : 'darkGrey'} >
{lang.t('configureCommentStream.apply')}
{t('configure.apply')}
</Button>
<p>{lang.t('configureCommentStream.description')}</p>
<p>{t('configure.description')}</p>
</div>
<ul>
<li>
@@ -30,8 +28,8 @@ export default ({handleChange, handleApply, changed, ...props}) => (
onChange={handleChange}
defaultChecked={props.premod}
info={{
title: lang.t('configureCommentStream.enablePremod'),
description: lang.t('configureCommentStream.enablePremodDescription')
title: t('configure.enable_premod'),
description: t('configure.enable_premod_description')
}} />
</li>
<li>
@@ -42,8 +40,8 @@ export default ({handleChange, handleApply, changed, ...props}) => (
onChange={handleChange}
defaultChecked={props.premodLinksEnable}
info={{
title: lang.t('configureCommentStream.enablePremodLinks'),
description: lang.t('configureCommentStream.enablePremodLinksDescription')
title: t('configure.enable_premod_links'),
description: t('configure.enable_premod_links_description')
}} />
</li>
<li>
@@ -54,8 +52,8 @@ export default ({handleChange, handleApply, changed, ...props}) => (
onChange={handleChange}
defaultChecked={props.questionBoxEnable}
info={{
title: lang.t('configureCommentStream.enableQuestionBox'),
description: lang.t('configureCommentStream.enableQuestionBoxDescription')
title: t('configure.enable_questionbox'),
description: t('configure.enable_questionbox_description')
}} />
<div className={`${props.questionBoxEnable ? null : styles.hidden}`} >
<TextField
@@ -63,7 +61,7 @@ export default ({handleChange, handleApply, changed, ...props}) => (
onChange={handleChange}
rows={3}
value={props.questionBoxContent}
label={lang.t('configureCommentStream.includeQuestionHere')}
label={t('configure.include_question_here')}
/>
</div>
</li>
@@ -2,13 +2,12 @@ import React, {Component} from 'react';
import {connect} from 'react-redux';
import {compose} from 'react-apollo';
import {I18n} from 'coral-framework';
import {updateOpenStatus, updateConfiguration} from 'coral-framework/actions/asset';
import CloseCommentsInfo from '../components/CloseCommentsInfo';
import ConfigureCommentStream from '../components/ConfigureCommentStream';
const lang = new I18n();
import t, {timeago} from 'coral-framework/services/i18n';
class ConfigureStreamContainer extends Component {
constructor (props) {
@@ -87,7 +86,7 @@ class ConfigureStreamContainer extends Component {
const {closedTimeout} = this.props.asset.settings;
const {created_at} = this.props.asset;
return lang.timeago(new Date(created_at).getTime() + (1000 * closedTimeout));
return timeago(new Date(created_at).getTime() + (1000 * closedTimeout));
}
render () {
@@ -108,8 +107,8 @@ class ConfigureStreamContainer extends Component {
questionBoxContent={dirtySettings.questionBoxContent}
/>
<hr />
<h3>{closedAt === 'open' ? 'Close' : 'Open'} Comment Stream</h3>
{(closedAt === 'open' && closedTimeout) ? <p>The comment stream will close in {this.getClosedIn()}.</p> : ''}
<h3>{closedAt === 'open' ? t('configure.close') : t('configure.open')} {t('configure.comment_stream')}</h3>
{(closedAt === 'open' && closedTimeout) ? <p>{t('configure.comment_stream_will_close')} {this.getClosedIn()}.</p> : ''}
<CloseCommentsInfo
onClick={this.toggleStatus}
status={closedAt}
-30
View File
@@ -1,30 +0,0 @@
{
"en": {
"configureCommentStream": {
"apply": "Apply",
"title": "Configure Comment Stream",
"description": "As an admin you may customize the settings for the comment stream for this asset",
"enablePremod": "Enable Premoderation",
"enablePremodDescription": "Moderators must approve any comment before its published.",
"enablePremodLinks": "Pre-Moderate Comments Containing Links",
"enablePremodLinksDescription": "Moderators must approve any comment containing a link before its published.",
"enableQuestionBox": "Ask readers a question",
"enableQuestionBoxDescription": "This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions, etc.",
"includeQuestionHere": "Write your question here."
}
},
"es": {
"configureCommentStream": {
"apply": "Aplicar",
"title": "Configurar los comentarios",
"description": "Como Administrador/a puedes modificar las opciones de los comentarios en este artículo",
"enablePremod": "Activar Pre Moderación",
"enablePremodDescription": "Los y las Moderadoras deben aprobar cualquier comentario antes de su publicación",
"enablePremodLinks": "Pre-Moderar Comentarios que contienen Enlaces",
"enablePremodLinksDescription": "Los y las moderadoras deben aprobar cualquier comentario que contengan enlaces antes de su publicación.",
"enableQuestionBox": "Hacer una pregunta a los y las lectoras.",
"enableQuestionBoxDescription": "Esta pregunta aparecera en la parte de arriba del hilo de comentarios.",
"includeQuestionHere": "Escribir la pregunta aquí."
}
}
}
@@ -1,8 +1,5 @@
import React, {PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
/**
* Countdown the number of seconds until a given Date
@@ -30,7 +27,7 @@ export class CountdownSeconds extends React.Component {
componentWillUnmount() {
if (this.countdownInterval) {
this.countdownInterval = clearInterval(this.countdownInterval);
}
}
}
render() {
const now = new Date();
@@ -39,7 +36,7 @@ export class CountdownSeconds extends React.Component {
const secRemaining = msRemaining / 1000;
const wholeSecRemaining = Math.floor(secRemaining);
const plural = secRemaining !== 1;
const units = lang.t(plural ? 'editComment.secondsPlural' : 'editComment.second');
const units = t(plural ? 'edit_comment.seconds_plural' : 'edit_comment.second');
let classFromProp;
if (typeof classNameForMsRemaining === 'function') {
classFromProp = classNameForMsRemaining(msRemaining);
@@ -6,9 +6,7 @@ import {CountdownSeconds} from './CountdownSeconds';
import {getEditableUntilDate} from './util';
import {Icon} from 'coral-ui';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
/**
* Renders a Comment's body in such a way that the end-user can edit it and save changes
@@ -83,11 +81,11 @@ export class EditableCommentContent extends React.Component {
successfullyEdited = true;
} catch (error) {
if (error.translation_key) {
addNotification('error', lang.t(`error.${error.translation_key}`));
addNotification('error', t(`error.${error.translation_key}`));
} else if (error.networkError) {
addNotification('error', lang.t('error.networkError'));
addNotification('error', t('error.network_error'));
} else {
addNotification('error', lang.t('editComment.unexpectedError'));
addNotification('error', t('edit_comment.unexpected_error'));
throw error;
}
}
@@ -116,9 +114,9 @@ export class EditableCommentContent extends React.Component {
return (comment.body !== originalBody) && !editWindowExpired;
}}
saveComment={this.editComment}
bodyLabel={lang.t('editComment.bodyInputLabel')}
bodyLabel={t('edit_comment.body_input_label')}
bodyPlaceholder=""
submitText={<span>{lang.t('editComment.saveButton')}</span>}
submitText={<span>{t('edit_comment.save_button')}</span>}
saveButtonCStyle="green"
cancelButtonClicked={this.props.stopEditing}
buttonClass={styles.button}
@@ -128,15 +126,15 @@ export class EditableCommentContent extends React.Component {
{
editWindowExpired
? <span>
{lang.t('editComment.editWindowExpired')}
{t('edit_comment.edit_window_expired')}
{
typeof this.props.stopEditing === 'function'
? <span>&nbsp;<a className={styles.link} onClick={this.props.stopEditing}>{lang.t('editComment.editWindowExpiredClose')}</a></span>
? <span>&nbsp;<a className={styles.link} onClick={this.props.stopEditing}>{t('edit_comment.edit_window_expired_close')}</a></span>
: null
}
</span>
: <span>
<Icon name="timer"/> {lang.t('editComment.editWindowTimerPrefix')}
<Icon name="timer"/> {t('edit_comment.edit_window_timer_prefix')}
<CountdownSeconds
until={editableUntil}
classNameForMsRemaining={(remainingMs) => (remainingMs <= 10 * 1000) ? styles.editWindowAlmostOver : '' }
@@ -1,10 +1,9 @@
import React from 'react';
const lang = new I18n(translations);
import Stream from '../containers/Stream';
import Slot from 'coral-framework/components/Slot';
import {can} from 'coral-framework/services/perms';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations';
import t from 'coral-framework/services/i18n';
import {TabBar, Tab, TabContent, Button} from 'coral-ui';
import Count from 'coral-plugin-comment-count/CommentCount';
import ProfileContainer from 'coral-settings/containers/ProfileContainer';
@@ -44,8 +43,8 @@ export default class Embed extends React.Component {
<div className="commentStream">
<TabBar onChange={this.changeTab} activeTab={activeTab}>
<Tab><Count count={totalCommentCount} /></Tab>
<Tab>{lang.t('myProfile')}</Tab>
<Tab restricted={!can(user, 'UPDATE_CONFIG')}>Configure Stream</Tab>
<Tab>{t('framework.my_profile')}</Tab>
<Tab restricted={!can(user, 'UPDATE_CONFIG')}>{t('framework.configure_stream')}</Tab>
</TabBar>
{commentId &&
<Button
@@ -53,7 +52,7 @@ export default class Embed extends React.Component {
style={{float: 'right'}}
onClick={viewAllComments}
>
{lang.t('showAllComments')}
{t('framework.show_all_comments')}
</Button>}
<Slot fill="embed" />
<TabContent show={activeTab === 'stream'}>
@@ -1,8 +1,6 @@
import React from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
// Render in place of a Comment when the author of the comment is ignored
const IgnoredCommentTombstone = () => (
@@ -14,7 +12,7 @@ const IgnoredCommentTombstone = () => (
padding: '1em',
color: '#3E4F71',
}}>
{lang.t('commentIsIgnored')}
{t('framework.comment_is_ignored')}
</p>
</div>
);
@@ -1,9 +1,7 @@
import React, {PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations.json';
import {ADDTL_COMMENTS_ON_LOAD_MORE} from '../constants/stream';
import {Button} from 'coral-ui';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const loadMoreComments = (assetId, comments, loadMore, parentId, replyCount) => {
@@ -31,13 +29,13 @@ class LoadMore extends React.Component {
replyCountFormat = (count) => {
if (count === 1) {
return lang.t('viewReply');
return t('framework.view_reply');
}
if (this.initialState) {
return lang.t('viewAllRepliesInitial', count);
return t('framework.view_all_replies_initial', count);
} else {
return lang.t('viewAllReplies', count);
return t('framework.view_all_replies', count);
}
}
@@ -50,7 +48,7 @@ class LoadMore extends React.Component {
this.initialState = false;
loadMoreComments(assetId, comments, loadMore, parentId, replyCount);
}}>
{topLevel ? lang.t('viewMoreComments') : this.replyCountFormat(replyCount)}
{topLevel ? t('framework.view_more_comments') : this.replyCountFormat(replyCount)}
</Button>
</div>
: null;
@@ -1,7 +1,6 @@
import React, {PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const onLoadMoreClick = ({loadMore, commentCount, firstCommentDate, assetId, setCommentCountCache}) => (e) => {
e.preventDefault();
@@ -22,8 +21,8 @@ const NewCount = (props) => {
props.commentCountCache && newComments > 0 ?
<button onClick={onLoadMoreClick(props)}>
{newComments === 1
? lang.t('newCount', newComments, lang.t('comment'))
: lang.t('newCount', newComments, lang.t('comments'))}
? t('framework.new_count', newComments, t('framework.comment'))
: t('framework.new_count', newComments, t('framework.comments'))}
</button>
: null
}
@@ -4,17 +4,16 @@ import NewCount from './NewCount';
import Comment from '../containers/Comment';
import SuspendedAccount from './SuspendedAccount';
import RestrictedMessageBox
from 'coral-framework/components/RestrictedMessageBox';
import Slot from 'coral-framework/components/Slot';
import InfoBox from 'coral-plugin-infobox/InfoBox';
import {can} from 'coral-framework/services/perms';
import I18n from 'coral-framework/modules/i18n/i18n';
import {ModerationLink} from 'coral-plugin-moderation';
import translations from 'coral-framework/translations';
import CommentBox from 'coral-plugin-commentbox/CommentBox';
import QuestionBox from 'coral-plugin-questionbox/QuestionBox';
import IgnoredCommentTombstone from './IgnoredCommentTombstone';
const lang = new I18n(translations);
import t, {timeago} from 'coral-framework/services/i18n';
class Stream extends React.Component {
setActiveReplyBox = (reactKey) => {
@@ -87,10 +86,10 @@ class Stream extends React.Component {
{!banned &&
temporarilySuspended &&
<RestrictedMessageBox>
{lang.t(
'temporarilySuspended',
{t(
'stream.temporarily_suspended',
this.props.root.settings.organizationName,
lang.timeago(user.suspension.until)
timeago(user.suspension.until)
)}
</RestrictedMessageBox>}
{banned &&
@@ -1,7 +1,5 @@
import React, {Component, PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations.json';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
import styles from './SuspendAccount.css';
import {Button} from 'coral-ui';
import validate from 'coral-framework/helpers/validate';
@@ -27,10 +25,10 @@ class SuspendedAccount extends Component {
editName(username)
.then(() => location.reload())
.catch((error) => {
this.setState({alert: lang.t(`error.${error.translation_key}`)});
this.setState({alert: t(`error.${error.translation_key}`)});
});
} else {
this.setState({alert: lang.t('editName.error')});
this.setState({alert: t('framework.edit_name.error')});
}
}
@@ -42,8 +40,8 @@ class SuspendedAccount extends Component {
return <RestrictedMessageBox>
<span>{
canEditName ?
lang.t('editName.msg')
: lang.t('bannedAccountMsg')
t('framework.edit_name.msg')
: t('framework.banned_account_msg')
}</span>
{
canEditName ?
@@ -55,20 +53,20 @@ class SuspendedAccount extends Component {
htmlFor='username'
className="screen-reader-text"
aria-hidden={true}>
{lang.t('editName.label')}
{t('framework.edit_name.label')}
</label>
<input
type='text'
className={styles.editNameInput}
value={username}
placeholder={lang.t('editName.label')}
placeholder={t('framework.edit_name.label')}
id='username'
onChange={(e) => this.setState({username: e.target.value})}
rows={3}/><br/>
<Button
onClick={this.onSubmitClick}>
{
lang.t('editName.button')
t('framework.edit_name.button')
}
</Button>
</div> : null
+2
View File
@@ -11,7 +11,9 @@ import reducers from './reducers';
import store, {injectReducers} from 'coral-framework/services/store';
import AppRouter from './AppRouter';
import {pym} from 'coral-framework';
import {loadPluginsTranslations} from 'coral-framework/helpers/plugins';
loadPluginsTranslations();
injectReducers(reducers);
// Don't run this in the popup.
+3 -6
View File
@@ -2,9 +2,7 @@ import * as actions from '../constants/asset';
import coralApi from '../helpers/request';
import {addNotification} from '../actions/notification';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from './../translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
export const fetchAssetRequest = () => ({type: actions.FETCH_ASSET_REQUEST});
export const fetchAssetSuccess = (asset) => ({type: actions.FETCH_ASSET_SUCCESS, asset});
@@ -19,7 +17,7 @@ export const updateConfiguration = (newConfig) => (dispatch, getState) => {
dispatch(updateAssetSettingsRequest());
coralApi(`/assets/${assetId}/settings`, {method: 'PUT', body: newConfig})
.then(() => {
dispatch(addNotification('success', lang.t('successUpdateSettings')));
dispatch(addNotification('success', t('framework.success_update_settings')));
dispatch(updateAssetSettingsSuccess(newConfig));
})
.catch((error) => dispatch(updateAssetSettingsFailure(error)));
@@ -30,7 +28,7 @@ export const updateOpenStream = (closedBody) => (dispatch, getState) => {
dispatch(fetchAssetRequest());
coralApi(`/assets/${assetId}/status`, {method: 'PUT', body: closedBody})
.then(() => {
dispatch(addNotification('success', lang.t('successUpdateSettings')));
dispatch(addNotification('success', t('framework.success_update_settings')));
dispatch(fetchAssetSuccess(closedBody));
})
.catch((error) => dispatch(fetchAssetFailure(error)));
@@ -48,4 +46,3 @@ export const updateOpenStatus = (status) => (dispatch) => {
dispatch(updateOpenStream({closedAt: new Date().getTime()}));
}
};
+5 -7
View File
@@ -5,9 +5,7 @@ import * as actions from '../constants/auth';
import * as Storage from '../helpers/storage';
import coralApi, {base} from '../helpers/request';
const lang = new I18n(translations);
import translations from './../translations';
import I18n from '../../coral-framework/modules/i18n/i18n';
import t from 'coral-framework/services/i18n';
export const showSignInDialog = () => (dispatch, getState) => {
const signInPopUp = window.open(
@@ -74,7 +72,7 @@ export const createUsername = (userId, formData) => (dispatch) => {
dispatch(updateUsername(formData));
})
.catch((error) => {
dispatch(createUsernameFailure(lang.t(`error.${error.translation_key}`)));
dispatch(createUsernameFailure(t(`error.${error.translation_key}`)));
});
};
@@ -146,12 +144,12 @@ export const fetchSignIn = (formData) => {
// the user might not have a valid email. prompt the user user re-request the confirmation email
dispatch(
signInFailure(lang.t('error.emailNotVerified', error.metadata))
signInFailure(t('error.email_not_verified', error.metadata))
);
} else {
// invalid credentials
dispatch(signInFailure(lang.t('error.emailPasswordError')));
dispatch(signInFailure(t('error.email_password')));
}
});
};
@@ -236,7 +234,7 @@ export const fetchSignUp = (formData, redirectUri) => (dispatch) => {
dispatch(signUpSuccess(user));
})
.catch((error) => {
let errorMessage = lang.t(`error.${error.message}`);
let errorMessage = t(`error.${error.message}`);
// if there is no translation defined, just show the error string
if (errorMessage === `error.${error.message}`) {
+3 -5
View File
@@ -2,9 +2,7 @@ import {addNotification} from '../actions/notification';
import coralApi from '../helpers/request';
import * as actions from '../constants/auth';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from './../translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const editUsernameFailure = (error) => ({type: actions.EDIT_USERNAME_FAILURE, error});
const editUsernameSuccess = () => ({type: actions.EDIT_USERNAME_SUCCESS});
@@ -13,9 +11,9 @@ export const editName = (username) => (dispatch) => {
return coralApi('/account/username', {method: 'PUT', body: {username}})
.then(() => {
dispatch(editUsernameSuccess());
dispatch(addNotification('success', lang.t('successNameUpdate')));
dispatch(addNotification('success', t('framework.success_name_update')));
})
.catch((error) => {
dispatch(editUsernameFailure(lang.t(`error.${error.translation_key}`)));
dispatch(editUsernameFailure(t(`error.${error.translation_key}`)));
});
};
@@ -1,11 +1,9 @@
import React from 'react';
import t from 'coral-framework/services/i18n';
import RestrictedMessageBox from './RestrictedMessageBox';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from 'coral-framework/translations.json';
const lang = new I18n(translations);
export default ({children, restricted, message = lang.t('contentNotAvailable'), restrictedComp}) => {
export default ({children, restricted, message = t('framework.content_not_available'), restrictedComp}) => {
if (restricted) {
return restrictedComp ? restrictedComp : <RestrictedMessageBox message={message} />;
} else {
@@ -16,4 +14,3 @@ export default ({children, restricted, message = lang.t('contentNotAvailable'),
);
}
};
+6 -8
View File
@@ -1,11 +1,9 @@
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from './../translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
export default {
email: lang.t('error.email'),
password: lang.t('error.password'),
username: lang.t('error.username'),
confirmPassword: lang.t('error.confirmPassword'),
organizationName: lang.t('error.organizationName'),
email: t('error.email'),
password: t('error.password'),
username: t('error.username'),
confirmPassword: t('error.confirm_password'),
organizationName: t('error.organization_name'),
};
+10
View File
@@ -6,6 +6,7 @@ import uniq from 'lodash/uniq';
import pick from 'lodash/pick';
import plugins from 'pluginsConfig';
import {getDefinitionName, mergeDocuments} from 'coral-framework/utils';
import {loadTranslations} from 'coral-framework/services/i18n';
export const pluginReducers = merge(
...plugins
@@ -88,3 +89,12 @@ export function getGraphQLExtensions() {
.filter((o) => o);
}
function getTranslations() {
return plugins
.map((o) => o.module.translations)
.filter((o) => o);
}
export function loadPluginsTranslations() {
getTranslations().forEach((t) => loadTranslations(t));
}
-2
View File
@@ -1,12 +1,10 @@
import pym from './services/PymConnection';
import I18n from './modules/i18n/i18n';
import actions from './actions';
// TODO (bc): Deprecate old actions. Spreading actions is now needed.
export default {
pym,
I18n,
actions,
...actions
};
@@ -1,78 +0,0 @@
import timeago from 'timeago.js';
import esTA from '../../../../node_modules/timeago.js/locales/es';
import has from 'lodash/has';
import get from 'lodash/get';
/**
* Default locales, this should be overriden by config file
*/
class i18n {
constructor (translations) {
/**
* Register locales
*/
this.locales = {'en': 'en', 'es': 'es'};
timeago.register('es_ES', esTA);
this.timeagoInstance = new timeago();
/**
* Load translations
*/
let trans = translations || {en: {}};
try {
const locale = localStorage.getItem('locale') || navigator.language;
localStorage.setItem('locale', locale);
const lang = this.locales[locale.split('-')[0]] || 'en';
this.translations = trans[lang];
} catch (err) {
this.translations = trans['en'];
}
this.setLocale = (locale) => {
try {
localStorage.setItem('locale', locale);
} catch (err) {
console.error(err);
}
};
this.getLocale = () => (
localStorage.getItem('locale') || navigator.locale || 'en-US'
);
/**
* Expose the translation function
*
* it takes a string with the translation key and returns
* the translation value or the key itself if not found
* it works with nested translations (my.page.title)
*
* any extra parameters are optional and replace a variable marked by {0}, {1}, etc in the translation.
*/
this.t = (key, ...replacements) => {
if (has(this.translations, key)) {
let translation = get(this.translations, key);
// replace any {n} with the arguments passed to this method
replacements.forEach((str, i) => {
translation = translation.replace(new RegExp(`\\{${i}\\}`, 'g'), str);
});
return translation;
} else {
console.warn(`${key} language key not set`);
return key;
}
};
this.timeago = (time) => {
return this.timeagoInstance.format(new Date(time));
};
}
}
export default i18n;
+81
View File
@@ -0,0 +1,81 @@
import ta from 'timeago.js';
import has from 'lodash/has';
import get from 'lodash/get';
import merge from 'lodash/merge';
import esTA from '../../../node_modules/timeago.js/locales/es';
import en from '../../../locales/en.yml';
import es from '../../../locales/es.yml';
// Translations are happening at https://www.transifex.com/the-coral-project/talk-1/dashboard/.
const defaultLanguage = 'en';
const translations = {...en, ...es};
let lang;
let timeagoInstance;
function setLocale(locale) {
try {
localStorage.setItem('locale', locale);
} catch (err) {
console.error(err);
}
}
function getLocale() {
return (localStorage.getItem('locale') || navigator.language || defaultLanguage).split('-')[0];
}
function init() {
const locale = getLocale();
setLocale(locale);
// Extract language key.
lang = locale.split('-')[0];
// Check if we have a translation in this language.
if (!(lang in translations)) {
lang = defaultLanguage;
}
ta.register('es', esTA);
timeagoInstance = ta();
}
export function loadTranslations(newTranslations) {
merge(translations, newTranslations);
}
export function timeago(time) {
return timeagoInstance.format(new Date(time), lang);
}
/**
* Expose the translation function
*
* it takes a string with the translation key and returns
* the translation value or the key itself if not found
* it works with nested translations (my.page.title)
*
* any extra parameters are optional and replace a variable marked by {0}, {1}, etc in the translation.
*/
export function t(key, ...replacements) {
const fullKey = `${lang}.${key}`;
if (has(translations, fullKey)) {
let translation = get(translations, fullKey);
// replace any {n} with the arguments passed to this method
replacements.forEach((str, i) => {
translation = translation.replace(new RegExp(`\\{${i}\\}`, 'g'), str);
});
return translation;
} else {
console.warn(`${fullKey} language key not set`);
return key;
}
}
export default t;
init();
-112
View File
@@ -1,112 +0,0 @@
{
"en": {
"MY_COMMENTS": "My Comments",
"profile": "Profile",
"myProfile": "My profile",
"successUpdateSettings": "The changes you have made have been applied to the comment stream on this article",
"successNameUpdate": "Your username has been updated",
"contentNotAvailable": "This content is not available",
"bannedAccountMsg": "Your account is currently suspended. This means that you cannot Like, Report, or write comments. Please contact us if you have any questions.",
"temporarilySuspended": "In accordance with {0}'s community guidlines, your account has been temporarily suspended. Please rejoin the conversation {1}.",
"editName": {
"msg": "Your account is currently suspended because your username has been deemed inappropriate. To restore your account, please enter a new username. Please contact us if you have any questions.",
"label": "New Username",
"button": "Submit",
"error": "Usernames can contain letters, numbers and _ only"
},
"viewMoreComments": "view more comments",
"showAllComments": "Show all comments",
"viewReply": "view reply",
"viewAllRepliesInitial": "view all {0} replies",
"viewAllReplies": "view {0} replies",
"newCount": "View {0} new {1}",
"comment": "comment",
"comments": "comments",
"commentIsIgnored": "This comment is hidden because you ignored this user.",
"editComment": {
"bodyInputLabel": "Edit this comment",
"saveButton": "Save changes",
"editWindowExpired": "You can no longer edit this comment. The time window to do so has expired. Why not post another one?",
"editWindowExpiredClose": "Close",
"editWindowTimerPrefix": "Edit Window: ",
"second": "second",
"secondsPlural": "seconds",
"unexpectedError": "Unexpected error while saving changes. Sorry!"
},
"error": {
"COMMENT_TOO_SHORT": "Your comment must have something in it",
"EDIT_WINDOW_ENDED": "You can no longer edit this comment. The time window to do so has expired.",
"emailNotVerified": "Email address {0} not verified.",
"email": "Not a valid E-Mail",
"networkError": "Failed to connect to server. Check your internet connection and try again.",
"password": "Password must be at least 8 characters",
"username": "Usernames can contain letters, numbers and _ only",
"confirmPassword": "Passwords don't match. Please, check again",
"organizationName": "Organization name must only contain letters or numbers.",
"emailPasswordError": "Email and/or password combination incorrect.",
"EMAIL_REQUIRED": "An email address is required",
"PASSWORD_REQUIRED": "Must input a password",
"PASSWORD_LENGTH": "Password is too short",
"EMAIL_IN_USE": "Email address already in use",
"EMAIL_USERNAME_IN_USE": "Email address or username already in use",
"USERNAME_IN_USE": "Username already in use",
"USERNAME_REQUIRED": "Must input a username",
"NO_SPECIAL_CHARACTERS": "Usernames can contain letters, numbers and _ only",
"PROFANITY_ERROR": "Usernames must not contain profanity. Please contact the administrator if you believe this to be in error.",
"NOT_AUTHORIZED": "Not authorized.",
"EDIT_USERNAME_NOT_AUTHORIZED": "You do not have permission to update your username."
}
},
"es": {
"profile": "Pérfil",
"MY_COMMENTS": "Mis Comentarios",
"myProfile": "Mi pérfil",
"successUpdateSettings": "La configuración de este articulo fue actualizada",
"successBioUpdate": "Tu biografia fue actualizada",
"contentNotAvailable": "El contenido no se encuentra disponible",
"bannedAccountMsg": "Tu cuenta se encuentra suspendida. Esto significa que no puedes gustar, marcar o escribir commentarios.",
"editNameMsg": "",
"viewMoreComments": "Ver commentarios más",
"viewReply": "ver respuesta",
"viewAllRepliesInitial": "ver todas las {0} respuestas",
"viewAllReplies": "ver {0} respuestas",
"newCount": "Ver {0} {1} más",
"comment": "commentario",
"comments": "commentarios",
"commentIsIgnored": "Este comentario está escondido porque has ignorado al usuario.",
"showAllComments": "Mostrar todos los comentarios",
"editComment": {
"bodyInputLabel": "Editar este comentario",
"saveButton": "Guardar cambios",
"editWindowExpired": "Ya no puedes editar este comentario. La ventana de tiempo para hacerlo ha caducado. ¿Por qué no publicar otro?",
"editWindowExpiredClose": "Cerca",
"editWindowTimerPrefix": "Ventana de edición: ",
"second": "segundo",
"secondsPlural": "segundos",
"unexpectedError": "Unexpected error while saving changes. Sorry!"
},
"error": {
"editWindowExpired": "Ya no puedes editar este comentario. La ventana de tiempo para hacerlo ha caducado.",
"emailNotVerified": "E-mail {0} no verificado.",
"email": "No es un e-mail válido",
"networkError": "Error al conectar con el servidor. Compruebe su conexión a Internet y vuelva a intentarlo.",
"password": "La contraseña debe tener por lo menos 8 caracteres",
"username": "Los nombres pueden contener letras, números y _",
"organizationName": "El nombre de la organización debe contener letras y/o números.",
"confirmPassword": "Las contraseñas no coinciden",
"emailPasswordError": "E-mail y/o contraseña incorrecta.",
"EMAIL_REQUIRED": "Se requiere un e-mail",
"PASSWORD_REQUIRED": "Debe ingresar una contraseña",
"PASSWORD_LENGTH": "La contraseña es muy corta",
"EMAIL_IN_USE": "El e-mail se encuentra en uso",
"EMAIL_USERNAME_IN_USE": "E-mail o Nombre en uso.",
"USERNAME_IN_USE": "Nombre en uso.",
"USERNAME_REQUIRED": "Debe ingresar un nombre",
"NO_SPECIAL_CHARACTERS": "Los nombres pueden contener letras, números y _",
"PROFANITY_ERROR": "Los nombres no pueden contener blasfemias. Por favor contacte al o la administradora si cree que esto es un error",
"NOT_AUTHORIZED": "Acción no autorizada.",
"EDIT_USERNAME_NOT_AUTHORIZED": "No tiene permiso para editar el nombre de usuario."
}
}
}
+5 -5
View File
@@ -1,6 +1,7 @@
import React, {Component, PropTypes} from 'react';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
import {Icon} from 'coral-ui';
import classnames from 'classnames';
@@ -12,7 +13,6 @@ export const commentIsBest = ({tags} = {}) => {
};
const name = 'coral-plugin-best';
const lang = new I18n(translations);
// It would be best if the backend/api held this business logic
const canModifyBestTag = ({roles = []} = {}) => roles && ['ADMIN', 'MODERATOR'].some((role) => roles.includes(role));
@@ -20,7 +20,7 @@ const canModifyBestTag = ({roles = []} = {}) => roles && ['ADMIN', 'MODERATOR'].
// Put this on a comment to show that it is best
export const BestIndicator = ({children = <Icon name='star'/>}) => (
<span aria-label={lang.t('commentIsBest')}>
<span aria-label={t('comment_is_best')}>
{ children }
</span>
);
@@ -98,7 +98,7 @@ export class BestButton extends Component {
<button onClick={isBest ? this.onClickRemoveBest : this.onClickAddBest}
disabled={disabled}
className={classnames(`${name}-button`, `e2e__${isBest ? 'unset' : 'set'}-best-comment`)}
aria-label={lang.t(isBest ? 'unsetBest' : 'setBest')}>
aria-label={t(isBest ? 'unset_best' : 'set_best')}>
<Icon name={ isBest ? 'star' : 'star_border' } />
</button>
);
@@ -1,12 +0,0 @@
{
"en": {
"setBest": "Tag as Best",
"unsetBest": "Untag as Best",
"commentIsBest": "This comment is one of the best"
},
"es": {
"setBest": "Etiquetar como el mejor",
"unsetBest": "Desetiquetar como el mejor",
"commentIsBest": "Este comentario es uno de los mejores"
}
}
@@ -1,11 +1,12 @@
import React, {PropTypes} from 'react';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
const name = 'coral-plugin-comment-count';
const CommentCount = ({count}) => {
return <div className={`${name}-text`}>
{`${count} ${count === 1 ? lang.t('comment') : lang.t('comment-plural')}`}
{`${count} ${count === 1 ? t('comment.comment') : t('comment_plural')}`}
</div>;
};
@@ -14,5 +15,3 @@ CommentCount.propTypes = {
};
export default CommentCount;
const lang = new I18n(translations);
@@ -1,10 +0,0 @@
{
"en": {
"comment": "Comment",
"comment-plural": "Comments"
},
"es": {
"comment": "Comentario",
"comment-plural": "Comentarios"
}
}
+7 -8
View File
@@ -1,6 +1,7 @@
import React, {PropTypes} from 'react';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
import Slot from 'coral-framework/components/Slot';
import {connect} from 'react-redux';
import {CommentForm} from './CommentForm';
@@ -11,9 +12,9 @@ export const name = 'coral-plugin-commentbox';
// if needed
export const notifyForNewCommentStatus = (addNotification, status) => {
if (status === 'REJECTED') {
addNotification('error', lang.t('comment-post-banned-word'));
addNotification('error', t('comment_box.comment_post_banned_word'));
} else if (status === 'PREMOD') {
addNotification('success', lang.t('comment-post-notif-premod'));
addNotification('success', t('comment_box.comment_post_notif_premod'));
}
};
@@ -156,10 +157,10 @@ class CommentBox extends React.Component {
key={this.state.postedCount}
defaultValue={this.props.defaultValue}
bodyInputId={isReply ? 'replyText' : 'commentText'}
bodyLabel={isReply ? lang.t('reply') : lang.t('comment')}
bodyLabel={isReply ? t('comment_box.reply') : t('comment.comment')}
maxCharCount={maxCharCount}
charCountEnable={this.props.charCountEnable}
bodyPlaceholder={lang.t('comment')}
bodyPlaceholder={t('comment.comment')}
bodyInputId={isReply ? 'replyText' : 'commentText'}
saveComment={authorId && this.postComment}
buttonContainerStart={<Slot
@@ -194,5 +195,3 @@ CommentBox.propTypes = {
const mapStateToProps = ({commentBox}) => ({commentBox});
export default connect(mapStateToProps, null)(CommentBox);
const lang = new I18n(translations);
@@ -1,13 +1,11 @@
import React, {PropTypes} from 'react';
import {Button} from 'coral-ui';
import classnames from 'classnames';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import Slot from 'coral-framework/components/Slot';
import {name} from './CommentBox';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
/**
* Common UI for Creating or Editing a Comment
@@ -56,9 +54,9 @@ export class CommentForm extends React.Component {
}
static get defaultProps() {
return {
bodyLabel: lang.t('comment'),
bodyPlaceholder: lang.t('comment'),
submitText: lang.t('post'),
bodyLabel: t('comment_box.comment'),
bodyPlaceholder: t('comment_box.comment'),
submitText: t('comment_box.post'),
saveButtonCStyle: 'darkGrey',
saveCommentEnabled: () => true,
};
@@ -109,7 +107,7 @@ export class CommentForm extends React.Component {
{
this.props.charCountEnable &&
<div className={`${name}-char-count ${length > maxCharCount ? `${name}-char-max` : ''}`}>
{maxCharCount && `${maxCharCount - length} ${lang.t('characters-remaining')}`}
{maxCharCount && `${maxCharCount - length} ${t('comment_box.characters_remaining')}`}
</div>
}
<div className={`${name}-button-container`}>
@@ -120,7 +118,7 @@ export class CommentForm extends React.Component {
cStyle='darkGrey'
className={classnames(`${name}-cancel-button`, buttonClass)}
onClick={this.props.cancelButtonClicked}>
{lang.t('cancel')}
{t('comment_box.cancel')}
</Button>
)
}
@@ -1,24 +0,0 @@
{
"en": {
"post": "Post",
"cancel": "Cancel",
"reply": "Reply",
"comment": "Post a comment",
"name": "Name",
"comment-post-notif": "Your comment has been posted.",
"comment-post-notif-premod": "Thank you for posting. Our moderation team will review your comment shortly.",
"comment-post-banned-word": "Your comment contains one or more words that are not permitted, so it will not be published. If you think this message is incorrect, please contact our moderation team.",
"characters-remaining": " characters remaining"
},
"es": {
"post": "Publicar",
"cancel": "Cancelar",
"reply": "Responder",
"comment": "Publicar un comentario",
"name": "Nombre",
"comment-post-notif": "Tu comentario ha sido publicado.",
"comment-post-notif-premod": "Gracias por el comentario. Nuestro equipo de moderación va a revisarlo muy pronto.",
"comment-post-banned-word": "Tu comentario contiene una o más palabras que no estan permitidas en nuestro espacio, por lo que no será publicado. Si crees que es un error, por favor contacta a nuestro equipo de moderación.",
"characters-remaining": "carácteres restantes"
}
}
+6 -7
View File
@@ -1,6 +1,7 @@
import React, {Component} from 'react';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
import {PopupMenu, Button} from 'coral-ui';
import onClickOutside from 'react-onclickoutside';
@@ -141,8 +142,8 @@ class FlagButton extends Component {
className={`${name}-button`}>
{
flagged
? <span className={`${name}-button-text`}>{lang.t('reported')}</span>
: <span className={`${name}-button-text`}>{lang.t('report')}</span>
? <span className={`${name}-button-text`}>{t('reported')}</span>
: <span className={`${name}-button-text`}>{t('report')}</span>
}
<i className={`${name}-icon material-icons ${flagged && 'flaggedIcon'}`}
style={flagged ? styles.flaggedIcon : {}}
@@ -176,7 +177,7 @@ class FlagButton extends Component {
{
this.state.reason && <div>
<label htmlFor={'message'} className={`${name}-popup-radio-label`}>
{lang.t('flag-reason')}
{t('flag_reason')}
</label><br/>
<textarea
className={`${name}-reason-text`}
@@ -215,5 +216,3 @@ const styles = {
color: 'inherit'
}
};
const lang = new I18n(translations);
+20 -22
View File
@@ -1,53 +1,51 @@
import React from 'react';
import FlagButton from './FlagButton';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
const FlagComment = (props) => <FlagButton {...props} getPopupMenu={getPopupMenu} />;
const getPopupMenu = [
() => {
return {
header: lang.t('step-1-header'),
header: t('step_1_header'),
options: [
{val: 'COMMENTS', text: lang.t('flag-comment')},
{val: 'USERS', text: lang.t('flag-username')}
{val: 'COMMENTS', text: t('flag_comment')},
{val: 'USERS', text: t('flag_username')}
],
button: lang.t('continue'),
button: t('continue'),
sets: 'itemType'
};
},
(itemType) => {
const options = itemType === 'COMMENTS' ?
[
{val: 'This comment is offensive', text: lang.t('comment-offensive')},
{val: 'This looks like an ad/marketing', text: lang.t('marketing')},
{val: 'I don\'t agree with this comment', text: lang.t('no-agree-comment')},
{val: 'Other', text: lang.t('other')}
{val: 'This comment is offensive', text: t('comment_offensive')},
{val: 'This looks like an ad/marketing', text: t('marketing')},
{val: 'I don\'t agree with this comment', text: t('no_agree_comment')},
{val: 'Other', text: t('other')}
]
: [
{val: 'This username is offensive', text: lang.t('username-offensive')},
{val: 'I don\'t like this username', text: lang.t('no-like-username')},
{val: 'This user is impersonating', text: lang.t('user-impersonating')},
{val: 'This looks like an ad/marketing', text: lang.t('marketing')},
{val: 'Other', text: lang.t('other')}
{val: 'This username is offensive', text: t('username_offensive')},
{val: 'I don\'t like this username', text: t('no_like_username')},
{val: 'This user is impersonating', text: t('user_impersonating')},
{val: 'This looks like an ad/marketing', text: t('marketing')},
{val: 'Other', text: t('other')}
];
return {
header: lang.t('step-2-header'),
header: t('step_2_header'),
options,
button: lang.t('continue'),
button: t('continue'),
sets: 'reason'
};
},
() => {
return {
header: lang.t('step-3-header'),
text: lang.t('thank-you'),
button: lang.t('done'),
header: t('step_3_header'),
text: t('thank_you'),
button: t('done'),
};
}
];
export default FlagComment;
const lang = new I18n(translations);
@@ -1,52 +0,0 @@
{
"en": {
"report": "Report",
"reported": "Reported",
"report-notif": "Thank you for reporting this comment. Our moderation team has been notified and will review it shortly.",
"report-notif-remove": "Your report has been removed.",
"step-1-header": "Report an issue",
"step-2-header": "Help us understand",
"step-3-header": "Thank you for your input",
"flag-username": "Report username",
"flag-comment": "Report comment",
"continue": "Continue",
"done": "Done",
"no-agree-comment": "I don't agree with this comment",
"comment-offensive": "This comment is offensive",
"personal-info": "This comment reveals personally identifiable information",
"username-offensive": "This username is offensive",
"no-like-username": "I don't like this username",
"bio-offensive": "This bio is offensive",
"no-like-bio": "I don't like this bio",
"marketing": "This looks like an ad/marketing",
"user-impersonating": "This user is impersonating",
"thank-you": "We value your safety and feedback. A moderator will review your report.",
"flag-reason": "Reason for reporting (Optional)",
"other": "Other"
},
"es": {
"report": "Reportar",
"reported": "Reportado",
"report-notif": "Gracias por reportar este comentario. Nuestro equipo de moderación ha sido notificado y muy pronto lo va a revisar.",
"report-notif-remove": "Tu reporte ha sido eliminada.",
"step-1-header": "Reportar un problema",
"step-2-header": "Ayudanos a comprender",
"step-3-header": "Gracias por tu participación",
"flag-username": "Reportar el nombre de usuario",
"flag-comment": "Reportar el comentario",
"continue": "Continuar",
"done": "hecho",
"no-agree-comment": "No estoy de acuerdo con este comentario",
"comment-offensive": "Este comentario es ofensivo",
"personal-info": "Este comentario muestra información personal",
"username-offensive": "Este nombre de usuario es ofensivo",
"no-like-username": "No me gusta este nombre de usuario",
"bio-offensive": "Esta biografia es ofensiva",
"no-like-bio": "No me gusta esta biografia",
"user-impersonating": "Este usuario suplanta a alguien",
"marketing": "Esto parece una propaganda",
"thank-you": "Valoramos tanto tu seguridad en este espacio como tus comentarios. Un o una moderadora van a leer tu reporte.",
"flag-reason": "Razón por la que hacer este reporte (Opcional)",
"other": "Otro"
}
}
+3 -1
View File
@@ -4,6 +4,8 @@ import styles from './Comment.css';
import PubDate from '../coral-plugin-pubdate/PubDate';
import Content from '../coral-plugin-commentcontent/CommentContent';
import t from 'coral-framework/services/i18n';
const Comment = (props) => {
return (
<div className={styles.myComment}>
@@ -25,7 +27,7 @@ const Comment = (props) => {
<ul>
<li>
<a onClick={props.link(`${props.asset.url}#${props.comment.id}`)}>
<Icon name="open_in_new" />View Conversation
<Icon name="open_in_new" />{t('view_conversation')}
</a>
</li>
<li>
@@ -1,13 +1,12 @@
import React, {PropTypes} from 'react';
import styles from './styles.css';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
const ModerationLink = (props) => props.isAdmin ? (
<div className={styles.moderationLink}>
<a href={`/admin/moderate/${props.assetId}`} target="_blank">
{lang.t('MODERATE_THIS_STREAM')}
{t('moderate_this_stream')}
</a>
</div>
) : null;
@@ -17,6 +16,4 @@ ModerationLink.propTypes = {
isAdmin: PropTypes.bool.isRequired
};
const lang = new I18n(translations);
export default ModerationLink;
@@ -1,8 +0,0 @@
{
"en": {
"MODERATE_THIS_STREAM": "Moderate this stream"
},
"es": {
"MODERATE_THIS_STREAM": "Modera este hilo de comentarios"
}
}
@@ -1,12 +1,10 @@
import React, {PropTypes} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import translations from './translations';
import onClickOutside from 'react-onclickoutside';
const name = 'coral-plugin-permalinks';
import {Button} from 'coral-ui';
import styles from './styles.css';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
class PermalinkButton extends React.Component {
@@ -56,7 +54,7 @@ class PermalinkButton extends React.Component {
ref={(ref) => this.linkButton = ref}
onClick={this.toggle}
className={`${name}-button`}>
{lang.t('permalink.permalink')}
{t('permalink')}
<i className={`${name}-icon material-icons`} aria-hidden={true}>link</i>
</button>
<div
@@ -1,12 +0,0 @@
{
"en": {
"permalink": {
"permalink": "Link"
}
},
"es": {
"permalink": {
"permalink": "Enlace"
}
}
}
+2 -3
View File
@@ -1,11 +1,10 @@
import React from 'react';
import {I18n} from '../coral-framework';
import {timeago} from 'coral-framework/services/i18n';
const lang = new I18n();
const name = 'coral-plugin-pubdate';
const PubDate = ({created_at}) => <div className={`${name}-text`}>
{lang.timeago(created_at)}
{timeago(created_at)}
</div>;
export default PubDate;
+4 -5
View File
@@ -1,6 +1,7 @@
import React, {PropTypes} from 'react';
import {I18n} from '../coral-framework';
import translations from './translations.json';
import t from 'coral-framework/services/i18n';
import classnames from 'classnames';
const name = 'coral-plugin-replies';
@@ -10,7 +11,7 @@ const ReplyButton = ({banned, onClick}) => {
<button
className={classnames(`${name}-reply-button`)}
onClick={onClick}>
{lang.t('reply')}
{t('reply')}
<i className={`${name}-icon material-icons`}
aria-hidden={true}>{banned ? 'BANNED' : 'reply'}</i>
</button>
@@ -23,5 +24,3 @@ ReplyButton.propTypes = {
};
export default ReplyButton;
const lang = new I18n(translations);
@@ -1,8 +0,0 @@
{
"en": {
"reply": "Reply"
},
"es": {
"reply": "Responder"
}
}
@@ -1,16 +1,15 @@
import React from 'react';
import styles from './NotLoggedIn.css';
import translations from '../translations';
import I18n from 'coral-framework/modules/i18n/i18n';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
export default ({showSignInDialog}) => (
<div className={styles.message}>
<div>
<a onClick={showSignInDialog}>{lang.t('signIn')}</a> {lang.t('toAccess')}
<a onClick={showSignInDialog}>{t('settings.sign_in')}</a> {t('settings.to_access')}
</div>
<div>
{lang.t('fromSettingsPage')}
{t('from_settings_page')}
</div>
</div>
);
@@ -1,7 +1,6 @@
import {connect} from 'react-redux';
import {compose, graphql, gql} from 'react-apollo';
import React, {Component} from 'react';
import I18n from 'coral-framework/modules/i18n/i18n';
import {bindActionCreators} from 'redux';
import {withStopIgnoringUser} from 'coral-framework/graphql/mutations';
@@ -13,8 +12,7 @@ import {Spinner} from 'coral-ui';
import CommentHistory from 'coral-plugin-history/CommentHistory';
import {showSignInDialog, checkLogin} from 'coral-framework/actions/auth';
import translations from '../translations';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
class ProfileContainer extends Component {
constructor() {
@@ -63,7 +61,7 @@ class ProfileContainer extends Component {
{me.ignoredUsers && me.ignoredUsers.length
? <div>
<h3>Ignored users</h3>
<h3>{t('framework.ignored_users')}</h3>
<IgnoredUsers
users={me.ignoredUsers}
stopIgnoring={stopIgnoringUser}
@@ -73,10 +71,10 @@ class ProfileContainer extends Component {
<hr />
<h3>My comments</h3>
<h3>{t('framework.my_comments')}</h3>
{me.comments.length
? <CommentHistory comments={me.comments} asset={asset} link={link} />
: <p>{lang.t('userNoComment')}</p>}
: <p>{t('user_no_comment')}</p>}
</div>
);
}
-22
View File
@@ -1,22 +0,0 @@
{
"en":{
"profile": "Profile",
"userNoComment": "You've never left a comment. Join the conversation!",
"allComments": "All Comments",
"profileSettings": "Profile Settings",
"myCommentHistory": "My comment History",
"signIn": "Sign in",
"toAccess": " to access Profile",
"fromSettingsPage": "From the Profile Page you can see your comment history."
},
"es":{
"profile": "Perfil",
"userNoComment": "No has dejado aún ningún comentario. ¡Únete a la conversación!",
"allComments": "Todos los comentarios",
"profileSettings": "Configuración del perfil",
"myCommentHistory": "Mi historial de comentarios",
"signIn": "Entrar",
"toAccess": "para acceder a al perfil",
"fromSettingsPage": "Desde la página de configuración puedes ver tu historia de comentarios."
}
}
-102
View File
@@ -1,102 +0,0 @@
{
"en": {
"signIn": {
"emailVerifyCTA": "Please verify your email address.",
"requestNewVerifyEmail": "Request another email:",
"verifyEmail": "Thank you for creating an account! We sent an email to the address you provided to verify your account.",
"verifyEmail2": "You must verify your account before engaging with the community.",
"notYou": "Not you?",
"loggedInAs": "Logged in as",
"facebookSignIn": "Sign in with Facebook",
"facebookSignUp": "Sign up with Facebook",
"logout": "Logout",
"signIn": "Sign in to join the conversation",
"or": "Or",
"email": "E-mail Address",
"password": "Password",
"forgotYourPass": "Forgot your password?",
"needAnAccount": "Need an account?",
"register": "Register",
"signUp": "Sign Up",
"confirmPassword": "Confirm Password",
"username": "Username",
"alreadyHaveAnAccount": "Already have an account?",
"recoverPassword": "Recover password",
"emailInUse": "Email address already in use",
"emailORusernameInUse": "Email address or Username already in use",
"requiredField": "This field is required",
"passwordsDontMatch": "Passwords don't match.",
"specialCharacters": "Usernames can contain letters, numbers and _ only",
"checkTheForm": "Invalid Form. Please, check the fields"
},
"createdisplay": {
"writeyourusername": "Edit your username",
"yourusername": "Your username appears on every comment you post.",
"ifyoudontchangeyourname": "If you don't change your username at this step, your Facebook display name will appear alongside of all your comments.",
"username": "Username",
"continue": "Continue with the same Facebook username",
"save": "Save",
"fakecommentdate": "1 minute ago",
"fakecommentbody": "This is an example comment. Readers can share their thoughts and opinions with newsrooms in the comments section.",
"requiredField": "Required field",
"errorCreate": "Error when changing username",
"checkTheForm": "Invalid Form. Please, check the fields",
"specialCharacters": "Usernames can contain letters, numbers and _ only"
},
"permalink": {
"permalink": "Link"
},
"report": "Report",
"like": "Like"
},
"es": {
"signIn": {
"emailVerifyCTA": "Por favor verifique su e-mail.",
"requestNewVerifyEmail": "Enviar otro correo:",
"verifyEmail": "¡Gracias por crear una cuenta! Le enviamos un correo a la dirección que dio para verificar su cuenta.",
"verifyEmail2": "Debe verificarla antes de poder involucrarse en la comunidad.",
"notYou": "¿No eres tu?",
"loggedInAs": "Entraste como",
"facebookSignIn": "Entrar con Facebook",
"facebookSignUp": "Regístrate con Facebook",
"logout": "Salir",
"signIn": "Entrar para Unirte a la Conversación",
"or": "o",
"email": "E-mail",
"password": "Contraseña",
"forgotYourPass": "¿Has olvidado tu contraseña?",
"needAnAccount": "¿Necesitas una cuenta?",
"register": "Regístrate",
"signUp": "Registro",
"confirmPassword": "Confirmar Contraseña",
"username": "Nombre",
"alreadyHaveAnAccount": "¿Ya tienes una cuenta?",
"recoverPassword": "Recuperar contraseña",
"emailInUse": "Este e-mail se encuentra en uso",
"emailORusernameInUse": "Este e-mail ó nombre de usuario se encuentran en uso",
"requiredField": "Este campo es requerido",
"passwordsDontMatch": "Las contraseñas no coinciden",
"specialCharacters": "Los nombres pueden contener letras, números y _",
"checkTheForm": "Formulario Inválido. Por favor, completa los campos"
},
"createdisplay": {
"writeyourusername": "Edita tu nombre",
"yourusername": "Tu nombre aparece en cada comentario que publiques.",
"ifyoudontchangeyourname": "Si no modificas tu nombre de usuario en este paso, tu nombre de Facebook aparecera al lado de cada comentario que publiques.",
"username": "Nombre",
"continue": "Continuar con nombre de Facebook",
"save": "Guardar",
"fakecommentdate": "hace un minuto",
"fakecommentbody": "Este es un comentario de ejemplo. Las lectoras pueden compartir sus ideas y opiniones con los periodistas en la sección de comentarios.",
"requiredField": "Campo necesario",
"errorCreate": "Hubo un error al cambiar el nombre de usuario",
"checkTheForm": "Formulario Inválido. Por favor, verifica los campos",
"specialCharacters": "Sólo pueden contener letras, números y _"
},
"permalink": {
"permalink": "Enlace"
},
"report": "Marcar",
"like": "Me gusta"
}
}
+355
View File
@@ -0,0 +1,355 @@
en:
bandialog:
are_you_sure: "Are you sure you would like to ban {0}?"
ban_user: "Ban User?"
banned_user: "Banned User"
cancel: Cancel
note: "Note: Banning this user will also place this comment in the Rejected queue."
yes_ban_user: "Yes, Ban User"
bio_offensive: "This bio is offensive"
cancel: Cancel
characters_remaining: "characters remaining"
comment:
anon: Anonymous
ban_user: "Ban User"
comment: "Post a comment"
flagged: flagged
view_context: "View context"
comment_box:
post: "Post"
cancel: "Cancel"
reply: "Reply"
comment: "Post a comment"
name: "Name"
comment_post_notif: "Your comment has been posted."
comment_post_notif_premod: "Thank you for posting. Our moderation team will review your comment shortly."
comment_post_banned_word: "Your comment contains one or more words that are not permitted, so it will not be published. If you think this message is incorrect, please contact our moderation team."
characters_remaining: "characters remaining"
comment_is_best: "This comment is one of the best"
comment_offensive: "This comment is offensive"
comment_plural: Comments
comment_post_banned_word: "Your comment contains one or more words that are not permitted, so it will not be published. If you think this message is incorrect, please contact our moderation team."
comment_post_notif: "Your comment has been posted."
comment_post_notif_premod: "Thank you for posting. Our moderation team will review your comment shortly."
community:
account_creation_date: "Account Creation Date"
active: Active
admin: Administrator
ads_marketing: "This looks like an ad/marketing"
are_you_sure: "Are you sure you would like to ban {0}?"
ban_user: "Ban User?"
banned: Banned
banned_user: "Banned User"
cancel: Cancel
dont_like_username: "I don't like this username"
flaggedaccounts: "Flagged Usernames"
flags: Flags
impersonating: "This user is impersonating"
loading: "Loading results"
moderator: Moderator
newsroom_role: "Newsroom Role"
no_flagged_accounts: "The Account Flags queue is currently empty."
no_results: "No users found with that user name or email address. They're hiding!"
note: "Note: Banning this user will not let them edit comment or remove anything."
offensive: "This comment is offensive"
other: Other
people: People
role: "Select role..."
select_status: "Select status..."
spam_ads: "Spam/Ads"
staff: "Staff"
status: Status
username_and_email: "Username and Email"
yes_ban_user: "Yes Ban User"
configure:
apply: Apply
banned_word_text: "Comments which contain these words or phrases (not case-sensitive) will be automatically removed from the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list."
banned_words_title: "Banned words list"
close: "Close"
close_after: "Close comments after"
close_stream: "Close Stream"
close_stream_configuration: "This comment stream is currently closed. By opening this comment stream new comments may be submitted and displayed"
closed_comments_desc: "Write a message to be displayed when when your comment stream is closed and no longer accepting comments."
closed_comments_label: "Write a message..."
closed_stream_settings: "Closed Stream Message"
comment_count_error: "Please enter a valid number."
comment_count_header: "Limit Comment Length"
comment_count_text_post: characters
comment_count_text_pre: "Comments will be limited to"
comment_settings: Settings
comment_stream: "Comment Stream"
comment_stream_will_close: "The comment stream will close in"
community: Community
configure: Configure
copy_and_paste: "Copy and paste code below into your CMS to embed your comment box in your articles"
custom_css_url: "Custom CSS URL"
custom_css_url_desc: "URL of a CSS stylesheet that will override default Embed Stream styles. Can be internal or external."
dashboard: Dashboard
days: Days
description: "As an admin you may customize the settings for the comment stream for this asset"
domain_list_text: "Enter the domains you would like to permit for Talk e.g. your local staging and production environments (ex. localhost:3000 staging.domain.com domain.com)."
domain_list_title: "Permitted Domains"
edit_comment_timeframe_heading: "Edit Comment Timeframe"
edit_comment_timeframe_text_pre: "Commenters will have"
edit_comment_timeframe_text_post: "seconds to edit their comments."
embed_comment_stream: "Embed Stream"
enable_premod_links_text: "Moderators must approve any comment containing a link before its published."
enable_pre_moderation: "Enable pre-moderation"
enable_pre_moderation_text: "Moderators must approve any comment before it is published."
enable_premod_links: "Pre-Moderate Comments Containing Links"
enable_premod: "Enable Premoderation"
enable_premod_description: "Moderators must approve any comment before its published."
enable_premod_links_description: "Moderators must approve any comment containing a link before its published."
enable_questionbox: "Ask readers a question"
enable_questionbox_description: "This question will appear at the top of this comment stream. Ask readers about a certain issue in the article or pose discussion questions etc."
hours: Hours
include_comment_stream: "Include Comment Stream Description for Readers"
include_comment_stream_desc: "Write a message to be added to the top of your comment stream. Pose a topic include community guidelines etc."
include_text: "Include your text here."
include_question_here: "Write your question here."
moderate: Moderate
moderation_settings: "Moderation Settings"
open: "Open"
open_stream: "Open Stream"
open_stream_configuration: "This comment stream is currently open. By closing this comment stream no new comments may be submitted and all previous comments will still be displayed."
require_email_verification: "Require Email Verification"
require_email_verification_text: "New Users must verify their email before commenting"
save_changes: "Save Changes"
shortcuts: Shortcuts
sign_out: "Sign Out"
stories: Stories
stream_settings: "Stream Settings"
suspect_word_title: "Suspect words list"
suspect_word_text: "Comments which contain these words or phrases (not case-sensitive) will be highlighted in the comment stream. Type a word and press Enter or Tab to add. Optionally paste a comma-separated list."
tech_settings: "Tech Settings"
title: "Configure Comment Stream"
weeks: Weeks
wordlist: "Banned Words"
continue: Continue
dashboard:
auto_update: "Data automatically updates every five minutes or when you Reload."
comment_count: comments
flags: Flags
most_flags: "Articles with the most flags"
most_conversations: "Articles with the most conversations"
next_update: "{0} minutes until next update."
no_activity: "There haven't been any comments anywhere in the last five minutes."
no_flags: "There have been no flags in the last 5 minutes! Hooray!"
no_likes: "There have been no likes in the last 5 minutes. All quiet."
done: Done
edit_comment:
body_input_label: "Edit this comment"
save_button: "Save changes"
edit_window_expired: "You can no longer edit this comment. The time window to do so has expired. Why not post another one?"
edit_window_expired_close: "Close"
edit_window_timer_prefix: "Edit Window: "
second: "second"
seconds_plural: "seconds"
unexpected_error: "Unexpected error while saving changes. Sorry!"
embedlink:
copy: "Copy to Clipboard"
error:
COMMENT_TOO_SHORT: "Your comment must have something in it"
NOT_AUTHORIZED: "You are not authorized to perform this action."
NO_SPECIAL_CHARACTERS: "Usernames can contain letters numbers and _ only"
PASSWORD_LENGTH: "Password is too short"
PROFANITY_ERROR: "Usernames must not contain profanity. Please contact the administrator if you believe this to be in error."
USERNAME_IN_USE: "Username already in use"
USERNAME_REQUIRED: "Must input a username"
EDIT_WINDOW_ENDED: "You can no longer edit this comment. The time window to do so has expired."
EDIT_USERNAME_NOT_AUTHORIZED: "You do not have permission to update your username."
EMAIL_IN_USE: "Email address already in use"
EMAIL_REQUIRED: "An email address is required"
LOGIN_MAXIMUM_EXCEEDED: "You have made too many unsuccessful password attempts. Please wait."
PASSWORD_REQUIRED: "Must input a password"
COMMENTING_CLOSED: "Commenting is already closed"
NOT_FOUND: "Resource not found"
INVALID_ASSET_URL: "Assert URL is invalid"
email: "Not a valid E-Mail"
confirm_password: "Passwords don't match. Please check again"
network_error: "Failed to connect to server. Check your internet connection and try again."
email_not_verified: "E-mail address {0} not verified."
email_password: "E-mail and/or password combination incorrect."
organization_name: "Organization name must only contain letters or numbers."
password: "Password must be at least 8 characters"
username: "Usernames can contain letters numbers and _ only"
flag_comment: "Report comment"
flag_reason: "Reason for reporting (Optional)"
flag_username: "Report username"
framework:
banned_account_msg: "Your account is currently suspended. This means that you cannot Like Report or write comments. Please contact us if you have any questions."
comment: comment
comment_is_ignored: "This comment is hidden because you ignored this user."
comments: comments
configure_stream: "Configure Stream"
content_not_available: "This content is not available"
edit_name:
button: Submit
error: "Usernames can contain letters numbers and _ only"
label: "New Username"
msg: "Your account is currently suspended because your username has been deemed inappropriate. To restore your account please enter a new username. Please contact us if you have any questions."
ignored_users: "Ignored users"
my_comments: "My Comments"
my_profile: "My profile"
new_count: "View {0} new {1}"
profile: Profile
show_all_comments: "Show all comments"
success_bio_update: "Your biography has been updated"
success_name_update: "Your username has been updated"
success_update_settings: "The changes you have made have been applied to the comment stream on this article"
view_all_replies: "view {0} replies"
view_all_replies_initial: "view all {0} replies"
view_more_comments: "view more comments"
view_reply: "view reply"
from_settings_page: "From the Profile Page you can see your comment history."
like: Like
loading_results: "Loading Results"
marketing: "This looks like an ad/marketing"
moderate_this_stream: "Moderate this stream"
modqueue:
account: "account flags"
actions: Actions
all: all
all_streams: "All Streams"
approve: "Approve"
approved: "Approved"
ban_user: "Ban"
billion: B
close: Close
dont_like_username: "Don't like username"
empty_queue: "No more comments to moderate! You're all caught up. Go have some ☕️"
flagged: flagged
impersonating: Impersonating
less_detail: "Less detail"
likes: likes
million: M
mod_faster: "Moderate faster with keyboard shortcuts"
moderate: "Moderate →"
more_detail: "More detail"
newest_first: "Newest First"
navigation: Navigation
next_comment: "Go to the next comment"
offensive: Offensive
oldest_first: "Oldest First"
other: Other
premod: pre-mod
prev_comment: "Go to the previous comment"
reject: "Reject"
rejected: "Rejected"
select_stream: "Select Stream"
shift_key:
shortcuts: Shortcuts
show_shortcuts: "Show Shortcuts"
singleview: "Toggle single comment edit view"
spam_ads: Spam/Ads
thismenu: "Open this menu"
thousand: k
try_these: "Try these"
view_more_shortcuts: "View more shortcuts"
my_comment_history: "My comment History"
name: Name
no_agree_comment: "I don't agree with this comment"
no_like_bio: "I don't like this bio"
no_like_username: "I don't like this username"
other: Other
permalink: Link
personal_info: "This comment reveals personally identifiable information"
post: Post
profile: Profile
profile_settings: "Profile Settings"
reply: Reply
report: Report
report_notif: "Thank you for reporting this comment. Our moderation team has been notified and will review it shortly."
report_notif_remove: "Your report has been removed."
reported: Reported
set_best: "Tag as Best"
settings:
all_comments: "All Comments"
from_settings_page: "From the Profile Page you can see your comment history."
my_comment_history: "My comment History"
profile: Profile
profile_settings: "Profile Settings"
sign_in: "Sign in"
to_access: "to access Profile"
user_no_comment: "You've never left a comment. Join the conversation!"
stream:
temporarily_suspended: "In accordance with {0}'s community guidlines, your account has been temporarily suspended. Please rejoin the conversation {1}."
step_1_header: "Report an issue"
step_2_header: "Help us understand"
step_3_header: "Thank you for your input"
streams:
all: All
article: Story
closed: Closed
empty_result: "No assets match this search. Maybe try widening your search?"
filter_streams: "Filter Streams"
newest: Newest
oldest: Oldest
open: Open
pubdate: "Publication Date"
search: Search
sort_by: "Sort By"
status: "Stream Status"
stream_status: "Stream Status"
suspenduser:
bio: bio
cancel: "Cancel"
days: "{0} days"
description_0: "Would you like to temporarily ban this user because of their {0}? Doing so will temporarily hide their comments until they rewrite their {0}."
description_1: "Suspending this user will temporarily disable their account and hide all of their comments on the site."
description_notify: "Suspending this user will temporarily disable their account and hide all of their comments on the site."
description_reject: "Would you like to temporarily ban this user because of their {0}? Doing so will temporarily hide their comments until they rewrite their {0}."
description_suspend: "You are suspending {0}. This comment will go to the Rejected queue, and {0} will not be allowed to like, report, reply or post until the suspension time is complete."
email: "Another member of the community recently flagged your username for review. Because of its content your user was rejected. This means you can no longer comment like or flag content until you rewrite your username. Please e-mail us if you have any questions or concerns."
email_subject: "Your account has been suspended"
email_message_reject: "Another member of the community recently flagged your username for review. Because of its content your user was rejected. This means you can no longer comment, like, or flag content until you rewrite your username. Please e-mail us if you have any questions or concerns."
email_message_suspend: "Dear {0},\n\nIn accordance with {1}s community guidelines, your account has been temporarily suspended. During the suspension, you will be unable to comment, flag or engage with fellow commenters. Please rejoin the conversation {2}."
error_email_message_empty: "You must specify an E-Mail message."
hours: "{0} hours"
no_cancel: "No cancel"
notify_suspend_until: "User {0} has been temporarily suspended. This suspension will automatically end {1}."
one_hour: "1 hour"
send: Send
select_duration: "Select suspension duration"
suspend_user: "Suspend User"
title: "Suspend a user"
title_0: "We noticed you rejected a username"
title_1: "Notify the user of their temporary suspension"
title_notify: "Notify the user of their temporary suspension"
title_reject: "We noticed you rejected a username"
title_suspend: "Suspend User"
username: username
write_message: "Write a message"
yes_suspend: "Yes suspend"
thank_you: "We value your safety and feedback. A moderator will review your report."
unset_best: "Untag as Best"
user:
bio_flags: "flags for this bio"
user_bio: "User Bio"
username_flags: "flags for this username"
user_impersonating: "This user is impersonating"
user_no_comment: "You've never left a comment. Join the conversation!"
username_offensive: "This username is offensive"
view_conversation: "View Conversation"
install:
initial:
description: "Let's set up your Talk community in just a few short steps."
submit: "Get Started"
add_organization:
description: "Please tell us the name of your organization. This will appear in emails when inviting new team members."
label: "Organization Name"
save: "Save"
create:
email: "Email address"
username: "Username"
password: "Password"
confirm_password: "Confirm Password"
save: "Save"
permitted_domains:
title: "Permitted domains"
description: "Enter the domains you would like to permit for Talk, e.g. your local, staging and production environments (ex. localhost:3000, staging.domain.com, domain.com)."
submit: "Finish install"
final:
description: "Thanks for installing Talk! We sent an email to verify your email address. While you finish setting up the account, you can start engaging with your readers now."
launch: "Launch Talk"
close: "Close this Installer"
+422
View File
@@ -0,0 +1,422 @@
es:
bandialog:
are_you_sure: "¿Estás segura que quieres suspender a {0}?"
ban_user: "¿Quieres suspender el Usuario?"
banned_user: "Usuario Suspendido"
cancel: Cancelar
note: "Nota: Suspender a este usuario también va a colocar este comentario en\
\ la cola de Rechazados."
yes_ban_user: "Si, Suspender al usuario"
bio_offensive: "Esta biografia es ofensiva"
cancel: Cancelar
characters_remaining: "carácteres restantes"
comment:
anon: Anónimo
ban_user: "Usuario Suspendido"
comment: "Publicar un comentario"
flagged: reportado
view_context: "Ver contexto"
comment_box:
post: "Publicar"
cancel: "Cancelar"
reply: "Responder"
comment: "Publicar un comentario"
name: "Nombre"
comment_post_notif: "Tu comentario ha sido publicado."
comment_post_notif_premod: "Gracias por el comentario. Nuestro equipo de moderació\
n va a revisarlo muy pronto."
comment_post_banned_word: "Tu comentario contiene una o más palabras que no está\
n permitidas en nuestro espacio, por lo que no será publicado. Si crees que\
\ es un error, por favor contacta a nuestro equipo de moderación."
characters_remaining: "carácteres restantes"
comment_is_best: "Este comentario es uno de los mejores"
comment_offensive: "Este comentario es ofensivo"
comment_plural: Comentarios
comment_post_banned_word: "Tu comentario contiene una o más palabras que no está\
n permitidas en nuestro espacio, por lo que no será publicado. Si crees que es\
\ un error, por favor contacta a nuestro equipo de moderación."
comment_post_notif: "Tu comentario ha sido publicado."
comment_post_notif_premod: "Gracias por el comentario. Nuestro equipo de moderació\
n va a revisarlo muy pronto."
community:
account_creation_date: "Fecha de creación de la cuenta"
active: Activa
admin: Administrator
are_you_sure: "¿Estas segura que quieres suspender a {0}?"
ban_user: "¿Quieres suspender al Usuario?"
banned: Suspendido
banned_user: "Usuario Suspendido"
cancel: Cancelar
dont_like_username: "No me gusta este nombre de usuario"
flaggedaccounts: "Nombres de Usuario Reportados"
flags: Reportes
impersonating: "El usuario esta suplantando identidad"
loading: "Cargando resultados"
moderator: Moderator
newsroom_role: "Rol en la redacción"
no_flagged_accounts: "No hay ninguna cuenta reportada en este momento."
no_results: "No se encontraron usuarios con ese nombre o correo."
note: "Nota: Suspender a este usuario no le va a permitir (al usuario) borrar\
\ ni editar ni comentar."
offensive: "Este comentario es ofensivo"
other: Otro
people: Gente
role: "Seleccionar rol..."
select_status: "Seleccionar estado..."
spam_ads: "Spam/Publicidad"
staff: "Personal"
status: Estado
username_and_email: "Usuario y Correo"
yes_ban_user: "Si, Suspendan el usuario"
configure:
apply: Aplicar
banned_word_text: "Comentarios que contengan estas palabras o frases, en mayusculas\
\ o minúsculas, serán automáticamente eliminados del hilo de comentario. Escribir\
\ una palabra y apretar Enter o Tabulador para agregarla. O pueden pegar una\
\ lista de palabras separadas por coma."
banned_words_title: "Lista de palabras prohibidas"
close: "Cerrar"
close_after: "Cerrar comentarios luego de"
close_stream: "Cerrar comentarios"
close_stream_configuration: "Este hilo de comentario está en este momento cerrado.\
\ Al abrirlo, nuevos comentarios serán publicados y mostrados."
closed_comments_desc: "Escribe un mensaje que será mostrado cuando los comentarios\
\ estén cerrados y no se acepten más comentarios."
closed_comments_label: "Escribe un mensaje..."
closed_stream_settings: "Mensaje que se muestra cuando no se aceptan más comentarios\
\ en el articulo"
comment_count_error: "Por favor escribir un número válido"
comment_count_header: "Limitar el largo del comentario"
comment_count_text_post: carácteres
comment_count_text_pre: "Los comentarios serán limitados a"
comment_settings: Configuración
comment_stream: "Hilo de Comentarios"
comment_stream_will_close: "El hilo de comentarios se cerrara"
community: Comunidad
configure: Configurar
copy_and_paste: "Copiar y pegar el código de más abajo en tu CMS para colocar\
\ la caja de comentarios en tus artículos"
custom_css_url: "URL CSS a medida"
custom_css_url_desc: "URL de una hoja de estilo que va a sobrescribir los estilos\
\ por defecto del hilo de comentarios. Puede ser interna o externa."
dashboard: Panel
days: Días
description: "Como Administrador/a puedes modificar la configuración de los comentarios\
\ en este artículo"
domain_list_text: "Agrega dominios permitidos a Talk, por ejemplo tu localhost,\
\ staging y ambientes de producción (ej. localhost:3000, staging.domain.com,\
\ domain.com)."
domain_list_title: "Dominios Permitidos"
edit_comment_timeframe_heading: "Periodo de Tiempo para Edición del Comentario"
edit_comment_timeframe_text_pre: "Los comentaristas tendrán"
edit_comment_timeframe_text_post: "segundos para editar sus comentarios."
embed_comment_stream: "Colocar Hilo de Comentarios"
enable_premod_links_text: "Los moderadores deben aprobar todo comentario que contenga\
\ un enlace antes de que sea publicado."
enable_pre_moderation: "Permitir pre-moderación"
enable_pre_moderation_text: "Los moderadores deben aprobar todo comentario antes\
\ que sea publicado."
enable_premod_links: "Pre-Moderar Comentarios que contienen Enlaces"
enable_premod: "Activar Pre Moderación"
enable_premod_description: "Los y las moderadoras deben aprobar cualquier comentario\
\ antes de su publicación"
enable_premod_links_description: "Los y las moderadoras deben aprobar cualquier\
\ comentario que contengan enlaces antes de su publicación."
enable_questionbox: "Hacer una pregunta a los y las lectoras."
enable_questionbox_description: "Esta pregunta aparecerá en la parte de arriba\
\ del hilo de comentarios."
hours: Horas
include_comment_stream: "Incluir Descripción de Hilo de Comentarios para Lectores"
include_comment_stream_desc: "Escribir un mensaje para ser incluido al principio\
\ del hilo de comentarios. Un tema planteado podría ser la guía de comunidad,\
\ etc."
include_text: "Agregar tu texto aquí."
include_question_here: "Escribir la pregunta aquí."
moderate: Moderar
moderation_settings: "Configuración de la Moderación"
open: "Abrir"
open_stream: "Abrir Hilo de Comentarios"
open_stream_configuration: "Este hilo de comentarios está abierto. Al cerrarlo\
\ no se podrán publicar nuevos comentarios pero todos los comentarios anteriores\
\ aún serán mostrados."
require_email_verification: "Necesita confirmación su correo"
require_email_verification_text: "Nuevos usuarios deben confirmar sus correos\
\ antes de comentar"
save_changes: "Guardar Cambios"
shortcuts: Atajos
sign_out: "Desconectar"
stories: Artículos
stream_settings: "Configuración de Comentarios"
suspect_word_title: "Lista de palabras sospechosas"
suspect_word_text: "Comentarios que contengan estas palabras o frases, considerando\
\ mayusculas y minúsculas, serán automáticamente destacadas en los comentarios\
\ publicados. Escribir una palabra y apretar Enter o Tabulador para agregarla.\
\ O pegar una lista de palabras separadas por coma."
tech_settings: "Configuración Técnica"
title: "Configurar los comentarios"
weeks: Semanas
wordlist: "Palabras Suspendidas"
continue: Continuar
dashboard:
auto_update: "Los datos se actualizan automáticamente cada cinco minutos o cuando\
\ refresca el navegador."
comment_count: comentarios
flags: Reportes
most_flags: "Artículos con la mayor cantidad de reportes"
most_conversations: "Artículos con las mayores conversaciones"
next_update: "{0} minutos hasta la próxima actualización."
no_activity: "¡No han habido comentarios en ningún lado en los últimos 5 minutos."
no_flags: "¡No ha habido ningún reporte en los últimos 5 minutos! Bravo!"
no_likes: "¡No ha habido ningún 'me gusta' en los últimos 5 minutos. Todo tranquilo."
done: Hecho
edit_comment:
body_input_label: "Editar este comentario"
save_button: "Guardar cambios"
edit_window_expired: "No se puede editar este comentario. El periodo de edición\
\ ya ha concluido. Podrías publicar uno nuevo :-)"
edit_window_expired_close: "Cerrar"
edit_window_timer_prefix: "Ventana Edición:"
second: "segundo"
seconds_plural: "segundos"
unexpected_error: "Lo siento. Ha habido un error no previsto al guardar los cambios."
embedlink:
copy: "Copiar al portapapeles"
error:
COMMENT_TOO_SHORT: "Tu comentario debe tener algo escrito"
NOT_AUTHORIZED: "Acción no autorizada."
NO_SPECIAL_CHARACTERS: "Los nombres pueden contener letras números y _"
PASSWORD_LENGTH: "Contraseña es muy corta"
PROFANITY_ERROR: "Los nombres no pueden contener blasfemias. Por favor contacte\
\ al o la administradora si cree que esto es un error"
USERNAME_IN_USE: "Este nombre ya está siendo usado."
USERNAME_REQUIRED: "Debe ingresar un nombre"
EDIT_WINDOW_ENDED: "No puedes editar este comentario. El tiempo de edición ha\
\ expirado."
EDIT_USERNAME_NOT_AUTHORIZED: "No tiene permiso para editar el nombre de usuario."
EMAIL_IN_USE: "Este correo se encuentra en uso"
EMAIL_REQUIRED: "Se requiere un correo"
LOGIN_MAXIMUM_EXCEEDED: "Ha realizado demasiados intentos fallidos de usar la\
\ contraseña. Por favor espere."
PASSWORD_REQUIRED: "Debe ingresar la contraseña"
COMMENTING_CLOSED: "Los comentarios ya estan cerrados"
NOT_FOUND: "Recurso no encontrado"
INVALID_ASSET_URL: "La URL del articulo no es valida"
email: "No es un correo válido"
confirm_password: "Las contraseñas no coinciden. Inténtelo nuevamente"
network_error: "Error al conectar con el servidor. Compruebe su conexión a Internet\
\ y vuelva a intentarlo."
email_not_verified: "Correo {0} no confirmado."
email_password: "Correo y/o contraseña incorrecta."
organization_name: "El nombre de la organización debe contener letras y/o números."
password: "La contraseña debe tener por lo menos 8 caracteres"
username: "Los nombres pueden contener letras números y _"
flag_comment: "Reportar este comentario"
flag_reason: "Razón por la que hacer este reporte (Opcional)"
flag_username: "Reportar el nombre de usuario"
framework:
banned_account_msg: "Tu cuenta se encuentra suspendida. Esto significa que no\
\ puedes gustar, marcar o escribir comentarios."
comment: comentario
comment_is_ignored: "Este comentario está escondido porque has ignorado al usuario."
comments: comentarios
configure_stream: "Configurar Hilo de Comentarios"
content_not_available: "Este contenido no se encuentra disponible"
edit_name:
button: Enviar
error: "Nombres de usuarios pueden solamente incluir letras, números y _"
label: "Nuevo Nombre"
msg: "Tu cuenta está suspendida porque tu nombre de usuario ha sido considerado\
\ no apropiado para el espacio. Para recuperar la cuenta, por favor ingresar\
\ un nuevo nombre de usuario. Contáctanos si tienes alguna pregunta."
ignored_users: "Usuarios ignorados"
my_comments: "Mis Comentarios"
my_profile: "Mi perfil"
new_count: "Ver {0} {1} nuevo"
profile: Perfil
show_all_comments: "Mostrar todos los comentarios"
success_bio_update: "Tu biografia fue actualizada"
success_name_update: "Tu nombre de usuario ha sido actualizado"
success_update_settings: "La configuración de este articulo fue actualizada"
view_all_replies: "ver {0} respuestas"
view_all_replies_initial: "ver todas las {0} respuestas"
view_more_comments: "Ver más comentarios"
view_reply: "ver respuesta"
from_settings_page: "Desde la página de configuración puedes ver tu historia de\
\ comentarios."
like: Me gusta
loading_results: "Cargando Resultados"
marketing: "Esto parece una propaganda"
moderate_this_stream: "Moderar este hilo de comentarios"
modqueue:
account: "reportes de cuentas"
actions: Acciones
all: todos
all_streams: "Todos los Hilos"
approve: "Aprobar"
approved: "Aprobado"
billion: B
close: Cerrar
dont_like_username: "No me gusta el nombre de usuario"
empty_queue: "¡No hay más comentarios para moderar! Tiempo para un ☕️"
flagged: Reportado
impersonating: Impersonando
less_detail: "Menos detalles"
likes: likes
million: M
mod_faster: "Moderar más rápido con atajos de teclado"
moderate: "Moderar →"
more_detail: "Más detalles"
newest_first: "Primero el más nuevo"
navigation: Navegación
next_comment: "Ir al siguiente comentario"
offensive: Ofensivo
oldest_first: "Primero el más antiguo"
other: Otro
premod: pre-mod
prev_comment: "Ir al comentario anterior"
reject: "Rechazar"
rejected: "rechazado"
select_stream: "Seleccionar hilo de comentarios"
shift_key:
shortcuts: Atajos
show_shortcuts: "Mostrar Atajos"
singleview: "Colocar vista de edición de comentario único"
spam_ads: Spam/Publicidad
thismenu: "Abrir este menu"
thousand: k
try_these: "Intentar estos"
view_more_shortcuts: "Ver más atajos"
my_comment_history: "Mi historial de comentarios"
name: Nombre
no_agree_comment: "No estoy de acuerdo con este comentario"
no_like_bio: "No me gusta esta biografia"
no_like_username: "No me gusta este nombre de usuario"
other: Otro
permalink: Enlace
personal_info: "Este comentario muestra información personal"
post: Publicar
profile: Perfil
profile_settings: "Configuración del Perfil"
reply: Responder
report: Reportar
report_notif: "Gracias por reportar este comentario. Nuestro equipo de moderació\
n ha sido notificado y muy pronto lo va a revisar."
report_notif_remove: "Tu reporte ha sido eliminado."
reported: Reportado
set_best: "Etiquetar como el mejor"
settings:
all_comments: "Todos los comentarios"
from_settings_page: "Desde la página de configuración puedes ver tu historial\
\ de comentarios."
my_comment_history: "Mi historial de comentarios"
profile: Perfil
profile_settings: "Configuración del perfil"
sign_in: "Entrar"
to_access: "para acceder al perfil"
user_no_comment: "No has dejado aún ningún comentario. ¡Únete a la conversació\
n!"
step_1_header: "Reportar un problema"
step_2_header: "Ayúdanos a comprender"
step_3_header: "Gracias por tu participación"
stream:
temporarily_suspended: "De acuerdo con la guía de la comunidad de {0}, su cuenta\
\ ha sido temporalmente suspendida. Por favor unirse a la conversación {1}."
streams:
all: Todos
article: Artículo
closed: Cerrado
empty_result: "Ningún articulo coincide con esta búsqueda. Intente expandir su\
\ búsqueda."
filter_streams: "Filtrar Hilos"
newest: Más nuevo
oldest: Más antiguo
open: Abierto
pubdate: "Fecha Publicación"
search: Buscar
sort_by: "Ordenar por"
status: "Estado del Hilo"
stream_status: "Estado del Hilo"
suspenduser:
bio: bio
cancel: "Cancelar"
days: "{0} días"
description_0: "¿Quiere suspender temporalmente a este usuario por su {0}? Hacerlo\
\ va a ocultar temporalmente todos sus comentarios hasta que edite su {0}."
description_1: "Suspender a este usuario va a deshabilitar temporalmente su cuenta\
\ y ocultar todos sus comentarios en el sitio."
description_notify: "Suspender a este usuario va a deshabilitar temporalmente\
\ su cuenta y ocultar todos sus comentarios en el sitio."
description_reject: "¿Quiere suspender temporalmente a este usuario por su {0}?\
\ Hacerlo va a ocultar temporalmente sus comentarios hasta que edite su {0}."
description_suspend: "Esta suspendiendo a {0}. Este comentario va a ir a la fila\
\ de Rechazados, y a {0} no se le va a permitir gustar, marcar, responder o\
\ publicar hasta que el tiempo de suspendido halla concluido."
email: "Otro miembro de la comunidad recientemente marco su nombre de usuario\
\ para revisarlo. Por su contenido su nombre de usuario ha sido rechazado. Esto\
\ significa que no puede comentar o marcar contenido hasta que edite su nombre\
\ de usuario. Envíenos un correo si tiene preguntas o comentarios."
email_subject: "Su cuenta ha sido suspendida"
email_message_reject: "Otro miembro de la comunidad hace poco ha marcado su nombre\
\ de usuario para revisar. Y este ha sido rechazado por su contenido. Esto significa\
\ que no puede comentar, gustar o marcar contenido hasta que edite su nombre\
\ de usuario. Envíenos un correo si tiene alguna preocupación o pregunta."
email_message_suspend: "Querida {0},\n\nDe acuerdo a la guía comunitaria de {1},\
\ su cuenta ha sido temporalmente suspendida. Durante este tiempo, no podrá\
\ comentar, marcar o involucrarse con otros comentaristas. Por favor unirse\
\ a la conversación {2}."
error_email_message_empty: "Debe especificar un mensaje de correo."
hours: "{0} horas"
no_cancel: "No cancelar"
notify_suspend_until: "Usuario {0} ha sido temporalmente suspendido. Esta suspension\
\ va a terminar automáticamente en {1}."
one_hour: "1 hora"
send: Enviar
select_duration: "Seleccionar la duración de la suspensión"
suspend_user: "Suspender Usuario"
title: "Suspender un usuario"
title_0: "Nos dimos cuenta que ha rechazado un nombre de usuario"
title_1: "Notificar al usuario de su suspensión temporal"
title_notify: "Notificar al usuario de su suspensión temporal"
title_reject: "Vimos que ha rechazado un nombre de usuario"
title_suspend: "Suspender Usuario"
username: nombre de usuario
write_message: "Escribir un mensaje"
yes_suspend: "Si, suspender"
thank_you: "Valoramos tanto su seguridad en este espacio como sus comentarios. Un\
\ o una moderadora va a leer su reporte."
unset_best: "Des-etiquetar como el mejor"
user:
bio_flags: "reportes para este bio"
user_bio: "Bio de Usuario"
username_flags: "reportes para este nombre de usuario"
user_impersonating: "Este usuario suplanta a alguien"
user_no_comment: "No has dejado aún ningún comentario. ¡Únete a la conversación!"
username_offensive: "Este nombre de usuario es ofensivo"
view_conversation: "Ver Conversación"
install:
initial:
description: "Vamos a crear su comunidad Talk en unos pocos pasos."
submit: "Empecemos"
add_organization:
description: "Por favor díganos el nombre de su organización. Esta aparecerá\
\ en correos cuando se inviten a nuevos miembros del equipo."
label: "Nombre de la Organización"
save: "Guardar"
create:
email: "Dirección de correo"
username: "Nombre de Usuario"
password: "Contraseña"
confirm_password: "Confirmar Contraseña"
save: "Guardar"
permitted_domains:
title: "Dominios permitidos"
description: "Ingresar los dominios en donde estará Talk, por ejemplo sus ambientes\
\ locales, de staging y producción (ej. localhost:3000, staging.domain.com,\
\ domain.com)."
submit: "Terminar la Instalación"
final:
description: "¡Gracias por instalar Talk! Enviamos un correo para verificar\
\ su dirección de correo. Mientras esta terminando de configurar su cuenta,\
\ ya puede comenzar a involucrarse con sus lectores."
launch: "Iniciar Talk"
close: "Cerrar este instalador"
+2 -1
View File
@@ -111,7 +111,8 @@
"simplemde": "^1.11.2",
"subscriptions-transport-ws": "^0.5.5-alpha.0",
"timekeeper": "^1.0.0",
"uuid": "^3.0.1"
"uuid": "^3.0.1",
"yaml-loader": "^0.4.0"
},
"devDependencies": {
"apollo-client": "^1.0.4",
@@ -1,13 +1,11 @@
import React from 'react';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux';
import translations from '../translations';
import I18n from 'coral-framework/modules/i18n/i18n';
import errorMsj from 'coral-framework/helpers/error';
import validate from 'coral-framework/helpers/validate';
import CreateUsernameDialog from './CreateUsernameDialog';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
import {
showCreateUsernameDialog,
@@ -69,7 +67,7 @@ class ChangeUsernameContainer extends React.Component {
const {addError} = this;
if (!value.length) {
addError(name, lang.t('createdisplay.requiredField'));
addError(name, t('createdisplay.required_field'));
} else if (!validate[name](value)) {
addError(name, errorMsj[name]);
} else {
@@ -97,7 +95,7 @@ class ChangeUsernameContainer extends React.Component {
this.props.createUsername(this.props.auth.user.id, this.state.formData);
validForm();
} else {
invalidForm(lang.t('createdisplay.checkTheForm'));
invalidForm(t('createdisplay.check_the_form'));
}
};
@@ -2,11 +2,8 @@ import React from 'react';
import styles from './styles.css';
import {Dialog, Alert, TextField} from 'coral-ui';
import {FakeComment} from './FakeComment';
import translations from '../translations';
import Button from 'coral-ui/components/Button';
import I18n from 'coral-framework/modules/i18n/i18n';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
const CreateUsernameDialog = ({
open,
@@ -25,39 +22,39 @@ const CreateUsernameDialog = ({
<div>
<div className={styles.header}>
<h1>
{lang.t('createdisplay.writeyourusername')}
{t('createdisplay.write_your_username')}
</h1>
</div>
<div>
<p className={styles.yourusername}>
{lang.t('createdisplay.yourusername')}
{t('createdisplay.your_username')}
</p>
<FakeComment
className={styles.fakeComment}
username={formData.username}
created_at={Date.now()}
body={lang.t('createdisplay.fakecommentbody')}
body={t('createdisplay.fake_comment_body')}
/>
<p className={styles.ifyoudont}>
{lang.t('createdisplay.ifyoudontchangeyourname')}
{t('createdisplay.if_you_dont_change_your_name')}
</p>
{props.auth.error && <Alert>{props.auth.error}</Alert>}
<form id="saveUsername" onSubmit={handleSubmitUsername}>
{props.errors.username &&
<span className={styles.hint}>
{' '}{lang.t('createdisplay.specialCharacters')}{' '}
{' '}{t('createdisplay.special_characters')}{' '}
</span>}
<div className={styles.saveusername}>
<TextField
id="username"
style={{fontSize: 16}}
type="string"
label={lang.t('createdisplay.username')}
label={t('createdisplay.username')}
value={formData.username}
onChange={handleChange}
/>
<Button id="save" type="submit" className={styles.saveButton}>
{lang.t('createdisplay.save')}
{t('createdisplay.save')}
</Button>
</div>
</form>
@@ -1,13 +1,10 @@
import React from 'react';
import translations from '../translations';
import {ReplyButton} from 'coral-plugin-replies';
import PubDate from 'coral-plugin-pubdate/PubDate';
import I18n from 'coral-framework/modules/i18n/i18n';
import AuthorName from 'coral-plugin-author-name/AuthorName';
import Content from 'coral-plugin-commentcontent/CommentContent';
import styles from 'coral-embed-stream/src/components/Comment.css';
const lang = new I18n(translations);
import t from 'coral-framework/services/i18n';
export const FakeComment = ({username, created_at, body}) => (
<div className={`comment ${styles.Comment}`} style={{marginLeft: 0 * 30}}>
@@ -19,7 +16,7 @@ export const FakeComment = ({username, created_at, body}) => (
<div className={`${'coral-plugin-likes'}-container`}>
<button className={'coral-plugin-likes-button'}>
<span className={'coral-plugin-likes-button-text'}>
{lang.t('like')}
{t('like')}
</span>
<i
className={`${'coral-plugin-likes'}-icon material-icons`}
@@ -42,7 +39,7 @@ export const FakeComment = ({username, created_at, body}) => (
<span
className={`comment__action-button comment__action-button--nowrap ${'coral-plugin-flags'}-button-text`}
>
{lang.t('permalink.permalink')}
{t('permalink')}
</span>
<i
className="coral-plugin-permalinks-icon material-icons"
@@ -57,7 +54,7 @@ export const FakeComment = ({username, created_at, body}) => (
<span
className={`comment__action-button comment__action-button--nowrap ${'coral-plugin-flags'}-button-text`}
>
{lang.t('report')}
{t('report')}
</span>
<i
className={`${'coral-plugin-flags'}-icon material-icons`}

Some files were not shown because too many files have changed in this diff Show More