diff --git a/src/async-components/views/dialogs/ExportE2eKeysDialog.js b/src/async-components/views/dialogs/ExportE2eKeysDialog.js index 56b9d56cc9..5abd758fa8 100644 --- a/src/async-components/views/dialogs/ExportE2eKeysDialog.js +++ b/src/async-components/views/dialogs/ExportE2eKeysDialog.js @@ -16,6 +16,7 @@ limitations under the License. import FileSaver from 'file-saver'; import React from 'react'; +import { _t } from '../../../languageHandler'; import * as Matrix from 'matrix-js-sdk'; import * as MegolmExportEncryption from '../../../utils/MegolmExportEncryption'; @@ -52,11 +53,11 @@ export default React.createClass({ const passphrase = this.refs.passphrase1.value; if (passphrase !== this.refs.passphrase2.value) { - this.setState({errStr: 'Passphrases must match'}); + this.setState({errStr: _t('Passphrases must match')}); return false; } if (!passphrase) { - this.setState({errStr: 'Passphrase must not be empty'}); + this.setState({errStr: _t('Passphrase must not be empty')}); return false; } @@ -109,24 +110,28 @@ export default React.createClass({ return (

- This process allows you to export the keys for messages - you have received in encrypted rooms to a local file. You - will then be able to import the file into another Matrix - client in the future, so that client will also be able to - decrypt these messages. + { _t( + 'This process allows you to export the keys for messages ' + + 'you have received in encrypted rooms to a local file. You ' + + 'will then be able to import the file into another Matrix ' + + 'client in the future, so that client will also be able to ' + + 'decrypt these messages.' + ) }

- The exported file will allow anyone who can read it to decrypt - any encrypted messages that you can see, so you should be - careful to keep it secure. To help with this, you should enter - a passphrase below, which will be used to encrypt the exported - data. It will only be possible to import the data by using the - same passphrase. + { _t( + 'The exported file will allow anyone who can read it to decrypt ' + + 'any encrypted messages that you can see, so you should be ' + + 'careful to keep it secure. To help with this, you should enter ' + + 'a passphrase below, which will be used to encrypt the exported ' + + 'data. It will only be possible to import the data by using the ' + + 'same passphrase.' + ) }

{this.state.errStr} @@ -135,7 +140,7 @@ export default React.createClass({
@@ -148,7 +153,7 @@ export default React.createClass({
diff --git a/src/async-components/views/dialogs/ImportE2eKeysDialog.js b/src/async-components/views/dialogs/ImportE2eKeysDialog.js index ddd13813e2..75b66e2969 100644 --- a/src/async-components/views/dialogs/ImportE2eKeysDialog.js +++ b/src/async-components/views/dialogs/ImportE2eKeysDialog.js @@ -19,6 +19,7 @@ import React from 'react'; import * as Matrix from 'matrix-js-sdk'; import * as MegolmExportEncryption from '../../../utils/MegolmExportEncryption'; import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; function readFileAsArrayBuffer(file) { return new Promise((resolve, reject) => { @@ -112,20 +113,23 @@ export default React.createClass({ return (

- This process allows you to import encryption keys - that you had previously exported from another Matrix - client. You will then be able to decrypt any - messages that the other client could decrypt. + { _t( + 'This process allows you to import encryption keys ' + + 'that you had previously exported from another Matrix ' + + 'client. You will then be able to decrypt any ' + + 'messages that the other client could decrypt.' + ) }

- The export file will be protected with a passphrase. - You should enter the passphrase here, to decrypt the - file. + { _t( + 'The export file will be protected with a passphrase. ' + + 'You should enter the passphrase here, to decrypt the file.' + ) }

{this.state.errStr} @@ -134,7 +138,7 @@ export default React.createClass({
@@ -147,7 +151,7 @@ export default React.createClass({
diff --git a/src/components/structures/FilePanel.js b/src/components/structures/FilePanel.js index b85e7dc2d2..75e53d4f77 100644 --- a/src/components/structures/FilePanel.js +++ b/src/components/structures/FilePanel.js @@ -95,7 +95,7 @@ var FilePanel = React.createClass({
; } else if (this.noRoom) { return
-
You must join the room to see its files
+
{_t("You must join the room to see its files")}
; } diff --git a/src/components/structures/MatrixChat.js b/src/components/structures/MatrixChat.js index d8e1f881f1..542869d0d1 100644 --- a/src/components/structures/MatrixChat.js +++ b/src/components/structures/MatrixChat.js @@ -699,9 +699,9 @@ module.exports = React.createClass({ modal.close(); console.error("Failed to leave room " + roomId + " " + err); Modal.createDialog(ErrorDialog, { - title: "Failed to leave room", + title: _t("Failed to leave room"), description: (err && err.message ? err.message : - "Server may be unavailable, overloaded, or you hit a bug."), + _t("Server may be unavailable, overloaded, or you hit a bug.")), }); }); } diff --git a/src/components/structures/UserSettings.js b/src/components/structures/UserSettings.js index f4bf8b18cb..6b63ad9ebd 100644 --- a/src/components/structures/UserSettings.js +++ b/src/components/structures/UserSettings.js @@ -55,7 +55,7 @@ const gHVersionLabel = function(repo, token='') { // Enumerate some simple 'flip a bit' UI settings (if any). // 'id' gives the key name in the im.vector.web.settings account data event // 'label' is how we describe it in the UI. -// Warning: Each "label" string below must be added to i18n/strings/en_EN.json, +// Warning: Each "label" string below must be added to i18n/strings/en_EN.json, // since they will be translated when rendered. const SETTINGS_LABELS = [ { @@ -90,7 +90,7 @@ const SETTINGS_LABELS = [ */ ]; -// Warning: Each "label" string below must be added to i18n/strings/en_EN.json, +// Warning: Each "label" string below must be added to i18n/strings/en_EN.json, // since they will be translated when rendered. const CRYPTO_SETTINGS_LABELS = [ { @@ -804,7 +804,7 @@ module.exports = React.createClass({ reject = ( - Reject all {invitedRooms.length} invites + {_t("Reject all %(invitedRooms)s invites", {invitedRooms: invitedRooms.length})} ); } diff --git a/src/components/views/create_room/CreateRoomButton.js b/src/components/views/create_room/CreateRoomButton.js index bb9406efe1..8f0368d690 100644 --- a/src/components/views/create_room/CreateRoomButton.js +++ b/src/components/views/create_room/CreateRoomButton.js @@ -16,8 +16,8 @@ limitations under the License. 'use strict'; -var React = require('react'); - +import React from 'react'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'CreateRoomButton', propTypes: { @@ -36,7 +36,7 @@ module.exports = React.createClass({ render: function() { return ( - + ); } }); diff --git a/src/components/views/dialogs/ChatCreateOrReuseDialog.js b/src/components/views/dialogs/ChatCreateOrReuseDialog.js index 1a6ddf0456..f563af6691 100644 --- a/src/components/views/dialogs/ChatCreateOrReuseDialog.js +++ b/src/components/views/dialogs/ChatCreateOrReuseDialog.js @@ -86,7 +86,7 @@ export default class ChatCreateOrReuseDialog extends React.Component {
-
Start new chat
+
{_("Start new chat")}
; const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); diff --git a/src/components/views/dialogs/ChatInviteDialog.js b/src/components/views/dialogs/ChatInviteDialog.js index 04f21c1404..3509ba35e9 100644 --- a/src/components/views/dialogs/ChatInviteDialog.js +++ b/src/components/views/dialogs/ChatInviteDialog.js @@ -272,8 +272,8 @@ module.exports = React.createClass({ if (MatrixClientPeg.get().isGuest()) { var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog"); Modal.createDialog(NeedToRegisterDialog, { - title: "Please Register", - description: "Guest users can't invite users. Please register." + title: _t("Please Register"), + description: _t("Guest users can't invite users. Please register."), }); return; } @@ -294,8 +294,8 @@ module.exports = React.createClass({ console.error(err.stack); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to invite", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t("Failed to invite"), + description: ((err && err.message) ? err.message : _t("Operation failed")), }); return null; }) @@ -307,8 +307,8 @@ module.exports = React.createClass({ console.error(err.stack); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to invite user", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t("Failed to invite user"), + description: ((err && err.message) ? err.message : _t("Operation failed")), }); return null; }) @@ -328,8 +328,8 @@ module.exports = React.createClass({ console.error(err.stack); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to invite", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t("Failed to invite"), + description: ((err && err.message) ? err.message : _t("Operation failed")), }); return null; }) @@ -385,7 +385,7 @@ module.exports = React.createClass({ if (errorList.length > 0) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to invite the following users to the " + room.name + " room:", + title: _t("Failed to invite the following users to the %(roomName)s room:", {roomName: room.name}), description: errorList.join(", "), }); } diff --git a/src/components/views/dialogs/ConfirmRedactDialog.js b/src/components/views/dialogs/ConfirmRedactDialog.js index db5197e338..7922b7b289 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.js +++ b/src/components/views/dialogs/ConfirmRedactDialog.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import sdk from '../../../index'; import classnames from 'classnames'; +import { _t } from '../../../languageHandler'; /* * A dialog for confirming a redaction. @@ -42,7 +43,7 @@ export default React.createClass({ render: function() { const BaseDialog = sdk.getComponent('views.dialogs.BaseDialog'); - const title = "Confirm Removal"; + const title = _t("Confirm Removal"); const confirmButtonClass = classnames({ 'mx_Dialog_primary': true, @@ -55,16 +56,16 @@ export default React.createClass({ title={title} >
- Are you sure you wish to remove (delete) this event? - Note that if you delete a room name or topic change, it could undo the change. + {_t("Are you sure you wish to remove (delete) this event? " + + "Note that if you delete a room name or topic change, it could undo the change.")}
diff --git a/src/components/views/dialogs/DeactivateAccountDialog.js b/src/components/views/dialogs/DeactivateAccountDialog.js index b4879982bf..da74e6b716 100644 --- a/src/components/views/dialogs/DeactivateAccountDialog.js +++ b/src/components/views/dialogs/DeactivateAccountDialog.js @@ -20,6 +20,7 @@ import sdk from '../../../index'; import MatrixClientPeg from '../../../MatrixClientPeg'; import * as Lifecycle from '../../../Lifecycle'; import Velocity from 'velocity-vector'; +import { _t } from '../../../languageHandler'; export default class DeactivateAccountDialog extends React.Component { constructor(props, context) { @@ -56,10 +57,10 @@ export default class DeactivateAccountDialog extends React.Component { Lifecycle.onLoggedOut(); this.props.onFinished(false); }, (err) => { - let errStr = 'Unknown error'; + let errStr = _t('Unknown error'); // https://matrix.org/jira/browse/SYN-744 if (err.httpStatus == 401 || err.httpStatus == 403) { - errStr = 'Incorrect password'; + errStr = _t('Incorrect password'); Velocity(this._passwordField, "callout.shake", 300); } this.setState({ @@ -91,23 +92,23 @@ export default class DeactivateAccountDialog extends React.Component { let cancelButton = null; if (!this.state.busy) { cancelButton = ; } return (
- Deactivate Account + {_t("Deactivate Account")}
-

This will make your account permanently unusable. You will not be able to re-register the same user ID.

+

{_t("This will make your account permanently unusable. You will not be able to re-register the same user ID.")}

-

This action is irreversible.

+

{_t("This action is irreversible.")}

-

To continue, please enter your password.

+

{_t("To continue, please enter your password.")}

-

Password:

+

{_t("Password")}:

- To verify that this device can be trusted, please contact its - owner using some other means (e.g. in person or a phone call) - and ask them whether the key they see in their User Settings - for this device matches the key below: + {_t("To verify that this device can be trusted, please contact its " + + "owner using some other means (e.g. in person or a phone call) " + + "and ask them whether the key they see in their User Settings " + + "for this device matches the key below:")}

    -
  • { props.device.getDisplayName() }
  • -
  • { props.device.deviceId}
  • -
  • { key }
  • +
  • { props.device.getDisplayName() }
  • +
  • { props.device.deviceId}
  • +
  • { key }

- If it matches, press the verify button below. - If it doesnt, then someone else is intercepting this device - and you probably want to press the blacklist button instead. + {_t("If it matches, press the verify button below. " + + "If it doesn't, then someone else is intercepting this device " + + "and you probably want to press the blacklist button instead.")}

- In future this verification process will be more sophisticated. + {_t("In future this verification process will be more sophisticated.")}

); @@ -61,9 +62,9 @@ export default function DeviceVerifyDialog(props) { return ( ); diff --git a/src/components/views/dialogs/SessionRestoreErrorDialog.js b/src/components/views/dialogs/SessionRestoreErrorDialog.js index 358bbf1fec..e7f6e19db7 100644 --- a/src/components/views/dialogs/SessionRestoreErrorDialog.js +++ b/src/components/views/dialogs/SessionRestoreErrorDialog.js @@ -18,6 +18,7 @@ import React from 'react'; import sdk from '../../../index'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; +import { _t } from '../../../languageHandler'; export default React.createClass({ @@ -51,21 +52,21 @@ export default React.createClass({ return ( + title={_t('Unable to restore session')}>
-

We encountered an error trying to restore your previous session. If - you continue, you will need to log in again, and encrypted chat - history will be unreadable.

+

{_t("We encountered an error trying to restore your previous session. If " + + "you continue, you will need to log in again, and encrypted chat " + + "history will be unreadable.")}

-

If you have previously used a more recent version of Riot, your session - may be incompatible with this version. Close this window and return - to the more recent version.

+

{_t("If you have previously used a more recent version of Riot, your session " + + "may be incompatible with this version. Close this window and return " + + "to the more recent version.")}

{bugreport}
diff --git a/src/components/views/dialogs/SetDisplayNameDialog.js b/src/components/views/dialogs/SetDisplayNameDialog.js index 1047e05c26..17de0aea1b 100644 --- a/src/components/views/dialogs/SetDisplayNameDialog.js +++ b/src/components/views/dialogs/SetDisplayNameDialog.js @@ -64,11 +64,11 @@ export default React.createClass({ return (
- Your display name is how you'll appear to others when you speak in rooms.
- What would you like it to be? + {_t("Your display name is how you'll appear to others when you speak in rooms. " + + "What would you like it to be?")}
diff --git a/src/components/views/dialogs/UnknownDeviceDialog.js b/src/components/views/dialogs/UnknownDeviceDialog.js index 4f3d4301f9..9ffad5d32a 100644 --- a/src/components/views/dialogs/UnknownDeviceDialog.js +++ b/src/components/views/dialogs/UnknownDeviceDialog.js @@ -20,6 +20,7 @@ import dis from '../../../dispatcher'; import MatrixClientPeg from '../../../MatrixClientPeg'; import GeminiScrollbar from 'react-gemini-scrollbar'; import Resend from '../../../Resend'; +import { _t } from '../../../languageHandler'; function DeviceListEntry(props) { const {userId, device} = props; @@ -120,17 +121,17 @@ export default React.createClass({ if (blacklistUnverified) { warning = (

- You are currently blacklisting unverified devices; to send - messages to these devices you must verify them. + {_t("You are currently blacklisting unverified devices; to send " + + "messages to these devices you must verify them.")}

); } else { warning = (

- We recommend you go through the verification process - for each device to confirm they belong to their legitimate owner, - but you can resend the message without verifying if you prefer. + {_t("We recommend you go through the verification process " + + "for each device to confirm they belong to their legitimate owner, " + + "but you can resend the message without verifying if you prefer.")}

); @@ -149,10 +150,10 @@ export default React.createClass({ >

- "{this.props.room.name}" contains devices that you haven't seen before. + {_t('"%(RoomName)s" contains devices that you haven\'t seen before.', {RoomName: this.props.room.name})}

{ warning } - Unknown devices: + {_t("Unknown devices")}:
diff --git a/src/components/views/elements/AddressTile.js b/src/components/views/elements/AddressTile.js index 9961a1a428..33cc7f9923 100644 --- a/src/components/views/elements/AddressTile.js +++ b/src/components/views/elements/AddressTile.js @@ -16,12 +16,13 @@ limitations under the License. 'use strict'; -var React = require('react'); -var classNames = require('classnames'); -var sdk = require("../../../index"); -var Invite = require("../../../Invite"); -var MatrixClientPeg = require("../../../MatrixClientPeg"); -var Avatar = require('../../../Avatar'); +import React from 'react'; +import classNames from 'classnames'; +import sdk from "../../../index"; +import Invite from "../../../Invite"; +import MatrixClientPeg from "../../../MatrixClientPeg"; +import Avatar from '../../../Avatar'; +import { _t } from '../../../languageHandler'; // React PropType definition for an object describing // an address that can be invited to a room (which @@ -142,7 +143,7 @@ export default React.createClass({ }); info = ( -
Unknown Address
+
{_t("Unknown Address")}
); } diff --git a/src/components/views/elements/DeviceVerifyButtons.js b/src/components/views/elements/DeviceVerifyButtons.js index 28a36c429e..dfca7e2600 100644 --- a/src/components/views/elements/DeviceVerifyButtons.js +++ b/src/components/views/elements/DeviceVerifyButtons.js @@ -18,6 +18,7 @@ import React from 'react'; import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; import Modal from '../../../Modal'; +import { _t } from '../../../languageHandler'; export default React.createClass({ displayName: 'DeviceVerifyButtons', @@ -82,14 +83,14 @@ export default React.createClass({ blacklistButton = ( ); } else { blacklistButton = ( ); } @@ -98,14 +99,14 @@ export default React.createClass({ verifyButton = ( ); } else { verifyButton = ( ); } diff --git a/src/components/views/elements/Dropdown.js b/src/components/views/elements/Dropdown.js index 82f8d753a9..c049c38a68 100644 --- a/src/components/views/elements/Dropdown.js +++ b/src/components/views/elements/Dropdown.js @@ -17,6 +17,7 @@ limitations under the License. import React from 'react'; import classnames from 'classnames'; import AccessibleButton from './AccessibleButton'; +import { _t } from '../../../languageHandler'; class MenuOption extends React.Component { constructor(props) { @@ -255,7 +256,7 @@ export default class Dropdown extends React.Component { }); if (options.length === 0) { return [
- No results + {_t("No results")}
]; } return options; diff --git a/src/components/views/elements/UserSelector.js b/src/components/views/elements/UserSelector.js index 266e10154f..955903aac0 100644 --- a/src/components/views/elements/UserSelector.js +++ b/src/components/views/elements/UserSelector.js @@ -16,7 +16,8 @@ limitations under the License. 'use strict'; -var React = require('react'); +import React from 'react'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'UserSelector', @@ -59,9 +60,9 @@ module.exports = React.createClass({ return
  • {user_id} - X
  • ; })} - +
    ); diff --git a/src/components/views/login/CaptchaForm.js b/src/components/views/login/CaptchaForm.js index 0977f947aa..b0dd29582b 100644 --- a/src/components/views/login/CaptchaForm.js +++ b/src/components/views/login/CaptchaForm.js @@ -16,7 +16,9 @@ limitations under the License. 'use strict'; -var React = require('react'); +import React from 'react'; +import { _t } from '../../../languageHandler'; + var DIV_ID = 'mx_recaptcha'; /** @@ -117,7 +119,7 @@ module.exports = React.createClass({ return (
    - This Home Server would like to make sure you are not a robot + {_t("This Home Server would like to make sure you are not a robot")}
    {error} diff --git a/src/components/views/login/CasLogin.js b/src/components/views/login/CasLogin.js index c818586d52..96e37875be 100644 --- a/src/components/views/login/CasLogin.js +++ b/src/components/views/login/CasLogin.js @@ -16,7 +16,8 @@ limitations under the License. 'use strict'; -var React = require('react'); +import React from 'react'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'CasLogin', @@ -28,7 +29,7 @@ module.exports = React.createClass({ render: function() { return (
    - +
    ); } diff --git a/src/components/views/login/CustomServerDialog.js b/src/components/views/login/CustomServerDialog.js index e6450adef1..f5c5c84e63 100644 --- a/src/components/views/login/CustomServerDialog.js +++ b/src/components/views/login/CustomServerDialog.js @@ -14,7 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -var React = require("react"); +import React from 'react'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'CustomServerDialog', @@ -23,24 +24,24 @@ module.exports = React.createClass({ return (
    - Custom Server Options + {_t("Custom Server Options")}
    - You can use the custom server options to sign into other Matrix - servers by specifying a different Home server URL. + {_t("You can use the custom server options to sign into other Matrix " + + "servers by specifying a different Home server URL.")}
    - This allows you to use this app with an existing Matrix account on - a different home server. + {_t("This allows you to use this app with an existing Matrix account on " + + "a different home server.")}

    - You can also set a custom identity server but this will typically prevent - interaction with users based on email address. + {_t("You can also set a custom identity server but this will typically prevent " + + "interaction with users based on email address.")}
    diff --git a/src/components/views/login/InteractiveAuthEntryComponents.js b/src/components/views/login/InteractiveAuthEntryComponents.js index c4084facb2..8c0be10ba9 100644 --- a/src/components/views/login/InteractiveAuthEntryComponents.js +++ b/src/components/views/login/InteractiveAuthEntryComponents.js @@ -20,6 +20,7 @@ import url from 'url'; import classnames from 'classnames'; import sdk from '../../../index'; +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 @@ -255,8 +256,8 @@ export const EmailIdentityAuthEntry = React.createClass({ } else { return (
    -

    An email has been sent to {this.props.inputs.emailAddress}

    -

    Please check your email to continue registration.

    +

    {_t("An email has been sent to")} {this.props.inputs.emailAddress}

    +

    {_t("Please check your email to continue registration.")}

    ); } @@ -348,7 +349,7 @@ export const MsisdnAuthEntry = React.createClass({ }); } else { this.setState({ - errorText: "Token incorrect", + errorText: _t("Token incorrect"), }); } }).catch((e) => { @@ -369,8 +370,8 @@ export const MsisdnAuthEntry = React.createClass({ }); return (
    -

    A text message has been sent to +{this._msisdn}

    -

    Please enter the code it contains:

    +

    {_t("A text message has been sent to")} +{this._msisdn}

    +

    {_t("Please enter the code it contains:")}

    ); } diff --git a/src/components/views/login/RegistrationForm.js b/src/components/views/login/RegistrationForm.js index 7ca5de72cd..f567c80bfd 100644 --- a/src/components/views/login/RegistrationForm.js +++ b/src/components/views/login/RegistrationForm.js @@ -21,6 +21,7 @@ import sdk from '../../../index'; import Email from '../../../email'; import { looksValid as phoneNumberLooksValid } from '../../../phonenumber'; import Modal from '../../../Modal'; +import { _t } from '../../../languageHandler'; const FIELD_EMAIL = 'field_email'; const FIELD_PHONE_COUNTRY = 'field_phone_country'; @@ -103,10 +104,10 @@ module.exports = React.createClass({ title: "Warning!", description:
    - If you don't specify an email address, you won't be able to reset your password.
    - Are you sure? + {_t("If you don't specify an email address, you won't be able to reset your password. " + + "Are you sure?")}
    , - button: "Continue", + button: _t("Continue"), onFinished: function(confirmed) { if (confirmed) { self._doSubmit(); @@ -304,7 +305,7 @@ module.exports = React.createClass({ } else if (this.state.selectedTeam) { belowEmailSection = (

    - You are registering with {this.state.selectedTeam.name} + {_t("You are registering with %(SelectedTeamName)s", {SelectedTeamName: this.state.selectedTeam.name})}

    ); } diff --git a/src/components/views/login/ServerConfig.js b/src/components/views/login/ServerConfig.js index 2853945425..3abe64cd2f 100644 --- a/src/components/views/login/ServerConfig.js +++ b/src/components/views/login/ServerConfig.js @@ -19,6 +19,7 @@ limitations under the License. var React = require('react'); var Modal = require('../../../Modal'); var sdk = require('../../../index'); +import { _t } from '../../../languageHandler'; /** * A pure UI component which displays the HS and IS to use. @@ -136,14 +137,14 @@ module.exports = React.createClass({ checked={!this.state.configVisible} onChange={this.onServerConfigVisibleChange.bind(this, false)} />   
    ); @@ -155,7 +156,7 @@ module.exports = React.createClass({
    - What does this mean? + {_t("What does this mean?")}
    diff --git a/src/components/views/messages/MAudioBody.js b/src/components/views/messages/MAudioBody.js index 73b9bdb200..0b6214b9bf 100644 --- a/src/components/views/messages/MAudioBody.js +++ b/src/components/views/messages/MAudioBody.js @@ -22,6 +22,7 @@ import MFileBody from './MFileBody'; import MatrixClientPeg from '../../../MatrixClientPeg'; import sdk from '../../../index'; import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile'; +import { _t } from '../../../languageHandler'; export default class MAudioBody extends React.Component { constructor(props) { @@ -77,7 +78,7 @@ export default class MAudioBody extends React.Component { return ( - Error decrypting audio + {_t("Error decrypting audio")} ); } diff --git a/src/components/views/messages/MImageBody.js b/src/components/views/messages/MImageBody.js index 0b4bc6ecb9..da6447c7e5 100644 --- a/src/components/views/messages/MImageBody.js +++ b/src/components/views/messages/MImageBody.js @@ -26,6 +26,7 @@ import dis from '../../../dispatcher'; import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile'; import q from 'q'; import UserSettingsStore from '../../../UserSettingsStore'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'MImageBody', @@ -56,7 +57,7 @@ module.exports = React.createClass({ const ImageView = sdk.getComponent("elements.ImageView"); const params = { src: httpUrl, - name: content.body && content.body.length > 0 ? content.body : 'Attachment', + name: content.body && content.body.length > 0 ? content.body : _t('Attachment'), mxEvent: this.props.mxEvent, }; @@ -191,7 +192,7 @@ module.exports = React.createClass({ return ( - Error decrypting image + {_t("Error decrypting image")} ); } @@ -238,13 +239,13 @@ module.exports = React.createClass({ } else if (content.body) { return ( - Image '{content.body}' cannot be displayed. + {_t("Image '%(Body)s' cannot be displayed.", {Body: content.body})} ); } else { return ( - This image cannot be displayed. + {_t("This image cannot be displayed.")} ); } diff --git a/src/components/views/messages/MVideoBody.js b/src/components/views/messages/MVideoBody.js index d843115caf..8caf9d8f96 100644 --- a/src/components/views/messages/MVideoBody.js +++ b/src/components/views/messages/MVideoBody.js @@ -24,6 +24,7 @@ import sdk from '../../../index'; import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile'; import q from 'q'; import UserSettingsStore from '../../../UserSettingsStore'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'MVideoBody', @@ -128,7 +129,7 @@ module.exports = React.createClass({ return ( - Error decrypting video + {_t("Error decrypting video")} ); } diff --git a/src/components/views/messages/TextualBody.js b/src/components/views/messages/TextualBody.js index 3df09fc444..83a35b9841 100644 --- a/src/components/views/messages/TextualBody.js +++ b/src/components/views/messages/TextualBody.js @@ -28,6 +28,7 @@ import ScalarAuthClient from '../../../ScalarAuthClient'; import Modal from '../../../Modal'; import SdkConfig from '../../../SdkConfig'; import dis from '../../../dispatcher'; +import { _t } from '../../../languageHandler'; linkifyMatrix(linkify); @@ -230,14 +231,14 @@ module.exports = React.createClass({ let QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); let integrationsUrl = SdkConfig.get().integrations_ui_url; Modal.createDialog(QuestionDialog, { - title: "Add an Integration", + title: _t("Add an Integration"), description:
    - You are about to be taken to a third-party site so you can - authenticate your account for use with {integrationsUrl}.
    - Do you wish to continue? + {_t("You are about to be taken to a third-party site so you can " + + "authenticate your account for use with {integrationsUrl}. " + + "Do you wish to continue?")}
    , - button: "Continue", + button: _t("Continue"), onFinished: function(confirmed) { if (!confirmed) { return; diff --git a/src/components/views/messages/UnknownBody.js b/src/components/views/messages/UnknownBody.js index 0efdbaf257..1b6f6426e5 100644 --- a/src/components/views/messages/UnknownBody.js +++ b/src/components/views/messages/UnknownBody.js @@ -16,7 +16,8 @@ limitations under the License. 'use strict'; -var React = require('react'); +import React from 'react'; +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ displayName: 'UnknownBody', @@ -24,7 +25,7 @@ module.exports = React.createClass({ render: function() { const text = this.props.mxEvent.getContent().body; return ( - + {text} ); diff --git a/src/components/views/room_settings/UrlPreviewSettings.js b/src/components/views/room_settings/UrlPreviewSettings.js index 1e9690f258..d221cd4fd8 100644 --- a/src/components/views/room_settings/UrlPreviewSettings.js +++ b/src/components/views/room_settings/UrlPreviewSettings.js @@ -20,6 +20,7 @@ var MatrixClientPeg = require('../../../MatrixClientPeg'); var sdk = require("../../../index"); var Modal = require("../../../Modal"); var UserSettingsStore = require('../../../UserSettingsStore'); +import { _t } from '../../../languageHandler'; module.exports = React.createClass({ @@ -120,19 +121,19 @@ module.exports = React.createClass({ - Disable URL previews by default for participants in this room + {_t("Disable URL previews by default for participants in this room")} ; } else { disableRoomPreviewUrls = ; } return (
    -

    URL Previews

    +

    {_t("URL Previews")}

    ); diff --git a/src/components/views/rooms/AuxPanel.js b/src/components/views/rooms/AuxPanel.js index 365cc18f99..f53512e684 100644 --- a/src/components/views/rooms/AuxPanel.js +++ b/src/components/views/rooms/AuxPanel.js @@ -14,11 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -var React = require('react'); -var MatrixClientPeg = require("../../../MatrixClientPeg"); -var sdk = require('../../../index'); -var dis = require("../../../dispatcher"); -var ObjectUtils = require('../../../ObjectUtils'); +import React from 'react'; +import MatrixClientPeg from "../../../MatrixClientPeg"; +import sdk from '../../../index'; +import dis from "../../../dispatcher"; +import ObjectUtils from '../../../ObjectUtils'; +import { _t } from '../../../languageHandler'; + module.exports = React.createClass({ displayName: 'AuxPanel', @@ -79,7 +81,7 @@ module.exports = React.createClass({ title="Drop File Here">
    - Drop file here to upload + {_t("Drop file here to upload")}
    ); @@ -89,7 +91,7 @@ module.exports = React.createClass({ if (this.props.displayConfCallNotification) { var supportedText, joinText; if (!MatrixClientPeg.get().supportsVoip()) { - supportedText = " (unsupported)"; + supportedText = _t(" (unsupported)"); } else { joinText = ( @@ -101,7 +103,7 @@ module.exports = React.createClass({ } conferenceCallNotification = (
    - Ongoing conference call{ supportedText }. { joinText } + {_t("Ongoing conference call%(supportedText)s. %(joinText)s", {supportedText: supportedText, joinText: joinText})}
    ); } diff --git a/src/components/views/rooms/MessageComposer.js b/src/components/views/rooms/MessageComposer.js index 99b16413b5..4b812263ce 100644 --- a/src/components/views/rooms/MessageComposer.js +++ b/src/components/views/rooms/MessageComposer.js @@ -121,7 +121,7 @@ export default class MessageComposer extends React.Component { title: _t('Upload Files'), description: (
    -

    { _t('Are you sure you want upload the following files?') }

    +

    { _t('Are you sure you want to upload the following files?') }

      {fileList}
    diff --git a/src/components/views/rooms/PresenceLabel.js b/src/components/views/rooms/PresenceLabel.js index 52d831fcf6..d06b46641c 100644 --- a/src/components/views/rooms/PresenceLabel.js +++ b/src/components/views/rooms/PresenceLabel.js @@ -16,10 +16,12 @@ limitations under the License. 'use strict'; -var React = require('react'); +import React from 'react'; + +import MatrixClientPeg from '../../../MatrixClientPeg'; +import sdk from '../../../index'; +import { _t } from '../../../languageHandler'; -var MatrixClientPeg = require('../../../MatrixClientPeg'); -var sdk = require('../../../index'); module.exports = React.createClass({ displayName: 'PresenceLabel', @@ -67,9 +69,9 @@ module.exports = React.createClass({ }, getPrettyPresence: function(presence) { - if (presence === "online") return "Online"; - if (presence === "unavailable") return "Idle"; // XXX: is this actually right? - if (presence === "offline") return "Offline"; + if (presence === "online") return _t("Online"); + if (presence === "unavailable") return _t("Idle"); // XXX: is this actually right? + if (presence === "offline") return _t("Offline"); return "Unknown"; }, diff --git a/src/i18n/strings/da.json b/src/i18n/strings/da.json index 60904eb4af..92665ac8d0 100644 --- a/src/i18n/strings/da.json +++ b/src/i18n/strings/da.json @@ -69,7 +69,7 @@ "Anyone who knows the room's link, including guests": "Alle der kender link til rummet, inklusiv gæster", "Are you sure you want to leave the room?": "Er du sikker på du vil forlade rummet?", "Are you sure you want to reject the invitation?": "Er du sikker på du vil afvise invitationen?", - "Are you sure you want upload the following files?": "Er du sikker på du vil sende de følgende filer?", + "Are you sure you want to upload the following files?": "Er du sikker på du vil sende de følgende filer?", "banned": "bortvist", "Banned users": "Bortviste brugere", "Bug Report": "Fejlrapport", diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json index 7d45dfadb5..f87efee01a 100644 --- a/src/i18n/strings/de_DE.json +++ b/src/i18n/strings/de_DE.json @@ -64,7 +64,7 @@ "Anyone who knows the room's link, including guests": "Jeder der den Raum-Link kennt - auch Gäste", "Are you sure you want to leave the room?": "Bist du sicher, dass du den Raum verlassen willst?", "Are you sure you want to reject the invitation?": "Bist du sicher, dass die die Einladung ablehnen willst?", - "Are you sure you want upload the following files?": "Bist du sicher, dass du die folgenden Dateien hochladen willst?", + "Are you sure you want to upload the following files?": "Bist du sicher, dass du die folgenden Dateien hochladen willst?", "banned": "gebannt", "Banned users": "Gebannte Nutzer", "Bug Report": "Fehlerbericht", diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 527219b4a6..114231e46b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -155,7 +155,7 @@ "Anyone who knows the room's link, including guests": "Anyone who knows the room's link, including guests", "Are you sure?": "Are you sure?", "Are you sure you want to reject the invitation?": "Are you sure you want to reject the invitation?", - "Are you sure you want upload the following files?": "Are you sure you want upload the following files?", + "Are you sure you want to upload the following files?": "Are you sure you want to upload the following files?", "Attachment": "Attachment", "Autoplay GIFs and videos": "Autoplay GIFs and videos", "%(senderName)s banned %(targetName)s.": "%(senderName)s banned %(targetName)s.", @@ -674,5 +674,90 @@ "%(oneUser)schanged their avatar %(repeats)s times": "%(oneUser)schanged their avatar %(repeats)s times", "%(severalUsers)schanged their avatar": "%(severalUsers)schanged their avatar", "%(oneUser)schanged their avatar": "%(oneUser)schanged their avatar", - "Please select the destination room for this message": "Please select the destination room for this message" + "Please select the destination room for this message": "Please select the destination room for this message", + "Passphrases must match": "Passphrases must match", + "Passphrase must not be empty": "Passphrase must not be empty", + "Export room keys": "Export room keys", + "Enter passphrase": "Enter passphrase", + "Confirm passphrase": "Confirm passphrase", + "Import room keys": "Import room keys", + "File to import": "File to import", + "Enter passphrase": "Enter passphrase", + "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.": "This process allows you to export the keys for messages you have received in encrypted rooms to a local file. You will then be able to import the file into another Matrix client in the future, so that client will also be able to decrypt these messages.", + "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.": "The exported file will allow anyone who can read it to decrypt any encrypted messages that you can see, so you should be careful to keep it secure. To help with this, you should enter a passphrase below, which will be used to encrypt the exported data. It will only be possible to import the data by using the same passphrase.", + "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.": "This process allows you to import encryption keys that you had previously exported from another Matrix client. You will then be able to decrypt any messages that the other client could decrypt.", + "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.": "The export file will be protected with a passphrase. You should enter the passphrase here, to decrypt the file.", "You must join the room to see its files": "You must join the room to see its files", "Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.", + "Reject all %(invitedRooms)s invites": "Reject all %(invitedRooms)s invites", + "Start new Chat": "Start new Chat", + "Guest users can't invite users. Please register.": "Guest users can't invite users. Please register.", + "Failed to invite": "Failed to invite", + "Failed to invite user": "Failed to invite user", + "Failed to invite the following users to the %(roomName)s room:": "Failed to invite the following users to the %(roomName)s room:", + "Confirm Removal": "Confirm Removal", + "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.", + "Unknown error": "Unknown error", + "Incorrect password": "Incorrect password", + "This will make your account permanently unusable. You will not be able to re-register the same user ID.": "This will make your account permanently unusable. You will not be able to re-register the same user ID.", + "This action is irreversible.": "This action is irreversible.", + "To continue, please enter your password.": "To continue, please enter your password.", + "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:": "To verify that this device can be trusted, please contact its owner using some other means (e.g. in person or a phone call) and ask them whether the key they see in their User Settings for this device matches the key below:", + "Device name": "Device name", + "Device key": "Device key", + "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.": "If it matches, press the verify button below. If it doesn't, then someone else is intercepting this device and you probably want to press the blacklist button instead.", + "In future this verification process will be more sophisticated.": "In future this verification process will be more sophisticated.", + "Verify device": "Verify device", + "I verify that the keys match": "I verify that the keys match", + "We encountered an error trying to restore your previous session. If you continue, you will need to log in again, and encrypted chat history will be unreadable.": "We encountered an error trying to restore your previous session. If you continue, you will need to log in again, and encrypted chat history will be unreadable.", + "Unable to restore session": "Unable to restore session", + "If you have previously used a more recent version of Riot, your session may be incompatible with this version. Close this window and return to the more recent version.": "If you have previously used a more recent version of Riot, your session may be incompatible with this version. Close this window and return to the more recent version.", + "Continue anyway": "Continue anyway", + "Your display name is how you'll appear to others when you speak in rooms. What would you like it to be?": "Your display name is how you'll appear to others when you speak in rooms. What would you like it to be?", + "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.": "You are currently blacklisting unverified devices; to send messages to these devices you must verify them.", + "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.": "We recommend you go through the verification process for each device to confirm they belong to their legitimate owner, but you can resend the message without verifying if you prefer.", + "\"%(RoomName)s\" contains devices that you haven't seen before.": "\"%(RoomName)s\" contains devices that you haven't seen before.", + "Unknown devices": "Unknown devices", + "Unknown Address": "Unknown Address", + "Unblacklist": "Unblacklist", + "Blacklist": "Blacklist", + "Unverify": "Unverify", + "Verify...": "Verify...", + "ex. @bob:example.com": "ex. @bob:example.com", + "Add User": "Add User", + "This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot", + "Sign in with CAS": "Sign in with CAS", + "Custom Server Options": "Custom Server Options", + "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.": "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.", + "This allows you to use this app with an existing Matrix account on a different home server.": "This allows you to use this app with an existing Matrix account on a different home server.", + "You can also set a custom identity server but this will typically prevent interaction with users based on email address.": "You can also set a custom identity server but this will typically prevent interaction with users based on email address.", + "Dismiss": "Dismiss", + "Please check your email to continue registration.": "Please check your email to continue registration.", + "Token incorrect": "Token incorrect", + "A text message has been sent to": "A text message has been sent to", + "Please enter the code it contains:": "Please enter the code it contains:", + "powered by Matrix": "powered by Matrix", + "If you don't specify an email address, you won't be able to reset your password. Are you sure?": "If you don't specify an email address, you won't be able to reset your password. Are you sure?", + "You are registering with %(SelectedTeamName)s": "You are registering with %(SelectedTeamName)s", + "Default server": "Default server", + "Custom server": "Custom server", + "Home server URL": "Home server URL", + "Identity server URL": "Identity server URL", + "What does this mean?": "What does this mean?", + "Error decrypting audio": "Error decrypting audio", + "Error decrypting image": "Error decrypting image", + "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", + "This image cannot be displayed.": "This image cannot be displayed.", + "Error decrypting video": "Error decrypting video", + "Add an Integration": "Add an Integration", + "You are about to be taken to a third-party site so you can authenticate your account for use with {integrationsUrl}. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with {integrationsUrl}. Do you wish to continue?", + "Removed or unknown message type": "Removed or unknown message type", + "Disable URL previews by default for participants in this room": "Disable URL previews by default for participants in this room", + "URL previews are %(globalDisableUrlPreview)s by default for participants in this room.": "URL previews are %(globalDisableUrlPreview)s by default for participants in this room.", + "URL Previews": "URL Previews", + "Enable URL previews for this room (affects only you)": "Enable URL previews for this room (affects only you)", + "Drop file here to upload": "Drop file here to upload", + " (unsupported)": " (unsupported)", + "Ongoing conference call%(supportedText)s. %(joinText)s": "Ongoing conference call%(supportedText)s. %(joinText)s", + "Online": "Online", + "Idle": "Idle", + "Offline": "Offline" } diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json index 673ff8ad1a..b7befdb555 100644 --- a/src/i18n/strings/fr.json +++ b/src/i18n/strings/fr.json @@ -199,7 +199,7 @@ "Anyone who knows the room's link, including guests": "Tout ceux qui connaissent le lien du salon, y compris les visiteurs", "Are you sure?": "Êtes-vous sûr ?", "Are you sure you want to reject the invitation?": "Êtes-vous sûr de vouloir rejeter l'invitation ?", - "Are you sure you want upload the following files?": "Êtes-vous sûr de vouloir télécharger les fichiers suivants ?", + "Are you sure you want to upload the following files?": "Êtes-vous sûr de vouloir télécharger les fichiers suivants ?", "Attachment": "Pièce jointe", "Autoplay GIFs and videos": "Jouer automatiquement les GIFs et vidéos", "%(senderName)s banned %(targetName)s.": "%(senderName)s a banni %(targetName)s.", diff --git a/src/i18n/strings/pt.json b/src/i18n/strings/pt.json index 4b309e6fd9..f57ee4109a 100644 --- a/src/i18n/strings/pt.json +++ b/src/i18n/strings/pt.json @@ -20,7 +20,7 @@ "Anyone who knows the room's link, including guests": "Qualquer pessoa que tenha o link da sala, incluindo visitantes", "Are you sure you want to leave the room?": "Você tem certeza que deseja sair da sala?", "Are you sure you want to reject the invitation?": "Você tem certeza que deseja rejeitar este convite?", - "Are you sure you want upload the following files?": "Você tem certeza que deseja enviar os seguintes arquivos?", + "Are you sure you want to upload the following files?": "Você tem certeza que deseja enviar os seguintes arquivos?", "banned": "baniu", "Banned users": "Usuárias/os banidas/os", "Bans user with given id": "Banir usuários com o identificador informado", diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json index 9a6060d9f6..45da093131 100644 --- a/src/i18n/strings/pt_BR.json +++ b/src/i18n/strings/pt_BR.json @@ -21,7 +21,7 @@ "Anyone who knows the room's link, including guests": "Qualquer pessoa que tenha o link da sala, incluindo visitantes", "Are you sure you want to leave the room?": "Você tem certeza que deseja sair da sala?", "Are you sure you want to reject the invitation?": "Você tem certeza que deseja rejeitar este convite?", - "Are you sure you want upload the following files?": "Você tem certeza que deseja enviar os seguintes arquivos?", + "Are you sure you want to upload the following files?": "Você tem certeza que deseja enviar os seguintes arquivos?", "banned": "baniu", "Banned users": "Usuárias/os banidas/os", "Bans user with given id": "Banir usuários com o identificador informado", diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json index 0902edb41a..9ed540a198 100644 --- a/src/i18n/strings/ru.json +++ b/src/i18n/strings/ru.json @@ -20,7 +20,7 @@ "Anyone who knows the room's link, apart from guests": "Любой, кто знает ссылку на комнату, кроме гостей", "Anyone who knows the room's link, including guests": "Любой, кто знает ссылку комнаты, включая гостей", "Are you sure you want to reject the invitation?": "Вы уверены что вы хотите отклонить приглашение?", - "Are you sure you want upload the following files?": "Вы уверены что вы хотите закачать следующий файл?", + "Are you sure you want to upload the following files?": "Вы уверены что вы хотите закачать следующий файл?", "banned": "banned", "Banned users": "Запрещенный пользователь", "Bans user with given id": "Запретить пользователя с определенным id", diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json index b6295de844..d719b56ecc 100644 --- a/src/i18n/strings/zh_Hant.json +++ b/src/i18n/strings/zh_Hant.json @@ -7,7 +7,7 @@ "Anyone who knows the room's link, including guests": "任何知道房間連結的人,包括訪客", "Are you sure?": "您確認嗎?", "Are you sure you want to reject the invitation?": "您確認要謝絕邀請嗎?", - "Are you sure you want upload the following files?": "您確認要上傳以下文件嗎?", + "Are you sure you want to upload the following files?": "您確認要上傳以下文件嗎?", "Attachment": "附件", "Autoplay GIFs and videos": "自動播放GIF和影片", "%(senderName)s banned %(targetName)s.": "%(senderName)s 封禁了 %(targetName)s。",