This commit is contained in:
David Baker 2017-05-23 14:12:53 +01:00
parent 7d59742a22
commit 6b6fa59f3e
36 changed files with 7547 additions and 186 deletions

View file

@ -4,6 +4,8 @@ Riot
Riot (formerly known as Vector) is a Matrix web client built using the Matrix Riot (formerly known as Vector) is a Matrix web client built using the Matrix
React SDK (https://github.com/matrix-org/matrix-react-sdk). React SDK (https://github.com/matrix-org/matrix-react-sdk).
[<img src="https://translate.nordgedanken.de/widgets/riot-web/-/multi-auto.svg" alt="Translationsstatus" width="340">](https://translate.nordgedanken.de/engage/riot-web/?utm_source=widget)
Getting Started Getting Started
=============== ===============
@ -281,6 +283,16 @@ If any of these steps error with, `file table overflow`, you are probably on a m
which has a very low limit on max open files. Run `ulimit -Sn 1024` and try again. which has a very low limit on max open files. Run `ulimit -Sn 1024` and try again.
You'll need to do this in each new terminal you open before building Riot. You'll need to do this in each new terminal you open before building Riot.
How to add a new translation?
=============================
Head to the [translating doc](docs/translating.md)
Adding Strings to the translations (Developer Guide)
====================================================
Head to the [translating dev doc](docs/translating-dev.md)
Triaging issues Triaging issues
=============== ===============

View file

@ -10,5 +10,6 @@
"servers": [ "servers": [
"matrix.org" "matrix.org"
] ]
} },
"languages": ["en", "de", "pt-br", "ru", "da"]
} }

26
docs/translating-dev.md Normal file
View file

