Skip to content
This repository has been archived by the owner on Sep 11, 2024. It is now read-only.

Commit

Permalink
Merge pull request #1608 from pafcu/simplify-translation
Browse files Browse the repository at this point in the history
Refactor translations
  • Loading branch information
lukebarnard1 committed Nov 16, 2017
2 parents 5104ebf + 342378f commit 29e6627
Show file tree
Hide file tree
Showing 20 changed files with 373 additions and 223 deletions.
20 changes: 18 additions & 2 deletions scripts/gen-i18n.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const walk = require('walk');
const flowParser = require('flow-parser');
const estreeWalker = require('estree-walker');

const TRANSLATIONS_FUNCS = ['_t', '_td', '_tJsx'];
const TRANSLATIONS_FUNCS = ['_t', '_td'];

const INPUT_TRANSLATIONS_FILE = 'src/i18n/strings/en_EN.json';
const OUTPUT_FILE = 'src/i18n/strings/en_EN.json';
Expand Down Expand Up @@ -126,7 +126,7 @@ function getTranslationsJs(file) {
if (tKey === null) return;

// check the format string against the args
// We only check _t: _tJsx is much more complex and _td has no args
// We only check _t: _td has no args
if (node.callee.name === '_t') {
try {
const placeholders = getFormatStrings(tKey);
Expand All @@ -139,6 +139,22 @@ function getTranslationsJs(file) {
throw new Error(`No value found for placeholder '${placeholder}'`);
}
}

// Validate tag replacements
if (node.arguments.length > 2) {
const tagMap = node.arguments[2];
for (const prop of tagMap.properties) {
if (prop.key.type === 'Literal') {
const tag = prop.key.value;
// RegExp same as in src/languageHandler.js
const regexp = new RegExp(`(<${tag}>(.*?)<\\/${tag}>|<${tag}>|<${tag}\\s*\\/>)`);
if (!tKey.match(regexp)) {
throw new Error(`No match for ${regexp} in ${tKey}`);
}
}
}
}

} catch (e) {
console.log();
console.error(`ERROR: ${file}:${node.loc.start.line} ${tKey}`);
Expand Down
7 changes: 5 additions & 2 deletions src/components/structures/FilePanel.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import React from 'react';
import Matrix from 'matrix-js-sdk';
import sdk from '../../index';
import MatrixClientPeg from '../../MatrixClientPeg';
import { _t, _tJsx } from '../../languageHandler';
import { _t } from '../../languageHandler';

/*
* Component which shows the filtered file using a TimelinePanel
Expand Down Expand Up @@ -92,7 +92,10 @@ const FilePanel = React.createClass({
if (MatrixClientPeg.get().isGuest()) {
return <div className="mx_FilePanel mx_RoomView_messageListWrapper">
<div className="mx_RoomView_empty">
{ _tJsx("You must <a>register</a> to use this functionality", /<a>(.*?)<\/a>/, (sub) => <a href="#/register" key="sub">{ sub }</a>) }
{ _t("You must <a>register</a> to use this functionality",
{},
{ 'a': (sub) => <a href="#/register" key="sub">{ sub }</a> })
}
</div>
</div>;
} else if (this.noRoom) {
Expand Down
10 changes: 5 additions & 5 deletions src/components/structures/GroupView.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import MatrixClientPeg from '../../MatrixClientPeg';
import sdk from '../../index';
import dis from '../../dispatcher';
import { sanitizedHtmlNode } from '../../HtmlUtils';
import { _t, _td, _tJsx } from '../../languageHandler';
import { _t, _td } from '../../languageHandler';
import AccessibleButton from '../views/elements/AccessibleButton';
import Modal from '../../Modal';
import classnames from 'classnames';
Expand Down Expand Up @@ -932,12 +932,12 @@ export default React.createClass({
className="mx_GroupView_groupDesc_placeholder"
onClick={this._onEditClick}
>
{ _tJsx(
{ _t(
'Your community hasn\'t got a Long Description, a HTML page to show to community members.<br />' +
'Click here to open settings and give it one!',
[/<br \/>/],
[(sub) => <br />])
}
{},
{ 'br': <br /> },
) }
</div>;
}
const groupDescEditingClasses = classnames({
Expand Down
10 changes: 5 additions & 5 deletions src/components/structures/MyGroups.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
import GeminiScrollbar from 'react-gemini-scrollbar';
import {MatrixClient} from 'matrix-js-sdk';
import sdk from '../../index';
import { _t, _tJsx } from '../../languageHandler';
import { _t } from '../../languageHandler';
import withMatrixClient from '../../wrappers/withMatrixClient';
import AccessibleButton from '../views/elements/AccessibleButton';
import dis from '../../dispatcher';
Expand Down Expand Up @@ -165,13 +165,13 @@ export default withMatrixClient(React.createClass({
<div className="mx_MyGroups_headerCard_header">
{ _t('Join an existing community') }
</div>
{ _tJsx(
{ _t(
'To join an existing community you\'ll have to '+
'know its community identifier; this will look '+
'something like <i>+example:matrix.org</i>.',
/<i>(.*)<\/i>/,
(sub) => <i>{ sub }</i>,
) }
{},
{ 'i': (sub) => <i>{ sub }</i> })
}
</div>
</div>
</div>
Expand Down
34 changes: 20 additions & 14 deletions src/components/structures/RoomStatusBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,12 @@ limitations under the License.
*/

import React from 'react';
import { _t, _tJsx } from '../../languageHandler';
import { _t } from '../../languageHandler';
import sdk from '../../index';
import WhoIsTyping from '../../WhoIsTyping';
import MatrixClientPeg from '../../MatrixClientPeg';
import MemberAvatar from '../views/avatars/MemberAvatar';

const HIDE_DEBOUNCE_MS = 10000;
const STATUS_BAR_HIDDEN = 0;
const STATUS_BAR_EXPANDED = 1;
const STATUS_BAR_EXPANDED_LARGE = 2;
Expand Down Expand Up @@ -272,12 +271,16 @@ module.exports = React.createClass({
{ this.props.unsentMessageError }
</div>
<div className="mx_RoomStatusBar_connectionLostBar_desc">
{ _tJsx("<a>Resend all</a> or <a>cancel all</a> now. You can also select individual messages to resend or cancel.",
[/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/],
[
(sub) => <a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this.props.onResendAllClick}>{ sub }</a>,
(sub) => <a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={this.props.onCancelAllClick}>{ sub }</a>,
],
{
_t("<resendText>Resend all</resendText> or <cancelText>cancel all</cancelText> now. " +
"You can also select individual messages to resend or cancel.",
{},
{
'resendText': (sub) =>
<a className="mx_RoomStatusBar_resend_link" key="resend" onClick={this.props.onResendAllClick}>{ sub }</a>,
'cancelText': (sub) =>
<a className="mx_RoomStatusBar_resend_link" key="cancel" onClick={this.props.onCancelAllClick}>{ sub }</a>,
},
) }
</div>
</div>
Expand Down Expand Up @@ -322,12 +325,15 @@ module.exports = React.createClass({
if (this.props.sentMessageAndIsAlone) {
return (
<div className="mx_RoomStatusBar_isAlone">
{ _tJsx("There's no one else here! Would you like to <a>invite others</a> or <a>stop warning about the empty room</a>?",
[/<a>(.*?)<\/a>/, /<a>(.*?)<\/a>/],
[
(sub) => <a className="mx_RoomStatusBar_resend_link" key="invite" onClick={this.props.onInviteClick}>{ sub }</a>,
(sub) => <a className="mx_RoomStatusBar_resend_link" key="nowarn" onClick={this.props.onStopWarningClick}>{ sub }</a>,
],
{ _t("There's no one else here! Would you like to <inviteText>invite others</inviteText> " +
"or <nowarnText>stop warning about the empty room</nowarnText>?",
{},
{
'inviteText': (sub) =>
<a className="mx_RoomStatusBar_resend_link" key="invite" onClick={this.props.onInviteClick}>{ sub }</a>,
'nowarnText': (sub) =>
<a className="mx_RoomStatusBar_resend_link" key="nowarn" onClick={this.props.onStopWarningClick}>{ sub }</a>,
},
) }
</div>
);
Expand Down
25 changes: 15 additions & 10 deletions src/components/structures/login/Login.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ limitations under the License.
'use strict';

import React from 'react';
import { _t, _tJsx } from '../../../languageHandler';
import { _t } from '../../../languageHandler';
import * as languageHandler from '../../../languageHandler';
import sdk from '../../../index';
import Login from '../../../Login';
Expand Down Expand Up @@ -272,17 +272,19 @@ module.exports = React.createClass({
!this.state.enteredHomeserverUrl.startsWith("http"))
) {
errorText = <span>
{ _tJsx("Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " +
{
_t("Can't connect to homeserver via HTTP when an HTTPS URL is in your browser bar. " +
"Either use HTTPS or <a>enable unsafe scripts</a>.",
/<a>(.*?)<\/a>/,
(sub) => { return <a href="https://www.google.com/search?&q=enable%20unsafe%20scripts">{ sub }</a>; },
{},
{ 'a': (sub) => { return <a href="https://www.google.com/search?&q=enable%20unsafe%20scripts">{ sub }</a>; } },
) }
</span>;
} else {
errorText = <span>
{ _tJsx("Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
/<a>(.*?)<\/a>/,
(sub) => { return <a href={this.state.enteredHomeserverUrl}>{ sub }</a>; },
{
_t("Can't connect to homeserver - please check your connectivity, ensure your <a>homeserver's SSL certificate</a> is trusted, and that a browser extension is not blocking requests.",
{},
{ 'a': (sub) => { return <a href={this.state.enteredHomeserverUrl}>{ sub }</a>; } },
) }
</span>;
}
Expand All @@ -293,7 +295,7 @@ module.exports = React.createClass({

componentForStep: function(step) {
switch (step) {
case 'm.login.password':
case 'm.login.password': {
const PasswordLogin = sdk.getComponent('login.PasswordLogin');
return (
<PasswordLogin
Expand All @@ -309,12 +311,14 @@ module.exports = React.createClass({
hsUrl={this.state.enteredHomeserverUrl}
/>
);
case 'm.login.cas':
}
case 'm.login.cas': {
const CasLogin = sdk.getComponent('login.CasLogin');
return (
<CasLogin onSubmit={this.onCasLogin} />
);
default:
}
default: {
if (!step) {
return;
}
Expand All @@ -323,6 +327,7 @@ module.exports = React.createClass({
{ _t('Sorry, this homeserver is using a login which is not recognised ') }({ step })
</div>
);
}
}
},

Expand Down
7 changes: 4 additions & 3 deletions src/components/views/dialogs/SessionRestoreErrorDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import React from 'react';
import sdk from '../../../index';
import SdkConfig from '../../../SdkConfig';
import Modal from '../../../Modal';
import { _t, _tJsx } from '../../../languageHandler';
import { _t } from '../../../languageHandler';


export default React.createClass({
Expand All @@ -45,9 +45,10 @@ export default React.createClass({
if (SdkConfig.get().bug_report_endpoint_url) {
bugreport = (
<p>
{ _tJsx(
{ _t(
"Otherwise, <a>click here</a> to send a bug report.",
/<a>(.*?)<\/a>/, (sub) => <a onClick={this._sendBugReport} key="bugreport" href='#'>{ sub }</a>,
{},
{ 'a': (sub) => <a onClick={this._sendBugReport} key="bugreport" href='#'>{ sub }</a> },
) }
</p>
);
Expand Down
23 changes: 10 additions & 13 deletions src/components/views/dialogs/SetMxIdDialog.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import sdk from '../../../index';
import MatrixClientPeg from '../../../MatrixClientPeg';
import classnames from 'classnames';
import KeyCode from '../../../KeyCode';
import { _t, _tJsx } from '../../../languageHandler';
import { _t } from '../../../languageHandler';

// The amount of time to wait for further changes to the input username before
// sending a request to the server
Expand Down Expand Up @@ -267,24 +267,21 @@ export default React.createClass({
</div>
{ usernameIndicator }
<p>
{ _tJsx(
{ _t(
'This will be your account name on the <span></span> ' +
'homeserver, or you can pick a <a>different server</a>.',
[
/<span><\/span>/,
/<a>(.*?)<\/a>/,
],
[
(sub) => <span>{ this.props.homeserverUrl }</span>,
(sub) => <a href="#" onClick={this.props.onDifferentServerClicked}>{ sub }</a>,
],
{},
{
'span': <span>{ this.props.homeserverUrl }</span>,
'a': (sub) => <a href="#" onClick={this.props.onDifferentServerClicked}>{ sub }</a>,
},
) }
</p>
<p>
{ _tJsx(
{ _t(
'If you already have a Matrix account you can <a>log in</a> instead.',
/<a>(.*?)<\/a>/,
[(sub) => <a href="#" onClick={this.props.onLoginClick}>{ sub }</a>],
{},
{ 'a': (sub) => <a href="#" onClick={this.props.onLoginClick}>{ sub }</a> },
) }
</p>
{ auth }
Expand Down
8 changes: 4 additions & 4 deletions src/components/views/login/CaptchaForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ limitations under the License.

import React from 'react';
import ReactDOM from 'react-dom';
import { _t, _tJsx } from '../../../languageHandler';
import { _t } from '../../../languageHandler';

const DIV_ID = 'mx_recaptcha';

Expand Down Expand Up @@ -67,10 +67,10 @@ module.exports = React.createClass({
// * jumping straight to a hosted captcha page (but we don't support that yet)
// * embedding the captcha in an iframe (if that works)
// * using a better captcha lib
ReactDOM.render(_tJsx(
ReactDOM.render(_t(
"Robot check is currently unavailable on desktop - please use a <a>web browser</a>",
/<a>(.*?)<\/a>/,
(sub) => { return <a href='https://riot.im/app'>{ sub }</a>; }), warning);
{},
{ 'a': (sub) => { return <a href='https://riot.im/app'>{ sub }</a>; }}), warning);
this.refs.recaptchaContainer.appendChild(warning);
} else {
const scriptTag = document.createElement('script');
Expand Down
12 changes: 9 additions & 3 deletions src/components/views/login/InteractiveAuthEntryComponents.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import url from 'url';
import classnames from 'classnames';

import sdk from '../../../index';
import { _t, _tJsx } from '../../../languageHandler';
import { _t } from '../../../languageHandler';

/* This file contains a collection of components which are used by the
* InteractiveAuth to prompt the user to enter the information needed
Expand Down Expand Up @@ -256,7 +256,10 @@ export const EmailIdentityAuthEntry = React.createClass({
} else {
return (
<div>
<p>{ _tJsx("An email has been sent to %(emailAddress)s", /%\(emailAddress\)s/, (sub) => <i>{this.props.inputs.emailAddress}</i>) }</p>
<p>{ _t("An email has been sent to %(emailAddress)s",
{ emailAddress: (sub) => <i>{ this.props.inputs.emailAddress }</i> },
) }
</p>
<p>{ _t("Please check your email to continue registration.") }</p>
</div>
);
Expand Down Expand Up @@ -370,7 +373,10 @@ export const MsisdnAuthEntry = React.createClass({
});
return (
<div>
<p>{ _tJsx("A text message has been sent to %(msisdn)s", /%\(msisdn\)s/, (sub) => <i>{this._msisdn}</i>) }</p>
<p>{ _t("A text message has been sent to %(msisdn)s",
{ msisdn: <i>this._msisdn</i> },
) }
</p>
<p>{ _t("Please enter the code it contains:") }</p>
<div className="mx_InteractiveAuthEntryComponents_msisdnWrapper">
<form onSubmit={this._onFormSubmit}>
Expand Down
Loading

0 comments on commit 29e6627

Please sign in to comment.