@ -0,0 +1,26 @@
# How to translate riot-web (Dev Guide)
## Requirements
- A working [Development Setup](../../#setting-up-a-dev-environment)
- Be able to understand English
- Be able to understand the language you want to translate riot-web into
## Adding new strings
1. Check if the import ``import _t from 'counterpart-riot'`` is present. If not add it to the other import statements.
2. Add ``_t()`` to your string. (Don't forget curly braces when you assign an expression to JSX attributes in the render method)
3. Add the String to the ``en_EN.json`` file in ``src/i18n`` or if you are working in matrix-react-sdk you can find the json file in ``src/i18n/strings``
## Adding variables inside a string.
1. Extend your ``_t()`` call. Instead of ``_t(STRING)`` use ``_t(STRING, {})``
2. Decide how to name it. Please think about if the person who has to translate it can understand what it does.
3. Add it to the array in ``_t`` for example ``_t(STRING, {variable: this.variable})``
4. Add the variable inside the string. The syntax for variables is ``%(variable)s``. Please note the s at the end. The name of the variable has to match the previous used name.
## Things to know/Style Guides
- Do not use it inside ``getDefaultProps`` at the point where ``getDefaultProps`` is initialized the translations aren't loaded yet and it causes missing translations.
- Do use ``Array.push()`` instead of directly defining it inside the array. Arrays are not able to access ``_t()`` at runtime.
- Do not include full stops, Emoji or similiar miscellaneous Things to the strings. They are not required to be translated.

57
docs/translating.md Normal file
View file

@ -0,0 +1,57 @@
# How to translate riot-web
## Requirements
- Web Browser
- Be able to understand English
- Be able to understand the language you want to translate riot-web into
## Step 1: Preparing your Weblate Profile
1. Head to https://translate.nordgedanken.de and register either via Github or email
2. After register check if you got a email to verify your account and click the link (if there is none head to step 1.4)
3. Log into weblate
4. Head to https://translate.nordgedanken.de/accounts/profile/ and select the languages you know and maybe another language you know too.
6. Head to https://translate.nordgedanken.de/accounts/profile/#subscriptions and select Riot Web as Project
## How to check if your language already is being translated
Go to https://translate.nordgedanken.de/projects/riot-web/ and in all 3 sub projects if your language is listed.
If it is listed go to Step 2a if not go to Step 2b
## Step 2a: Helping on existing languages.
1. Head to one of the projects listed https://translate.nordgedanken.de/projects/riot-web/
2. Click on the ``translate`` button on the right side of your language
3. Fill in the translations in the writeable field. You will see the original English string and the String of your second language above.
Head to the explanations under Steb 2b
## Step 2b: Adding a new language
1. Go to one of the projects listed https://translate.nordgedanken.de/projects/riot-web/
2. Click the ``Start new language`` button at the bottom
3. Select our language
4. Start translating like in 2a.3
5. Repeat these steps for the other projects which are listed at the link of step 2b.1
6. Add your language to the array at the [config example](../../blob/develop/config.sample.json#L14)
### What means the green button under the text field?
The green button let you save our translations directly. Please only use it if you are 100% sure about that translation. If you do not know a translation please DO NOT click that button. Use the arrows above the translations field and click to the right.
### What means the yellow button under the text field?
The yellow button has to be used if you are unsure about the translation but you have a rough idea. It ads a new suggestion to the string which can than be reviewed by others.
### What are "%(something)s"?
These things are variables that are filled inside the code. They can be room names, usernames or similiar. If you find one use it for changing the word order but do not delete it as thing are missing if you do so.
### "I want to come back to this string. How?"
You can use inside the translation field "Review needed" checkbox. It will be shown as Strings that need to be reviewed.
### Further reading
The official Doc provides some more in-deepth explanation on how to do translations and talks about do and don't's. You can find it at: https://docs.weblate.org/en/latest/user/translating.html

View file

@ -56,6 +56,7 @@
"babel-runtime": "^6.11.6", "babel-runtime": "^6.11.6",
"browser-request": "^0.3.3", "browser-request": "^0.3.3",
"classnames": "^2.1.2", "classnames": "^2.1.2",
"counterpart-riot": "^0.17.9",
"draft-js": "^0.8.1", "draft-js": "^0.8.1",
"extract-text-webpack-plugin": "^0.9.1", "extract-text-webpack-plugin": "^0.9.1",
"favico.js": "^0.3.10", "favico.js": "^0.3.10",

View file

@ -13,12 +13,32 @@ const COPY_LIST = [
["src/skins/vector/{fonts,img}/**", "webapp"], ["src/skins/vector/{fonts,img}/**", "webapp"],
["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"], ["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
["node_modules/emojione/assets/png/*", "webapp/emojione/png/"], ["node_modules/emojione/assets/png/*", "webapp/emojione/png/"],
["./config.json", "webapp", {directwatch: 1}], ["./config.json", "webapp", { directwatch: 1 }],
["src/i18n/", "webapp/i18n/", { languages: 1 }],
["node_modules/matrix-react-sdk/src/i18n/strings/", "webapp/i18n/", { languages: 1 }],
]; ];
const parseArgs = require('minimist'); const parseArgs = require('minimist');
const Cpx = require('cpx'); const Cpx = require('cpx');
const chokidar = require('chokidar'); const chokidar = require('chokidar');
const fs = require('fs');
const rimraf = require('rimraf');
// cleanup language files before copying them.
//rimraf("webapp/", function () { console.log('cleanup language files'); });
//From http://stackoverflow.com/a/20525865/4929236
function generateFileArray(dir, files_) {
files_ = files_ || [];
var files = fs.readdirSync(dir);
for (var i in files) {
var name = files[i];
if (name != 'basefile.json') {
files_.push(name);
}
}
return files_;
}
const argv = parseArgs( const argv = parseArgs(
process.argv.slice(2), {} process.argv.slice(2), {}
@ -45,8 +65,32 @@ function next(i, err) {
const source = ent[0]; const source = ent[0];
const dest = ent[1]; const dest = ent[1];
const opts = ent[2] || {}; const opts = ent[2] || {};
let cpx = undefined;
const cpx = new Cpx.Cpx(source, dest); if (opts.languages) {
const sourceFiles = generateFileArray(source);
let Sourcelanguages = {};
if (!fs.existsSync(dest)) {
fs.mkdirSync(dest);
}
sourceFiles.forEach(file => {
const fileContents = fs.readFileSync(source + file).toString();
Sourcelanguages[file] = JSON.parse(fileContents);
});
sourceFiles.forEach(file => {
if (!fs.existsSync(dest + file)) {
let o = Object.assign({}, Sourcelanguages[file]);
fs.writeFileSync(dest + file, JSON.stringify(o, null, 4));
} else {
const fileContents = fs.readFileSync(dest + file).toString();
let o = Object.assign(JSON.parse(fileContents), Sourcelanguages[file]);
fs.writeFileSync(dest + file, JSON.stringify(o, null, 4));
}
});
} else {
cpx = new Cpx.Cpx(source, dest);
}
if (verbose) { if (verbose) {
cpx.on("copy", (event) => { cpx.on("copy", (event) => {
@ -57,7 +101,7 @@ function next(i, err) {
}); });
} }
const cb = (err) => {next(i+1, err)}; const cb = (err) => { next(i + 1, err) };
if (watch) { if (watch) {
if (opts.directwatch) { if (opts.directwatch) {
@ -65,20 +109,65 @@ function next(i, err) {
// which in the case of config.json is '.', which inevitably takes // which in the case of config.json is '.', which inevitably takes
// ages to crawl. So we create our own watcher on the files // ages to crawl. So we create our own watcher on the files
// instead. // instead.
const copy = () => {cpx.copy(errCheck)}; const copy = () => { cpx.copy(errCheck) };
chokidar.watch(source) chokidar.watch(source)
.on('add', copy) .on('add', copy)
.on('change', copy) .on('change', copy)
.on('ready', cb) .on('ready', cb)
.on('error', errCheck); .on('error', errCheck);
} else if (opts.languages) {
if (verbose) {
console.log('don\'t copy language file');
}
next(i + 1, err);
} else { } else {
cpx.on('watch-ready', cb); cpx.on('watch-ready', cb);
cpx.on("watch-error", cb); cpx.on("watch-error", cb);
cpx.watch(); cpx.watch();
} }
} else if (opts.languages) {
if (verbose) {
console.log('don\'t copy language file');
}
next(i + 1, err);
} else { } else {
cpx.copy(cb); cpx.copy(cb);
} }
} }
// Generate Language List
const testFolder = 'src/i18n/';
let languages = {};
// Check if webapp exists
if (!fs.existsSync('webapp')) {
fs.mkdirSync('webapp');
}
// Check if i18n exists
if (!fs.existsSync('webapp/i18n/')) {
fs.mkdirSync('webapp/i18n/');
}
if (!fs.existsSync('webapp/i18n/languages.json')) {
rimraf("webapp/i18n/languages.json", function() { console.log('cleanup languages.json file'); });
}
fs.readdir(testFolder, function(err, files) {
if (err) {
throw err;
}
files.forEach(function(file) {
var normalizedLanguage = file.toLowerCase().replace("_", "-").split('.json')[0];
var languageParts = normalizedLanguage.split('-');
if (file != 'basefile.json') {
if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
languages[languageParts[0]] = file;
} else {
languages[normalizedLanguage] = file;
}
}
});
fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4));
})
next(0); next(0);

View file

@ -18,7 +18,8 @@ limitations under the License.
var React = require('react'); var React = require('react');
var ReactDOM = require('react-dom'); var ReactDOM = require('react-dom');
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk');
import _t from 'counterpart-riot';
var dis = require('matrix-react-sdk/lib/dispatcher'); var dis = require('matrix-react-sdk/lib/dispatcher');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
@ -120,7 +121,7 @@ module.exports = React.createClass({
homeButton = ( homeButton = (
<AccessibleButton className="mx_BottomLeftMenu_homePage" onClick={ this.onHomeClick } onMouseEnter={ this.onHomeMouseEnter } onMouseLeave={ this.onHomeMouseLeave } > <AccessibleButton className="mx_BottomLeftMenu_homePage" onClick={ this.onHomeClick } onMouseEnter={ this.onHomeMouseEnter } onMouseLeave={ this.onHomeMouseLeave } >
<TintableSvg src="img/icons-home.svg" width="25" height="25" /> <TintableSvg src="img/icons-home.svg" width="25" height="25" />
{ this.getLabel("Welcome page", this.state.homeHover) } { this.getLabel(_t("Welcome page"), this.state.homeHover) }
</AccessibleButton> </AccessibleButton>
); );
} }
@ -131,19 +132,19 @@ module.exports = React.createClass({
{ homeButton } { homeButton }
<AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } > <AccessibleButton className="mx_BottomLeftMenu_people" onClick={ this.onPeopleClick } onMouseEnter={ this.onPeopleMouseEnter } onMouseLeave={ this.onPeopleMouseLeave } >
<TintableSvg src="img/icons-people.svg" width="25" height="25" /> <TintableSvg src="img/icons-people.svg" width="25" height="25" />
{ this.getLabel("Start chat", this.state.peopleHover) } { this.getLabel(_t("Start chat"), this.state.peopleHover) }
</AccessibleButton> </AccessibleButton>
<AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } > <AccessibleButton className="mx_BottomLeftMenu_directory" onClick={ this.onDirectoryClick } onMouseEnter={ this.onDirectoryMouseEnter } onMouseLeave={ this.onDirectoryMouseLeave } >
<TintableSvg src="img/icons-directory.svg" width="25" height="25"/> <TintableSvg src="img/icons-directory.svg" width="25" height="25"/>
{ this.getLabel("Room directory", this.state.directoryHover) } { this.getLabel(_t("Room directory"), this.state.directoryHover) }
</AccessibleButton> </AccessibleButton>
<AccessibleButton className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } > <AccessibleButton className="mx_BottomLeftMenu_createRoom" onClick={ this.onRoomsClick } onMouseEnter={ this.onRoomsMouseEnter } onMouseLeave={ this.onRoomsMouseLeave } >
<TintableSvg src="img/icons-create-room.svg" width="25" height="25" /> <TintableSvg src="img/icons-create-room.svg" width="25" height="25" />
{ this.getLabel("Create new room", this.state.roomsHover) } { this.getLabel(_t("Create new room"), this.state.roomsHover) }
</AccessibleButton> </AccessibleButton>
<AccessibleButton className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } > <AccessibleButton className="mx_BottomLeftMenu_settings" onClick={ this.onSettingsClick } onMouseEnter={ this.onSettingsMouseEnter } onMouseLeave={ this.onSettingsMouseLeave } >
<TintableSvg src="img/icons-settings.svg" width="25" height="25" /> <TintableSvg src="img/icons-settings.svg" width="25" height="25" />
{ this.getLabel("Settings", this.state.settingsHover) } { this.getLabel(_t("Settings"), this.state.settingsHover) }
</AccessibleButton> </AccessibleButton>
</div> </div>
</div> </div>

View file

@ -16,14 +16,15 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); import React from 'react';
var sdk = require('matrix-react-sdk'); import _t from 'counterpart-riot';
var Matrix = require("matrix-js-sdk"); import sdk from 'matrix-react-sdk';
var dis = require('matrix-react-sdk/lib/dispatcher'); import Matrix from "matrix-js-sdk";
var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); import dis from 'matrix-react-sdk/lib/dispatcher';
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
var Modal = require('matrix-react-sdk/lib/Modal'); import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc';
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); import Modal from 'matrix-react-sdk/lib/Modal';
import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'RightPanel', displayName: 'RightPanel',
@ -34,7 +35,7 @@ module.exports = React.createClass({
collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel collapsed: React.PropTypes.bool, // currently unused property to request for a minimized view of the panel
}, },
Phase : { Phase: {
MemberList: 'MemberList', MemberList: 'MemberList',
FilePanel: 'FilePanel', FilePanel: 'FilePanel',
NotificationPanel: 'NotificationPanel', NotificationPanel: 'NotificationPanel',
@ -91,8 +92,8 @@ module.exports = React.createClass({
if (MatrixClientPeg.get().isGuest()) { if (MatrixClientPeg.get().isGuest()) {
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog"); var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, { Modal.createDialog(NeedToRegisterDialog, {
title: "Please Register", title: _t('Please Register'),
description: "Guest users can't invite users. Please register to invite." description: _t('Guest users can\'t invite users. Please register to invite') + '.'
}); });
return; return;
} }
@ -188,7 +189,7 @@ module.exports = React.createClass({
<div className="mx_RightPanel_icon" > <div className="mx_RightPanel_icon" >
<TintableSvg src="img/icon-invite-people.svg" width="35" height="35" /> <TintableSvg src="img/icon-invite-people.svg" width="35" height="35" />
</div> </div>
<div className="mx_RightPanel_message">Invite to this room</div> <div className="mx_RightPanel_message">{ _t('Invite to this room') }</div>
</AccessibleButton>; </AccessibleButton>;
} }
@ -197,30 +198,30 @@ module.exports = React.createClass({
if (this.props.roomId) { if (this.props.roomId) {
buttonGroup = buttonGroup =
<div className="mx_RightPanel_headerButtonGroup"> <div className="mx_RightPanel_headerButtonGroup">
<AccessibleButton className="mx_RightPanel_headerButton" <AccessibleButton className="mx_RightPanel_headerButton"
title="Members" onClick={ this.onMemberListButtonClick }> title={ _t('Members') } onClick={ this.onMemberListButtonClick }>
<div className="mx_RightPanel_headerButton_badge">{ membersBadge ? membersBadge : <span>&nbsp;</span>}</div> <div className="mx_RightPanel_headerButton_badge">{ membersBadge ? membersBadge : <span>&nbsp;</span>}</div>
<TintableSvg src="img/icons-people.svg" width="25" height="25"/> <TintableSvg src="img/icons-people.svg" width="25" height="25"/>
{ membersHighlight } { membersHighlight }
</AccessibleButton> </AccessibleButton>
<AccessibleButton <AccessibleButton
className="mx_RightPanel_headerButton mx_RightPanel_filebutton" className="mx_RightPanel_headerButton mx_RightPanel_filebutton"
title="Files" onClick={ this.onFileListButtonClick }> title={ _t('Files') } onClick={ this.onFileListButtonClick }>
<div className="mx_RightPanel_headerButton_badge">&nbsp;</div> <div className="mx_RightPanel_headerButton_badge">&nbsp;</div>
<TintableSvg src="img/icons-files.svg" width="25" height="25"/> <TintableSvg src="img/icons-files.svg" width="25" height="25"/>
{ filesHighlight } { filesHighlight }
</AccessibleButton> </AccessibleButton>
<AccessibleButton <AccessibleButton
className="mx_RightPanel_headerButton mx_RightPanel_notificationbutton" className="mx_RightPanel_headerButton mx_RightPanel_notificationbutton"
title="Notifications" onClick={ this.onNotificationListButtonClick }> title={ _t('Notifications') } onClick={ this.onNotificationListButtonClick }>
<div className="mx_RightPanel_headerButton_badge">&nbsp;</div> <div className="mx_RightPanel_headerButton_badge">&nbsp;</div>
<TintableSvg src="img/icons-notifications.svg" width="25" height="25"/> <TintableSvg src="img/icons-notifications.svg" width="25" height="25"/>
{ notificationsHighlight } { notificationsHighlight }
</AccessibleButton> </AccessibleButton>
<div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" title="Hide panel" onClick={ this.onCollapseClick }> <div className="mx_RightPanel_headerButton mx_RightPanel_collapsebutton" title="Hide panel" onClick={ this.onCollapseClick }>
<TintableSvg src="img/minimise.svg" width="10" height="16"/> <TintableSvg src="img/minimise.svg" width="10" height="16"/>
</div> </div>
</div>; </div>;
} }
if (!this.props.collapsed) { if (!this.props.collapsed) {

View file

@ -30,6 +30,8 @@ var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix');
var sanitizeHtml = require('sanitize-html'); var sanitizeHtml = require('sanitize-html');
var q = require('q'); var q = require('q');
import _t from 'counterpart-riot';
import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils'; import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils';
linkifyMatrix(linkify); linkifyMatrix(linkify);
@ -80,8 +82,8 @@ module.exports = React.createClass({
} }
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to get protocol list from Home Server", title: _t('Failed to get protocol list from Home Server'),
description: "The Home Server may be too old to support third party networks", description: _t('The Home Server may be too old to support third party networks'),
}); });
}); });
@ -176,8 +178,8 @@ module.exports = React.createClass({
console.error("Failed to get publicRooms: %s", JSON.stringify(err)); console.error("Failed to get publicRooms: %s", JSON.stringify(err));
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to get public room list", title: _t('Failed to get public room list'),
description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"), description: ((err && err.message) ? err.message : _t('The server may be unavailable or overloaded'))
}); });
}); });
}, },
@ -191,31 +193,31 @@ module.exports = React.createClass({
*/ */
removeFromDirectory: function(room) { removeFromDirectory: function(room) {
var alias = get_display_alias_for_room(room); var alias = get_display_alias_for_room(room);
var name = room.name || alias || "Unnamed room"; var name = room.name || alias || _t('Unnamed room');
var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); var QuestionDialog = sdk.getComponent("dialogs.QuestionDialog");
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
var desc; var desc;
if (alias) { if (alias) {
desc = `Delete the room alias '${alias}' and remove '${name}' from the directory?`; desc = _t('Delete the room alias %(alias)s and remove %(name)s from the directory?', {alias: alias, name: name});
} else { } else {
desc = `Remove '${name}' from the directory?`; desc = _t('Remove %(name)s from the directory?', {name: name});
} }
Modal.createDialog(QuestionDialog, { Modal.createDialog(QuestionDialog, {
title: "Remove from Directory", title: _t('Remove from Directory'),
description: desc, description: desc,
onFinished: (should_delete) => { onFinished: (should_delete) => {
if (!should_delete) return; if (!should_delete) return;
var Loader = sdk.getComponent("elements.Spinner"); var Loader = sdk.getComponent("elements.Spinner");
var modal = Modal.createDialog(Loader); var modal = Modal.createDialog(Loader);
var step = `remove '${name}' from the directory.`; var step = _t('remove %(name)s from the directory', {name: name}) + '.';
MatrixClientPeg.get().setRoomDirectoryVisibility(room.room_id, 'private').then(() => { MatrixClientPeg.get().setRoomDirectoryVisibility(room.room_id, 'private').then(() => {
if (!alias) return; if (!alias) return;
step = 'delete the alias.'; step = _t('delete the alias') + '.';
return MatrixClientPeg.get().deleteAlias(alias); return MatrixClientPeg.get().deleteAlias(alias);
}).done(() => { }).done(() => {
modal.close(); modal.close();
@ -225,8 +227,8 @@ module.exports = React.createClass({
this.refreshRoomList(); this.refreshRoomList();
console.error("Failed to " + step + ": " + err); console.error("Failed to " + step + ": " + err);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to " + step, title: _t('Error'),
description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"), description: ((err && err.message) ? err.message : _t('The server may be unavailable or overloaded'))
}); });
}); });
} }
@ -314,8 +316,8 @@ module.exports = React.createClass({
if (!fields) { if (!fields) {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Unable to join network", title: _t('Unable to join network'),
description: "Riot does not know how to join a room on this network", description: _t('Riot does not know how to join a room on this network'),
}); });
return; return;
} }
@ -325,15 +327,15 @@ module.exports = React.createClass({
} else { } else {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Room not found", title: _t('Room not found'),
description: "Couldn't find a matching Matrix room", description: _t('Couldn\'t find a matching Matrix room'),
}); });
} }
}, (e) => { }, (e) => {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Fetching third party location failed", title: _t('Fetching third party location failed'),
description: "Unable to look up room ID from server", description: _t('Unable to look up room ID from server'),
}); });
}); });
} }
@ -353,8 +355,8 @@ module.exports = React.createClass({
if (!room.world_readable && !room.guest_can_join) { if (!room.world_readable && !room.guest_can_join) {
var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog"); var NeedToRegisterDialog = sdk.getComponent("dialogs.NeedToRegisterDialog");
Modal.createDialog(NeedToRegisterDialog, { Modal.createDialog(NeedToRegisterDialog, {
title: "Failed to join the room", title: _t('Failed to join the room'),
description: "This room is inaccessible to guests. You may be able to join if you register." description: _t('This room is inaccessible to guests. You may be able to join if you register') + '.'
}); });
return; return;
} }
@ -368,7 +370,7 @@ module.exports = React.createClass({
avatarUrl: room.avatar_url, avatarUrl: room.avatar_url,
// XXX: This logic is duplicated from the JS SDK which // XXX: This logic is duplicated from the JS SDK which
// would normally decide what the name is. // would normally decide what the name is.
name: room.name || room_alias || "Unnamed room", name: room.name || room_alias || _t('Unnamed room'),
}; };
} }
// It's not really possible to join Matrix rooms by ID because the HS has no way to know // It's not really possible to join Matrix rooms by ID because the HS has no way to know
@ -393,18 +395,18 @@ module.exports = React.createClass({
var self = this; var self = this;
var guestRead, guestJoin, perms; var guestRead, guestJoin, perms;
for (var i = 0; i < rooms.length; i++) { for (var i = 0; i < rooms.length; i++) {
var name = rooms[i].name || get_display_alias_for_room(rooms[i]) || "Unnamed room"; var name = rooms[i].name || get_display_alias_for_room(rooms[i]) || _t('Unnamed room');
guestRead = null; guestRead = null;
guestJoin = null; guestJoin = null;
if (rooms[i].world_readable) { if (rooms[i].world_readable) {
guestRead = ( guestRead = (
<div className="mx_RoomDirectory_perm">World readable</div> <div className="mx_RoomDirectory_perm">{ _t('World readable') }</div>
); );
} }
if (rooms[i].guest_can_join) { if (rooms[i].guest_can_join) {
guestJoin = ( guestJoin = (
<div className="mx_RoomDirectory_perm">Guests can join</div> <div className="mx_RoomDirectory_perm">{ _t('Guests can join') }</div>
); );
} }
@ -493,7 +495,7 @@ module.exports = React.createClass({
if (this.state.protocolsLoading) { if (this.state.protocolsLoading) {
return ( return (
<div className="mx_RoomDirectory"> <div className="mx_RoomDirectory">
<SimpleRoomHeader title="Directory" /> <SimpleRoomHeader title={ _t('Directory') } />
<Loader /> <Loader />
</div> </div>
); );
@ -511,7 +513,7 @@ module.exports = React.createClass({
// request from the scrollpanel because there isn't one // request from the scrollpanel because there isn't one
let scrollpanel_content; let scrollpanel_content;
if (rows.length == 0) { if (rows.length == 0) {
scrollpanel_content = <i>No rooms to show</i>; scrollpanel_content = <i>{ _t('No rooms to show') }</i>;
} else { } else {
scrollpanel_content = <table ref="directory_table" className="mx_RoomDirectory_table"> scrollpanel_content = <table ref="directory_table" className="mx_RoomDirectory_table">
<tbody> <tbody>
@ -545,9 +547,9 @@ module.exports = React.createClass({
} }
let placeholder = 'Search for a room'; let placeholder = _t('Search for a room');
if (!this.state.instanceId) { if (!this.state.instanceId) {
placeholder = '#example:' + this.state.roomServer; placeholder = _t('#example') + ':' + this.state.roomServer;
} else if (instance_expected_field_type) { } else if (instance_expected_field_type) {
placeholder = instance_expected_field_type.placeholder; placeholder = instance_expected_field_type.placeholder;
} }
@ -564,7 +566,7 @@ module.exports = React.createClass({
const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox'); const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox');
return ( return (
<div className="mx_RoomDirectory"> <div className="mx_RoomDirectory">
<SimpleRoomHeader title="Directory" icon="img/icons-directory.svg"/> <SimpleRoomHeader title={ _t('Directory') } icon="img/icons-directory.svg" />
<div className="mx_RoomDirectory_list"> <div className="mx_RoomDirectory_list">
<div className="mx_RoomDirectory_listheader"> <div className="mx_RoomDirectory_listheader">
<DirectorySearchBox <DirectorySearchBox

View file

@ -20,7 +20,8 @@ var React = require('react');
var ReactDOM = require('react-dom'); var ReactDOM = require('react-dom');
var classNames = require('classnames'); var classNames = require('classnames');
var DropTarget = require('react-dnd').DropTarget; var DropTarget = require('react-dnd').DropTarget;
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk');
import _t from 'counterpart-riot';
var dis = require('matrix-react-sdk/lib/dispatcher'); var dis = require('matrix-react-sdk/lib/dispatcher');
var Unread = require('matrix-react-sdk/lib/Unread'); var Unread = require('matrix-react-sdk/lib/Unread');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
@ -463,7 +464,7 @@ var RoomSubList = React.createClass({
return ( return (
<AccessibleButton className="mx_RoomSubList_ellipsis" onClick={this._showFullMemberList}> <AccessibleButton className="mx_RoomSubList_ellipsis" onClick={this._showFullMemberList}>
<div className="mx_RoomSubList_line"></div> <div className="mx_RoomSubList_line"></div>
<div className="mx_RoomSubList_more">more</div> <div className="mx_RoomSubList_more">{ _t("more") }</div>
<div className={ badgeClasses }>{ content }</div> <div className={ badgeClasses }>{ content }</div>
</AccessibleButton> </AccessibleButton>
); );
@ -509,8 +510,8 @@ var RoomSubList = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to add tag " + self.props.tagName + " to room" + err); console.error("Failed to add tag " + self.props.tagName + " to room" + err);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + self.props.tagName + " to room", title: _t('Failed to add tag %(tagName)s to room', {tagName: self.props.tagName}),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
break; break;
@ -530,7 +531,7 @@ var RoomSubList = React.createClass({
var target; var target;
if (this.state.sortedList.length == 0 && this.props.editable) { if (this.state.sortedList.length == 0 && this.props.editable) {
target = <RoomDropTarget label={ 'Drop here to ' + this.props.verb }/>; target = <RoomDropTarget label={ _t("Drop here %(toAction)s", {toAction: this.props.verb}) }/>;
} }
if (this.state.sortedList.length > 0 || this.props.editable) { if (this.state.sortedList.length > 0 || this.props.editable) {

View file

@ -17,6 +17,7 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
import _t from 'counterpart-riot';
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk')
var dis = require('matrix-react-sdk/lib/dispatcher'); var dis = require('matrix-react-sdk/lib/dispatcher');
var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc');
@ -134,7 +135,7 @@ module.exports = React.createClass({
className="mx_SearchBox_search" className="mx_SearchBox_search"
value={ this.state.searchTerm } value={ this.state.searchTerm }
onChange={ this.onChange } onChange={ this.onChange }
placeholder="Filter room names" placeholder={ _t('Filter room names') }
/> />
]; ];
} }

View file

@ -21,6 +21,7 @@ var React = require('react');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
var dis = require('matrix-react-sdk/lib/dispatcher'); var dis = require('matrix-react-sdk/lib/dispatcher');
var sdk = require('matrix-react-sdk'); var sdk = require('matrix-react-sdk');
import _t from 'counterpart-riot';
var Modal = require('matrix-react-sdk/lib/Modal'); var Modal = require('matrix-react-sdk/lib/Modal');
var Resend = require("matrix-react-sdk/lib/Resend"); var Resend = require("matrix-react-sdk/lib/Resend");
import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore'; import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore';
@ -74,8 +75,8 @@ module.exports = React.createClass({
// display error message stating you couldn't delete this. // display error message stating you couldn't delete this.
var code = e.errcode || e.statusCode; var code = e.errcode || e.statusCode;
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Error", title: _t('Error'),
description: "You cannot delete this message. (" + code + ")" description: _t('You cannot delete this message. (%(code)s)', {code: code})
}); });
}).done(); }).done();
}, },
@ -121,7 +122,7 @@ module.exports = React.createClass({
if (eventStatus === 'not_sent') { if (eventStatus === 'not_sent') {
resendButton = ( resendButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onResendClick}> <div className="mx_MessageContextMenu_field" onClick={this.onResendClick}>
Resend { _t('Resend') }
</div> </div>
); );
} }
@ -129,7 +130,7 @@ module.exports = React.createClass({
if (!eventStatus && !this.props.mxEvent.isRedacted()) { // sent and not redacted if (!eventStatus && !this.props.mxEvent.isRedacted()) { // sent and not redacted
redactButton = ( redactButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onRedactClick}> <div className="mx_MessageContextMenu_field" onClick={this.onRedactClick}>
Redact { _t('Redact') }
</div> </div>
); );
} }
@ -137,21 +138,21 @@ module.exports = React.createClass({
if (eventStatus === "queued" || eventStatus === "not_sent") { if (eventStatus === "queued" || eventStatus === "not_sent") {
cancelButton = ( cancelButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onCancelSendClick}> <div className="mx_MessageContextMenu_field" onClick={this.onCancelSendClick}>
Cancel Sending { _t('Cancel Sending') }
</div> </div>
); );
} }
viewSourceButton = ( viewSourceButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}> <div className="mx_MessageContextMenu_field" onClick={this.onViewSourceClick}>
View Source { _t('View Source') }
</div> </div>
); );
if (this.props.mxEvent.getType() !== this.props.mxEvent.getWireType()) { if (this.props.mxEvent.getType() !== this.props.mxEvent.getWireType()) {
viewClearSourceButton = ( viewClearSourceButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onViewClearSourceClick}> <div className="mx_MessageContextMenu_field" onClick={this.onViewClearSourceClick}>
View Decrypted Source { _t('View Decrypted Source') }
</div> </div>
); );
} }
@ -160,7 +161,7 @@ module.exports = React.createClass({
if (this.props.eventTileOps.isWidgetHidden()) { if (this.props.eventTileOps.isWidgetHidden()) {
unhidePreviewButton = ( unhidePreviewButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onUnhidePreviewClick}> <div className="mx_MessageContextMenu_field" onClick={this.onUnhidePreviewClick}>
Unhide Preview { _t('Unhide Preview') }
</div> </div>
) )
} }
@ -170,13 +171,13 @@ module.exports = React.createClass({
permalinkButton = ( permalinkButton = (
<div className="mx_MessageContextMenu_field"> <div className="mx_MessageContextMenu_field">
<a href={ "https://matrix.to/#/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() } <a href={ "https://matrix.to/#/" + this.props.mxEvent.getRoomId() +"/"+ this.props.mxEvent.getId() }
target="_blank" rel="noopener" onClick={ this.closeMenu }>Permalink</a> target="_blank" rel="noopener" onClick={ this.closeMenu }>{ _t('Permalink') }</a>
</div> </div>
); );
const quoteButton = ( const quoteButton = (
<div className="mx_MessageContextMenu_field" onClick={this.onQuoteClick}> <div className="mx_MessageContextMenu_field" onClick={this.onQuoteClick}>
Quote { _t('Quote') }
</div> </div>
); );
@ -185,7 +186,7 @@ module.exports = React.createClass({
externalURLButton = ( externalURLButton = (
<div className="mx_MessageContextMenu_field"> <div className="mx_MessageContextMenu_field">
<a href={ this.props.mxEvent.event.content.external_url } <a href={ this.props.mxEvent.event.content.external_url }
rel="noopener" target="_blank" onClick={ this.closeMenu }>Source URL</a> rel="noopener" target="_blank" onClick={ this.closeMenu }>{ _t('Source URL') }</a>
</div> </div>
); );
} }

View file

@ -21,6 +21,7 @@ import q from 'q';
import React from 'react'; import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import sdk from 'matrix-react-sdk'; import sdk from 'matrix-react-sdk';
import _t from 'counterpart-riot';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import dis from 'matrix-react-sdk/lib/dispatcher'; import dis from 'matrix-react-sdk/lib/dispatcher';
import DMRoomMap from 'matrix-react-sdk/lib/utils/DMRoomMap'; import DMRoomMap from 'matrix-react-sdk/lib/utils/DMRoomMap';
@ -70,8 +71,8 @@ module.exports = React.createClass({
}).fail(function(err) { }).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to remove tag " + tagNameOff + " from room", title: _t('Failed to remove tag %(tagName)s from room', {tagName: tagNameOff}),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
} }
@ -87,8 +88,8 @@ module.exports = React.createClass({
}).fail(function(err) { }).fail(function(err) {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + tagNameOn + " to room", title: _t('Failed to remove tag %(tagName)s from room', {tagName: tagNameOn}),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
} }
@ -148,8 +149,8 @@ module.exports = React.createClass({
}, (err) => { }, (err) => {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to set Direct Message status of room", title: _t('Failed to set Direct Message status of room'),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
}, },
@ -187,8 +188,8 @@ module.exports = React.createClass({
var errCode = err.errcode || "unknown error code"; var errCode = err.errcode || "unknown error code";
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: `Failed to forget room (${errCode})`, title: _t('Failed to forget room %(errCode)s', {errCode: errCode}),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
@ -274,22 +275,22 @@ module.exports = React.createClass({
<div className={ alertMeClasses } onClick={this._onClickAlertMe} > <div className={ alertMeClasses } onClick={this._onClickAlertMe} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" /> <img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" /> <img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off-copy.svg" width="16" height="12" />
All messages (loud) { _t('All messages (loud)') }
</div> </div>
<div className={ allNotifsClasses } onClick={this._onClickAllNotifs} > <div className={ allNotifsClasses } onClick={this._onClickAllNotifs} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" /> <img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off.svg" width="16" height="12" /> <img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-off.svg" width="16" height="12" />
All messages { _t('All messages') }
</div> </div>
<div className={ mentionsClasses } onClick={this._onClickMentions} > <div className={ mentionsClasses } onClick={this._onClickMentions} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" /> <img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-mentions.svg" width="16" height="12" /> <img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute-mentions.svg" width="16" height="12" />
Mentions only { _t('Mentions only') }
</div> </div>
<div className={ muteNotifsClasses } onClick={this._onClickMute} > <div className={ muteNotifsClasses } onClick={this._onClickMute} >
<img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" /> <img className="mx_RoomTileContextMenu_notif_activeIcon" src="img/notif-active.svg" width="12" height="12" />
<img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute.svg" width="16" height="12" /> <img className="mx_RoomTileContextMenu_notif_icon mx_filterFlipColor" src="img/icon-context-mute.svg" width="16" height="12" />
Mute { _t('Mute') }
</div> </div>
</div> </div>
); );
@ -306,16 +307,16 @@ module.exports = React.createClass({
switch (membership) { switch (membership) {
case "join": case "join":
leaveClickHandler = this._onClickLeave; leaveClickHandler = this._onClickLeave;
leaveText = "Leave"; leaveText = _t('Leave');
break; break;
case "leave": case "leave":
case "ban": case "ban":
leaveClickHandler = this._onClickForget; leaveClickHandler = this._onClickForget;
leaveText = "Forget"; leaveText = _t('Forget');
break; break;
case "invite": case "invite":
leaveClickHandler = this._onClickReject; leaveClickHandler = this._onClickReject;
leaveText = "Reject"; leaveText = _t('Reject');
break; break;
} }
@ -353,17 +354,17 @@ module.exports = React.createClass({
<div className={ favouriteClasses } onClick={this._onClickFavourite} > <div className={ favouriteClasses } onClick={this._onClickFavourite} >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_fave.svg" width="15" height="15" /> <img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_fave.svg" width="15" height="15" />
<img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_fave_on.svg" width="15" height="15" /> <img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_fave_on.svg" width="15" height="15" />
Favourite { _t('Favourite') }
</div> </div>
<div className={ lowPriorityClasses } onClick={this._onClickLowPriority} > <div className={ lowPriorityClasses } onClick={this._onClickLowPriority} >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_low.svg" width="15" height="15" /> <img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_low.svg" width="15" height="15" />
<img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_low_on.svg" width="15" height="15" /> <img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_low_on.svg" width="15" height="15" />
Low Priority { _t('Low Priority') }
</div> </div>
<div className={ dmClasses } onClick={this._onClickDM} > <div className={ dmClasses } onClick={this._onClickDM} >
<img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_person.svg" width="15" height="15" /> <img className="mx_RoomTileContextMenu_tag_icon" src="img/icon_context_person.svg" width="15" height="15" />
<img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_person_on.svg" width="15" height="15" /> <img className="mx_RoomTileContextMenu_tag_icon_set" src="img/icon_context_person_on.svg" width="15" height="15" />
Direct Chat { _t('Direct Chat') }
</div> </div>
</div> </div>
); );

View file

@ -25,6 +25,7 @@ var filesize = require('filesize');
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
const Modal = require('matrix-react-sdk/lib/Modal'); const Modal = require('matrix-react-sdk/lib/Modal');
const sdk = require('matrix-react-sdk'); const sdk = require('matrix-react-sdk');
import _t from 'counterpart-riot';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'ImageView', displayName: 'ImageView',
@ -76,8 +77,8 @@ module.exports = React.createClass({
// display error message stating you couldn't delete this. // display error message stating you couldn't delete this.
var code = e.errcode || e.statusCode; var code = e.errcode || e.statusCode;
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Error", title: _t('Error'),
description: "You cannot delete this image. (" + code + ")" description: _t('You cannot delete this image. (%(code)s)', {code: code})
}); });
}).done(); }).done();
} }
@ -150,14 +151,14 @@ module.exports = React.createClass({
var eventMeta; var eventMeta;
if(showEventMeta) { if(showEventMeta) {
eventMeta = (<div className="mx_ImageView_metadata"> eventMeta = (<div className="mx_ImageView_metadata">
Uploaded on { DateUtils.formatDate(new Date(this.props.mxEvent.getTs())) } by { this.props.mxEvent.getSender() } { _t('Uploaded on %(date)s by %(user)s', {date: DateUtils.formatDate(new Date(this.props.mxEvent.getTs())), user: this.props.mxEvent.getSender()}) }
</div>); </div>);
} }
var eventRedact; var eventRedact;
if(showEventMeta) { if(showEventMeta) {
eventRedact = (<div className="mx_ImageView_button" onClick={this.onRedactClick}> eventRedact = (<div className="mx_ImageView_button" onClick={this.onRedactClick}>
Redact { _t('Redact') }
</div>); </div>);
} }
@ -169,7 +170,7 @@ module.exports = React.createClass({
<img src={this.props.src} style={style}/> <img src={this.props.src} style={style}/>
<div className="mx_ImageView_labelWrapper"> <div className="mx_ImageView_labelWrapper">
<div className="mx_ImageView_label"> <div className="mx_ImageView_label">
<AccessibleButton className="mx_ImageView_cancel" onClick={ this.props.onFinished }><img src="img/cancel-white.svg" width="18" height="18" alt="Close"/></AccessibleButton> <AccessibleButton className="mx_ImageView_cancel" onClick={ this.props.onFinished }><img src="img/cancel-white.svg" width="18" height="18" alt={ _t('Close') }/></AccessibleButton>
<div className="mx_ImageView_shim"> <div className="mx_ImageView_shim">
</div> </div>
<div className="mx_ImageView_name"> <div className="mx_ImageView_name">
@ -178,7 +179,7 @@ module.exports = React.createClass({
{ eventMeta } { eventMeta }
<a className="mx_ImageView_link" href={ this.props.src } download={ this.props.name } target="_blank" rel="noopener"> <a className="mx_ImageView_link" href={ this.props.src } download={ this.props.name } target="_blank" rel="noopener">
<div className="mx_ImageView_download"> <div className="mx_ImageView_download">
Download this file<br/> { _t('Download this file') }<br/>
<span className="mx_ImageView_size">{ size_res }</span> <span className="mx_ImageView_size">{ size_res }</span>
</div> </div>
</a> </a>

View file

@ -17,6 +17,7 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
import _t from 'counterpart-riot';
var Notifier = require("matrix-react-sdk/lib/Notifier"); var Notifier = require("matrix-react-sdk/lib/Notifier");
var sdk = require('matrix-react-sdk') var sdk = require('matrix-react-sdk')
var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton');
@ -37,7 +38,7 @@ module.exports = React.createClass({
<div className="mx_MatrixToolbar"> <div className="mx_MatrixToolbar">
<img className="mx_MatrixToolbar_warning" src="img/warning.svg" width="24" height="23" alt="/!\"/> <img className="mx_MatrixToolbar_warning" src="img/warning.svg" width="24" height="23" alt="/!\"/>
<div className="mx_MatrixToolbar_content"> <div className="mx_MatrixToolbar_content">
You are not receiving desktop notifications. <a className="mx_MatrixToolbar_link" onClick={ this.onClick }>Enable them now</a> { _t('You are not receiving desktop notifications') } <a className="mx_MatrixToolbar_link" onClick={ this.onClick }> { _t('Enable them now') }</a>
</div> </div>
<AccessibleButton className="mx_MatrixToolbar_close" onClick={ this.hideToolbar } ><img src="img/cancel.svg" width="18" height="18" /></AccessibleButton> <AccessibleButton className="mx_MatrixToolbar_close" onClick={ this.hideToolbar } ><img src="img/cancel.svg" width="18" height="18" /></AccessibleButton>
</div> </div>

View file

@ -15,6 +15,7 @@ limitations under the License.
*/ */
var React = require("react"); var React = require("react");
import _t from 'counterpart-riot';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'VectorCustomServerDialog', displayName: 'VectorCustomServerDialog',
@ -26,24 +27,14 @@ module.exports = React.createClass({
return ( return (
<div className="mx_ErrorDialog"> <div className="mx_ErrorDialog">
<div className="mx_Dialog_title"> <div className="mx_Dialog_title">
Custom Server Options { _t('Custom Server Options') }
</div> </div>
<div className="mx_Dialog_content"> <div className="mx_Dialog_content">
<span> <span dangerouslySetInnerHTML={{__html: _t('customServer_text')}} />
You can use the custom server options to sign into other Matrix
servers by specifying a different Home server URL.
<br/>
This allows you to use Riot with an existing Matrix account on
a different home server.
<br/>
<br/>
You can also set a custom identity server but you won't be able to
invite users by email address, or be invited by email address yourself.
</span>
</div> </div>
<div className="mx_Dialog_buttons"> <div className="mx_Dialog_buttons">
<button onClick={this.props.onFinished} autoFocus={true}> <button onClick={this.props.onFinished} autoFocus={true}>
Dismiss { _t('Dismiss') }
</button> </button>
</div> </div>
</div> </div>

View file

@ -17,6 +17,7 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
import _t from 'counterpart-riot';
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'VectorLoginFooter', displayName: 'VectorLoginFooter',
@ -30,7 +31,7 @@ module.exports = React.createClass({
<a href="https://medium.com/@RiotChat">blog</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp; <a href="https://medium.com/@RiotChat">blog</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;
<a href="https://twitter.com/@RiotChat">twitter</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp; <a href="https://twitter.com/@RiotChat">twitter</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;
<a href="https://github.com/vector-im/vector-web">github</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp; <a href="https://github.com/vector-im/vector-web">github</a>&nbsp;&nbsp;&middot;&nbsp;&nbsp;
<a href="https://matrix.org">powered by Matrix</a> <a href="https://matrix.org">{ _t('powered by Matrix') }</a>
</div> </div>
); );
} }

View file

@ -14,19 +14,23 @@ See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
*/ */
'use strict'; // 'use strict';
var React = require('react'); import React from 'react';
import _t from 'counterpart-riot';
import DateUtils from 'matrix-react-sdk/lib/DateUtils';
var days = [ function getdaysArray() {
"Sunday", var days = [];
"Monday", days.push(_t('Sunday'));
"Tuesday", days.push(_t('Monday'));
"Wednesday", days.push(_t('Tuesday'));
"Thursday", days.push(_t('Wednesday'));
"Friday", days.push(_t('Thursday'));
"Saturday" days.push(_t('Friday'));
]; days.push(_t('Saturday'));
return days;
}
module.exports = React.createClass({ module.exports = React.createClass({
displayName: 'DateSeparator', displayName: 'DateSeparator',
@ -34,19 +38,20 @@ module.exports = React.createClass({
var date = new Date(this.props.ts); var date = new Date(this.props.ts);
var today = new Date(); var today = new Date();
var yesterday = new Date(); var yesterday = new Date();
var days = getdaysArray();
yesterday.setDate(today.getDate() - 1); yesterday.setDate(today.getDate() - 1);
var label; var label;
if (date.toDateString() === today.toDateString()) { if (date.toDateString() === today.toDateString()) {
label = "Today"; label = _t('Today');
} }
else if (date.toDateString() === yesterday.toDateString()) { else if (date.toDateString() === yesterday.toDateString()) {
label = "Yesterday"; label = _t('Yesterday');
} }
else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) { else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) {
label = days[date.getDay()]; label = days[date.getDay()];
} }
else { else {
label = date.toDateString(); label = DateUtils.formatFullDate(date);
} }
return ( return (

View file

@ -23,6 +23,7 @@ import {DropTarget} from 'react-dnd';
import dis from 'matrix-react-sdk/lib/dispatcher'; import dis from 'matrix-react-sdk/lib/dispatcher';
import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg';
import sdk from 'matrix-react-sdk'; import sdk from 'matrix-react-sdk';
import _t from 'counterpart-riot';
import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile'; import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile';
import * as Rooms from 'matrix-react-sdk/lib/Rooms'; import * as Rooms from 'matrix-react-sdk/lib/Rooms';
import Modal from 'matrix-react-sdk/lib/Modal'; import Modal from 'matrix-react-sdk/lib/Modal';
@ -90,8 +91,8 @@ var roomTileSource = {
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to set direct chat tag " + err); console.error("Failed to set direct chat tag " + err);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to set direct chat tag", title: _t('Failed to set direct chat tag'),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
return; return;
@ -115,8 +116,8 @@ var roomTileSource = {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to remove tag " + prevTag + " from room: " + err); console.error("Failed to remove tag " + prevTag + " from room: " + err);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to remove tag " + prevTag + " from room", title: _t('Failed to remove tag %(tagName)s from room', {tagName: prevTag}),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
} }
@ -137,8 +138,8 @@ var roomTileSource = {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to add tag " + newTag + " to room: " + err); console.error("Failed to add tag " + newTag + " to room: " + err);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to add tag " + newTag + " to room", title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}),
description: ((err && err.message) ? err.message : "Operation failed"), description: ((err && err.message) ? err.message : _t('Operation failed')),
}); });
}); });
} }
@ -241,4 +242,3 @@ DragSource('RoomTile', roomTileSource, function(connect, monitor) {
isDragging: monitor.isDragging() isDragging: monitor.isDragging()
}; };
})(RoomTile)); })(RoomTile));

View file

@ -16,6 +16,7 @@ limitations under the License.
'use strict'; 'use strict';
var React = require('react'); var React = require('react');
import _t from 'counterpart-riot';
var q = require("q"); var q = require("q");
var sdk = require('matrix-react-sdk'); var sdk = require('matrix-react-sdk');
var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg');
@ -131,8 +132,8 @@ module.exports = React.createClass({
}, (error) => { }, (error) => {
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Error saving email notification preferences", title: _t('Error saving email notification preferences'),
description: "An error occurred whilst saving your email notification preferences.", description: _t('An error occurred whilst saving your email notification preferences') + '.',
}); });
}); });
}, },
@ -175,9 +176,10 @@ module.exports = React.createClass({
var TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); var TextInputDialog = sdk.getComponent("dialogs.TextInputDialog");
Modal.createDialog(TextInputDialog, { Modal.createDialog(TextInputDialog, {
title: "Keywords", title: _t('Keywords'),
description: "Enter keywords separated by a comma:", description: _t('Enter keywords separated by a comma') + ':',
value: keywords, value: keywords,
button: _t('OK'),
onFinished: function onFinished(should_leave, newValue) { onFinished: function onFinished(should_leave, newValue) {
if (should_leave && newValue !== keywords) { if (should_leave && newValue !== keywords) {
@ -240,8 +242,8 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to change settings: " + error); console.error("Failed to change settings: " + error);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to change settings", title: _t('Failed to change settings'),
description: ((error && error.message) ? error.message : "Operation failed"), description: ((error && error.message) ? error.message : _t('Operation failed')),
onFinished: self._refreshFromServer onFinished: self._refreshFromServer
}); });
}); });
@ -310,8 +312,8 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Can't update user notification settings: " + error); console.error("Can't update user notification settings: " + error);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Can't update user notification settings", title: _t('Can\'t update user notification settings'),
description: ((error && error.message) ? error.message : "Operation failed"), description: ((error && error.message) ? error.message : _t('Operation failed')),
onFinished: self._refreshFromServer onFinished: self._refreshFromServer
}); });
}); });
@ -352,8 +354,8 @@ module.exports = React.createClass({
var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
console.error("Failed to update keywords: " + error); console.error("Failed to update keywords: " + error);
Modal.createDialog(ErrorDialog, { Modal.createDialog(ErrorDialog, {
title: "Failed to update keywords", title: _t('Failed to update keywords'),
description: ((error && error.message) ? error.message : "Operation failed"), description: ((error && error.message) ? error.message : _t('Operation failed')),
onFinished: self._refreshFromServer onFinished: self._refreshFromServer
}); });
} }
@ -562,8 +564,8 @@ module.exports = React.createClass({
// Build the rules not managed by Vector UI // Build the rules not managed by Vector UI
var otherRulesDescriptions = { var otherRulesDescriptions = {
'.m.rule.message': "Notify for all other messages/rooms", '.m.rule.message': _t('Notify for all other messages/rooms'),
'.m.rule.fallback': "Notify me for anything else" '.m.rule.fallback': _t('Notify me for anything else'),
}; };
for (var i in defaultRules.others) { for (var i in defaultRules.others) {
@ -698,7 +700,7 @@ module.exports = React.createClass({
</div> </div>
<div className="mx_UserNotifSettings_labelCell"> <div className="mx_UserNotifSettings_labelCell">
<label htmlFor="enableNotifications"> <label htmlFor="enableNotifications">
Enable notifications for this account { _t('Enable notifications for this account') }
</label> </label>
</div> </div>
</div> </div>
@ -713,7 +715,7 @@ module.exports = React.createClass({
{masterPushRuleDiv} {masterPushRuleDiv}
<div className="mx_UserSettings_notifTable"> <div className="mx_UserSettings_notifTable">
All notifications are currently disabled for all targets. { _t('All notifications are currently disabled for all targets') }.
</div> </div>
</div> </div>
); );
@ -723,13 +725,13 @@ module.exports = React.createClass({
let emailNotificationsRow; let emailNotificationsRow;
if (emailThreepids.length === 0) { if (emailThreepids.length === 0) {
emailNotificationsRow = <div> emailNotificationsRow = <div>
Add an email address above to configure email notifications { _t('Add an email address above to configure email notifications') }
</div>; </div>;
} else { } else {
// This only supports the first email address in your profile for now // This only supports the first email address in your profile for now
emailNotificationsRow = this.emailNotificationsRow( emailNotificationsRow = this.emailNotificationsRow(
emailThreepids[0].address, emailThreepids[0].address,
"Enable email notifications ("+emailThreepids[0].address+")" _t('Enable email notifications') + ' (' + emailThreepids[0].address + ')'
); );
} }
@ -737,7 +739,7 @@ module.exports = React.createClass({
var externalRules = []; var externalRules = [];
for (var i in this.state.externalPushRules) { for (var i in this.state.externalPushRules) {
var rule = this.state.externalPushRules[i]; var rule = this.state.externalPushRules[i];
externalRules.push(<li>{ rule.description }</li>); externalRules.push(<li>{ _t(rule.description) }</li>);
} }
// Show keywords not displayed by the vector UI as a single external push rule // Show keywords not displayed by the vector UI as a single external push rule
@ -748,12 +750,12 @@ module.exports = React.createClass({
} }
if (externalKeyWords.length) { if (externalKeyWords.length) {
externalKeyWords = externalKeyWords.join(", "); externalKeyWords = externalKeyWords.join(", ");
externalRules.push(<li>Notifications on the following keywords follow rules which cant be displayed here: { externalKeyWords }</li>); externalRules.push(<li>{ _t('Notifications on the following keywords follow rules which cant be displayed here:') } { externalKeyWords }</li>);
} }
var devicesSection; var devicesSection;
if (this.state.pushers === undefined) { if (this.state.pushers === undefined) {
devicesSection = <div className="error">Unable to fetch notification target list</div> devicesSection = <div className="error">{ _t('Unable to fetch notification target list') }</div>
} else if (this.state.pushers.length == 0) { } else if (this.state.pushers.length == 0) {
devicesSection = null; devicesSection = null;
} else { } else {
@ -774,7 +776,7 @@ module.exports = React.createClass({
} }
if (devicesSection) { if (devicesSection) {
devicesSection = (<div> devicesSection = (<div>
<h3>Notification targets</h3> <h3>{ _t('Notification targets') }</h3>
{ devicesSection } { devicesSection }
</div>); </div>);
} }
@ -783,9 +785,9 @@ module.exports = React.createClass({
if (externalRules.length) { if (externalRules.length) {
advancedSettings = ( advancedSettings = (
<div> <div>
<h3>Advanced notifications settings</h3> <h3>{ _t('Advanced notifications settings') }</h3>
There are advanced notifications which are not shown here.<br/> { _t('There are advanced notifications which are not shown here') }.<br/>
You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply. { _t('You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply') }.
<ul> <ul>
{ externalRules } { externalRules }
</ul> </ul>
@ -812,7 +814,7 @@ module.exports = React.createClass({
</div> </div>
<div className="mx_UserNotifSettings_labelCell"> <div className="mx_UserNotifSettings_labelCell">
<label htmlFor="enableDesktopNotifications"> <label htmlFor="enableDesktopNotifications">
Enable desktop notifications { _t('Enable desktop notifications') }
</label> </label>
</div> </div>
</div> </div>
@ -830,7 +832,7 @@ module.exports = React.createClass({
</div> </div>
<div className="mx_UserNotifSettings_labelCell"> <div className="mx_UserNotifSettings_labelCell">
<label htmlFor="enableDesktopAudioNotifications"> <label htmlFor="enableDesktopAudioNotifications">
Enable audible notifications in web client { _t('Enable audible notifications in web client') }
</label> </label>
</div> </div>
</div> </div>
@ -842,9 +844,9 @@ module.exports = React.createClass({
<thead> <thead>
<tr> <tr>
<th width="55%"></th> <th width="55%"></th>
<th width="15%">Off</th> <th width="15%">{ _t('Off') }</th>
<th width="15%">On</th> <th width="15%">{ _t('On') }</th>
<th width="15%">Noisy</th> <th width="15%">{ _t('Noisy') }</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>

1
src/i18n/basefile.json Normal file
View file

@ -0,0 +1 @@
{}

88
src/i18n/be.json Normal file
View file

@ -0,0 +1,88 @@
{
"Add an email address above to configure email notifications": "Дадайце адрас электроннай пошты вышэй, каб наладзіць апавяшчэнні",
"All messages": "Усе паведамленні",
"All messages (loud)": "Усе паведамленні (гучна)",
"All notifications are currently disabled for all targets.": "Усе апавяшчэнні ў цяперашні час адключаныя для ўсіх мэтаў.",
"An error occurred whilst saving your email notification preferences": "Адбылася памылка падчас захавання налады апавяшчэнняў па электроннай пошце",
"Cancel Sending": "Адмяніць адпраўку",
"Can't update user notification settings": "Немагчыма абнавіць налады апавяшчэнняў карыстальніка",
"Close": "Зачыніць",
"Create new room": "Стварыць новы пакой",
"Couldn't find a matching Matrix room": "Не атрымалася знайсці адпаведны пакой Matrix",
"Custom Server Options": "Карыстальніцкія параметры сервера",
"delete the alias": "выдаліць псеўданім",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Выдаліць псеўданім пакоя %(alias)s і выдаліць %(name)s з каталога?",
"Direct Chat": "Прамы чат",
"Directory": "Каталог",
"Dismiss": "Aдхіліць",
"Download this file": "Спампаваць гэты файл",
"Drop here to %(verb)s": "Перацягнуць сюды %(verb)s",
"Enable audible notifications in web client": "Ўключыць гукавыя апавяшчэнні ў вэб-кліенце",
"Enable desktop notifications": "Ўключыць апавяшчэнні на працоўным стале",
"Enable email notifications": "Ўключыць паведамлення па электроннай пошце",
"Enable notifications for this account": "Ўключыць апавяшчэнні для гэтага ўліковага запісу",
"Enable them now": "Уключыць іх зараз",
"Enter keywords separated by a comma": "Калі ласка, увядзіце ключавыя словы, падзеленыя коскамі",
"Error": "Памылка",
"Error saving email notification preferences": "Памылка захавання налад апавяшчэнняў па электроннай пошце",
"#example": "#прыклад",
"Failed to": "Не атрымалася",
"Failed to add tag %(tagName)s to room": "Не атрымалася дадаць %(tagName)s ў пакоі",
"Failed to change settings": "Не атрымалася змяніць налады",
"Failed to forget room %(errCode)s": "Не атрымалася забыць пакой %(errCode)s",
"Failed to update keywords": "Не атрымалася абнавіць ключавыя словы",
"Failed to get protocol list from Home Server": "Не ўдалося атрымаць спіс пратаколаў ад хатняга сервера",
"Failed to get public room list": "Не ўдалося атрымаць спіс агульных пакояў",
"Failed to join the room": "Не ўдалося далучыцца да пакоя",
"Failed to remove tag %(prevTag)s from room": "Не ўдалося выдаліць %(prevTag)s з пакоя",
"Failed to set direct chat tag": "Не ўдалося ўсталяваць тэг прамога чата",
"Failed to set Direct Message status of room": "Не ўдалося ўсталяваць статут прамога паведамлення пакою",
"Favourite": "Улюбёнае",
"Fetching third party location failed": "Не ўдалося атрымаць месцазнаходжанне трэцяга боку",
"Files": "Файлы",
"Filter room names": "Фільтр iмёнаў пакояў",
"Forget": "Забыць",
" from room": " з пакоя",
"Guests can join": "Госці могуць далучыцца",
"Guest users can't invite users. Please register to invite": осцi не могуць запрашаць карыстальнікаў. Калі ласка, зарэгіструйцеся, каб запрасiць",
"Invite to this room": "Запрасіць у гэты пакой",
"Keywords": "Ключавыя словы",
"Leave": "Пакінуць",
"Low Priority": "Нізкі прыярытэт",
"Members": "Удзельнікі",
"Mentions only": "Толькі згадкі",
"Mute": "Без гуку",
"No rooms to show": "Няма пакояў для паказу",
"Noisy": "Шумна",
"Notification targets": "Мэты апавяшчэння",
"Notifications": "Апавяшчэнні",
"Notifications on the following keywords follow rules which cant be displayed here": "Апавяшчэнні па наступных ключавых словах прытрымліваюцца правілаў, якія не могуць быць адлюстраваны тут",
"Notify for all other messages/rooms": "Апавяшчаць для ўсіх іншых паведамленняў/пакояў",
"Notify me for anything else": "Паведаміць мне што-небудзь яшчэ",
"Off": "Выключыць",
"On": "Уключыць",
"Operation failed": "Не атрымалася выканаць аперацыю",
"Permalink": "Пастаянная спасылка",
"Please Register": "Калі ласка, зарэгіструйцеся",
"powered by Matrix": "працуе на Matrix",
"Quote": "Цытата",
"Redact": "Адрэдагаваць",
"Reject": "Адхіліць",
"Remove %(name)s from the directory?": "Выдаліць %(name)s з каталога?",
"Remove": "Выдалiць",
"remove %(name)s from the directory": "выдаліць %(name)s з каталога",
"Remove from Directory": "Выдалiць з каталога",
"Resend": "Паўторна",
"Riot does not know how to join a room on this network": "Riot не ведае, як увайсці ў пакой у гэтай сетке",
"Room directory": "Каталог пакояў",
"Room not found": "Пакой не знойдзены",
"Search for a room": "Пошук па пакоі",
"Settings": "Налады",
"Source URL": "URL-адрас крыніцы",
"Start chat": "Пачаць чат",
"The Home Server may be too old to support third party networks": "Хатні сервер можа быць занадта стары для падтрымкі іншых сетак",
"There are advanced notifications which are not shown here": "Ёсць пашыраныя апавяшчэння, якія не паказаныя тут",
"The server may be unavailable or overloaded": "Сервер можа быць недаступны ці перагружаны",
"This room is inaccessible to guests. You may be able to join if you register": "Гэты пакой недаступны для гасцей. Вы можаце далучыцца, калі вы зарэгіструецеся",
" to room": " ў пакоі"
}

84
src/i18n/da.json Normal file
View file

@ -0,0 +1,84 @@
{
"Add an email address above to configure email notifications": "Tilføj en emailadresse ovenfor for at konfigurere e-mail-underretninger",
"All notifications are currently disabled for all targets.": "Alle meddelelser er for øjeblikket deaktiveret for alle mål.",
"An error occurred whilst saving your email notification preferences": "Der opstod en fejl under opbevaring af dine e-mail-underretningsindstillinger",
"and remove": "Og fjern",
"Can't update user notification settings": "Kan ikke opdatere brugermeddelelsesindstillinger",
"Create new room": "Opret nyt rum",
"Couldn't find a matching Matrix room": "Kunne ikke finde et matchende Matrix-rum",
"Custom Server Options": "Brugerdefinerede serverindstillinger",
"delete the alias": "Slet aliaset",
"Delete the room alias": "Slet room alias",
"Direct Chat": "Personligt Chat",
"Directory": "Rum fortegnelse",
"Dismiss": "Afskedige",
"Drop here to": "Drop her til",
"Enable audible notifications in web client": "Aktivér hørbare underretninger i webklienten",
"Enable desktop notifications": "Aktivér desktop meddelelser",
"Enable email notifications": "Aktivér e-mail-underretninger",
"Enable notifications for this account": "Aktivér underretninger for dette brugernavn",
"Enable them now": "Aktivér dem nu",
"Enter keywords separated by a comma": "Indtast søgeord adskilt af et komma",
"Error": "Fejl",
"Error saving email notification preferences": "Fejl ved at gemme e-mail-underretningsindstillinger",
"#example": "#eksempel",
"Failed to": "Var ikke i stand til at",
"Failed to add tag ": "Kunne ikke tilføje tag ",
"Failed to change settings": "Kunne ikke ændre indstillinger",
"Failed to update keywords": "Kunne ikke opdatere søgeord",
"Failed to get protocol list from Home Server": "Kunne ikke få protokolliste fra Home Server",
"Failed to get public room list": "Kunne ikke få offentlig rumliste",
"Failed to join the room": "Kunne ikke komme ind i rumet",
"Failed to remove tag ": "Kunne ikke fjerne tag ",
"Failed to set Direct Message status of room": "Kunne ikke indstille direkte beskedstatus for rumet",
"Favourite": "Favorit",
"Fetching third party location failed": "Hentning af tredjeparts placering mislykkedes",
"Files": "Filer",
"Filter room names": "Filtrer rumnavne",
"Forget": "Glem",
"from the directory": "fra fortegnelsen",
" from room": " fra rum",
"Guests can join": "Gæster kan deltage",
"Guest users can't invite users. Please register to invite": "Gæstebrugere kan ikke invitere brugere. Tilmeld dig venligst for at invitere",
"Invite to this room": "Inviter til dette rum",
"Keywords": "Søgeord",
"Leave": "Forlade",
"Low Priority": "Lav prioritet",
"Members": "Medlemmer",
"No rooms to show": "Ingen rum at vise",
"Noisy": "Støjende",
"Notification targets": "Meddelelsesmål",
"Notifications": "Meddelser",
"Notifications on the following keywords follow rules which cant be displayed here": "Meddelelser om følgende søgeord følger regler, der ikke kan vises her",
"Notify for all other messages/rooms": "Underret om alle andre meddelelser / rum",
"Notify me for anything else": "Underret mig om noget andet",
"Off": "Slukket",
"On": "Tændt",
"Operation failed": "Operation mislykkedes",
"Please Register": "Vær venlig at registrere",
"powered by Matrix": "Drevet af Matrix",
"Reject": "Afvise",
"Remove": "Fjerne",
"remove": "fjerner",
"Remove from Directory": "Fjern fra fortegnelse",
"Riot does not know how to join a room on this network": "Riot ved ikke, hvordan man kan deltage i et rum på dette netværk",
"Room directory": "Rum fortegnelse",
"Room not found": "Rumet ikke fundet",
"Search for a room": "Søg efter et rum",
"Settings": "Indstillinger",
"Start chat": "Begyndt chat",
"The Home Server may be too old to support third party networks": "Hjemmeserveren kan være for gammel til at understøtte tredjepartsnetværk",
"There are advanced notifications which are not shown here": "Der er avancerede meddelelser, som ikke vises her",
"The server may be unavailable or overloaded": "Serveren kan være utilgængelig eller overbelastet",
"This room is inaccessible to guests. You may be able to join if you register": "Dette rum er utilgængeligt for gæster. Du kan være i stand til at deltage, hvis du registrerer dig",
" to room": " til rum",
"Unable to fetch notification target list": "Kan ikke hente meddelelsesmålliste",
"Unable to join network": "Kan ikke deltage i netværket",
"Unable to look up room ID from server": "Kunne ikke slå op på rum-id fra server",
"unknown error code": "Ukendt fejlkode",
"Unnamed room": "Unnamed rum",
"World readable": "Læselig til alle",
"You are not receiving desktop notifications": "Du modtager ikke desktop meddelelser",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Du har muligvis konfigureret dem i en anden klient end Riot. Du kan ikke tune dem i Riot, men de gælder stadig",
"Close": "Luk"
}

122
src/i18n/de_DE.json Normal file
View file

@ -0,0 +1,122 @@
{
"Please Register": "Bitte registrieren",
"Guest users can't invite users. Please register to invite.": "Gäste können keine User einladen. Zum Einladen bitte anmelden.",
"Members": "Mitglieder",
"Files": "Dateien",
"Notifications": "Benachrichtigungen",
"Invite to this room": "In diesen Raum einladen",
"Filter room names": "Raum Namen filtern",
"Start chat": "Neuen Chat starten",
"Room directory": "Raum Verzeichnis",
"Create new room": "Neuen Raum erstellen",
"Settings": "Einstellungen",
"powered by Matrix": "gebaut mit Matrix",
"Custom Server Options": "Optionen für eigenen Server",
"customServer_text": "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.<br/>This allows you to use Riot with an existing Matrix account on a different home server.<br/><br/>You can also set a custom identity server but you won't be able to invite users by email address, or be invited by email address yourself.",
"Dismiss": "ausblenden",
"Failed to get protocol list from Home Server": "Fehler beim Abrufen der Protokollliste vom Home Server",
"The Home Server may be too old to support third party networks": "Der Home Server kann zu alt sein, um Drittanbieter-Netzwerke zu unterstützen",
"Directory": "Raum Verzeichnis",
"#example:": "#beispiel:",
"Search for a room": "Suche einen Raum",
"No rooms to show": "Keine Räume zum anzeigen",
"World readable": "Jeder kann lesen",
"Guests can join": "Gäste können beitreten",
"You are not receiving desktop notifications": "Du erhältst keine Desktop Benachrichtigungen",
"Enable them now": "Aktiviere diese jetzt",
"Add an email address above to configure email notifications": "Füge eine E-Mail Adresse hinzu um Benachrichtigungen via E-Mail zu erhalten",
"All notifications are currently disabled for all targets.": "Im Moment sind alle Benachrichtigungen für alle Ziele deaktiviert.",
"An error occurred whilst saving your email notification preferences": "Ein Fehler trat auf während deine E-Mail Einstellungen gespeichert wurden",
"and remove": "und entfernen",
"Can't update user notification settings": "Kann Benutzerdefinierte Einstellungen nicht aktualisieren",
"Couldn't find a matching Matrix room": "Kann keinen entsprechenden Matrix Raum finden",
"delete the alias": "Lösche den Alias",
"Delete the room alias": "Lösche den Raum Alias",
"Direct Chat": "Privater Chat",
"Drop here to": "Hier ablegen",
"Enable audible notifications in web client": "Aktiviere Audio Benachrichtigungen",
"Enable desktop notifications": "Aktiviere Desktop Benachrichtigungen",
"Enable email notifications": "Aktiviere E-Mail Benachrichtigungen",
"Enable notifications for this account": "Aktiviere Benachrichtigungen für diesen Benutzer",
"Enter keywords separated by a comma": "Gebe Suchbegriffe getrennt durch Kommata ein",
"Error": "Fehler",
"Error saving email notification preferences": "Fehler beim Speichern der E-Mail Benachrichtigungseinstellungen",
"#example": "#Beispiel",
"Failed to": "Konnte nicht",
"Failed to add tag ": "Konnte Tag nicht hinzufügen ",
"Failed to change settings": "Konnte Einstellungen nicht ändern",
"Failed to update keywords": "Konnte Suchbegriff nicht aktualisieren",
"Failed to get public room list": "Konnte keine öffentliche Raumliste laden",
"Failed to join the room": "Fehler beim Betreten des Raumes",
"Failed to remove tag ": "Konnte Tag nicht entfernen ",
"Failed to set Direct Message status of room": "Konnte den direkten Benachrichtigungsstatus nicht setzen",
"Favourite": "Favorit",
"Fetching third party location failed": "Das Abrufen des Drittanbieterstandorts ist fehlgeschlagen",
"Forget": "Lösche",
"from the directory": "aus dem Verzeichnis",
" from room": " aus dem Raum",
"Guest users can't invite users. Please register to invite": "Gastnutzer können keine Nutzer einladen. Bitte registriere dich um Nutzer einzuladen",
"Keywords": "Suchbegriff",
"Leave": "Verlassen",
"Low Priority": "Niedrige Priorität",
"Noisy": "Laut",
"Notification targets": "Benachrichtigungsziel",
"Notifications on the following keywords follow rules which cant be displayed here": "Benachrichtigungen zu folgenden Stichwörtern folgen Regeln, die hier nicht angezeigt werden können",
"Notify for all other messages/rooms": "Benachrichtigung für alle anderen Mitteilungen/ Räume",
"Operation failed": "Ausführung fehlgeschlagen",
"Reject": "ablehnen",
"Remove": "Entferne",
"remove": "Entferner",
"Remove from Directory": "Vom Raum Verzeichnis entfernen",
"Riot does not know how to join a room on this network": "Riot weiß nicht, wie es einem Raum auf diesem Netzwerk beitreten soll",
"Room not found": "Raum nicht gefunden",
"There are advanced notifications which are not shown here": "Es existieren erweiterte Benachrichtigungen, welche hier nicht angezeigt werden",
"The server may be unavailable or overloaded": "Der Server ist vermutlich nicht erreichbar oder überlastet",
"This room is inaccessible to guests. You may be able to join if you register": "Dieser Raum ist nicht verfügbar für Gäste. Vermutlich klappt es wenn du dich anmeldest",
"Unable to fetch notification target list": "Nicht möglich die Zielliste für Benachrichtigungen zu erhalten",
"Unable to join network": "Es ist nicht möglich, dem Netzwerk beizutreten",
"unknown error code": "Unbekannter Fehlercode",
"Unnamed room": "Unbenannter Raum",
"Notify me for anything else": "Benachrichtige mich für alles andere",
"Off": "Aus",
"On": "An",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Du hast sie eventuell auf einem anderen Client als Riot konfiguriert. Sie sind in Riot nicht anpassbar gelten aber trotzdem",
" to room": " an Raum",
"Drop here to %(verb)s": "%(verb)s hierher ziehen",
"All messages": "Alle Nachrichten",
"All messages (loud)": "Alle Nachrichten (laut)",
"Cancel Sending": "Senden abbrechen",
"Close": "Schließen",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Soll der Raumalias %(alias)s gelöscht und der %(name)s aus dem Verzeichnis entfernt werden?",
"Download this file": "Datei Herunterladen",
"Failed to add tag %(tagName)s to room": "Das Hinzufügen des Tags %(tagName)s für den Raum ist fehlgeschlagen",
"Failed to forget room %(errCode)s": "Das Entfernen des Raums %(errCode)s aus deiner Liste ist fehlgeschlagen",
"Failed to remove tag %(prevTag)s from room": "Das Entfernen des Tags %(prevTag)s für den Raum ist fehlgeschlagen",
"Failed to set direct chat tag": "Fehler beim setzen der Direct Chat Kennzeichnung",
"Mentions only": "Nur, wenn du erwähnt wirst",
"Mute": "Lautlos",
"Permalink": "Permanenter Link",
"Quote": "Zitat",
"Redact": "Redaktionell entfernen",
"Remove %(name)s from the directory?": "Soll der Raum %(name)s aus dem Verzeichnis entfernt werden?",
"remove %(name)s from the directory": "entferne %(name)s aus dem Verzeichnis",
"Resend": "Erneut Senden",
"Source URL": "Quell-URL",
"Unable to look up room ID from server": "Es ist nicht möglich, die Raum-ID auf dem Server nachzuschlagen",
"Unhide Preview": "Vorschau wieder anzeigen",
"Uploaded on %(date)s by %(user)s": "Hochgeladen am %(date)s durch %(user)s",
"View Decrypted Source": "Entschlüsselten Quellcode ansehen",
"View Source": "Quellcode ansehen",
"You cannot delete this image. (%(code)s)": "Das Bild kann nicht gelöscht werden. (%(code)s)",
"You cannot delete this message. (%(code)s)": "Die Nachricht kann nicht gelöscht werden. (%(code)s)",
"Today": "Heute",
"Wednesday": "Mittwoch",
"Thursday": "Donnerstag",
"Friday": "Freitag",
"Saturday": "Samstag",
"Tuesday": "Dienstag",
"Sunday": "Sonntag",
"Monday": "Montag",
"Yesterday": "Gestern",
"Welcome page": "Willkommensseite"
}

120
src/i18n/en_EN.json Normal file
View file

@ -0,0 +1,120 @@
{
"Add an email address above to configure email notifications": "Add an email address above to configure email notifications",
"All messages": "All messages",
"All messages (loud)": "All messages (loud)",
"All notifications are currently disabled for all targets.": "All notifications are currently disabled for all targets.",
"An error occurred whilst saving your email notification preferences": "An error occurred whilst saving your email notification preferences",
"Call invitation": "Call invitation",
"Cancel Sending": "Cancel Sending",
"Can't update user notification settings": "Can't update user notification settings",
"Close": "Close",
"Create new room": "Create new room",
"Couldn't find a matching Matrix room": "Couldn't find a matching Matrix room",
"Custom Server Options": "Custom Server Options",
"delete the alias": "delete the alias",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Delete the room alias %(alias)s and remove %(name)s from the directory?",
"Direct Chat": "Direct Chat",
"Directory": "Directory",
"Dismiss": "Dismiss",
"Download this file": "Download this file",
"Drop here to %(verb)s": "Drop here to %(verb)s",
"Enable audible notifications in web client": "Enable audible notifications in web client",
"Enable desktop notifications": "Enable desktop notifications",
"Enable email notifications": "Enable email notifications",
"Enable notifications for this account": "Enable notifications for this account",
"Enable them now": "Enable them now",
"Enter keywords separated by a comma": "Enter keywords separated by a comma",
"Error": "Error",
"Error saving email notification preferences": "Error saving email notification preferences",
"#example": "#example",
"Failed to": "Failed to",
"Failed to add tag %(tagName)s to room": "Failed to add tag %(tagName)s to room",
"Failed to change settings": "Failed to change settings",
"Failed to forget room %(errCode)s": "Failed to forget room %(errCode)s",
"Failed to update keywords": "Failed to update keywords",
"Failed to get protocol list from Home Server": "Failed to get protocol list from Home Server",
"Failed to get public room list": "Failed to get public room list",
"Failed to join the room": "Failed to join the room",
"Failed to remove tag %(prevTag)s from room": "Failed to remove tag %(prevTag)s from room",
"Failed to set direct chat tag": "Failed to set direct chat tag",
"Failed to set Direct Message status of room": "Failed to set Direct Message status of room",
"Favourite": "Favourite",
"Fetching third party location failed": "Fetching third party location failed",
"Files": "Files",
"Filter room names": "Filter room names",
"Forget": "Forget",
" from room": " from room",
"Guests can join": "Guests can join",
"Guest users can't invite users. Please register to invite": "Guest users can't invite users. Please register to invite",
"Invite to this room": "Invite to this room",
"Keywords": "Keywords",
"Leave": "Leave",
"Low Priority": "Low Priority",
"Members": "Members",
"Mentions only": "Mentions only",
"Messages containing my display name": "Messages containing my display name",
"Messages containing my user name": "Messages containing my user name",
"Messages in group chats": "Messages in group chats",
"Messages in one-to-one chats": "Messages in one-to-one chats",
"Messages sent by bot": "Messages sent by bot",
"more": "more",
"Mute": "Mute",
"No rooms to show": "No rooms to show",
"Noisy": "Noisy",
"Notification targets": "Notification targets",
"Notifications": "Notifications",
"Notifications on the following keywords follow rules which cant be displayed here": "Notifications on the following keywords follow rules which cant be displayed here",
"Notify for all other messages/rooms": "Notify for all other messages/rooms",
"Notify me for anything else": "Notify me for anything else",
"Off": "Off",
"On": "On",
"Operation failed": "Operation failed",
"Permalink": "Permalink",
"Please Register": "Please Register",
"powered by Matrix": "powered by Matrix",
"Quote": "Quote",
"Redact": "Redact",
"Reject": "Reject",
"Remove %(name)s from the directory?": "Remove %(name)s from the directory?",
"Remove": "Remove",
"remove %(name)s from the directory": "remove %(name)s from the directory",
"Remove from Directory": "Remove from Directory",
"Resend": "Resend",
"Riot does not know how to join a room on this network": "Riot does not know how to join a room on this network",
"Room directory": "Room directory",
"Room not found": "Room not found",
"Search for a room": "Search for a room",
"Settings": "Settings",
"Source URL": "Source URL",
"Start chat": "Start chat",
"The Home Server may be too old to support third party networks": "The Home Server may be too old to support third party networks",
"There are advanced notifications which are not shown here": "There are advanced notifications which are not shown here",
"The server may be unavailable or overloaded": "The server may be unavailable or overloaded",
"This room is inaccessible to guests. You may be able to join if you register": "This room is inaccessible to guests. You may be able to join if you register",
" to room": " to room",
"Unable to fetch notification target list": "Unable to fetch notification target list",
"Unable to join network": "Unable to join network",
"Unable to look up room ID from server": "Unable to look up room ID from server",
"Unhide Preview": "Unhide Preview",
"unknown error code": "unknown error code",
"Unnamed room": "Unnamed room",
"Uploaded on %(date)s by %(user)s": "Uploaded on %(date)s by %(user)s",
"View Decrypted Source": "View Decrypted Source",
"View Source": "View Source",
"When I'm invited to a room": "When I'm invited to a room",
"World readable": "World readable",
"You cannot delete this image. (%(code)s)": "You cannot delete this image. (%(code)s)",
"You cannot delete this message. (%(code)s)": "You cannot delete this message. (%(code)s)",
"You are not receiving desktop notifications": "You are not receiving desktop notifications",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply",
"Sunday": "Sunday",
"Monday": "Monday",
"Tuesday": "Tuesday",
"Wednesday": "Wednesday",
"Thursday": "Thursday",
"Friday": "Friday",
"Saturday": "Saturday",
"Today": "Today",
"Yesterday": "Yesterday",
"Welcome page": "Welcome page"
}

66
src/i18n/fr.json Normal file
View file

@ -0,0 +1,66 @@
{
"Add an email address above to configure email notifications": "Ajouter une adresse email pour la configuration des notifications par email",
"All messages": "Tous les messages",
"All messages (loud)": "Tous les messages (fort)",
"All notifications are currently disabled for all targets.": "Toutes les notification sont désactivées pour tous les appareils.",
"An error occurred whilst saving your email notification preferences": "Une erreur est survenue lors de la sauvegarde de vos préférences de notifications mails",
"Cancel Sending": "Annuler Envois",
"Can't update user notification settings": "Impossible de mettre à jour les notifications utilisateur",
"Close": "Fermer",
"Create new room": "Créer un nouveau salon",
"Couldn't find a matching Matrix room": "Impossible de trouver un salon Matrix",
"Custom Server Options": "Options de Serveur Personnalisé",
"delete the alias": "Supprimer l'alias",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Supprimer le salon alias %(alias)s et supprimer %(name)s du répertoire?",
"Direct Chat": "Chat direct",
"Directory": "Dossier",
"Dismiss": "Rejeter",
"Download this file": "Télécharger ce fichier",
"Drop here to %(verb)s": "Déposer ici pour %(verb)s",
"Enable audible notifications in web client": "Activer les notifications sonores pour le client web",
"Enable desktop notifications": "Activer les notifications de bureau",
"Enable email notifications": "Activer les notifications par e-mail",
"Enable notifications for this account": "Activer les notifications pour ce compte",
"Enable them now": "Les activer maintenant",
"Enter keywords separated by a comma": "Entrez les mots clés séparés par une virgule",
"Error": "Erreur",
"Error saving email notification preferences": "Erreur lors de la sauvegarde des notifications par email",
"#example": "#exemple",
"Failed to": "Echec pour",
"Failed to add tag %(tagName)s to room": "Echec lors de l'ajout du tag %(tagName)s pour le salon",
"Failed to change settings": "Changement de configuration échouée",
"Failed to forget room %(errCode)s": "Echec lors de l'oublie du salon %(errCode)s",
"Failed to update keywords": "Échec dans la mise à jour des mots clés",
"Failed to get protocol list from Home Server": "Echec lors de la récupération depuis le serveur maison",
"Failed to get public room list": "Echec lors de la récupération de la liste des salons publics",
"Failed to join the room": "Échec pour joindre le salon",
"Failed to remove tag %(prevTag)s from room": "Échec dans la suppression de létiquette %(prevTag)s du salon",
"Failed to set direct chat tag": "Échec dans l'attribution d'une étiquette dans le chat direct",
"Favourite": "Favouris",
"Operation failed": "L'opération a échoué",
"Please Register": "Veuillez vous enregistrer",
"powered by Matrix": "propulsé par Matrix",
"Quote": "Citer",
"Redact": "Rédiger",
"Reject": "Rejeter",
"Remove %(name)s from the directory?": "Supprimer %(name)s du répertoire?",
"Remove": "Supprimer",
"Resend": "Renvoyer",
"Settings": "Paramètres",
"Start chat": "Démarrer la discussion",
"unknown error code": "Code erreur inconnu",
"View Source": "Voir la Source",
"You cannot delete this image. (%(code)s)": "Vous ne pouvez pas supprimer cette image. (%(code)s)",
"You cannot delete this message. (%(code)s)": "Vous ne pouvez pas supprimer ce message. (%(code)s)",
"You are not receiving desktop notifications": "Vous ne recevez pas les notifications sur votre bureau",
"Sunday": "Dimanche",
"Monday": "Lundi",
"Tuesday": "Mardi",
"Wednesday": "Mercredi",
"Thursday": "Jeudi",
"Friday": "Vendredi",
"Saturday": "Samedi",
"Today": "Aujourd'hui",
"Yesterday": "Hier",
"Welcome page": "Page de bienvenue"
}

5
src/i18n/ml.json Normal file
View file

@ -0,0 +1,5 @@
{
"Add an email address above to configure email notifications": "ഇ മെയില്‍ അറിയിപ്പുകൾ ലഭിക്കാന്‍ മുകളില്‍ ഇ-മെയില്‍ വിലാസം നല്‍കൂ",
"All messages": "എല്ലാ സന്ദേശങ്ങളും",
"All messages (loud)": "എല്ലാ സന്ദേശങ്ങളും (ഉച്ചത്തിൽ)"
}

1
src/i18n/pl.json Normal file
View file

@ -0,0 +1 @@
{}

116
src/i18n/pt.json Normal file
View file

@ -0,0 +1,116 @@
{
"Add an email address above to configure email notifications": "Adicione um endereço de email acima para configurar as notificações por email",
"All messages": "Todas as mensagens",
"All messages (loud)": "Todas as mensagens (alto)",
"All notifications are currently disabled for all targets": "Todas as notificações estão atualmente desativadas para todos os destinos",
"An error occurred whilst saving your email notification preferences": "Um erro ocorreu enquanto salvava suas preferências de notificação por email",
"Cancel Sending": "Cancelar o envio",
"Can't update user notification settings": "Não é possível atualizar as preferências de notificação",
"Close": "Fechar",
"Create new room": "Criar nova sala",
"Couldn't find a matching Matrix room": "Não foi possível encontrar uma sala correspondente no servidor Matrix",
"Custom Server Options": "Opções de customização do servidor",
"delete the alias": "apagar o apelido da sala",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Apagar o apelido %(alias)s da sala e remover %(nome)s da lista pública?",
"Direct Chat": "Conversa pessoal",
"Directory": "Diretório",
"Dismiss": "Encerrar",
"Download this file": "Baixar este arquivo",
"Drop here to %(verb)s": "Arraste aqui para %(verb)s",
"Enable audible notifications in web client": "Ativar notificações de áudio no cliente web",
"Enable desktop notifications": "Ativar notificações no desktop",
"Enable email notifications": "Ativar notificações por email",
"Enable notifications for this account": "Ativar notificações para esta conta",
"Enable them now": "Habilitar agora",
"Enter keywords separated by a comma": "Coloque cada palavras-chave separada por vírgula",
"Error": "Erro",
"Error saving email notification preferences": "Erro ao salvar as preferências de notificação por email",
"#example:": "#exemplo",
"Failed to": "Falha ao",
"Failed to add tag %(tagName)s to room": "Falha ao adicionar %(tagName)s à sala",
"Failed to change settings": "Falha ao mudar as preferências",
"Failed to forget room %(errCode)s": "Falha ao esquecer a sala %(errCode)s",
"Failed to update keywords": "Falha ao alterar as palavras-chave",
"Failed to get protocol list from Home Server": "Falha em acessar a lista de protocolos do servidor padrão",
"Failed to get public room list": "Falha ao acessar a lista pública de salas",
"Failed to join the room": "Falha ao entrar na sala",
"Failed to remove tag %(tag)s from room": "Falha ao remover a palavra-chave %(tag)s da sala",
"Failed to set direct chat tag": "Falha ao definir conversa como pessoal",
"Failed to set Direct Message status of room": "Falha em definr a mensagem de status da sala",
"Favourite": "Favorito",
"Fetching third party location failed": "Falha ao acessar localização de terceiros",
"Files": "Arquivos",
"Filter room names": "Filtrar salas por título",
"Forget": "Esquecer",
" from room": " da sala",
"Guests can join": "Convidados podem entrar",
"Guest users can't invite users. Please register to invite": "Usuários convidados não podem convidar outros usuários. Por gentileza se registre para enviar convites",
"Invite to this room": "Convidar para esta sala",
"Keywords": "Palavras-chave",
"Leave": "Sair",
"Low Priority": "Baixa prioridade",
"Members": "Membros",
"Mentions only": "Apenas menções",
"Mute": "Mudo",
"No rooms to show": "Não existem salas a serem exibidas",
"Noisy": "Barulhento",
"Notification targets": "Alvos de notificação",
"Notifications": "Notificações",
"Notifications on the following keywords follow rules which cant be displayed here:": "Notificações sobre as seguintes palavras-chave seguem regras que não podem ser exibidas aqui",
"Notify for all other messages/rooms": "Notificar para todas as outras mensagens e salas",
"Notify me for anything else": "Notificar-me sobre qualquer outro evento",
"Off": "Desativado",
"On": "Ativado",
"Operation failed": "A operação falhou",
"Permalink": "Link permanente",
"Please Register": "Por favor, cadastre-se",
"powered by Matrix": "distribuído por Matrix",
"Quote": "Citar",
"Redact": "Remover",
"Reject": "Rejeitar",
"Remove": "Remover",
"Remove %(name)s from the directory?": "Remover %(name)s da lista pública de salas?",
"remove %(name)s from the directory": "remover %(name)s da lista pública de salas",
"Remove from Directory": "Remover da lista pública de salas",
"Resend": "Reenviar",
"Riot does not know how to join a room on this network": "O sistema não sabe como entrar na sala desta rede",
"Room directory": "Lista de salas públicas",
"Room not found": "Sala não encontrada",
"Search for a room": "Procurar por uma sala",
"Settings": "Configurações",
"Source URL": "URL fonte",
"Start chat": "Começar conversa",
"The Home Server may be too old to support third party networks": "O servidor pode ser muito antigo para suportar redes de terceiros",
"There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui",
"The server may be unavailable or overloaded": "O servidor pode estar inacessível ou sobrecarregado",
"This room is inaccessible to guests. You may be able to join if you register": "Esta sala é inacessível para convidados. Você poderá entrar caso se registre",
" to room": " na sala",
"Unable to fetch notification target list": "Não foi possível obter a lista de alvos de notificação",
"Unable to join network": "Não foi possível conectar na rede",
"Unable to look up room ID from server": "Não foi possivel buscar identificação da sala no servidor",
"Unhide Preview": "Mostrar a pré-visualização novamente",
"unknown error code": "código de erro desconhecido",
"Unnamed room": "Sala sem nome",
"Uploaded on %(date)s by %(user)s": "Enviada em %(date)s por %(user)s",
"View Decrypted Source": "Ver a fonte descriptografada",
"View Source": "Ver a fonte",
"World readable": "Público",
"You cannot delete this image. (%(code)s)": "Você não pode apagar esta imagem. (%(code)s)",
"You cannot delete this message. (%(code)s)": "Você não pode apagar esta mensagem. (%(code)s)",
"You are not receiving desktop notifications": "Você não está recebendo notificações desktop",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Você pode te-las configurado em outro cliente além do Riot. Você não pode ajustá-las no Riot, mas ainda assim elas se aplicam aqui",
"Sunday": "Domingo",
"Monday": "Segunda",
"Tuesday": "Terça",
"Wednesday": "Quarta",
"Thursday": "Quinta",
"Friday": "Sexta",
"Saturday": "Sábado",
"Today": "Hoje",
"Yesterday": "Ontem",
"All notifications are currently disabled for all targets.": "Todas as notificações estão atualmente desabilitadas para todos os recipientes.",
"#example": "#exemplo",
"Failed to remove tag %(prevTag)s from room": "Não foi possível remover a marcação %(prevTag)s desta sala",
"Notifications on the following keywords follow rules which cant be displayed here": "As notificações sobre as palavras-chave abaixo seguem regras que não podem ser mostradas aqui",
"Welcome page": "Página de boas vindas"
}

124
src/i18n/pt_BR.json Normal file
View file

@ -0,0 +1,124 @@
{
"Add an email address above to configure email notifications": "Insira um endereço de email no campo acima para configurar suas notificações por email",
"All messages": "Todas as mensagens",
"All messages (loud)": "Todas as mensagens (alto)",
"All notifications are currently disabled for all targets": "Todas as notificações estão atualmente desativadas para todos os destinos",
"An error occurred whilst saving your email notification preferences": "Um erro ocorreu enquanto o sistema estava salvando suas preferências de notificação por email",
"Call invitation": "Convite para chamada",
"Cancel Sending": "Cancelar o envio",
"Can't update user notification settings": "Não é possível atualizar as preferências de notificação",
"Close": "Fechar",
"Create new room": "Criar nova sala",
"Couldn't find a matching Matrix room": "Não foi possível encontrar uma sala correspondente no servidor Matrix",
"Custom Server Options": "Opções de personalização do servidor",
"delete the alias": "apagar o apelido da sala",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Apagar o apelido %(alias)s da sala e remover %(nome)s da lista pública?",
"Direct Chat": "Conversa pessoal",
"Directory": "Diretório",
"Dismiss": "Encerrar",
"Download this file": "Baixar este arquivo",
"Drop here to %(verb)s": "Arraste aqui para %(verb)s",
"Enable audible notifications in web client": "Ativar notificações de áudio no cliente web",
"Enable desktop notifications": "Ativar notificações no desktop",
"Enable email notifications": "Ativar notificações por email",
"Enable notifications for this account": "Ativar notificações para esta conta",
"Enable them now": "Habilitar agora",
"Enter keywords separated by a comma": "Coloque cada palavras-chave separada por vírgula",
"Error": "Erro",
"Error saving email notification preferences": "Erro ao salvar as preferências de notificação por email",
"#example:": "#exemplo",
"Failed to": "Falha ao",
"Failed to add tag %(tagName)s to room": "Falha ao adicionar %(tagName)s à sala",
"Failed to change settings": "Falhou ao mudar as preferências",
"Failed to forget room %(errCode)s": "Falhou ao esquecer a sala %(errCode)s",
"Failed to update keywords": "Falhou ao alterar as palavras-chave",
"Failed to get protocol list from Home Server": "Falha em acessar a lista de protocolos do servidor padrão",
"Failed to get public room list": "Falha ao acessar a lista pública de salas",
"Failed to join the room": "Falhou ao entrar na sala",
"Failed to remove tag %(tag)s from room": "Falha ao remover a palavra-chave %(tag)s da sala",
"Failed to set direct chat tag": "Falha ao definir conversa como pessoal",
"Failed to set Direct Message status of room": "Falha em definir a mensagem de status da sala",
"Favourite": "Favorito",
"Fetching third party location failed": "Falha ao acessar localização de terceiros",
"Files": "Arquivos",
"Filter room names": "Filtrar salas por título",
"Forget": "Esquecer",
" from room": " da sala",
"Guests can join": "Convidados podem entrar",
"Guest users can't invite users. Please register to invite": "Usuários convidados não podem convidar outros usuários. Por gentileza se registre para enviar convites",
"Invite to this room": "Convidar para esta sala",
"Keywords": "Palavras-chave",
"Leave": "Sair",
"Low Priority": "Baixa prioridade",
"Members": "Membros",
"Mentions only": "Apenas menções",
"Messages containing my display name": "Mensagens contendo meu nome público",
"Messages containing my user name": "Mensagens contendo meu nome de usuário",
"Messages in group chats": "Mensagens em salas",
"Messages in one-to-one chats": "Mensagens em conversas pessoais",
"Messages sent by bot": "Mensagens enviadas por bots",
"more": "ver mais",
"Mute": "Mudo",
"No rooms to show": "Não existem salas a serem exibidas",
"Noisy": "Barulhento",
"Notification targets": "Alvos de notificação",
"Notifications": "Notificações",
"Notifications on the following keywords follow rules which cant be displayed here:": "Notificações sobre as seguintes palavras-chave seguem regras que não podem ser exibidas aqui",
"Notify for all other messages/rooms": "Notificar para todas as outras mensagens e salas",
"Notify me for anything else": "Notificar-me sobre qualquer outro evento",
"Off": "Desativado",
"On": "Ativado",
"Operation failed": "A operação falhou",
"Permalink": "Link permanente",
"Please Register": "Por favor, cadastre-se",
"powered by Matrix": "distribuído por Matrix",
"Quote": "Citar",
"Redact": "Remover",
"Reject": "Rejeitar",
"Remove": "Remover",
"Remove %(name)s from the directory?": "Remover %(name)s da lista pública de salas?",
"remove %(name)s from the directory": "remover %(name)s da lista pública de salas",
"Remove from Directory": "Remover da lista pública de salas",
"Resend": "Reenviar",
"Riot does not know how to join a room on this network": "O sistema não sabe como entrar na sala desta rede",
"Room directory": "Lista de salas públicas",
"Room not found": "Sala não encontrada",
"Search for a room": "Procurar por uma sala",
"Settings": "Configurações",
"Source URL": "URL fonte",
"Start chat": "Começar conversa",
"The Home Server may be too old to support third party networks": "O servidor pode ser muito antigo para suportar redes de terceiros",
"There are advanced notifications which are not shown here": "Existem opções avançadas que não são exibidas aqui",
"The server may be unavailable or overloaded": "O servidor pode estar inacessível ou sobrecarregado",
"This room is inaccessible to guests. You may be able to join if you register": "Esta sala é inacessível para convidados. Você poderá entrar caso se registre",
" to room": " para sala",
"Unable to fetch notification target list": "Não foi possível obter a lista de alvos de notificação",
"Unable to join network": "Não foi possível conectar na rede",
"Unable to look up room ID from server": "Não foi possível buscar identificação da sala no servidor",
"Unhide Preview": "Mostrar a pré-visualização novamente",
"unknown error code": "código de erro desconhecido",
"Unnamed room": "Sala sem nome",
"Uploaded on %(date)s by %(user)s": "Enviada em %(date)s por %(user)s",
"View Decrypted Source": "Ver a fonte descriptografada",
"View Source": "Ver a fonte",
"When I'm invited to a room": "Quando sou convidada(o) a uma sala",
"World readable": "Público",
"You cannot delete this image. (%(code)s)": "Você não pode apagar esta imagem. (%(code)s)",
"You cannot delete this message. (%(code)s)": "Você não pode apagar esta mensagem. (%(code)s)",
"You are not receiving desktop notifications": "Você não está recebendo notificações desktop",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Você pode te-las configurado em outro cliente além do Riot. Você não pode ajustá-las no Riot, mas ainda assim elas se aplicam aqui",
"Sunday": "Domingo",
"Monday": "Segunda",
"Tuesday": "Terça",
"Wednesday": "Quarta",
"Thursday": "Quinta",
"Friday": "Sexta",
"Saturday": "Sábado",
"Today": "Hoje",
"Yesterday": "Ontem",
"All notifications are currently disabled for all targets.": "Todas as notificações estão atualmente desabilitadas para todos os destinatários.",
"#example": "#exemplo",
"Failed to remove tag %(prevTag)s from room": "Não foi possível remover a marcação %(prevTag)s desta sala",
"Notifications on the following keywords follow rules which cant be displayed here": "As notificações sobre as palavras-chave abaixo seguem regras que não podem ser mostradas aqui",
"Welcome page": "Página de boas vindas"
}

119
src/i18n/ru.json Normal file
View file

@ -0,0 +1,119 @@
{
"Add an email address above to configure email notifications": "Добавьте email адресс для настройки оповещений",
"All notifications are currently disabled for all targets.": "Все оповещения отключены.",
"An error occurred whilst saving your email notification preferences": "Возникла ошибка при сохранении настроек оповещения вашего email",
"and remove": "и удалить",
"Can't update user notification settings": "Не возможно обновить пользовательские настройки оповещения",
"Create new room": "Создать комнату",
"Couldn't find a matching Matrix room": "Не возможно найти подходящую Матрикс комнату",
"Custom Server Options": "Настройки пользовательского сервера",
"delete the alias": "удалить привязку",
"Delete the room alias": "Удалить привязку комнаты",
"Direct Chat": "Персональное сообщение",
"Directory": "Каталог",
"Dismiss": "Отелонено",
"Drop here to": "Перетащите сюда",
"Enable audible notifications in web client": "Включить звуковые оповещения в веб клиенте",
"Enable desktop notifications": "Включить оповещения на рабочем столе",
"Enable email notifications": "Включить email оповещения",
"Enable notifications for this account": "Включить оповещения для этого аккаунта",
"Enable them now": "Включить сейчас",
"Enter keywords separated by a comma": "Введите ключевые слова, разделенные запятой",
"Error": "Ошибка",
"Error saving email notification preferences": "Ошибка сохранения настроек email оповещений",
"#example": "#пример",
"Failed to": "Не удалось",
"Failed to add tag ": "Не удалось добавить тег ",
"Failed to change settings": "Не удалось изменить настройки",
"Failed to update keywords": "Не удалось обновить ключевые слова",
"Failed to get protocol list from Home Server": "Не удалось получить список протоколов с Пользовательского Сервера",
"Failed to get public room list": "Не удалось получить список публичных комнат",
"Failed to join the room": "Не удалось присоединиться к комнате",
"Failed to remove tag ": "Не удалось удалить тег ",
"Failed to set Direct Message status of room": "Не удалось задать статус комнаты Персональное Сообщение",
"Favourite": "Фаворит",
"Fetching third party location failed": "Не удалось получить местоположение",
"Files": "Файлы",
"Filter room names": "Отфильтровать по названию комнаты",
"Forget": "Забыть",
"from the directory": "из каталога",
" from room": " из комнаты",
"Guests can join": "Гость может присоединиться",
"Guest users can't invite users. Please register to invite": "Гость не может приглашать пользователей. Зарегистрируйтесь для приглошений",
"Invite to this room": "Пригласить в эту комнату",
"Keywords": "Ключевые слова",
"Leave": "Покинуть",
"Low Priority": "Низкий приоритет",
"Members": "Пользователи",
"No rooms to show": "Нет комнат для отображения",
"Noisy": "Шумный",
"Notification targets": "Цели уведомления",
"Notifications": "Уведомления",
"Notifications on the following keywords follow rules which cant be displayed here": "Уведомления по следующим ключевым словам соответствуют правилам, которые нельзя отобразить здесь",
"Notify for all other messages/rooms": "Уведомить обо всех других сообщениях/комнатах",
"Notify me for anything else": "Уведомить меня обо всем кроме",
"Off": "Выключить",
"On": "Включить",
"Operation failed": "Операция не удалась",
"Please Register": "Пожалуйста зарегистрируйтесь",
"powered by Matrix": "разработано в Matrix",
"Reject": "Отклонить",
"Remove": "Удалить",
"remove": "удалить",
"Remove from Directory": "Удалить из каталога",
"Riot does not know how to join a room on this network": "Riot не знает как присоединиться к этой сети",
"Room directory": "Каталог комнат",
"Room not found": "Комната не найдена",
"Search for a room": "Искать комнату",
"Settings": "Настройки",
"Start chat": "Начать чат",
"The Home Server may be too old to support third party networks": "Пользовательский сервер может быть слишком старым для поддержки сторонних сетей",
"There are advanced notifications which are not shown here": "TЗдесь представлены расширенные уведомления, которые здесь не показаны",
"The server may be unavailable or overloaded": "Возможно, сервер недоступен или перегружен",
"This room is inaccessible to guests. You may be able to join if you register": "Эта комната недоступна для гостей. Вы можете присоединиться, если зарегистрируетесь",
" to room": " к комнате",
"Unable to fetch notification target list": "Не удалось получить список целевых уведомлений",
"Unable to join network": "Не возможно присоединиться к сети",
"Unable to look up room ID from server": "Не возможно найти ID комнаты на сервере",
"unknown error code": "неизвестная ошибка",
"Unnamed room": "Комната без названия",
"World readable": "Читаем мир",
"You are not receiving desktop notifications": "Вы не получаете уведомления на рабочем столе",
"You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Вы могли настроить их в клиенте, отличном от Riot. Вы не можете настроить их в Riot, но они все еще применяются",
"All messages": "Все сообщения",
"All messages (loud)": "Все сообщения (громко)",
"Cancel Sending": "Отмена отправки",
"Close": "Закрыть",
"Download this file": "Скачать этот файл",
"Drop here to %(verb)s": "Вставить сюда для %(verb)s",
"Delete the room alias %(alias)s and remove %(name)s from the directory?": "Удалить псевдоним комнаты %(alias)s и очистить %(name)s из каталога?",
"Failed to add tag %(tagName)s to room": "Не удалось добавить тег %(tagName)s в комнату",
"Failed to forget room %(errCode)s": "Не удалось забыть комнату %(errCode)s",
"Failed to remove tag %(prevTag)s from room": "Не удалось удалить тег %(prevTag)s из комнаты",
"Failed to set direct chat tag": "Не удалось установить прямой чат тег",
"Unhide Preview": "Показать пред. просмотр",
"Uploaded on %(date)s by %(user)s": "Загружено %(date)s %(user)s",
"View Decrypted Source": "Просмотр зашыфрованного источника",
"View Source": "Просмотр источника",
"You cannot delete this image. (%(code)s)": "Вы не можете удалить это изображение. (%(code)s)",
"You cannot delete this message. (%(code)s)": "Вы не можете удалить это сообщение. (%(code)s)",
"Sunday": "Воскресенье",
"Monday": "Понедельник",
"Tuesday": "Вторник",
"Wednesday": "Среда",
"Thursday": "Четверг",
"Friday": "Пятница",
"Saturday": "Субота",
"Today": "Сегодня",
"Yesterday": "Вчера",
"Mentions only": "Только упоминание",
"Mute": "Беззвучный",
"Permalink": "Пстоянная ссылка",
"Quote": "Цитата",
"Redact": "Удалить",
"Remove %(name)s from the directory?": "Удалить %(name)s из каталога?",
"remove %(name)s from the directory": "удалить %(name)s из каталога",
"Resend": "Переслать снова",
"Source URL": "Источник URL",
"Welcome page": "Домашняя страница"
}

View file

@ -18,6 +18,7 @@ limitations under the License.
var StandardActions = require('./StandardActions'); var StandardActions = require('./StandardActions');
var PushRuleVectorState = require('./PushRuleVectorState'); var PushRuleVectorState = require('./PushRuleVectorState');
import _t from 'counterpart-riot';
class VectorPushRuleDefinition { class VectorPushRuleDefinition {
constructor(opts) { constructor(opts) {

View file

@ -175,7 +175,8 @@ limitations under the License.
} }
.mx_Login_type_dropdown { .mx_Login_type_dropdown {
width: 125px; display: inline-block;
min-width: 125px;
align-self: flex-end; align-self: flex-end;
} }

View file

@ -55,6 +55,9 @@ if (process.env.NODE_ENV !== 'production') {
var RunModernizrTests = require("./modernizr"); // this side-effects a global var RunModernizrTests = require("./modernizr"); // this side-effects a global
var ReactDOM = require("react-dom"); var ReactDOM = require("react-dom");
// Workaround for broken export
import * as counterpart from 'counterpart-riot';
var languageHandler = require("matrix-react-sdk/lib/languageHandler");
var sdk = require("matrix-react-sdk"); var sdk = require("matrix-react-sdk");
var PlatformPeg = require("matrix-react-sdk/lib/PlatformPeg"); var PlatformPeg = require("matrix-react-sdk/lib/PlatformPeg");
sdk.loadSkin(require('../component-index')); sdk.loadSkin(require('../component-index'));
@ -62,6 +65,7 @@ var VectorConferenceHandler = require('../VectorConferenceHandler');
var UpdateChecker = require("./updater"); var UpdateChecker = require("./updater");
var q = require('q'); var q = require('q');
var request = require('browser-request'); var request = require('browser-request');
import Modal from 'matrix-react-sdk/lib/Modal';
import url from 'url'; import url from 'url';
@ -214,6 +218,20 @@ function getConfig() {
return deferred.promise; return deferred.promise;
} }
// This is needed to not load the UserSettingsStore before languages are laoded
function getLocalSettings() {
const localSettingsString = localStorage.getItem('mx_local_settings') || '{}';
return JSON.parse(localSettingsString);
}
// This is needed to not load the UserSettingsStore before languages are laoded
function setLocalSetting(type, value) {
const settings = getLocalSettings();
settings[type] = value;
// FIXME: handle errors
localStorage.setItem('mx_local_settings', JSON.stringify(settings));
}
function onLoadCompleted() { function onLoadCompleted() {
// if we did a token login, we're now left with the token, hs and is // if we did a token login, we're now left with the token, hs and is
// url as query params in the url; a little nasty but let's redirect to // url as query params in the url; a little nasty but let's redirect to
@ -228,8 +246,8 @@ function onLoadCompleted() {
} }
} }
async function loadApp() { async function loadApp() {
const fragparts = parseQsFromFragment(window.location); const fragparts = parseQsFromFragment(window.location);
const params = parseQs(window.location); const params = parseQs(window.location);
@ -263,6 +281,17 @@ async function loadApp() {
configError = e; configError = e;
} }
if (!configJson.languages) {
let languages;
try {
languages = await languageHandler.getAllLanguageKeysFromJson();
} catch (e) {
console.log("couldn't load languages from languages.json: error = "+e);
languages = ['en'];
}
configJson.languages = languages;
}
if (window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser')) { if (window.localStorage && window.localStorage.getItem('mx_accepts_unsupported_browser')) {
console.log('User has previously accepted risks in using an unsupported browser'); console.log('User has previously accepted risks in using an unsupported browser');
validBrowser = true; validBrowser = true;
@ -309,4 +338,17 @@ async function loadApp() {
} }
} }
loadApp(); function loadLanguage(callback) {
const _localSettings = getLocalSettings();
var languages = [];
if (!_localSettings.hasOwnProperty('language')) {
languages = languageHandler.getNormalizedLanguageKeys(languageHandler.getLanguageFromBrowser());
}else {
languages = languageHandler.getNormalizedLanguageKeys(_localSettings.language);
}
languageHandler.setLanguage(languages, counterpart);
setLocalSetting('language', languages[0]);
callback();
}
loadLanguage(loadApp);

200
yarn-error.log Normal file
View file

@ -0,0 +1,200 @@
Arguments:
C:\Program Files\nodejs\node.exe C:\Program Files (x86)\Yarn\bin\yarn.js install
PATH:
C:\Users\marce\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\local\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\usr\bin;C:\Program Files\Git\mingw64\bin;C:\Program Files\Git\usr\bin;C:\Users\marce\bin;C:\ProgramData\Oracle\Java\javapath;C:\Python27;C:\Python27\Scripts;C:\Program Files (x86)\Razer Chroma SDK\bin;C:\Program Files\Razer Chroma SDK\bin;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0;C:\Windows\system32\config\systemprofile\AppData\Local\Microsoft\WindowsApps;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\PuTTY;C:\Program Files (x86)\QuickTime\QTSystem;C:\Program Files\Git\cmd;C:\ProgramData\chocolatey\bin;C:\Program Files\Java\jdk1.8.0_131\bin;C:\Android\android-sdk\tools;C:\Android\android-sdk\platform-tools;C:\Program Files\nodejs;C:\Program Files (x86)\Yarn\bin;C:\Ruby23\bin;C:\Users\marce\.cargo\bin;C:\Users\marce\AppData\Local\Microsoft\WindowsApps;C:\Users\marce\AppData\Local\atom\bin;C:\Program Files\Docker Toolbox;C:\Users\marce\AppData\Roaming\npm;C:\Users\marce\AppData\Local\Yarn\.bin;C:\Program Files\Git\usr\bin\vendor_perl;C:\Program Files\Git\usr\bin\core_perl
Yarn version:
0.23.4
Node version:
7.10.0
Platform:
win32 x64
npm manifest:
{
"name": "riot-web",
"productName": "Riot",
"main": "electron/src/electron-main.js",
"version": "0.9.9",
"description": "A feature-rich client for Matrix.org",
"author": "Vector Creations Ltd.",
"repository": {
"type": "git",
"url": "https://github.com/vector-im/riot-web"
},
"license": "Apache-2.0",
"files": [
"AUTHORS.rst",
"CONTRIBUTING.rst",
"deploy",
"docs",
"karma.conf.js",
"lib",
"release.sh",
"scripts",
"src",
"test",
"webpack.config.js"
],
"style": "bundle.css",
"matrix-react-parent": "matrix-react-sdk",
"scripts": {
"reskindex": "reskindex -h src/header",
"build:res": "node scripts/copy-res.js",
"build:modernizr": "modernizr -c .modernizr.json -d src/vector/modernizr.js",
"build:compile": "babel --source-maps -d lib src",
"build:bundle": "cross-env NODE_ENV=production webpack -p --progress",
"build:bundle:dev": "webpack --optimize-occurence-order --progress",
"build:electron": "npm run clean && npm run build && build -wml --ia32 --x64",
"build": "npm run build:res && npm run build:bundle",
"build:dev": "npm run build:res && npm run build:bundle:dev",
"dist": "scripts/package.sh",
"install:electron": "install-app-deps",
"electron": "npm run install:electron && electron .",
"start:res": "node scripts/copy-res.js -w",
"start:js": "webpack-dev-server --output-filename=bundles/_dev_/[name].js --output-chunk-file=bundles/_dev_/[name].js -w --progress",
"start:js:prod": "cross-env NODE_ENV=production webpack-dev-server -w --progress",
"start": "parallelshell \"npm run start:res\" \"npm run start:js\"",
"start:prod": "parallelshell \"npm run start:res\" \"npm run start:js:prod\"",
"lint": "eslint src/",
"lintall": "eslint src/ test/",
"clean": "rimraf lib webapp electron/dist",
"prepublish": "npm run build:compile",
"test": "karma start --single-run=true --autoWatch=false --browsers PhantomJS --colors=false",
"test-multi": "karma start"
},
"dependencies": {
"babel-polyfill": "^6.5.0",
"babel-runtime": "^6.11.6",
"browser-request": "^0.3.3",
"classnames": "^2.1.2",
"counterpart": "Nordgedanken/counterpart#develop",
"draft-js": "^0.8.1",
"extract-text-webpack-plugin": "^0.9.1",
"favico.js": "^0.3.10",
"filesize": "3.5.6",
"flux": "~2.0.3",
"gfm.css": "^1.1.1",
"highlight.js": "^9.0.0",
"linkifyjs": "^2.1.3",
"matrix-js-sdk": "matrix-org/matrix-js-sdk#develop",
"matrix-react-sdk": "matrix-org/matrix-react-sdk#develop",
"modernizr": "^3.1.0",
"pako": "^1.0.5",
"q": "^1.4.1",
"react": "^15.4.0",
"react-dnd": "^2.1.4",
"react-dnd-html5-backend": "^2.1.2",
"react-dom": "^15.4.0",
"react-gemini-scrollbar": "matrix-org/react-gemini-scrollbar#39d858c",
"sanitize-html": "^1.11.1",
"ua-parser-js": "^0.7.10",
"url": "^0.11.0"
},
"devDependencies": {
"autoprefixer": "^6.6.0",
"babel-cli": "^6.5.2",
"babel-core": "^6.14.0",
"babel-eslint": "^6.1.0",
"babel-loader": "^6.2.5",
"babel-plugin-add-module-exports": "^0.2.1",
"babel-plugin-transform-async-to-generator": "^6.16.0",
"babel-plugin-transform-class-properties": "^6.16.0",
"babel-plugin-transform-object-rest-spread": "^6.16.0",
"babel-plugin-transform-runtime": "^6.15.0",
"babel-preset-es2015": "^6.16.0",
"babel-preset-es2016": "^6.16.0",
"babel-preset-es2017": "^6.16.0",
"babel-preset-react": "^6.16.0",
"babel-preset-stage-2": "^6.17.0",
"chokidar": "^1.6.1",
"cpx": "^1.3.2",
"cross-env": "^4.0.0",
"css-raw-loader": "^0.1.1",
"electron-builder": "^11.2.4",
"electron-builder-squirrel-windows": "^11.2.1",
"emojione": "^2.2.7",
"eslint": "^3.14.0",
"eslint-config-google": "^0.7.1",
"eslint-plugin-flowtype": "^2.30.0",
"eslint-plugin-react": "^6.9.0",
"expect": "^1.16.0",
"fs-extra": "^0.30.0",
"html-webpack-plugin": "^2.24.0",
"json-loader": "^0.5.3",
"karma": "^0.13.22",
"karma-chrome-launcher": "^0.2.3",
"karma-cli": "^0.1.2",
"karma-junit-reporter": "^0.4.1",
"karma-mocha": "^0.2.2",
"karma-phantomjs-launcher": "^1.0.0",
"karma-webpack": "^1.7.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"mocha": "^2.4.5",
"parallelshell": "^1.2.0",
"phantomjs-prebuilt": "^2.1.7",
"postcss-extend": "^1.0.5",
"postcss-import": "^9.0.0",
"postcss-loader": "^1.2.2",
"postcss-mixins": "^5.4.1",
"postcss-nested": "^1.0.0",
"postcss-scss": "^0.4.0",
"postcss-simple-vars": "^3.0.0",
"postcss-strip-inline-comments": "^0.1.5",
"react-addons-perf": "^15.4.0",
"react-addons-test-utils": "^15.4.0",
"rimraf": "^2.4.3",
"source-map-loader": "^0.1.5",
"webpack": "^1.12.14",
"webpack-dev-server": "^1.16.2"
},
"optionalDependencies": {
"olm": "https://matrix.org/packages/npm/olm/olm-2.2.1.tgz"
},
"build": {
"appId": "im.riot.app",
"category": "Network",
"electronVersion": "1.6.2",
"//asar=false": "https://github.com/electron-userland/electron-builder/issues/675",
"asar": false,
"dereference": true,
"//files": "We bundle everything, so we only need to include webapp/",
"files": [
"node_modules/**",
"src/**",
"img/**"
],
"extraResources": [
"webapp/**/*"
],
"linux": {
"target": "deb",
"maintainer": "support@riot.im",
"desktop": {
"StartupWMClass": "riot-web"
}
},
"win": {
"target": "squirrel"
},
"directories": {
"buildResources": "electron/build",
"output": "electron/dist",
"app": "electron"
}
}
}
yarn manifest:
No manifest
Lockfile:
No lockfile
Trace:
Error: https://registry.yarnpkg.com/emojione/-/emojione-2.2.7.tgz: unexpected end of file
at Zlib._handle.onerror (zlib.js:355:17)

6076
yarn.lock Normal file

File diff suppressed because it is too large Load diff