diff --git a/.gitignore b/.gitignore index 7f753927ce..060ca6e934 100644 --- a/.gitignore +++ b/.gitignore @@ -12,5 +12,8 @@ /.npmrc .DS_Store npm-debug.log +electron/dist +electron/pub +/.idea /config.json /src/component-index.js diff --git a/README.md b/README.md index 3410787361..4c5452e146 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,19 @@ 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. You'll need to do this in each new terminal you open before building Riot. +How to add a new translation? +============================= + +[translationsstatus](https://translate.nordgedanken.de/engage/riot-web/?utm_source=widget) + + +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 =============== @@ -300,7 +313,7 @@ bug or feature: * feature bug severity: - + * cosmetic - feature works functionally but UI/UX is broken * critical - whole app doesn't work * major - entire feature doesn't work diff --git a/config.sample.json b/config.sample.json index 9be92fa747..405742bab8 100644 --- a/config.sample.json +++ b/config.sample.json @@ -11,5 +11,5 @@ "matrix.org" ] }, - "welcomeUserId": "@RiotBot:matrix.org" + "welcomeUserId": "@riot-bot:matrix.org" } diff --git a/docs/translating-dev.md b/docs/translating-dev.md new file mode 100644 index 0000000000..80d4b64a3a --- /dev/null +++ b/docs/translating-dev.md @@ -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. +- If using translated strings as constants, translated strings can't be in constants loaded at class-load time since the translations won't be loaded. +- If a string is presented in the UI with punctuation like a full stop, include this in the translation strings, since punctuation varies between languages too. diff --git a/docs/translating.md b/docs/translating.md new file mode 100644 index 0000000000..ca9920d323 --- /dev/null +++ b/docs/translating.md @@ -0,0 +1,64 @@ +# 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 0: Join #riotweb-translations:matrix.org + +1. Come and join https://riot.im/develop/#/room/#riotweb-translations:matrix.org +2. Read scrollback and/or ask if anyone else is working on your language, and co-ordinate if needed. In general little-or-no coordination is needed though :) + +## Step 1: Preparing your Weblate Profile + +1. Head to https://translate.nordgedanken.de and register either via Github or email +2. After registering check if you got an 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 visit the 2 sub-projects. +If your language is listed go to Step 2a and 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 a 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 + +### 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 adds a new suggestion to the string which can than be reviewed by others. + +### What are "%(something)s"? + +These things are variables that are expanded when displayed by Riot. They can be room names, usernames or similar. If you find one, you can move to the right place for your language, but not delete it as the variable will be missing if you do. + +A special case is `%(urlStart)s` and `%(urlEnd)s` which are used to mark the beginning of a hyperlink (i.e. `` and ``. You must keep these markers surrounding the equivalent string in your language that needs to be hyperlinked. + +### "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 Weblate doc provides some more in-deepth explanation on how to do translations and talks about do and don'ts. You can find it at: https://docs.weblate.org/en/latest/user/translating.html diff --git a/electron_app/src/electron-main.js b/electron_app/src/electron-main.js index ab844bd371..ca8c3a1be6 100644 --- a/electron_app/src/electron-main.js +++ b/electron_app/src/electron-main.js @@ -1,5 +1,3 @@ -// @flow - /* Copyright 2016 Aviral Dasgupta Copyright 2016 OpenMarket Ltd @@ -20,15 +18,14 @@ limitations under the License. // Squirrel on windows starts the app with various flags // as hooks to tell us when we've been installed/uninstalled // etc. -const check_squirrel_hooks = require('./squirrelhooks'); -if (check_squirrel_hooks()) return; +const checkSquirrelHooks = require('./squirrelhooks'); +if (checkSquirrelHooks()) return; const electron = require('electron'); -const url = require('url'); const tray = require('./tray'); - -const VectorMenu = require('./vectormenu'); +const vectorMenu = require('./vectormenu'); +const webContentsHandler = require('./webcontents-handler'); const windowStateKeeper = require('electron-window-state'); @@ -42,12 +39,6 @@ try { // Continue with the defaults (ie. an empty config) } -const PERMITTED_URL_SCHEMES = [ - 'http:', - 'https:', - 'mailto:', -]; - const UPDATE_POLL_INTERVAL_MS = 60 * 60 * 1000; const INITIAL_UPDATE_DELAY_MS = 30 * 1000; @@ -59,13 +50,13 @@ function safeOpenURL(target) { // so put fairly stringent limits on what can be opened // (for instance, open /bin/sh does indeed open a terminal // with a shell, albeit with no arguments) - const parsed_url = url.parse(target); - if (PERMITTED_URL_SCHEMES.indexOf(parsed_url.protocol) > -1) { + const parsedUrl = url.parse(target); + if (PERMITTED_URL_SCHEMES.indexOf(parsedUrl.protocol) > -1) { // explicitly use the URL re-assembled by the url library, // so we know the url parser has understood all the parts // of the input string - const new_target = url.format(parsed_url); - electron.shell.openExternal(new_target); + const newTarget = url.format(parsedUrl); + electron.shell.openExternal(newTarget); } } @@ -79,20 +70,19 @@ function onWindowOrNavigate(ev, target) { } function onLinkContextMenu(ev, params) { - const popup_menu = new electron.Menu(); - popup_menu.append(new electron.MenuItem({ + const popupMenu = new electron.Menu(); + + popupMenu.append(new electron.MenuItem({ label: params.linkURL, - click() { - safeOpenURL(params.linkURL); - }, + click() { safeOpenURL(params.linkURL); }, })); - popup_menu.append(new electron.MenuItem({ + + popupMenu.append(new electron.MenuItem({ label: 'Copy Link Address', - click() { - electron.clipboard.writeText(params.linkURL); - }, + click() { electron.clipboard.writeText(params.linkURL); }, })); - popup_menu.popup(); + + popupMenu.popup(); ev.preventDefault(); } @@ -107,13 +97,13 @@ function pollForUpdates() { try { electron.autoUpdater.checkForUpdates(); } catch (e) { - console.log("Couldn't check for update", e); + console.log('Couldn\'t check for update', e); } } -function startAutoUpdate(update_base_url) { - if (update_base_url.slice(-1) !== '/') { - update_base_url = update_base_url + '/'; +function startAutoUpdate(updateBaseUrl) { + if (updateBaseUrl.slice(-1) !== '/') { + updateBaseUrl = updateBaseUrl + '/'; } try { // For reasons best known to Squirrel, the way it checks for updates @@ -121,7 +111,7 @@ function startAutoUpdate(update_base_url) { // hits a URL that either gives it a 200 with some json or // 204 No Content. On windows it takes a base path and looks for // files under that path. - if (process.platform == 'darwin') { + if (process.platform === 'darwin') { // include the current version in the URL we hit. Electron doesn't add // it anywhere (apart from the User-Agent) so it's up to us. We could // (and previously did) just use the User-Agent, but this doesn't @@ -129,16 +119,15 @@ function startAutoUpdate(update_base_url) { // and also acts as a convenient cache-buster to ensure that when the // app updates it always gets a fresh value to avoid update-looping. electron.autoUpdater.setFeedURL( - update_base_url + - 'macos/?localVersion=' + encodeURIComponent(electron.app.getVersion()) - ); - } else if (process.platform == 'win32') { - electron.autoUpdater.setFeedURL(update_base_url + 'win32/' + process.arch + '/'); + `${updateBaseUrl}macos/?localVersion=${encodeURIComponent(electron.app.getVersion())}`); + + } else if (process.platform === 'win32') { + electron.autoUpdater.setFeedURL(`${updateBaseUrl}win32/${process.arch}/`); } else { // Squirrel / electron only supports auto-update on these two platforms. // I'm not even going to try to guess which feed style they'd use if they // implemented it on Linux, or if it would be different again. - console.log("Auto update not supported on this platform"); + console.log('Auto update not supported on this platform'); } // We check for updates ourselves rather than using 'updater' because we need to // do it in the main process (and we don't really need to check every 10 minutes: @@ -151,7 +140,7 @@ function startAutoUpdate(update_base_url) { setInterval(pollForUpdates, UPDATE_POLL_INTERVAL_MS); } catch (err) { // will fail if running in debug mode - console.log("Couldn't enable update checking", err); + console.log('Couldn\'t enable update checking', err); } } @@ -162,7 +151,7 @@ function startAutoUpdate(update_base_url) { // Assuming we generally run from the console when developing, // this is far preferable. process.on('uncaughtException', function(error) { - console.log("Unhandled exception", error); + console.log('Unhandled exception', error); }); electron.ipcMain.on('install_update', installUpdate); @@ -186,6 +175,24 @@ electron.ipcMain.on('setBadgeCount', function(ev, count) { } }); +let powerSaveBlockerId; +electron.ipcMain.on('app_onAction', function(ev, payload) { + switch (payload.action) { + case 'call_state': + if (powerSaveBlockerId && powerSaveBlockerId.isStarted(powerSaveBlockerId)) { + if (payload.state === 'ended') { + electron.powerSaveBlocker.stop(powerSaveBlockerId); + } + } else { + if (payload.state === 'connected') { + powerSaveBlockerId = electron.powerSaveBlocker.start('prevent-display-sleep'); + } + } + break; + } +}); + + electron.app.commandLine.appendSwitch('--enable-usermedia-screen-capturing'); const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirectory) => { @@ -198,30 +205,28 @@ const shouldQuit = electron.app.makeSingleInstance((commandLine, workingDirector }); if (shouldQuit) { - console.log("Other instance detected: exiting"); - electron.app.quit() + console.log('Other instance detected: exiting'); + electron.app.quit(); } electron.app.on('ready', () => { if (vectorConfig.update_base_url) { - console.log("Starting auto update with base URL: " + vectorConfig.update_base_url); + console.log(`Starting auto update with base URL: ${vectorConfig.update_base_url}`); startAutoUpdate(vectorConfig.update_base_url); } else { - console.log("No update_base_url is defined: auto update is disabled"); + console.log('No update_base_url is defined: auto update is disabled'); } - const icon_path = `${__dirname}/../img/riot.` + ( - process.platform == 'win32' ? 'ico' : 'png' - ); + const iconPath = `${__dirname}/../img/riot.${process.platform === 'win32' ? 'ico' : 'png'}`; // Load the previous window state with fallback to defaults - let mainWindowState = windowStateKeeper({ + const mainWindowState = windowStateKeeper({ defaultWidth: 1024, defaultHeight: 768, }); mainWindow = new electron.BrowserWindow({ - icon: icon_path, + icon: iconPath, show: false, autoHideMenuBar: true, @@ -231,12 +236,12 @@ electron.app.on('ready', () => { height: mainWindowState.height, }); mainWindow.loadURL(`file://${__dirname}/../../webapp/index.html`); - electron.Menu.setApplicationMenu(VectorMenu); + electron.Menu.setApplicationMenu(vectorMenu); // Create trayIcon icon tray.create(mainWindow, { - icon_path: icon_path, - brand: vectorConfig.brand || 'Riot' + icon_path: iconPath, + brand: vectorConfig.brand || 'Riot', }); if (!process.argv.includes('--hidden')) { @@ -249,7 +254,7 @@ electron.app.on('ready', () => { mainWindow = null; }); mainWindow.on('close', (e) => { - if (!appQuitting && (tray.hasTray() || process.platform == 'darwin')) { + if (!appQuitting && (tray.hasTray() || process.platform === 'darwin')) { // On Mac, closing the window just hides it // (this is generally how single-window Mac apps // behave, eg. Mail.app) @@ -259,15 +264,7 @@ electron.app.on('ready', () => { } }); - mainWindow.webContents.on('new-window', onWindowOrNavigate); - mainWindow.webContents.on('will-navigate', onWindowOrNavigate); - - mainWindow.webContents.on('context-menu', function(ev, params) { - if (params.linkURL) { - onLinkContextMenu(ev, params); - } - }); - + webContentsHandler(mainWindow.webContents); mainWindowState.manage(mainWindow); }); diff --git a/electron_app/src/squirrelhooks.js b/electron_app/src/squirrelhooks.js index 15ed670f0c..728c9cfb2c 100644 --- a/electron_app/src/squirrelhooks.js +++ b/electron_app/src/squirrelhooks.js @@ -16,30 +16,30 @@ limitations under the License. const path = require('path'); const spawn = require('child_process').spawn; -const app = require('electron').app; +const {app} = require('electron'); -function run_update_exe(args, done) { +function runUpdateExe(args, done) { // Invokes Squirrel's Update.exe which will do things for us like create shortcuts // Note that there's an Update.exe in the app-x.x.x directory and one in the parent // directory: we need to run the one in the parent directory, because it discovers // information about the app by inspecting the directory it's run from. const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe'); - console.log('Spawning `%s` with args `%s`', updateExe, args); + console.log(`Spawning '${updateExe}' with args '${args}'`); spawn(updateExe, args, { - detached: true + detached: true, }).on('close', done); -}; +} -function check_squirrel_hooks() { - if (process.platform != 'win32') return false; +function checkSquirrelHooks() { + if (process.platform !== 'win32') return false; const cmd = process.argv[1]; const target = path.basename(process.execPath); if (cmd === '--squirrel-install' || cmd === '--squirrel-updated') { - run_update_exe(['--createShortcut=' + target + ''], app.quit); + runUpdateExe(['--createShortcut=' + target + ''], app.quit); return true; } else if (cmd === '--squirrel-uninstall') { - run_update_exe(['--removeShortcut=' + target + ''], app.quit); + runUpdateExe(['--removeShortcut=' + target + ''], app.quit); return true; } else if (cmd === '--squirrel-obsolete') { app.quit(); @@ -48,4 +48,4 @@ function check_squirrel_hooks() { return false; } -module.exports = check_squirrel_hooks; +module.exports = checkSquirrelHooks; diff --git a/electron_app/src/tray.js b/electron_app/src/tray.js index 5409194d8f..9df1a0fb60 100644 --- a/electron_app/src/tray.js +++ b/electron_app/src/tray.js @@ -25,9 +25,7 @@ exports.hasTray = function hasTray() { exports.create = function(win, config) { // no trays on darwin - if (process.platform === 'darwin' || trayIcon) { - return; - } + if (process.platform === 'darwin' || trayIcon) return; const toggleWin = function() { if (win.isVisible() && !win.isMinimized()) { @@ -41,12 +39,10 @@ exports.create = function(win, config) { const contextMenu = Menu.buildFromTemplate([ { - label: 'Show/Hide ' + config.brand, + label: `Show/Hide ${config.brand}`, click: toggleWin, }, - { - type: 'separator', - }, + { type: 'separator' }, { label: 'Quit', click: function() { diff --git a/electron_app/src/vectormenu.js b/electron_app/src/vectormenu.js index 70ed3ac33c..ab30b376b3 100644 --- a/electron_app/src/vectormenu.js +++ b/electron_app/src/vectormenu.js @@ -14,170 +14,112 @@ See the License for the specific language governing permissions and limitations under the License. */ -const electron = require('electron'); +const {app, shell, Menu} = require('electron'); // Menu template from http://electron.atom.io/docs/api/menu/, edited const template = [ { label: 'Edit', submenu: [ - { - role: 'undo' - }, - { - role: 'redo' - }, - { - type: 'separator' - }, - { - role: 'cut' - }, - { - role: 'copy' - }, - { - role: 'paste' - }, - { - role: 'pasteandmatchstyle' - }, - { - role: 'delete' - }, - { - role: 'selectall' - } - ] + { role: 'undo' }, + { role: 'redo' }, + { type: 'separator' }, + { role: 'cut' }, + { role: 'copy' }, + { role: 'paste' }, + { role: 'pasteandmatchstyle' }, + { role: 'delete' }, + { role: 'selectall' }, + ], }, { label: 'View', submenu: [ - { - type: 'separator' - }, - { - role: 'resetzoom' - }, - { - role: 'zoomin' - }, - { - role: 'zoomout' - }, - { - type: 'separator' - }, - { - role: 'togglefullscreen' - }, - { - role: 'toggledevtools' - } - ] + { type: 'separator' }, + { role: 'resetzoom' }, + { role: 'zoomin' }, + { role: 'zoomout' }, + { type: 'separator' }, + { role: 'togglefullscreen' }, + { role: 'toggledevtools' }, + ], }, { role: 'window', submenu: [ - { - role: 'minimize' - }, - { - role: 'close' - } - ] + { role: 'minimize' }, + { role: 'close' }, + ], }, { role: 'help', submenu: [ { label: 'riot.im', - click () { electron.shell.openExternal('https://riot.im/') } - } - ] - } + click() { shell.openExternal('https://riot.im/'); }, + }, + ], + }, ]; // macOS has specific menu conventions... if (process.platform === 'darwin') { // first macOS menu is the name of the app - const name = electron.app.getName() + const name = app.getName(); template.unshift({ label: name, submenu: [ - { - role: 'about' - }, - { - type: 'separator' - }, + { role: 'about' }, + { type: 'separator' }, { role: 'services', - submenu: [] + submenu: [], }, - { - type: 'separator' - }, - { - role: 'hide' - }, - { - role: 'hideothers' - }, - { - role: 'unhide' - }, - { - type: 'separator' - }, - { - role: 'quit' - } - ] - }) + { type: 'separator' }, + { role: 'hide' }, + { role: 'hideothers' }, + { role: 'unhide' }, + { type: 'separator' }, + { role: 'quit' }, + ], + }); // Edit menu. // This has a 'speech' section on macOS template[1].submenu.push( - { - type: 'separator' - }, + { type: 'separator' }, { label: 'Speech', submenu: [ - { - role: 'startspeaking' - }, - { - role: 'stopspeaking' - } - ] - } - ) + { role: 'startspeaking' }, + { role: 'stopspeaking' }, + ], + }); + // Window menu. // This also has specific functionality on macOS template[3].submenu = [ { label: 'Close', accelerator: 'CmdOrCtrl+W', - role: 'close' + role: 'close', }, { label: 'Minimize', accelerator: 'CmdOrCtrl+M', - role: 'minimize' + role: 'minimize', }, { label: 'Zoom', - role: 'zoom' + role: 'zoom', }, { - type: 'separator' + type: 'separator', }, { label: 'Bring All to Front', - role: 'front' - } - ] + role: 'front', + }, + ]; } else { template.unshift({ label: 'File', @@ -186,12 +128,10 @@ if (process.platform === 'darwin') { /*{ role: 'about' },*/ - { - role: 'quit' - } - ] + { role: 'quit' }, + ], }); } -module.exports = electron.Menu.buildFromTemplate(template) +module.exports = Menu.buildFromTemplate(template); diff --git a/electron_app/src/webcontents-handler.js b/electron_app/src/webcontents-handler.js new file mode 100644 index 0000000000..37416ebe96 --- /dev/null +++ b/electron_app/src/webcontents-handler.js @@ -0,0 +1,122 @@ +const {clipboard, nativeImage, Menu, MenuItem, shell} = require('electron'); +const url = require('url'); + +const PERMITTED_URL_SCHEMES = [ + 'http:', + 'https:', + 'mailto:', +]; + +function safeOpenURL(target) { + // openExternal passes the target to open/start/xdg-open, + // so put fairly stringent limits on what can be opened + // (for instance, open /bin/sh does indeed open a terminal + // with a shell, albeit with no arguments) + const parsedUrl = url.parse(target); + if (PERMITTED_URL_SCHEMES.indexOf(parsedUrl.protocol) > -1) { + // explicitly use the URL re-assembled by the url library, + // so we know the url parser has understood all the parts + // of the input string + const newTarget = url.format(parsedUrl); + shell.openExternal(newTarget); + } +} + +function onWindowOrNavigate(ev, target) { + // always prevent the default: if something goes wrong, + // we don't want to end up opening it in the electron + // app, as we could end up opening any sort of random + // url in a window that has node scripting access. + ev.preventDefault(); + safeOpenURL(target); +} + +function onLinkContextMenu(ev, params) { + const url = params.linkURL || params.srcURL; + + const popupMenu = new Menu(); + popupMenu.append(new MenuItem({ + label: url, + click() { + safeOpenURL(url); + }, + })); + + if (params.mediaType && params.mediaType === 'image' && !url.startsWith('file://')) { + popupMenu.append(new MenuItem({ + label: 'Copy Image', + click() { + if (url.startsWith('data:')) { + clipboard.writeImage(nativeImage.createFromDataURL(url)); + } else { + ev.sender.copyImageAt(params.x, params.y); + } + }, + })); + } + + popupMenu.append(new MenuItem({ + label: 'Copy Link Address', + click() { + clipboard.writeText(url); + }, + })); + popupMenu.popup(); + ev.preventDefault(); +} + +function _CutCopyPasteSelectContextMenus(params) { + return [{ + role: 'cut', + enabled: params.editFlags.canCut, + }, { + role: 'copy', + enabled: params.editFlags.canCopy, + }, { + role: 'paste', + enabled: params.editFlags.canPaste, + }, { + role: 'pasteandmatchstyle', + enabled: params.editFlags.canPaste, + }, { + role: 'selectall', + enabled: params.editFlags.canSelectAll, + }]; +} + +function onSelectedContextMenu(ev, params) { + const items = _CutCopyPasteSelectContextMenus(params); + const popupMenu = Menu.buildFromTemplate(items); + + popupMenu.popup(); + ev.preventDefault(); +} + +function onEditableContextMenu(ev, params) { + const items = [ + { role: 'undo' }, + { role: 'redo', enabled: params.editFlags.canRedo }, + { type: 'separator' }, + ].concat(_CutCopyPasteSelectContextMenus(params)); + + const popupMenu = Menu.buildFromTemplate(items); + + popupMenu.popup(); + ev.preventDefault(); +} + + +module.exports = (webContents) => { + webContents.on('new-window', onWindowOrNavigate); + webContents.on('will-navigate', onWindowOrNavigate); + + webContents.on('context-menu', function(ev, params) { + if (params.linkURL || params.srcURL) { + onLinkContextMenu(ev, params); + } else if (params.selectionText) { + onSelectedContextMenu(ev, params); + } else if (params.isEditable) { + onEditableContextMenu(ev, params); + } + }); +}; diff --git a/karma.conf.js b/karma.conf.js index b0a48c92ba..1e04366313 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -47,7 +47,6 @@ webpack_config.module.noParse.push(/sinon\/pkg\/sinon\.js$/); webpack_config.resolve.alias['sinon'] = 'sinon/pkg/sinon.js'; webpack_config.resolve.root = [ - path.resolve('./src'), path.resolve('./test'), ]; diff --git a/package.json b/package.json index f95a032a7d..29b5beee07 100644 --- a/package.json +++ b/package.json @@ -65,8 +65,8 @@ "gfm.css": "^1.1.1", "highlight.js": "^9.0.0", "linkifyjs": "^2.1.3", - "matrix-js-sdk": "0.7.8", - "matrix-react-sdk": "0.8.9", + "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", @@ -104,6 +104,7 @@ "emojione": "^2.2.7", "eslint": "^3.14.0", "eslint-config-google": "^0.7.1", + "eslint-plugin-babel": "^4.1.1", "eslint-plugin-flowtype": "^2.30.0", "eslint-plugin-react": "^6.9.0", "expect": "^1.16.0", @@ -158,6 +159,7 @@ ], "linux": { "target": "deb", + "category": "Network;InstantMessaging;Chat", "maintainer": "support@riot.im", "desktop": { "StartupWMClass": "riot-web" diff --git a/res/flags/AD.png b/res/flags/AD.png index 8e777b9822..d5d59645fe 100644 Binary files a/res/flags/AD.png and b/res/flags/AD.png differ diff --git a/res/flags/AE.png b/res/flags/AE.png index 1c4a2bb790..05c7418aa4 100644 Binary files a/res/flags/AE.png and b/res/flags/AE.png differ diff --git a/res/flags/AF.png b/res/flags/AF.png index 7d369371f5..bc7cef0916 100644 Binary files a/res/flags/AF.png and b/res/flags/AF.png differ diff --git a/res/flags/AG.png b/res/flags/AG.png index 78c03626ba..d48facad47 100644 Binary files a/res/flags/AG.png and b/res/flags/AG.png differ diff --git a/res/flags/AI.png b/res/flags/AI.png index 8a70782310..8fd27cd39e 100644 Binary files a/res/flags/AI.png and b/res/flags/AI.png differ diff --git a/res/flags/AL.png b/res/flags/AL.png index b19c7bc52d..883835ffb3 100644 Binary files a/res/flags/AL.png and b/res/flags/AL.png differ diff --git a/res/flags/AM.png b/res/flags/AM.png index b39695fd49..b1bb36b987 100644 Binary files a/res/flags/AM.png and b/res/flags/AM.png differ diff --git a/res/flags/AO.png b/res/flags/AO.png index 5aee75af1b..ae68b12c44 100644 Binary files a/res/flags/AO.png and b/res/flags/AO.png differ diff --git a/res/flags/AQ.png b/res/flags/AQ.png index fa76fbb278..146e9c0a04 100644 Binary files a/res/flags/AQ.png and b/res/flags/AQ.png differ diff --git a/res/flags/AR.png b/res/flags/AR.png index 28750f42a8..8142adfc83 100644 Binary files a/res/flags/AR.png and b/res/flags/AR.png differ diff --git a/res/flags/AS.png b/res/flags/AS.png index 36ba9b34df..cc5bf30daf 100644 Binary files a/res/flags/AS.png and b/res/flags/AS.png differ diff --git a/res/flags/AT.png b/res/flags/AT.png index 487fee823c..e32414bd6a 100644 Binary files a/res/flags/AT.png and b/res/flags/AT.png differ diff --git a/res/flags/AU.png b/res/flags/AU.png index 7004861f7f..8d1e143791 100644 Binary files a/res/flags/AU.png and b/res/flags/AU.png differ diff --git a/res/flags/AW.png b/res/flags/AW.png index 238084e4a8..6ec178847e 100644 Binary files a/res/flags/AW.png and b/res/flags/AW.png differ diff --git a/res/flags/AX.png b/res/flags/AX.png index 07ac7742ab..ba269c0453 100644 Binary files a/res/flags/AX.png and b/res/flags/AX.png differ diff --git a/res/flags/AZ.png b/res/flags/AZ.png index 686dbed76c..2bf3c746e7 100644 Binary files a/res/flags/AZ.png and b/res/flags/AZ.png differ diff --git a/res/flags/BA.png b/res/flags/BA.png index 5cfbb6d657..3e3ec3fc76 100644 Binary files a/res/flags/BA.png and b/res/flags/BA.png differ diff --git a/res/flags/BB.png b/res/flags/BB.png index dcdbae7a9a..694050ca46 100644 Binary files a/res/flags/BB.png and b/res/flags/BB.png differ diff --git a/res/flags/BD.png b/res/flags/BD.png index 3bd977a442..6de2cde85b 100644 Binary files a/res/flags/BD.png and b/res/flags/BD.png differ diff --git a/res/flags/BE.png b/res/flags/BE.png index 555ac8bb74..742ba9231f 100644 Binary files a/res/flags/BE.png and b/res/flags/BE.png differ diff --git a/res/flags/BF.png b/res/flags/BF.png index 5a80be2aaa..17f9f67d26 100644 Binary files a/res/flags/BF.png and b/res/flags/BF.png differ diff --git a/res/flags/BG.png b/res/flags/BG.png index 6d8be358f9..b01d3ff57b 100644 Binary files a/res/flags/BG.png and b/res/flags/BG.png differ diff --git a/res/flags/BH.png b/res/flags/BH.png index 0d98e0e051..d0f82e8285 100644 Binary files a/res/flags/BH.png and b/res/flags/BH.png differ diff --git a/res/flags/BI.png b/res/flags/BI.png index e2659e3bc1..21865ac720 100644 Binary files a/res/flags/BI.png and b/res/flags/BI.png differ diff --git a/res/flags/BJ.png b/res/flags/BJ.png index 13fa3c91e7..a7c6091434 100644 Binary files a/res/flags/BJ.png and b/res/flags/BJ.png differ diff --git a/res/flags/BL.png b/res/flags/BL.png index 8e50a79605..6d50a0f544 100644 Binary files a/res/flags/BL.png and b/res/flags/BL.png differ diff --git a/res/flags/BM.png b/res/flags/BM.png index 53de7c39b2..310a25ea23 100644 Binary files a/res/flags/BM.png and b/res/flags/BM.png differ diff --git a/res/flags/BN.png b/res/flags/BN.png index 3ed976ebff..bc4da8d9a6 100644 Binary files a/res/flags/BN.png and b/res/flags/BN.png differ diff --git a/res/flags/BO.png b/res/flags/BO.png index 8e20ea8cee..144b8d32db 100644 Binary files a/res/flags/BO.png and b/res/flags/BO.png differ diff --git a/res/flags/BQ.png b/res/flags/BQ.png index 1547226606..0897943760 100644 Binary files a/res/flags/BQ.png and b/res/flags/BQ.png differ diff --git a/res/flags/BR.png b/res/flags/BR.png index 7a2bc17adc..0278492592 100644 Binary files a/res/flags/BR.png and b/res/flags/BR.png differ diff --git a/res/flags/BS.png b/res/flags/BS.png index 2a152575c6..2b05a8fc7c 100644 Binary files a/res/flags/BS.png and b/res/flags/BS.png differ diff --git a/res/flags/BT.png b/res/flags/BT.png index 4782cf34a6..1f031df071 100644 Binary files a/res/flags/BT.png and b/res/flags/BT.png differ diff --git a/res/flags/BV.png b/res/flags/BV.png index 991a6cd76c..aafb0f1776 100644 Binary files a/res/flags/BV.png and b/res/flags/BV.png differ diff --git a/res/flags/BW.png b/res/flags/BW.png index cd78895521..3084016718 100644 Binary files a/res/flags/BW.png and b/res/flags/BW.png differ diff --git a/res/flags/BY.png b/res/flags/BY.png index 40cdd8a7dd..ce9de9c9c7 100644 Binary files a/res/flags/BY.png and b/res/flags/BY.png differ diff --git a/res/flags/BZ.png b/res/flags/BZ.png index 5de79b7630..33620c3f31 100644 Binary files a/res/flags/BZ.png and b/res/flags/BZ.png differ diff --git a/res/flags/CA.png b/res/flags/CA.png index 68bcac9997..4bbf8b1169 100644 Binary files a/res/flags/CA.png and b/res/flags/CA.png differ diff --git a/res/flags/CC.png b/res/flags/CC.png index 13fe2b7f4d..fd40fc8a78 100644 Binary files a/res/flags/CC.png and b/res/flags/CC.png differ diff --git a/res/flags/CD.png b/res/flags/CD.png index c19304093e..230aacd454 100644 Binary files a/res/flags/CD.png and b/res/flags/CD.png differ diff --git a/res/flags/CF.png b/res/flags/CF.png index 6df7750774..c58ed4f7b2 100644 Binary files a/res/flags/CF.png and b/res/flags/CF.png differ diff --git a/res/flags/CG.png b/res/flags/CG.png index 2d37cd50a8..6c2441e3e0 100644 Binary files a/res/flags/CG.png and b/res/flags/CG.png differ diff --git a/res/flags/CH.png b/res/flags/CH.png index 00d3871728..9fd87167df 100644 Binary files a/res/flags/CH.png and b/res/flags/CH.png differ diff --git a/res/flags/CI.png b/res/flags/CI.png index 82c7606ee9..9741b9b11f 100644 Binary files a/res/flags/CI.png and b/res/flags/CI.png differ diff --git a/res/flags/CK.png b/res/flags/CK.png index 26bca5f9c9..6cca35967c 100644 Binary files a/res/flags/CK.png and b/res/flags/CK.png differ diff --git a/res/flags/CL.png b/res/flags/CL.png index 317ec573fc..13b993d15d 100644 Binary files a/res/flags/CL.png and b/res/flags/CL.png differ diff --git a/res/flags/CM.png b/res/flags/CM.png index c5605d6391..bca5730fb5 100644 Binary files a/res/flags/CM.png and b/res/flags/CM.png differ diff --git a/res/flags/CN.png b/res/flags/CN.png index 1c25ab8662..e086855c73 100644 Binary files a/res/flags/CN.png and b/res/flags/CN.png differ diff --git a/res/flags/CO.png b/res/flags/CO.png index b328c1ea82..65c0aba447 100644 Binary files a/res/flags/CO.png and b/res/flags/CO.png differ diff --git a/res/flags/CR.png b/res/flags/CR.png index df959197fe..b351c67a53 100644 Binary files a/res/flags/CR.png and b/res/flags/CR.png differ diff --git a/res/flags/CU.png b/res/flags/CU.png index 60f6a8c8f2..e7a25c60b3 100644 Binary files a/res/flags/CU.png and b/res/flags/CU.png differ diff --git a/res/flags/CV.png b/res/flags/CV.png index 2dfe516d29..f249bbaa46 100644 Binary files a/res/flags/CV.png and b/res/flags/CV.png differ diff --git a/res/flags/CW.png b/res/flags/CW.png index 2380de1568..e02cacd3dd 100644 Binary files a/res/flags/CW.png and b/res/flags/CW.png differ diff --git a/res/flags/CX.png b/res/flags/CX.png index 49a51c164b..3ea21422f0 100644 Binary files a/res/flags/CX.png and b/res/flags/CX.png differ diff --git a/res/flags/CY.png b/res/flags/CY.png index 08a0e372e2..3182f48bd2 100644 Binary files a/res/flags/CY.png and b/res/flags/CY.png differ diff --git a/res/flags/CZ.png b/res/flags/CZ.png index 90ceaa242a..5462334638 100644 Binary files a/res/flags/CZ.png and b/res/flags/CZ.png differ diff --git a/res/flags/DE.png b/res/flags/DE.png index 90cab7e9a4..93e269166b 100644 Binary files a/res/flags/DE.png and b/res/flags/DE.png differ diff --git a/res/flags/DJ.png b/res/flags/DJ.png index c424a807a8..243bb7390d 100644 Binary files a/res/flags/DJ.png and b/res/flags/DJ.png differ diff --git a/res/flags/DK.png b/res/flags/DK.png index 5a3845ad10..fc74cc396c 100644 Binary files a/res/flags/DK.png and b/res/flags/DK.png differ diff --git a/res/flags/DM.png b/res/flags/DM.png index e7fb60c04a..c3a0e9d102 100644 Binary files a/res/flags/DM.png and b/res/flags/DM.png differ diff --git a/res/flags/DO.png b/res/flags/DO.png index 03c2f1b9d4..5c4a004fef 100644 Binary files a/res/flags/DO.png and b/res/flags/DO.png differ diff --git a/res/flags/DZ.png b/res/flags/DZ.png index 9d63939e7f..1589d0cc40 100644 Binary files a/res/flags/DZ.png and b/res/flags/DZ.png differ diff --git a/res/flags/EC.png b/res/flags/EC.png index 92e2a9e929..4c53dead1c 100644 Binary files a/res/flags/EC.png and b/res/flags/EC.png differ diff --git a/res/flags/EE.png b/res/flags/EE.png index 081568695f..3668de7919 100644 Binary files a/res/flags/EE.png and b/res/flags/EE.png differ diff --git a/res/flags/EG.png b/res/flags/EG.png index 7e9d6c5cc1..66ec709df7 100644 Binary files a/res/flags/EG.png and b/res/flags/EG.png differ diff --git a/res/flags/EH.png b/res/flags/EH.png index f8e59b21fc..148be93c08 100644 Binary files a/res/flags/EH.png and b/res/flags/EH.png differ diff --git a/res/flags/ER.png b/res/flags/ER.png index ffeb28dac8..7cb8441514 100644 Binary files a/res/flags/ER.png and b/res/flags/ER.png differ diff --git a/res/flags/ES.png b/res/flags/ES.png index 3ce59fe891..aae73b6fcb 100644 Binary files a/res/flags/ES.png and b/res/flags/ES.png differ diff --git a/res/flags/ET.png b/res/flags/ET.png index f9d92859c4..7b420f02f4 100644 Binary files a/res/flags/ET.png and b/res/flags/ET.png differ diff --git a/res/flags/FI.png b/res/flags/FI.png index 0930988c29..42f64bf360 100644 Binary files a/res/flags/FI.png and b/res/flags/FI.png differ diff --git a/res/flags/FJ.png b/res/flags/FJ.png index 2a78075da4..cecc683c9c 100644 Binary files a/res/flags/FJ.png and b/res/flags/FJ.png differ diff --git a/res/flags/FK.png b/res/flags/FK.png index 52543390c7..6074fea09c 100644 Binary files a/res/flags/FK.png and b/res/flags/FK.png differ diff --git a/res/flags/FM.png b/res/flags/FM.png index 0ba546ed38..45fdb66426 100644 Binary files a/res/flags/FM.png and b/res/flags/FM.png differ diff --git a/res/flags/FO.png b/res/flags/FO.png index 2a0cd64579..d8fd75c638 100644 Binary files a/res/flags/FO.png and b/res/flags/FO.png differ diff --git a/res/flags/FR.png b/res/flags/FR.png index ef05d74bc7..6d50a0f544 100644 Binary files a/res/flags/FR.png and b/res/flags/FR.png differ diff --git a/res/flags/GA.png b/res/flags/GA.png index 6539d6dd21..3808a61f1d 100644 Binary files a/res/flags/GA.png and b/res/flags/GA.png differ diff --git a/res/flags/GB.png b/res/flags/GB.png index 2938e61b8b..589be70063 100644 Binary files a/res/flags/GB.png and b/res/flags/GB.png differ diff --git a/res/flags/GD.png b/res/flags/GD.png index a55638e7ed..babe1e4cc6 100644 Binary files a/res/flags/GD.png and b/res/flags/GD.png differ diff --git a/res/flags/GE.png b/res/flags/GE.png index c6cfd2b069..d34cddeca9 100644 Binary files a/res/flags/GE.png and b/res/flags/GE.png differ diff --git a/res/flags/GF.png b/res/flags/GF.png index dfc1badffc..98828a5906 100644 Binary files a/res/flags/GF.png and b/res/flags/GF.png differ diff --git a/res/flags/GG.png b/res/flags/GG.png index a79f8c1f30..aec8969b28 100644 Binary files a/res/flags/GG.png and b/res/flags/GG.png differ diff --git a/res/flags/GH.png b/res/flags/GH.png index bda5d6f661..70b1a623de 100644 Binary files a/res/flags/GH.png and b/res/flags/GH.png differ diff --git a/res/flags/GI.png b/res/flags/GI.png index 620b50b3df..9aa58327e3 100644 Binary files a/res/flags/GI.png and b/res/flags/GI.png differ diff --git a/res/flags/GL.png b/res/flags/GL.png index c3d6bcf36b..cf1645c2b5 100644 Binary files a/res/flags/GL.png and b/res/flags/GL.png differ diff --git a/res/flags/GM.png b/res/flags/GM.png index fa2d771ee2..ec374fb3c3 100644 Binary files a/res/flags/GM.png and b/res/flags/GM.png differ diff --git a/res/flags/GN.png b/res/flags/GN.png index dabe7ce494..46874b4d98 100644 Binary files a/res/flags/GN.png and b/res/flags/GN.png differ diff --git a/res/flags/GP.png b/res/flags/GP.png index 7bf7695635..81b7abdf0e 100644 Binary files a/res/flags/GP.png and b/res/flags/GP.png differ diff --git a/res/flags/GQ.png b/res/flags/GQ.png index edae61e9e8..7fd1015e8b 100644 Binary files a/res/flags/GQ.png and b/res/flags/GQ.png differ diff --git a/res/flags/GR.png b/res/flags/GR.png index 5abc59d393..101de51eab 100644 Binary files a/res/flags/GR.png and b/res/flags/GR.png differ diff --git a/res/flags/GS.png b/res/flags/GS.png index baa930d0a3..772c2cbe6d 100644 Binary files a/res/flags/GS.png and b/res/flags/GS.png differ diff --git a/res/flags/GT.png b/res/flags/GT.png index 10ef0cdd16..d5bd8c1e46 100644 Binary files a/res/flags/GT.png and b/res/flags/GT.png differ diff --git a/res/flags/GU.png b/res/flags/GU.png index 166c121e1a..8923085d5a 100644 Binary files a/res/flags/GU.png and b/res/flags/GU.png differ diff --git a/res/flags/GW.png b/res/flags/GW.png index fb59de837c..20c268ce06 100644 Binary files a/res/flags/GW.png and b/res/flags/GW.png differ diff --git a/res/flags/GY.png b/res/flags/GY.png index 65499a7ca3..86f56635ef 100644 Binary files a/res/flags/GY.png and b/res/flags/GY.png differ diff --git a/res/flags/HK.png b/res/flags/HK.png index 3958838402..907dc59624 100644 Binary files a/res/flags/HK.png and b/res/flags/HK.png differ diff --git a/res/flags/HM.png b/res/flags/HM.png index 26a61cbff4..8d1e143791 100644 Binary files a/res/flags/HM.png and b/res/flags/HM.png differ diff --git a/res/flags/HN.png b/res/flags/HN.png index bf923cb81b..4cf8c3112c 100644 Binary files a/res/flags/HN.png and b/res/flags/HN.png differ diff --git a/res/flags/HR.png b/res/flags/HR.png index 139e143b8f..413ceb1586 100644 Binary files a/res/flags/HR.png and b/res/flags/HR.png differ diff --git a/res/flags/HT.png b/res/flags/HT.png index 2583da392f..097abeb434 100644 Binary files a/res/flags/HT.png and b/res/flags/HT.png differ diff --git a/res/flags/HU.png b/res/flags/HU.png index 625846af53..23499bf63c 100644 Binary files a/res/flags/HU.png and b/res/flags/HU.png differ diff --git a/res/flags/ID.png b/res/flags/ID.png index f88d48af94..80200657c6 100644 Binary files a/res/flags/ID.png and b/res/flags/ID.png differ diff --git a/res/flags/IE.png b/res/flags/IE.png index 17f255fc26..63f2220118 100644 Binary files a/res/flags/IE.png and b/res/flags/IE.png differ diff --git a/res/flags/IL.png b/res/flags/IL.png index 6c9a6b57d8..0268826321 100644 Binary files a/res/flags/IL.png and b/res/flags/IL.png differ diff --git a/res/flags/IM.png b/res/flags/IM.png index 936e801d72..c777acc490 100644 Binary files a/res/flags/IM.png and b/res/flags/IM.png differ diff --git a/res/flags/IN.png b/res/flags/IN.png index ecba2f9c48..85fa9bfe72 100644 Binary files a/res/flags/IN.png and b/res/flags/IN.png differ diff --git a/res/flags/IO.png b/res/flags/IO.png index b0edb1610f..1675d8e7db 100644 Binary files a/res/flags/IO.png and b/res/flags/IO.png differ diff --git a/res/flags/IQ.png b/res/flags/IQ.png index 19055f14f7..f2c21f7260 100644 Binary files a/res/flags/IQ.png and b/res/flags/IQ.png differ diff --git a/res/flags/IR.png b/res/flags/IR.png index 9056d21ec2..0b8e67506c 100644 Binary files a/res/flags/IR.png and b/res/flags/IR.png differ diff --git a/res/flags/IS.png b/res/flags/IS.png index 06be01a879..5ee3e63c5c 100644 Binary files a/res/flags/IS.png and b/res/flags/IS.png differ diff --git a/res/flags/IT.png b/res/flags/IT.png index 50e17b22a9..53b967be99 100644 Binary files a/res/flags/IT.png and b/res/flags/IT.png differ diff --git a/res/flags/JE.png b/res/flags/JE.png index 456a1a837e..a1437aba78 100644 Binary files a/res/flags/JE.png and b/res/flags/JE.png differ diff --git a/res/flags/JM.png b/res/flags/JM.png index 5e4e73d325..0d462fa3ae 100644 Binary files a/res/flags/JM.png and b/res/flags/JM.png differ diff --git a/res/flags/JO.png b/res/flags/JO.png index 5982705bbe..8934db7eca 100644 Binary files a/res/flags/JO.png and b/res/flags/JO.png differ diff --git a/res/flags/JP.png b/res/flags/JP.png index 009a990a49..6f92d52365 100644 Binary files a/res/flags/JP.png and b/res/flags/JP.png differ diff --git a/res/flags/KE.png b/res/flags/KE.png index b5a9f733e4..866b3f15dc 100644 Binary files a/res/flags/KE.png and b/res/flags/KE.png differ diff --git a/res/flags/KG.png b/res/flags/KG.png index acf6646b8a..56b433c756 100644 Binary files a/res/flags/KG.png and b/res/flags/KG.png differ diff --git a/res/flags/KH.png b/res/flags/KH.png index 58ad9c6175..e1ddd5f84c 100644 Binary files a/res/flags/KH.png and b/res/flags/KH.png differ diff --git a/res/flags/KI.png b/res/flags/KI.png index 49902d25aa..8b7c54bc0f 100644 Binary files a/res/flags/KI.png and b/res/flags/KI.png differ diff --git a/res/flags/KM.png b/res/flags/KM.png index 9fa9a454e1..227a3b3396 100644 Binary files a/res/flags/KM.png and b/res/flags/KM.png differ diff --git a/res/flags/KN.png b/res/flags/KN.png index 3b39f8f7ae..bc6189bed1 100644 Binary files a/res/flags/KN.png and b/res/flags/KN.png differ diff --git a/res/flags/KP.png b/res/flags/KP.png index eacc3ad0fd..c92248b910 100644 Binary files a/res/flags/KP.png and b/res/flags/KP.png differ diff --git a/res/flags/KR.png b/res/flags/KR.png index a0df8da033..ab1cb94943 100644 Binary files a/res/flags/KR.png and b/res/flags/KR.png differ diff --git a/res/flags/KW.png b/res/flags/KW.png index c6839950d8..0b41c7a532 100644 Binary files a/res/flags/KW.png and b/res/flags/KW.png differ diff --git a/res/flags/KY.png b/res/flags/KY.png index 3f82fa749e..7af5290d31 100644 Binary files a/res/flags/KY.png and b/res/flags/KY.png differ diff --git a/res/flags/KZ.png b/res/flags/KZ.png index 4b43621212..e10a1255a0 100644 Binary files a/res/flags/KZ.png and b/res/flags/KZ.png differ diff --git a/res/flags/LA.png b/res/flags/LA.png index ee9c41ea18..6ad67d4255 100644 Binary files a/res/flags/LA.png and b/res/flags/LA.png differ diff --git a/res/flags/LB.png b/res/flags/LB.png index 7b4d66537f..865df57a42 100644 Binary files a/res/flags/LB.png and b/res/flags/LB.png differ diff --git a/res/flags/LC.png b/res/flags/LC.png index d97f8d8dc7..e83a2d08bc 100644 Binary files a/res/flags/LC.png and b/res/flags/LC.png differ diff --git a/res/flags/LI.png b/res/flags/LI.png index c75a229fa8..57034d367c 100644 Binary files a/res/flags/LI.png and b/res/flags/LI.png differ diff --git a/res/flags/LK.png b/res/flags/LK.png index 2ca1a0c167..6e7ad58254 100644 Binary files a/res/flags/LK.png and b/res/flags/LK.png differ diff --git a/res/flags/LR.png b/res/flags/LR.png index 41bf4a96ce..46c3b84a92 100644 Binary files a/res/flags/LR.png and b/res/flags/LR.png differ diff --git a/res/flags/LS.png b/res/flags/LS.png index 10cf81b054..79b505d490 100644 Binary files a/res/flags/LS.png and b/res/flags/LS.png differ diff --git a/res/flags/LT.png b/res/flags/LT.png index 17a36c71ce..7740cdc0a0 100644 Binary files a/res/flags/LT.png and b/res/flags/LT.png differ diff --git a/res/flags/LU.png b/res/flags/LU.png index 675a891dd6..8f383e674e 100644 Binary files a/res/flags/LU.png and b/res/flags/LU.png differ diff --git a/res/flags/LV.png b/res/flags/LV.png index 763a612026..a0f36d89c4 100644 Binary files a/res/flags/LV.png and b/res/flags/LV.png differ diff --git a/res/flags/LY.png b/res/flags/LY.png index 5211a9024f..2884c4c0a9 100644 Binary files a/res/flags/LY.png and b/res/flags/LY.png differ diff --git a/res/flags/MA.png b/res/flags/MA.png index 098db5009b..1f76cfc9bd 100644 Binary files a/res/flags/MA.png and b/res/flags/MA.png differ diff --git a/res/flags/MC.png b/res/flags/MC.png index 8d1a98132c..06fc2ad166 100644 Binary files a/res/flags/MC.png and b/res/flags/MC.png differ diff --git a/res/flags/MD.png b/res/flags/MD.png index 6ca6f734c9..8e54c2b815 100644 Binary files a/res/flags/MD.png and b/res/flags/MD.png differ diff --git a/res/flags/ME.png b/res/flags/ME.png index c7fccac3b9..97424d4ec2 100644 Binary files a/res/flags/ME.png and b/res/flags/ME.png differ diff --git a/res/flags/MF.png b/res/flags/MF.png index 7f6824e0ab..6d50a0f544 100644 Binary files a/res/flags/MF.png and b/res/flags/MF.png differ diff --git a/res/flags/MG.png b/res/flags/MG.png index 55bc89850a..28bfccc9e8 100644 Binary files a/res/flags/MG.png and b/res/flags/MG.png differ diff --git a/res/flags/MH.png b/res/flags/MH.png index 4484977945..e482a65924 100644 Binary files a/res/flags/MH.png and b/res/flags/MH.png differ diff --git a/res/flags/MK.png b/res/flags/MK.png index ef8d2e55ee..84e2e65e76 100644 Binary files a/res/flags/MK.png and b/res/flags/MK.png differ diff --git a/res/flags/ML.png b/res/flags/ML.png index b8c5737f3d..38fec34796 100644 Binary files a/res/flags/ML.png and b/res/flags/ML.png differ diff --git a/res/flags/MM.png b/res/flags/MM.png index afac494059..70a03c6b14 100644 Binary files a/res/flags/MM.png and b/res/flags/MM.png differ diff --git a/res/flags/MN.png b/res/flags/MN.png index 6e3de3381b..1e1bbe6089 100644 Binary files a/res/flags/MN.png and b/res/flags/MN.png differ diff --git a/res/flags/MO.png b/res/flags/MO.png index 02118edf4b..3833d683e7 100644 Binary files a/res/flags/MO.png and b/res/flags/MO.png differ diff --git a/res/flags/MP.png b/res/flags/MP.png index a85be51b1b..63119096b0 100644 Binary files a/res/flags/MP.png and b/res/flags/MP.png differ diff --git a/res/flags/MQ.png b/res/flags/MQ.png index 92eb07275d..9cab441aec 100644 Binary files a/res/flags/MQ.png and b/res/flags/MQ.png differ diff --git a/res/flags/MR.png b/res/flags/MR.png index 95a5272652..c144de17f7 100644 Binary files a/res/flags/MR.png and b/res/flags/MR.png differ diff --git a/res/flags/MS.png b/res/flags/MS.png index a811c5bd0f..1221707042 100644 Binary files a/res/flags/MS.png and b/res/flags/MS.png differ diff --git a/res/flags/MT.png b/res/flags/MT.png index 857672bf3a..7963aa618a 100644 Binary files a/res/flags/MT.png and b/res/flags/MT.png differ diff --git a/res/flags/MU.png b/res/flags/MU.png index 8f6abb7331..d5d4d4008d 100644 Binary files a/res/flags/MU.png and b/res/flags/MU.png differ diff --git a/res/flags/MV.png b/res/flags/MV.png index bdb8119f5f..0f2ecb4389 100644 Binary files a/res/flags/MV.png and b/res/flags/MV.png differ diff --git a/res/flags/MW.png b/res/flags/MW.png index c684776a33..d0a5d24f55 100644 Binary files a/res/flags/MW.png and b/res/flags/MW.png differ diff --git a/res/flags/MX.png b/res/flags/MX.png index aee282de37..096cb1111f 100644 Binary files a/res/flags/MX.png and b/res/flags/MX.png differ diff --git a/res/flags/MY.png b/res/flags/MY.png index 3941aa8cb1..17f18ac519 100644 Binary files a/res/flags/MY.png and b/res/flags/MY.png differ diff --git a/res/flags/MZ.png b/res/flags/MZ.png index dd497c23c1..66be6563c6 100644 Binary files a/res/flags/MZ.png and b/res/flags/MZ.png differ diff --git a/res/flags/NA.png b/res/flags/NA.png index 68e4aeabe6..7ecfd317c7 100644 Binary files a/res/flags/NA.png and b/res/flags/NA.png differ diff --git a/res/flags/NC.png b/res/flags/NC.png index ffcc21662b..11126ade77 100644 Binary files a/res/flags/NC.png and b/res/flags/NC.png differ diff --git a/res/flags/NE.png b/res/flags/NE.png index 08950d2f37..d584fa8429 100644 Binary files a/res/flags/NE.png and b/res/flags/NE.png differ diff --git a/res/flags/NF.png b/res/flags/NF.png index 2728ed548b..c054042591 100644 Binary files a/res/flags/NF.png and b/res/flags/NF.png differ diff --git a/res/flags/NG.png b/res/flags/NG.png index 5812b2d29c..73aee15b3f 100644 Binary files a/res/flags/NG.png and b/res/flags/NG.png differ diff --git a/res/flags/NI.png b/res/flags/NI.png index d09e132955..fd044933e4 100644 Binary files a/res/flags/NI.png and b/res/flags/NI.png differ diff --git a/res/flags/NL.png b/res/flags/NL.png index f920328273..0897943760 100644 Binary files a/res/flags/NL.png and b/res/flags/NL.png differ diff --git a/res/flags/NO.png b/res/flags/NO.png index 0bedee3f18..aafb0f1776 100644 Binary files a/res/flags/NO.png and b/res/flags/NO.png differ diff --git a/res/flags/NP.png b/res/flags/NP.png index e7775c2516..744458e17e 100644 Binary files a/res/flags/NP.png and b/res/flags/NP.png differ diff --git a/res/flags/NR.png b/res/flags/NR.png index 4760404ba6..58c2afb228 100644 Binary files a/res/flags/NR.png and b/res/flags/NR.png differ diff --git a/res/flags/NU.png b/res/flags/NU.png index 7c130d5b88..007c99eca5 100644 Binary files a/res/flags/NU.png and b/res/flags/NU.png differ diff --git a/res/flags/NZ.png b/res/flags/NZ.png index 67c98728fc..839368dd7b 100644 Binary files a/res/flags/NZ.png and b/res/flags/NZ.png differ diff --git a/res/flags/OM.png b/res/flags/OM.png index a6762503fa..63a893367f 100644 Binary files a/res/flags/OM.png and b/res/flags/OM.png differ diff --git a/res/flags/PA.png b/res/flags/PA.png index ed18bddaf6..3515d95d37 100644 Binary files a/res/flags/PA.png and b/res/flags/PA.png differ diff --git a/res/flags/PE.png b/res/flags/PE.png index 7485279cb6..58f70b8d18 100644 Binary files a/res/flags/PE.png and b/res/flags/PE.png differ diff --git a/res/flags/PF.png b/res/flags/PF.png index 6623f41346..2f33f2574f 100644 Binary files a/res/flags/PF.png and b/res/flags/PF.png differ diff --git a/res/flags/PG.png b/res/flags/PG.png index 92504c5147..c796f587c6 100644 Binary files a/res/flags/PG.png and b/res/flags/PG.png differ diff --git a/res/flags/PH.png b/res/flags/PH.png index d6d676210d..0d98de0386 100644 Binary files a/res/flags/PH.png and b/res/flags/PH.png differ diff --git a/res/flags/PK.png b/res/flags/PK.png index f7c8bb94e8..87f4e2f492 100644 Binary files a/res/flags/PK.png and b/res/flags/PK.png differ diff --git a/res/flags/PL.png b/res/flags/PL.png index 8303b1ea89..273869dfc6 100644 Binary files a/res/flags/PL.png and b/res/flags/PL.png differ diff --git a/res/flags/PM.png b/res/flags/PM.png index 2507c86eae..b74c396d92 100644 Binary files a/res/flags/PM.png and b/res/flags/PM.png differ diff --git a/res/flags/PN.png b/res/flags/PN.png index c5e1d88463..e34c62d598 100644 Binary files a/res/flags/PN.png and b/res/flags/PN.png differ diff --git a/res/flags/PR.png b/res/flags/PR.png index 938c83502f..8efdb91252 100644 Binary files a/res/flags/PR.png and b/res/flags/PR.png differ diff --git a/res/flags/PS.png b/res/flags/PS.png index d106ba89fa..7a0cceec00 100644 Binary files a/res/flags/PS.png and b/res/flags/PS.png differ diff --git a/res/flags/PT.png b/res/flags/PT.png index 168f060570..49e290827c 100644 Binary files a/res/flags/PT.png and b/res/flags/PT.png differ diff --git a/res/flags/PW.png b/res/flags/PW.png index 2d6e5d5b51..6cb2e1e70d 100644 Binary files a/res/flags/PW.png and b/res/flags/PW.png differ diff --git a/res/flags/PY.png b/res/flags/PY.png index 9cae9a780c..a61c42c423 100644 Binary files a/res/flags/PY.png and b/res/flags/PY.png differ diff --git a/res/flags/QA.png b/res/flags/QA.png index ce9d31edaf..bb091cc88c 100644 Binary files a/res/flags/QA.png and b/res/flags/QA.png differ diff --git a/res/flags/RE.png b/res/flags/RE.png index 85c2571022..6d50a0f544 100644 Binary files a/res/flags/RE.png and b/res/flags/RE.png differ diff --git a/res/flags/RO.png b/res/flags/RO.png index e77996d5ad..4495d29eb0 100644 Binary files a/res/flags/RO.png and b/res/flags/RO.png differ diff --git a/res/flags/RS.png b/res/flags/RS.png index fc7a2ab717..ebb0f28a7b 100644 Binary files a/res/flags/RS.png and b/res/flags/RS.png differ diff --git a/res/flags/RU.png b/res/flags/RU.png index 8b3df77988..64532ffa58 100644 Binary files a/res/flags/RU.png and b/res/flags/RU.png differ diff --git a/res/flags/RW.png b/res/flags/RW.png index 87f718674e..64b3cfff04 100644 Binary files a/res/flags/RW.png and b/res/flags/RW.png differ diff --git a/res/flags/SA.png b/res/flags/SA.png index d93b91c7c4..250de6f6f5 100644 Binary files a/res/flags/SA.png and b/res/flags/SA.png differ diff --git a/res/flags/SB.png b/res/flags/SB.png index e9a2a8f3f0..5833c130eb 100644 Binary files a/res/flags/SB.png and b/res/flags/SB.png differ diff --git a/res/flags/SC.png b/res/flags/SC.png index 488ac3bef3..ce5248f434 100644 Binary files a/res/flags/SC.png and b/res/flags/SC.png differ diff --git a/res/flags/SD.png b/res/flags/SD.png index 6ba8c5cac3..d8711a83d6 100644 Binary files a/res/flags/SD.png and b/res/flags/SD.png differ diff --git a/res/flags/SE.png b/res/flags/SE.png index e7bd806f4f..81880931f3 100644 Binary files a/res/flags/SE.png and b/res/flags/SE.png differ diff --git a/res/flags/SG.png b/res/flags/SG.png index 797069fc9e..6f00e57923 100644 Binary files a/res/flags/SG.png and b/res/flags/SG.png differ diff --git a/res/flags/SH.png b/res/flags/SH.png index b2c589d0c5..055dde68bc 100644 Binary files a/res/flags/SH.png and b/res/flags/SH.png differ diff --git a/res/flags/SI.png b/res/flags/SI.png index be8e7a8973..9635983406 100644 Binary files a/res/flags/SI.png and b/res/flags/SI.png differ diff --git a/res/flags/SJ.png b/res/flags/SJ.png index 1dd7e78627..aafb0f1776 100644 Binary files a/res/flags/SJ.png and b/res/flags/SJ.png differ diff --git a/res/flags/SK.png b/res/flags/SK.png index be3d10f221..84c7021f0a 100644 Binary files a/res/flags/SK.png and b/res/flags/SK.png differ diff --git a/res/flags/SL.png b/res/flags/SL.png index b3f997b163..c5ed199141 100644 Binary files a/res/flags/SL.png and b/res/flags/SL.png differ diff --git a/res/flags/SM.png b/res/flags/SM.png index b30f77ad69..1af1ca284f 100644 Binary files a/res/flags/SM.png and b/res/flags/SM.png differ diff --git a/res/flags/SN.png b/res/flags/SN.png index b5cdb2101d..d0b1843561 100644 Binary files a/res/flags/SN.png and b/res/flags/SN.png differ diff --git a/res/flags/SO.png b/res/flags/SO.png index 5f80850834..64e2970b9d 100644 Binary files a/res/flags/SO.png and b/res/flags/SO.png differ diff --git a/res/flags/SR.png b/res/flags/SR.png index a2d124e92b..b072dda835 100644 Binary files a/res/flags/SR.png and b/res/flags/SR.png differ diff --git a/res/flags/SS.png b/res/flags/SS.png index 19c65899c2..83933d4521 100644 Binary files a/res/flags/SS.png and b/res/flags/SS.png differ diff --git a/res/flags/ST.png b/res/flags/ST.png index 1d2befe46d..c102721a86 100644 Binary files a/res/flags/ST.png and b/res/flags/ST.png differ diff --git a/res/flags/SV.png b/res/flags/SV.png index fc3a9ca40d..80de92e556 100644 Binary files a/res/flags/SV.png and b/res/flags/SV.png differ diff --git a/res/flags/SX.png b/res/flags/SX.png index 6051aaa624..dd52215c5d 100644 Binary files a/res/flags/SX.png and b/res/flags/SX.png differ diff --git a/res/flags/SY.png b/res/flags/SY.png index 0d51d071fb..78f45b7c0b 100644 Binary files a/res/flags/SY.png and b/res/flags/SY.png differ diff --git a/res/flags/SZ.png b/res/flags/SZ.png index a7366cb638..2182f4ff93 100644 Binary files a/res/flags/SZ.png and b/res/flags/SZ.png differ diff --git a/res/flags/TC.png b/res/flags/TC.png index 39971bb9b2..3e3e19d4b3 100644 Binary files a/res/flags/TC.png and b/res/flags/TC.png differ diff --git a/res/flags/TD.png b/res/flags/TD.png index 1fb647d488..753bec22b0 100644 Binary files a/res/flags/TD.png and b/res/flags/TD.png differ diff --git a/res/flags/TF.png b/res/flags/TF.png index 41bd93343a..6d50a0f544 100644 Binary files a/res/flags/TF.png and b/res/flags/TF.png differ diff --git a/res/flags/TG.png b/res/flags/TG.png index 560fc0988b..8501ada655 100644 Binary files a/res/flags/TG.png and b/res/flags/TG.png differ diff --git a/res/flags/TH.png b/res/flags/TH.png index 9ee5ce8997..0c884c329e 100644 Binary files a/res/flags/TH.png and b/res/flags/TH.png differ diff --git a/res/flags/TJ.png b/res/flags/TJ.png index ca4be07739..3c9026fa0f 100644 Binary files a/res/flags/TJ.png and b/res/flags/TJ.png differ diff --git a/res/flags/TK.png b/res/flags/TK.png index 88a7eb1a24..fd605749ea 100644 Binary files a/res/flags/TK.png and b/res/flags/TK.png differ diff --git a/res/flags/TL.png b/res/flags/TL.png index fa6c365b9b..b4c834b1d6 100644 Binary files a/res/flags/TL.png and b/res/flags/TL.png differ diff --git a/res/flags/TM.png b/res/flags/TM.png index 6cc0539da6..d18cb939a9 100644 Binary files a/res/flags/TM.png and b/res/flags/TM.png differ diff --git a/res/flags/TN.png b/res/flags/TN.png index 1cc09ec6f0..21c4b98be7 100644 Binary files a/res/flags/TN.png and b/res/flags/TN.png differ diff --git a/res/flags/TO.png b/res/flags/TO.png index 44c42ce0d1..c828206e35 100644 Binary files a/res/flags/TO.png and b/res/flags/TO.png differ diff --git a/res/flags/TR.png b/res/flags/TR.png index 4e63d61b9c..f2a5bd22c8 100644 Binary files a/res/flags/TR.png and b/res/flags/TR.png differ diff --git a/res/flags/TT.png b/res/flags/TT.png index 3831347f56..66d698334b 100644 Binary files a/res/flags/TT.png and b/res/flags/TT.png differ diff --git a/res/flags/TV.png b/res/flags/TV.png index 2f24fbf728..7a127f51ae 100644 Binary files a/res/flags/TV.png and b/res/flags/TV.png differ diff --git a/res/flags/TW.png b/res/flags/TW.png index cda05c9b4c..2353ba1b0a 100644 Binary files a/res/flags/TW.png and b/res/flags/TW.png differ diff --git a/res/flags/TZ.png b/res/flags/TZ.png index a60d5b3fa6..7949f65d8a 100644 Binary files a/res/flags/TZ.png and b/res/flags/TZ.png differ diff --git a/res/flags/UA.png b/res/flags/UA.png index f62089b695..687e305294 100644 Binary files a/res/flags/UA.png and b/res/flags/UA.png differ diff --git a/res/flags/UG.png b/res/flags/UG.png index 8fb590e864..0a21ad15c3 100644 Binary files a/res/flags/UG.png and b/res/flags/UG.png differ diff --git a/res/flags/US.png b/res/flags/US.png index f6b7ab982d..c3a245b767 100644 Binary files a/res/flags/US.png and b/res/flags/US.png differ diff --git a/res/flags/UY.png b/res/flags/UY.png index 11abe8c100..21a347c6fc 100644 Binary files a/res/flags/UY.png and b/res/flags/UY.png differ diff --git a/res/flags/UZ.png b/res/flags/UZ.png index 5d9168a3ea..643b6ae0cf 100644 Binary files a/res/flags/UZ.png and b/res/flags/UZ.png differ diff --git a/res/flags/VA.png b/res/flags/VA.png index 4e5a92bdd7..63a13c0e81 100644 Binary files a/res/flags/VA.png and b/res/flags/VA.png differ diff --git a/res/flags/VC.png b/res/flags/VC.png index 4a8dfa41ea..da991a9344 100644 Binary files a/res/flags/VC.png and b/res/flags/VC.png differ diff --git a/res/flags/VE.png b/res/flags/VE.png index 3632def0ca..e75e17c9f0 100644 Binary files a/res/flags/VE.png and b/res/flags/VE.png differ diff --git a/res/flags/VG.png b/res/flags/VG.png index 15a5e5fadb..46f93cad1e 100644 Binary files a/res/flags/VG.png and b/res/flags/VG.png differ diff --git a/res/flags/VI.png b/res/flags/VI.png index 986a53d2fe..8c849a733e 100644 Binary files a/res/flags/VI.png and b/res/flags/VI.png differ diff --git a/res/flags/VN.png b/res/flags/VN.png index f19db790e3..6ea2122f9d 100644 Binary files a/res/flags/VN.png and b/res/flags/VN.png differ diff --git a/res/flags/VU.png b/res/flags/VU.png index a322030a28..bad3ba4d46 100644 Binary files a/res/flags/VU.png and b/res/flags/VU.png differ diff --git a/res/flags/WF.png b/res/flags/WF.png index 5f6e2bedaa..d94359dcc4 100644 Binary files a/res/flags/WF.png and b/res/flags/WF.png differ diff --git a/res/flags/WS.png b/res/flags/WS.png index de43a37312..f8b80e5ba9 100644 Binary files a/res/flags/WS.png and b/res/flags/WS.png differ diff --git a/res/flags/YE.png b/res/flags/YE.png index b132bc13c4..8b9bbd8942 100644 Binary files a/res/flags/YE.png and b/res/flags/YE.png differ diff --git a/res/flags/YT.png b/res/flags/YT.png index 5c450dfb91..328879361e 100644 Binary files a/res/flags/YT.png and b/res/flags/YT.png differ diff --git a/res/flags/ZA.png b/res/flags/ZA.png index adec062d1d..7f0a52d3b2 100644 Binary files a/res/flags/ZA.png and b/res/flags/ZA.png differ diff --git a/res/flags/ZM.png b/res/flags/ZM.png index 56287f589b..87adc3afaa 100644 Binary files a/res/flags/ZM.png and b/res/flags/ZM.png differ diff --git a/res/flags/ZW.png b/res/flags/ZW.png index e58dff382b..742c9f7e71 100644 Binary files a/res/flags/ZW.png and b/res/flags/ZW.png differ diff --git a/scripts/check-i18n.pl b/scripts/check-i18n.pl new file mode 120000 index 0000000000..7d74c7a463 --- /dev/null +++ b/scripts/check-i18n.pl @@ -0,0 +1 @@ +../../matrix-react-sdk/scripts/check-i18n.pl \ No newline at end of file diff --git a/scripts/copy-res.js b/scripts/copy-res.js index c177925900..45aecebefb 100755 --- a/scripts/copy-res.js +++ b/scripts/copy-res.js @@ -3,6 +3,23 @@ // copies the resources into the webapp directory. // +// Languages are listed manually so we can choose when to include +// a translation in the app (because having a translation with only +// 3 strings translated is just frustrating) +// This could readily be automated, but it's nice to explicitly +// control when we languages are available. +const INCLUDE_LANGS = [ + //'be' Omitted because no translations in react-sdk + 'en_EN', + 'da', + 'de_DE', + 'fr', + 'be', + 'pt', + 'pt_BR', + 'ru', +]; + // cpx includes globbed parts of the filename in the destination, but excludes // common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and // "dest/b/...". @@ -14,12 +31,20 @@ const COPY_LIST = [ ["src/skins/vector/{fonts,img}/**", "webapp"], ["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"], ["node_modules/emojione/assets/png/*", "webapp/emojione/png/"], - ["./config.json", "webapp", {directwatch: 1}], + ["./config.json", "webapp", { directwatch: 1 }], ]; +INCLUDE_LANGS.forEach(function(l) { + COPY_LIST.push([ + l, "webapp/i18n/", { lang: 1 }, + ]); +}); + const parseArgs = require('minimist'); const Cpx = require('cpx'); const chokidar = require('chokidar'); +const fs = require('fs'); +const rimraf = require('rimraf'); const argv = parseArgs( process.argv.slice(2), {} @@ -35,6 +60,15 @@ function errCheck(err) { } } +// Check if webapp exists +if (!fs.existsSync('webapp')) { + fs.mkdirSync('webapp'); +} +// Check if i18n exists +if (!fs.existsSync('webapp/i18n/')) { + fs.mkdirSync('webapp/i18n/'); +} + function next(i, err) { errCheck(err); @@ -46,10 +80,13 @@ function next(i, err) { const source = ent[0]; const dest = ent[1]; const opts = ent[2] || {}; + let cpx = undefined; - const cpx = new Cpx.Cpx(source, dest); + if (!opts.lang) { + cpx = new Cpx.Cpx(source, dest); + } - if (verbose) { + if (verbose && cpx) { cpx.on("copy", (event) => { console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`); }); @@ -58,7 +95,7 @@ function next(i, err) { }); } - const cb = (err) => {next(i+1, err)}; + const cb = (err) => { next(i + 1, err) }; if (watch) { if (opts.directwatch) { @@ -66,20 +103,74 @@ function next(i, err) { // which in the case of config.json is '.', which inevitably takes // ages to crawl. So we create our own watcher on the files // instead. - const copy = () => {cpx.copy(errCheck)}; + const copy = () => { cpx.copy(errCheck) }; chokidar.watch(source) .on('add', copy) .on('change', copy) .on('ready', cb) .on('error', errCheck); + } else if (opts.lang) { + const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + source + '.json'; + const riotWebFile = 'src/i18n/strings/' + source + '.json'; + + const translations = {}; + const makeLang = () => { genLangFile(source, dest) }; + [reactSdkFile, riotWebFile].forEach(function(f) { + chokidar.watch(f) + .on('add', makeLang) + .on('change', makeLang) + //.on('ready', cb) We'd have to do this when both files are ready + .on('error', errCheck); + }); + next(i + 1, err); } else { cpx.on('watch-ready', cb); cpx.on("watch-error", cb); cpx.watch(); } + } else if (opts.lang) { + genLangFile(source, dest); + next(i + 1, err); } else { cpx.copy(cb); } } +function genLangFile(lang, dest) { + const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json'; + const riotWebFile = 'src/i18n/strings/' + lang + '.json'; + + const translations = {}; + [reactSdkFile, riotWebFile].forEach(function(f) { + if (fs.existsSync(f)) { + Object.assign( + translations, + JSON.parse(fs.readFileSync(f).toString()) + ); + } + }); + fs.writeFileSync(dest + lang + '.json', JSON.stringify(translations, null, 4)); + if (verbose) { + console.log("Generated language file: " + lang); + } +} + +function genLangList() { + const languages = {}; + INCLUDE_LANGS.forEach(function(lang) { + const normalizedLanguage = lang.toLowerCase().replace("_", "-"); + const languageParts = normalizedLanguage.split('-'); + if (languageParts.length == 2 && languageParts[0] == languageParts[1]) { + languages[languageParts[0]] = lang + '.json'; + } else { + languages[normalizedLanguage] = lang + '.json'; + } + }); + fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4)); + if (verbose) { + console.log("Generated language list"); + } +} + +genLangList(); next(0); diff --git a/scripts/fetch-develop.deps.sh b/scripts/fetch-develop.deps.sh index c3bfb4e169..bbbc834152 100755 --- a/scripts/fetch-develop.deps.sh +++ b/scripts/fetch-develop.deps.sh @@ -40,11 +40,13 @@ dodep matrix-org matrix-react-sdk mkdir -p node_modules cd node_modules +rm -r matrix-js-sdk 2> /dev/null ln -s ../matrix-js-sdk ./ pushd matrix-js-sdk npm install popd +rm -r matrix-react-sdk 2> /dev/null ln -s ../matrix-react-sdk ./ pushd matrix-react-sdk mkdir -p node_modules diff --git a/scripts/genflags.sh b/scripts/genflags.sh index 826a0299f1..d960c6de0f 100755 --- a/scripts/genflags.sh +++ b/scripts/genflags.sh @@ -18,6 +18,9 @@ # - imagemagick --with-rsvg (because default imagemagick SVG # renderer does not produce accurate results) # +# on macOS, this is most easily done with: +# brew install imagemagick --with-librsvg +# # This will clone the googlei18n flag repo before converting # all phonenumber.js-supported country flags (as SVGs) into # PNGs that can be used by CountryDropdown.js. @@ -42,17 +45,18 @@ for f in region-flags/svg/*.svg; do # Run imagemagick convert # -background none : transparent background - # -thumbnail 25x15 : resize the flag to have a height of 15. + # -resize 50x30 : resize the flag to have a height of 15px (2x) # By default, aspect ratio is respected so the width will # be correct and not necessarily 25px. + # -filter Lanczos : use sharper resampling to avoid muddiness # -gravity Center : keep the image central when adding an -extent # -border 1 : add a 1px border around the flag # -bordercolor : set the border colour - # -extent 27x27 : surround the image with padding so that it - # has the dimensions 27x27. - convert $f -background none -thumbnail 25x15 \ - -gravity Center -border 1 -bordercolor \#e0e0e0 \ - -extent 27x27 $f.png + # -extent 54x54 : surround the image with padding so that it + # has the dimensions 27x27px (2x). + convert $f -background none -filter Lanczos -resize 50x30 \ + -gravity Center -border 1 -bordercolor \#e0e0e0 \ + -extent 54x54 $f.png # $f.png will be region-flags/svg/XX.svg.png at this point @@ -61,6 +65,6 @@ for f in region-flags/svg/*.svg; do # Replace .svg with .png newname=${newname%.svg}.png # Move the file to flags directory - mv $f.png res/flags/$newname + mv $f.png ../res/flags/$newname echo "Generated res/flags/"$newname done diff --git a/scripts/jenkins.sh b/scripts/jenkins.sh index 17f86fe126..4f2e940564 100755 --- a/scripts/jenkins.sh +++ b/scripts/jenkins.sh @@ -34,11 +34,9 @@ npm run lintall -- -f checkstyle -o eslint.xml || true rm dist/riot-*.tar.gz || true # rm previous artifacts without failing if it doesn't exist - # node_modules deps from 'npm install' don't have a .git dir so can't - # rev-parse; but they do set the commit in package.json under 'gitHead' which - # we're grabbing here. -REACT_SHA=$(grep 'gitHead' node_modules/matrix-react-sdk/package.json | cut -d \" -f 4 | head -c 12) -JSSDK_SHA=$(grep 'gitHead' node_modules/matrix-js-sdk/package.json | cut -d \" -f 4 | head -c 12) +# Since the deps are fetched from git, we can rev-parse +REACT_SHA=$(cd node_modules/matrix-react-sdk; git rev-parse --short=12 HEAD) +JSSDK_SHA=$(cd node_modules/matrix-js-sdk; git rev-parse --short=12 HEAD) VECTOR_SHA=$(git rev-parse --short=12 HEAD) # use the ACTUAL SHA rather than assume develop diff --git a/src/components/structures/RightPanel.js b/src/components/structures/RightPanel.js index 2c606e8c1d..7e2b8cb841 100644 --- a/src/components/structures/RightPanel.js +++ b/src/components/structures/RightPanel.js @@ -16,14 +16,15 @@ limitations under the License. 'use strict'; -var React = require('react'); -var sdk = require('matrix-react-sdk'); -var Matrix = require("matrix-js-sdk"); -var dis = require('matrix-react-sdk/lib/dispatcher'); -var MatrixClientPeg = require("matrix-react-sdk/lib/MatrixClientPeg"); -var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); -var Modal = require('matrix-react-sdk/lib/Modal'); -var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); +import React from 'react'; +import { _t } from 'matrix-react-sdk/lib/languageHandler'; +import sdk from 'matrix-react-sdk'; +import Matrix from "matrix-js-sdk"; +import dis from 'matrix-react-sdk/lib/dispatcher'; +import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; +import rate_limited_func from 'matrix-react-sdk/lib/ratelimitedfunc'; +import Modal from 'matrix-react-sdk/lib/Modal'; +import AccessibleButton from 'matrix-react-sdk/lib/components/views/elements/AccessibleButton'; module.exports = React.createClass({ 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 }, - Phase : { + Phase: { MemberList: 'MemberList', FilePanel: 'FilePanel', NotificationPanel: 'NotificationPanel', @@ -100,6 +101,10 @@ module.exports = React.createClass({ }); }, + onLoginClick: function() { + dis.dispatch({ action: 'start_login' }); + }, + onRoomStateMember: function(ev, state, member) { // redraw the badge on the membership list if (this.state.phase == this.Phase.MemberList && member.roomId === this.props.roomId) { @@ -184,7 +189,7 @@ module.exports = React.createClass({
-
Invite to this room
+
{ _t('Invite to this room') }
; } @@ -194,21 +199,21 @@ module.exports = React.createClass({ buttonGroup =
+ title={ _t('Members') } onClick={ this.onMemberListButtonClick }>
{ membersBadge ? membersBadge :  }
{ membersHighlight }
+ title={ _t('Files') } onClick={ this.onFileListButtonClick }>
 
{ filesHighlight }
+ title={ _t('Notifications') } onClick={ this.onNotificationListButtonClick }>
 
{ notificationsHighlight } @@ -217,6 +222,10 @@ module.exports = React.createClass({
; + } else if (MatrixClientPeg.get().isGuest()) { + buttonGroup = + Login + ; } if (!this.props.collapsed) { diff --git a/src/components/structures/RoomDirectory.js b/src/components/structures/RoomDirectory.js index 4f0e585e25..313f535360 100644 --- a/src/components/structures/RoomDirectory.js +++ b/src/components/structures/RoomDirectory.js @@ -30,6 +30,8 @@ var linkifyMatrix = require('matrix-react-sdk/lib/linkify-matrix'); var sanitizeHtml = require('sanitize-html'); var q = require('q'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; + import {instanceForInstanceId, protocolNameForInstanceId} from '../../utils/DirectoryUtils'; linkifyMatrix(linkify); @@ -80,8 +82,8 @@ module.exports = React.createClass({ } const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to get protocol list from Home Server", - description: "The Home Server may be too old to support third party networks", + title: _t('Failed to get protocol list from Home Server'), + 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)); var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to get public room list", - description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"), + title: _t('Failed to get public room list'), + 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) { 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 ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); var desc; 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 { - desc = `Remove '${name}' from the directory?`; + desc = _t('Remove %(name)s from the directory?', {name: name}); } Modal.createDialog(QuestionDialog, { - title: "Remove from Directory", + title: _t('Remove from Directory'), description: desc, onFinished: (should_delete) => { if (!should_delete) return; var Loader = sdk.getComponent("elements.Spinner"); 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(() => { if (!alias) return; - step = 'delete the alias.'; + step = _t('delete the alias') + '.'; return MatrixClientPeg.get().deleteAlias(alias); }).done(() => { modal.close(); @@ -225,8 +227,8 @@ module.exports = React.createClass({ this.refreshRoomList(); console.error("Failed to " + step + ": " + err); Modal.createDialog(ErrorDialog, { - title: "Failed to " + step, - description: ((err && err.message) ? err.message : "The server may be unavailable or overloaded"), + title: _t('Error'), + description: ((err && err.message) ? err.message : _t('The server may be unavailable or overloaded')) }); }); } @@ -314,8 +316,8 @@ module.exports = React.createClass({ if (!fields) { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Unable to join network", - description: "Riot does not know how to join a room on this network", + title: _t('Unable to join network'), + description: _t('Riot does not know how to join a room on this network'), }); return; } @@ -325,15 +327,15 @@ module.exports = React.createClass({ } else { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Room not found", - description: "Couldn't find a matching Matrix room", + title: _t('Room not found'), + description: _t('Couldn\'t find a matching Matrix room'), }); } }, (e) => { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Fetching third party location failed", - description: "Unable to look up room ID from server", + title: _t('Fetching third party location failed'), + description: _t('Unable to look up room ID from server'), }); }); } @@ -364,7 +366,7 @@ module.exports = React.createClass({ avatarUrl: room.avatar_url, // XXX: This logic is duplicated from the JS SDK which // 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 @@ -389,18 +391,18 @@ module.exports = React.createClass({ var self = this; var guestRead, guestJoin, perms; 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; guestJoin = null; if (rooms[i].world_readable) { guestRead = ( -
World readable
+
{ _t('World readable') }
); } if (rooms[i].guest_can_join) { guestJoin = ( -
Guests can join
+
{ _t('Guests can join') }
); } @@ -489,7 +491,7 @@ module.exports = React.createClass({ if (this.state.protocolsLoading) { return (
- +
); @@ -507,7 +509,7 @@ module.exports = React.createClass({ // request from the scrollpanel because there isn't one let scrollpanel_content; if (rows.length == 0) { - scrollpanel_content = No rooms to show; + scrollpanel_content = { _t('No rooms to show') }; } else { scrollpanel_content = @@ -541,9 +543,9 @@ module.exports = React.createClass({ } - let placeholder = 'Search for a room'; + let placeholder = _t('Search for a room'); if (!this.state.instanceId) { - placeholder = '#example:' + this.state.roomServer; + placeholder = _t('#example') + ':' + this.state.roomServer; } else if (instance_expected_field_type) { placeholder = instance_expected_field_type.placeholder; } @@ -560,7 +562,7 @@ module.exports = React.createClass({ const DirectorySearchBox = sdk.getComponent('elements.DirectorySearchBox'); return (
- +
-
more
+
{ _t("more") }
{ content }
); @@ -512,8 +513,8 @@ var RoomSubList = React.createClass({ var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to add tag " + self.props.tagName + " to room" + err); Modal.createDialog(ErrorDialog, { - title: "Failed to add tag " + self.props.tagName + " to room", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to add tag %(tagName)s to room', {tagName: self.props.tagName}), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); break; diff --git a/src/components/structures/SearchBox.js b/src/components/structures/SearchBox.js index 729e7ef772..faee0b5f71 100644 --- a/src/components/structures/SearchBox.js +++ b/src/components/structures/SearchBox.js @@ -17,6 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; var sdk = require('matrix-react-sdk') var dis = require('matrix-react-sdk/lib/dispatcher'); var rate_limited_func = require('matrix-react-sdk/lib/ratelimitedfunc'); @@ -134,7 +135,7 @@ module.exports = React.createClass({ className="mx_SearchBox_search" value={ this.state.searchTerm } onChange={ this.onChange } - placeholder="Filter room names" + placeholder={ _t('Filter room names') } /> ]; } diff --git a/src/components/views/context_menus/MessageContextMenu.js b/src/components/views/context_menus/MessageContextMenu.js index db416b8a06..e135557209 100644 --- a/src/components/views/context_menus/MessageContextMenu.js +++ b/src/components/views/context_menus/MessageContextMenu.js @@ -16,13 +16,14 @@ limitations under the License. 'use strict'; -var React = require('react'); +const React = require('react'); -var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); -var dis = require('matrix-react-sdk/lib/dispatcher'); -var sdk = require('matrix-react-sdk'); -var Modal = require('matrix-react-sdk/lib/Modal'); -var Resend = require("matrix-react-sdk/lib/Resend"); +const MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); +const dis = require('matrix-react-sdk/lib/dispatcher'); +const sdk = require('matrix-react-sdk'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; +const Modal = require('matrix-react-sdk/lib/Modal'); +const Resend = require("matrix-react-sdk/lib/Resend"); import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore'; module.exports = React.createClass({ @@ -45,7 +46,7 @@ module.exports = React.createClass({ }, onViewSourceClick: function() { - var ViewSource = sdk.getComponent('structures.ViewSource'); + const ViewSource = sdk.getComponent('structures.ViewSource'); Modal.createDialog(ViewSource, { content: this.props.mxEvent.event, }, 'mx_Dialog_viewsource'); @@ -70,12 +71,12 @@ module.exports = React.createClass({ MatrixClientPeg.get().redactEvent( this.props.mxEvent.getRoomId(), this.props.mxEvent.getId() ).catch(function(e) { - var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); // display error message stating you couldn't delete this. - var code = e.errcode || e.statusCode; + const code = e.errcode || e.statusCode; Modal.createDialog(ErrorDialog, { - title: "Error", - description: "You cannot delete this message. (" + code + ")" + title: _t('Error'), + description: _t('You cannot delete this message. (%(code)s)', {code: code}) }); }).done(); }, @@ -88,6 +89,14 @@ module.exports = React.createClass({ if (this.props.onFinished) this.props.onFinished(); }, + onForwardClick: function() { + dis.dispatch({ + action: 'forward_event', + content: this.props.mxEvent, + }); + this.closeMenu(); + }, + closeMenu: function() { if (this.props.onFinished) this.props.onFinished(); }, @@ -99,7 +108,7 @@ module.exports = React.createClass({ if (this.props.onFinished) this.props.onFinished(); }, - onQuoteClick: function () { + onQuoteClick: function() { console.log(this.props.mxEvent); dis.dispatch({ action: 'quote', @@ -108,20 +117,21 @@ module.exports = React.createClass({ }, render: function() { - var eventStatus = this.props.mxEvent.status; - var resendButton; - var viewSourceButton; - var viewClearSourceButton; - var redactButton; - var cancelButton; - var permalinkButton; - var unhidePreviewButton; - var externalURLButton; + const eventStatus = this.props.mxEvent.status; + let resendButton; + let redactButton; + let cancelButton; + let forwardButton; + let viewSourceButton; + let viewClearSourceButton; + let unhidePreviewButton; + let permalinkButton; + let externalURLButton; if (eventStatus === 'not_sent') { resendButton = (
- Resend + { _t('Resend') }
); } @@ -129,7 +139,7 @@ module.exports = React.createClass({ if (!eventStatus && !this.props.mxEvent.isRedacted()) { // sent and not redacted redactButton = (
- Redact + { _t('Redact') }
); } @@ -137,21 +147,32 @@ module.exports = React.createClass({ if (eventStatus === "queued" || eventStatus === "not_sent") { cancelButton = (
- Cancel Sending + { _t('Cancel Sending') }
); } + if (!eventStatus && this.props.mxEvent.getType() === 'm.room.message') { + const content = this.props.mxEvent.getContent(); + if (content.msgtype && content.msgtype !== 'm.bad.encrypted' && content.hasOwnProperty('body')) { + forwardButton = ( +
+ Forward Message +
+ ); + } + } + viewSourceButton = (
- View Source + { _t('View Source') }
); if (this.props.mxEvent.getType() !== this.props.mxEvent.getWireType()) { viewClearSourceButton = (
- View Decrypted Source + { _t('View Decrypted Source') }
); } @@ -160,9 +181,9 @@ module.exports = React.createClass({ if (this.props.eventTileOps.isWidgetHidden()) { unhidePreviewButton = (
- Unhide Preview + { _t('Unhide Preview') }
- ) + ); } } @@ -170,13 +191,13 @@ module.exports = React.createClass({ permalinkButton = (
Permalink + target="_blank" rel="noopener" onClick={ this.closeMenu }>{ _t('Permalink') }
); const quoteButton = (
- Quote + { _t('Quote') }
); @@ -185,7 +206,7 @@ module.exports = React.createClass({ externalURLButton = (
Source URL + rel="noopener" target="_blank" onClick={ this.closeMenu }>{ _t('Source URL') }
); } @@ -196,6 +217,7 @@ module.exports = React.createClass({ {resendButton} {redactButton} {cancelButton} + {forwardButton} {viewSourceButton} {viewClearSourceButton} {unhidePreviewButton} @@ -204,5 +226,5 @@ module.exports = React.createClass({ {externalURLButton}
); - } + }, }); diff --git a/src/components/views/context_menus/RoomTileContextMenu.js b/src/components/views/context_menus/RoomTileContextMenu.js index 7efa68485c..a7b19689fe 100644 --- a/src/components/views/context_menus/RoomTileContextMenu.js +++ b/src/components/views/context_menus/RoomTileContextMenu.js @@ -21,6 +21,7 @@ import q from 'q'; import React from 'react'; import classNames from 'classnames'; import sdk from 'matrix-react-sdk'; +import { _t } from 'matrix-react-sdk/lib/languageHandler'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import dis from 'matrix-react-sdk/lib/dispatcher'; import DMRoomMap from 'matrix-react-sdk/lib/utils/DMRoomMap'; @@ -70,8 +71,8 @@ module.exports = React.createClass({ }).fail(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to remove tag " + tagNameOff + " from room", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to remove tag %(tagName)s from room', {tagName: tagNameOff}), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); } @@ -87,8 +88,8 @@ module.exports = React.createClass({ }).fail(function(err) { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to add tag " + tagNameOn + " to room", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to remove tag %(tagName)s from room', {tagName: tagNameOn}), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); } @@ -148,8 +149,8 @@ module.exports = React.createClass({ }, (err) => { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Failed to set Direct Message status of room", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to set Direct Message status of room'), + 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 ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: `Failed to forget room (${errCode})`, - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to forget room %(errCode)s', {errCode: errCode}), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); @@ -274,22 +275,22 @@ module.exports = React.createClass({
- All messages (loud) + { _t('All messages (loud)') }
- All messages + { _t('All messages') }
- Mentions only + { _t('Mentions only') }
- Mute + { _t('Mute') }
); @@ -306,16 +307,16 @@ module.exports = React.createClass({ switch (membership) { case "join": leaveClickHandler = this._onClickLeave; - leaveText = "Leave"; + leaveText = _t('Leave'); break; case "leave": case "ban": leaveClickHandler = this._onClickForget; - leaveText = "Forget"; + leaveText = _t('Forget'); break; case "invite": leaveClickHandler = this._onClickReject; - leaveText = "Reject"; + leaveText = _t('Reject'); break; } @@ -353,17 +354,17 @@ module.exports = React.createClass({
- Favourite + { _t('Favourite') }
- Low Priority + { _t('Low Priority') }
- Direct Chat + { _t('Direct Chat') }
); diff --git a/src/components/views/elements/ImageView.js b/src/components/views/elements/ImageView.js index ab3e9ee8f0..dd0490ac0c 100644 --- a/src/components/views/elements/ImageView.js +++ b/src/components/views/elements/ImageView.js @@ -25,6 +25,7 @@ var filesize = require('filesize'); var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); const Modal = require('matrix-react-sdk/lib/Modal'); const sdk = require('matrix-react-sdk'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; module.exports = React.createClass({ displayName: 'ImageView', @@ -76,8 +77,8 @@ module.exports = React.createClass({ // display error message stating you couldn't delete this. var code = e.errcode || e.statusCode; Modal.createDialog(ErrorDialog, { - title: "Error", - description: "You cannot delete this image. (" + code + ")" + title: _t('Error'), + description: _t('You cannot delete this image. (%(code)s)', {code: code}) }); }).done(); } @@ -150,14 +151,14 @@ module.exports = React.createClass({ var eventMeta; if(showEventMeta) { eventMeta = (
- 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()}) }
); } var eventRedact; if(showEventMeta) { eventRedact = (
- Redact + { _t('Redact') }
); } @@ -169,7 +170,7 @@ module.exports = React.createClass({
- Close + {
@@ -178,7 +179,7 @@ module.exports = React.createClass({ { eventMeta }
- Download this file
+ { _t('Download this file') }
{ size_res }
diff --git a/src/components/views/globals/MatrixToolbar.js b/src/components/views/globals/MatrixToolbar.js index dbe4196aad..6d47ad1b9e 100644 --- a/src/components/views/globals/MatrixToolbar.js +++ b/src/components/views/globals/MatrixToolbar.js @@ -17,6 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; var Notifier = require("matrix-react-sdk/lib/Notifier"); var sdk = require('matrix-react-sdk') var AccessibleButton = require('matrix-react-sdk/lib/components/views/elements/AccessibleButton'); @@ -37,7 +38,7 @@ module.exports = React.createClass({
/!\
- You are not receiving desktop notifications. Enable them now + { _t('You are not receiving desktop notifications') } { _t('Enable them now') }
diff --git a/src/components/views/login/VectorCustomServerDialog.js b/src/components/views/login/VectorCustomServerDialog.js index 65ec1f84ba..d7fe545a0a 100644 --- a/src/components/views/login/VectorCustomServerDialog.js +++ b/src/components/views/login/VectorCustomServerDialog.js @@ -15,6 +15,7 @@ limitations under the License. */ var React = require("react"); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; module.exports = React.createClass({ displayName: 'VectorCustomServerDialog', @@ -26,24 +27,14 @@ module.exports = React.createClass({ return (
- Custom Server Options + { _t('Custom Server Options') }
- - You can use the custom server options to sign into other Matrix - servers by specifying a different Home server URL. -
- This allows you to use Riot with an existing Matrix account on - a different home server. -
-
- 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. -
+
diff --git a/src/components/views/login/VectorLoginFooter.js b/src/components/views/login/VectorLoginFooter.js index 1382a86277..e905afc1de 100644 --- a/src/components/views/login/VectorLoginFooter.js +++ b/src/components/views/login/VectorLoginFooter.js @@ -17,6 +17,7 @@ limitations under the License. 'use strict'; var React = require('react'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; module.exports = React.createClass({ displayName: 'VectorLoginFooter', @@ -30,7 +31,7 @@ module.exports = React.createClass({ blog  ·   twitter  ·   github  ·   - powered by Matrix + { _t('powered by Matrix') }
); } diff --git a/src/components/views/messages/DateSeparator.js b/src/components/views/messages/DateSeparator.js index 89cc44db89..7acc9bd61e 100644 --- a/src/components/views/messages/DateSeparator.js +++ b/src/components/views/messages/DateSeparator.js @@ -14,19 +14,21 @@ See the License for the specific language governing permissions and limitations under the License. */ -'use strict'; +import React from 'react'; +import { _t } from 'matrix-react-sdk/lib/languageHandler'; +import DateUtils from 'matrix-react-sdk/lib/DateUtils'; -var React = require('react'); - -var days = [ - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday" -]; +function getdaysArray() { + return [ + _t('Sunday'), + _t('Monday'), + _t('Tuesday'), + _t('Wednesday'), + _t('Thursday'), + _t('Friday'), + _t('Saturday'), + ]; +} module.exports = React.createClass({ displayName: 'DateSeparator', @@ -34,19 +36,20 @@ module.exports = React.createClass({ var date = new Date(this.props.ts); var today = new Date(); var yesterday = new Date(); + var days = getdaysArray(); yesterday.setDate(today.getDate() - 1); var label; if (date.toDateString() === today.toDateString()) { - label = "Today"; + label = _t('Today'); } else if (date.toDateString() === yesterday.toDateString()) { - label = "Yesterday"; + label = _t('Yesterday'); } else if (today.getTime() - date.getTime() < 6 * 24 * 60 * 60 * 1000) { label = days[date.getDay()]; } else { - label = date.toDateString(); + label = DateUtils.formatFullDate(date); } return ( diff --git a/src/components/views/messages/MessageTimestamp.js b/src/components/views/messages/MessageTimestamp.js index a97f54b173..dacfad925a 100644 --- a/src/components/views/messages/MessageTimestamp.js +++ b/src/components/views/messages/MessageTimestamp.js @@ -16,19 +16,23 @@ limitations under the License. 'use strict'; -var React = require('react'); -var DateUtils = require('matrix-react-sdk/lib/DateUtils'); +import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore'; +const React = require('react'); +const DateUtils = require('matrix-react-sdk/lib/DateUtils'); module.exports = React.createClass({ displayName: 'MessageTimestamp', + propTypes: { + showTwelveHour: React.PropTypes.bool, + }, + render: function() { - var date = new Date(this.props.ts); + const date = new Date(this.props.ts); return ( - { DateUtils.formatTime(date) } + { DateUtils.formatTime(date, this.props.showTwelveHour) } ); }, }); - diff --git a/src/components/views/rooms/DNDRoomTile.js b/src/components/views/rooms/DNDRoomTile.js index 4bcf29ed9a..6abb5bd06c 100644 --- a/src/components/views/rooms/DNDRoomTile.js +++ b/src/components/views/rooms/DNDRoomTile.js @@ -23,6 +23,7 @@ import {DropTarget} from 'react-dnd'; import dis from 'matrix-react-sdk/lib/dispatcher'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; import sdk from 'matrix-react-sdk'; +import { _t } from 'matrix-react-sdk/lib/languageHandler'; import RoomTile from 'matrix-react-sdk/lib/components/views/rooms/RoomTile'; import * as Rooms from 'matrix-react-sdk/lib/Rooms'; import Modal from 'matrix-react-sdk/lib/Modal'; @@ -90,8 +91,8 @@ var roomTileSource = { const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to set direct chat tag " + err); Modal.createDialog(ErrorDialog, { - title: "Failed to set direct chat tag", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to set direct chat tag'), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); return; @@ -115,8 +116,8 @@ var roomTileSource = { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to remove tag " + prevTag + " from room: " + err); Modal.createDialog(ErrorDialog, { - title: "Failed to remove tag " + prevTag + " from room", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to remove tag %(tagName)s from room', {tagName: prevTag}), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); } @@ -137,8 +138,8 @@ var roomTileSource = { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to add tag " + newTag + " to room: " + err); Modal.createDialog(ErrorDialog, { - title: "Failed to add tag " + newTag + " to room", - description: ((err && err.message) ? err.message : "Operation failed"), + title: _t('Failed to add tag %(tagName)s to room', {tagName: newTag}), + description: ((err && err.message) ? err.message : _t('Operation failed')), }); }); } @@ -241,4 +242,3 @@ DragSource('RoomTile', roomTileSource, function(connect, monitor) { isDragging: monitor.isDragging() }; })(RoomTile)); - diff --git a/src/components/views/settings/Notifications.js b/src/components/views/settings/Notifications.js index 11dc79ac20..11948acebe 100644 --- a/src/components/views/settings/Notifications.js +++ b/src/components/views/settings/Notifications.js @@ -16,6 +16,7 @@ limitations under the License. 'use strict'; var React = require('react'); +import { _t } from 'matrix-react-sdk/lib/languageHandler'; var q = require("q"); var sdk = require('matrix-react-sdk'); var MatrixClientPeg = require('matrix-react-sdk/lib/MatrixClientPeg'); @@ -131,8 +132,8 @@ module.exports = React.createClass({ }, (error) => { var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createDialog(ErrorDialog, { - title: "Error saving email notification preferences", - description: "An error occurred whilst saving your email notification preferences.", + title: _t('Error saving email notification preferences'), + description: _t('An error occurred whilst saving your email notification preferences.'), }); }); }, @@ -175,8 +176,8 @@ module.exports = React.createClass({ var TextInputDialog = sdk.getComponent("dialogs.TextInputDialog"); Modal.createDialog(TextInputDialog, { - title: "Keywords", - description: "Enter keywords separated by a comma:", + title: _t('Keywords'), + description: _t('Enter keywords separated by a comma:'), value: keywords, onFinished: function onFinished(should_leave, newValue) { @@ -240,8 +241,8 @@ module.exports = React.createClass({ var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to change settings: " + error); Modal.createDialog(ErrorDialog, { - title: "Failed to change settings", - description: ((error && error.message) ? error.message : "Operation failed"), + title: _t('Failed to change settings'), + description: ((error && error.message) ? error.message : _t('Operation failed')), onFinished: self._refreshFromServer }); }); @@ -310,8 +311,8 @@ module.exports = React.createClass({ var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Can't update user notification settings: " + error); Modal.createDialog(ErrorDialog, { - title: "Can't update user notification settings", - description: ((error && error.message) ? error.message : "Operation failed"), + title: _t('Can\'t update user notification settings'), + description: ((error && error.message) ? error.message : _t('Operation failed')), onFinished: self._refreshFromServer }); }); @@ -352,8 +353,8 @@ module.exports = React.createClass({ var ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); console.error("Failed to update keywords: " + error); Modal.createDialog(ErrorDialog, { - title: "Failed to update keywords", - description: ((error && error.message) ? error.message : "Operation failed"), + title: _t('Failed to update keywords'), + description: ((error && error.message) ? error.message : _t('Operation failed')), onFinished: self._refreshFromServer }); } @@ -562,8 +563,8 @@ module.exports = React.createClass({ // Build the rules not managed by Vector UI var otherRulesDescriptions = { - '.m.rule.message': "Notify for all other messages/rooms", - '.m.rule.fallback': "Notify me for anything else" + '.m.rule.message': _t('Notify for all other messages/rooms'), + '.m.rule.fallback': _t('Notify me for anything else'), }; for (var i in defaultRules.others) { @@ -698,7 +699,7 @@ module.exports = React.createClass({
@@ -713,7 +714,7 @@ module.exports = React.createClass({ {masterPushRuleDiv}
- All notifications are currently disabled for all targets. + { _t('All notifications are currently disabled for all targets.') }.
); @@ -723,13 +724,13 @@ module.exports = React.createClass({ let emailNotificationsRow; if (emailThreepids.length === 0) { emailNotificationsRow =
- Add an email address above to configure email notifications + { _t('Add an email address above to configure email notifications') }
; } else { // This only supports the first email address in your profile for now emailNotificationsRow = this.emailNotificationsRow( emailThreepids[0].address, - "Enable email notifications ("+emailThreepids[0].address+")" + _t('Enable email notifications') + ' (' + emailThreepids[0].address + ')' ); } @@ -737,7 +738,7 @@ module.exports = React.createClass({ var externalRules = []; for (var i in this.state.externalPushRules) { var rule = this.state.externalPushRules[i]; - externalRules.push(
  • { rule.description }
  • ); + externalRules.push(
  • { _t(rule.description) }
  • ); } // Show keywords not displayed by the vector UI as a single external push rule @@ -748,12 +749,12 @@ module.exports = React.createClass({ } if (externalKeyWords.length) { externalKeyWords = externalKeyWords.join(", "); - externalRules.push(
  • Notifications on the following keywords follow rules which can’t be displayed here: { externalKeyWords }
  • ); + externalRules.push(
  • { _t('Notifications on the following keywords follow rules which can’t be displayed here:') } { externalKeyWords }
  • ); } var devicesSection; if (this.state.pushers === undefined) { - devicesSection =
    Unable to fetch notification target list
    + devicesSection =
    { _t('Unable to fetch notification target list') }
    } else if (this.state.pushers.length == 0) { devicesSection = null; } else { @@ -774,7 +775,7 @@ module.exports = React.createClass({ } if (devicesSection) { devicesSection = (
    -

    Notification targets

    +

    { _t('Notification targets') }

    { devicesSection }
    ); } @@ -783,9 +784,9 @@ module.exports = React.createClass({ if (externalRules.length) { advancedSettings = (
    -

    Advanced notifications settings

    - There are advanced notifications which are not shown here.
    - You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply. +

    { _t('Advanced notification settings') }

    + { _t('There are advanced notifications which are not shown here') }.
    + { _t('You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply') }. @@ -812,7 +813,7 @@ module.exports = React.createClass({
    @@ -830,7 +831,7 @@ module.exports = React.createClass({
    @@ -842,9 +843,9 @@ module.exports = React.createClass({ - - - + + + diff --git a/src/i18n/strings/basefile.json b/src/i18n/strings/basefile.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/i18n/strings/basefile.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/i18n/strings/be.json b/src/i18n/strings/be.json new file mode 100644 index 0000000000..18b0179ab8 --- /dev/null +++ b/src/i18n/strings/be.json @@ -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 %(toAction)s": "Перацягнуць сюды %(toAction)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 %(tagName)s from room": "Не ўдалося выдаліць %(tagName)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 can’t 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": " ў пакоі" +} diff --git a/src/i18n/strings/da.json b/src/i18n/strings/da.json new file mode 100644 index 0000000000..780d0bbb41 --- /dev/null +++ b/src/i18n/strings/da.json @@ -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 can’t 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" +} diff --git a/src/i18n/strings/de_DE.json b/src/i18n/strings/de_DE.json new file mode 100644 index 0000000000..d030e29d1a --- /dev/null +++ b/src/i18n/strings/de_DE.json @@ -0,0 +1,131 @@ +{ + "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", + "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 ist eventuell zu alt, 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:": "Trage Schlagworte, mit Komma getrennt, 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": "Einstellungen konnten nicht geändert werden", + "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 can’t 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": "Aktion 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 %(toAction)s": "%(toAction)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 %(tagName)s from room": "Das Entfernen des Tags %(tagName)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": "Stummschalten", + "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", + "Advanced notification settings": "Erweiterte Benachrichtigungs-Einstellungen", + "Call invitation": "Anruf-Einladung", + "Messages containing my display name": "Nachrichten, die meinen Anzeigenamen enthalten", + "Messages containing my user name": "Nachrichten, die meinen Nutzernamen enthalten", + "Messages in group chats": "Nachrichten in Chat-Gruppen", + "Messages in one-to-one chats": "Nachrichten in Eins-zu-Eins-Chats", + "Messages sent by bot": "Nachrichten von Bots", + "more": "mehr", + "When I'm invited to a room": "Wenn ich in einen Raum eingeladen werde", + "customServer_text": "Du kannst die erweiterten Server-Optioen nutzen um dich an anderen Matrix-Servern mittels anderer Heimserver-URL anzumelden.
    Dies erlaubt dir Riot mit einem existierendem Konto auf einem anderen Heimserver zu nutzen.

    Du kannst auch einen benutzerdefinierten Identitäts-Server setzen, aber du wirst dann nicht in der Lage sein, Nutzer per E-Mail-Adresse einzuladen oder selbst mit E-Mail-Adresse eingeladen zu werden." +} diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json new file mode 100644 index 0000000000..039f5b76d3 --- /dev/null +++ b/src/i18n/strings/en_EN.json @@ -0,0 +1,122 @@ +{ + "Add an email address above to configure email notifications": "Add an email address above to configure email notifications", + "Advanced notification settings": "Advanced notification settings", + "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", + "customServer_text": "You can use the custom server options to sign into other Matrix servers by specifying a different Home server URL.
    This allows you to use Riot with an existing Matrix account on a different home server.

    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.", + "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 %(toAction)s": "Drop here %(toAction)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 %(tagName)s from room": "Failed to remove tag %(tagName)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 can’t be displayed here:": "Notifications on the following keywords follow rules which can’t 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" +} diff --git a/src/i18n/strings/es.json b/src/i18n/strings/es.json new file mode 100644 index 0000000000..beef27c12f --- /dev/null +++ b/src/i18n/strings/es.json @@ -0,0 +1,116 @@ +{ + "Add an email address above to configure email notifications": "Añade una dirección de email arriba para configurar las notificaciones por email", + "Advanced notification settings": "Configuración de notificaciones avanzada", + "All messages": "Todos los mensajes", + "An error occurred whilst saving your email notification preferences.": "Se ha producido un error al guardar las preferencias de notificación por email.", + "Call invitation": "Invitación a la llamada", + "Cancel Sending": "Cancelar envío", + "Can't update user notification settings": "No se puede actualizar la configuración de notificación de usuario", + "Close": "Cerrar", + "Create new room": "Crear nueva sala", + "Couldn't find a matching Matrix room": "No se encontró una sala Matrix que coincidiera", + "Custom Server Options": "Opciones de Servidor Personalizado", + "customServer_text": "Puedes utilizar las opciones de servidor personalizadas para iniciar sesión en otros servidores Matrix especificando una URL de Home server distinta.
    Esto te permite usar Riot con una cuenta Matrix existente en un Home server distinto.

    También puedes configurar un servidor de identidad personalizado, pero no podrás invitar usuarios por dirección de email, ni ser invitado por email por ti mismo.", + "delete the alias": "borrar el alias", + "Delete the room alias %(alias)s and remove %(name)s from the directory?": "¿Borrar la sala alias %(alias)s y retirar %(name)s del directorio?", + "Direct Chat": "Chat Directo", + "Directory": "Directorio", + "Download this file": "Descargar este archivo", + "Drop here %(toAction)s": "Soltar aquí %(toAction)s", + "Enable audible notifications in web client": "Habilitar notificaciones audibles en el cliente web", + "Enable desktop notifications": "Habilitar notificaciones de escritorio", + "Enable email notifications": "Habilitar notificaciones por email", + "Enable notifications for this account": "Habilitar notificaciones para esta cuenta", + "Enable them now": "Habilitarlos ahora", + "Enter keywords separated by a comma:": "Introduzca palabras clave separadas por una coma:", + "Error": "Error", + "Error saving email notification preferences": "Error al guardar las preferencias de notificación por email", + "#example": "#ejemplo", + "Failed to add tag %(tagName)s to room": "Error al añadir la etiqueta %(tagName)s a la sala", + "Failed to change settings": "Error al cambiar la configuración", + "Failed to forget room %(errCode)s": "No se pudo olvidar la habitación %(errCode)s", + "Failed to update keywords": "Error al actualizar las palabras clave", + "Failed to get protocol list from Home Server": "Error al obtener la lista de protocolos de Home Server", + "Failed to get public room list": "No se pudo obtener la lista de salas públicas", + "Failed to join the room": "No se puede unir a la habitación", + "Failed to remove tag %(tagName)s from room": "Error al eliminar la etiqueta %(tagName)s de la sala", + "Failed to set direct chat tag": "Error al establecer la etiqueta de chat directo", + "Failed to set Direct Message status of room": "No se pudo establecer el estado de Mensaje Directo de la sala", + "Favourite": "Favorito", + "Fetching third party location failed": "Falló la obtención de la ubicación de un tercero", + "Files": "Archivos", + "Filter room names": "Filtrar los nombres de las salas", + "Forget": "Olvidar", + " from room": " de la sala", + "Guests can join": "Los invitados se pueden unir", + "Guest users can't invite users. Please register to invite": "Los usuarios invitados no pueden invitar usuarios. Por favor, regístrate para poder invitar", + "Invite to this room": "Invitar a esta sala", + "Keywords": "Palabras clave", + "Leave": "Salir", + "Low Priority": "Baja Prioridad", + "Members": "Miembros", + "Mentions only": "Sólo menciones", + "Messages containing my display name": "Mensajes que contienen mi nombre para mostrar", + "Messages containing my user name": "Mensajes que contienen mi nombre de usuario", + "Messages in group chats": "Mensajes en chats de grupo", + "Messages in one-to-one chats": "Mensajes en chats uno a uno", + "Messages sent by bot": "Mensajes enviados por bot", + "more": "más", + "Mute": "Mute", + "No rooms to show": "Sin salas para mostrar", + "Noisy": "Ruidoso", + "Notification targets": "Objetivos de notificación", + "Notifications": "Notificaciones", + "Notifications on the following keywords follow rules which can’t be displayed here:": "Las notificaciones de las siguientes palabras clave siguen reglas que no se pueden mostrar aquí:", + "Notify me for anything else": "Notificarme para cualquier otra cosa", + "Off": "Apagado", + "On": "Encendido", + "Operation failed": "Operación fallida", + "Permalink": "Enlace permanente", + "Please Register": "Por favor regístrate", + "Quote": "Citar", + "Redact": "Redactar", + "Reject": "Rechazar", + "Remove %(name)s from the directory?": "¿Retirar %(name)s del directorio?", + "Remove": "Eliminar", + "remove %(name)s from the directory": "retirar %(name)s del directorio", + "Remove from Directory": "Retirar del Directorio", + "Resend": "Reenviar", + "Riot does not know how to join a room on this network": "Riot no sabe cómo unirse a una sala en esta red", + "Room directory": "Directorio de salas", + "Room not found": "Sala no encontrada", + "Search for a room": "Buscar sala", + "Settings": "Ajustes", + "Source URL": "URL de origen", + "Start chat": "Comenzar chat", + "The Home Server may be too old to support third party networks": "El Home Server puede ser demasiado antiguo para soportar redes de terceros", + "There are advanced notifications which are not shown here": "Hay notificaciones avanzadas que no se muestran aquí", + "The server may be unavailable or overloaded": "El servidor puede estar no disponible o sobrecargado", + "This room is inaccessible to guests. You may be able to join if you register": "Esta sala es inaccesible para los invitados. Puedes unirse si te registras", + " to room": " a la sala", + "Unable to fetch notification target list": "No se puede obtener la lista de objetivos de notificación", + "Unable to join network": "No se puede unir a la red", + "Unable to look up room ID from server": "No se puede buscar el ID de la sala desde el servidor", + "Unhide Preview": "Mostrar Vista Previa", + "unknown error code": "Código de error desconocido", + "Unnamed room": "Sala sin nombre", + "Uploaded on %(date)s by %(user)s": "Subido el %(date)s por %(user)s", + "View Decrypted Source": "Ver Fuente Descifrada", + "View Source": "Ver Fuente", + "When I'm invited to a room": "Cuando estoy invitado a una sala", + "World readable": "Legible por todo el mundo", + "You cannot delete this image. (%(code)s)": "No puedes eliminar esta imagen. (%(code)s)", + "You cannot delete this message. (%(code)s)": "No puedes eliminar este mensaje. (%(code)s)", + "You are not receiving desktop notifications": "No estás recibiendo notificaciones de escritorio", + "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Es posible que los hayas configurado en un cliente que no sea Riot. No puedes ajustarlos en Riot, pero todavía se aplican", + "Sunday": "Domingo", + "Monday": "Lunes", + "Tuesday": "Martes", + "Wednesday": "Miércoles", + "Thursday": "Jueves", + "Friday": "Viernes", + "Saturday": "Sábado", + "Today": "Hoy", + "Yesterday": "Ayer", + "Welcome page": "Página de bienvenida" +} diff --git a/src/i18n/strings/fi.json b/src/i18n/strings/fi.json new file mode 100644 index 0000000000..d2e594327d --- /dev/null +++ b/src/i18n/strings/fi.json @@ -0,0 +1,3 @@ +{ + "Sunday": "Sunnuntai" +} diff --git a/src/i18n/strings/fr.json b/src/i18n/strings/fr.json new file mode 100644 index 0000000000..dfd38e868a --- /dev/null +++ b/src/i18n/strings/fr.json @@ -0,0 +1,124 @@ +{ + "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 notifications 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 par e-mail", + "Cancel Sending": "Annuler l'envoi", + "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 l'alias %(alias)s du salon et supprimer %(name)s du répertoire ?", + "Direct Chat": "Conversation Directe", + "Directory": "Répertoire", + "Dismiss": "Rejeter", + "Download this file": "Télécharger ce fichier", + "Drop here %(toAction)s": "Déposer ici pour %(toAction)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 de l'adhésion au salon", + "Failed to remove tag %(tagName)s from room": "Échec dans la suppression de l’étiquette %(tagName)s du salon", + "Failed to set direct chat tag": "Échec dans l'attribution d'une étiquette dans le chat direct", + "Favourite": "Favoris", + "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 une 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 d'accueil", + "Call invitation": "Appel entrant", + "Failed to set Direct Message status of room": "Échec de la configuration de l'état de Message Direct du salon", + "Fetching third party location failed": "Échec de la récupération de la localisation tierce", + "Files": "Fichiers", + "Filter room names": "Filtrer les noms des salons", + "Forget": "Oublier", + " from room": " du salon", + "Guest users can't invite users. Please register to invite": "Les invités ne peuvent démarrer une discussion. Merci de vous enregistrer pour pouvoir démarrer une discussion", + "Invite to this room": "Inviter dans ce salon", + "Keywords": "Mots-clés", + "Leave": "Quitter", + "Low Priority": "Priorité Basse", + "Members": "Membres", + "Mentions only": "Seulement les mentions", + "Messages containing my display name": "Messages contenant mon nom", + "Messages containing my user name": "Message contenant mon nom d'utilisateur", + "Messages in group chats": "Messages dans les conversations de groupe", + "Messages in one-to-one chats": "Messages dans les conversations directes", + "Messages sent by bot": "Messages envoyés par des robots", + "more": "plus", + "Mute": "Muet", + "No rooms to show": "Aucun salon à afficher", + "Noisy": "Sonore", + "Notification targets": "Appareils recevant les notifications", + "Notifications": "Notifications", + "Notifications on the following keywords follow rules which can’t be displayed here": "Les mots-clés suivants suivent des règles de notification qui ne peuvent être affichées ici", + "Notify for all other messages/rooms": "Me notifier pour tous les autres messages/salons", + "Notify me for anything else": "Me notifier pour tout le reste", + "Off": "Désactivé", + "On": "Activé", + "Permalink": "Permalien", + "remove %(name)s from the directory": "supprimer %(name)s du répertoire", + "Remove from Directory": "Supprimer du répertoire", + "Riot does not know how to join a room on this network": "Riot ne peut pas joindre un salon sur ce réseau", + "Room directory": "Répertoire des salons", + "Room not found": "Salon non trouvé", + "Search for a room": "Chercher un salon", + "Source URL": "URL source", + "The Home Server may be too old to support third party networks": "Le Home Server semble trop ancien pour supporter des réseaux tiers", + "There are advanced notifications which are not shown here": "Il existe une configuration avancée des notifications qui ne peut être affichée ici", + "The server may be unavailable or overloaded": "Le serveur est indisponible ou surchargé", + "This room is inaccessible to guests. You may be able to join if you register": "Ce salon n'est pas ouvert aux invités. Vous pourrez peut-être le rejoindre si vous vous enregistrez", + "Unable to fetch notification target list": "Impossible de récupérer la liste des appareils recevant les notifications", + "Unable to join network": "Impossible de rejoindre le réseau", + "Unable to look up room ID from server": "Impossible de récupérer l'ID du salon sur le serveur", + "Unhide Preview": "Dévoiler l'aperçu", + "Unnamed room": "Salon anonyme", + "Uploaded on %(date)s by %(user)s": "Téléchargé le %(date)s par %(user)s", + "View Decrypted Source": "Voir la source décryptée", + "When I'm invited to a room": "Quand je suis invité dans un salon", + "World readable": "Visible par tout le monde", + "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Vous les avez probablement configurées dans un autre client que Riot. Vous ne pouvez pas les configurer dans Riot mais elles s'appliquent quand même", + "Guests can join": "Ouvert aux invités", + " to room": " au salon", + "Advanced notification settings": "Paramètres de notifications avancés", + "An error occurred whilst saving your email notification preferences.": "Une erreur est survenue lors de la sauvegarde de vos préférences de notifications mail.", + "customServer_text": "Vous pouvez utiliser l'option de serveur personnalisé pour vous connectez à d'autres serveurs Matrix, en spécifiant une adresse différente pour Home serveur.
    Cela permet d'utiliser Riot avec un compte existant sur un Home serveur différent.

    Vous pouvez aussi indiquer un serveur d'identité personnel mais vous ne pourrez plus inviter des utilisateurs par email, ou être invité par email.", + "Notifications on the following keywords follow rules which can’t be displayed here:": "Les notifications pour les mots clés suivant répondent à des critères qui ne peuvent pas être affichés ici :" +} diff --git a/src/i18n/strings/hu.json b/src/i18n/strings/hu.json new file mode 100644 index 0000000000..09fa3df9e0 --- /dev/null +++ b/src/i18n/strings/hu.json @@ -0,0 +1,68 @@ +{ + "Add an email address above to configure email notifications": "E-mail értesítés beállításához írd be az e-mail címed", + "Advanced notification settings": "Haladó értesítési beállítások", + "All messages": "Minden üzenet", + "All messages (loud)": "Minden üzenet (hangos)", + "All notifications are currently disabled for all targets.": "Minden céleszközön minden értesítés tiltva van.", + "An error occurred whilst saving your email notification preferences.": "Hiba történt az e-mail értesítés beállításánál.", + "Call invitation": "Hívás meghívó", + "Cancel Sending": "Küldés megszakítása", + "Can't update user notification settings": "Nem sikerül frissíteni az értesítési beállításokat", + "Close": "Bezár", + "Create new room": "Új szoba készítés", + "Couldn't find a matching Matrix room": "Nem található a keresett Matrix szoba", + "Custom Server Options": "Egyedi szerver beállítások", + "delete the alias": "becenév törlése", + "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Törlöd a(z) %(alias)s szobát és kiveszed a könyvtárból ezt: %(name)s?", + "Direct Chat": "Közvetlen csevegés", + "Directory": "Könyvtár", + "Dismiss": "Eltűntet", + "Download this file": "Fájl letöltése", + "Drop here %(toAction)s": "%(toAction)s -t húzd ide", + "Enable audible notifications in web client": "Hallható értesítések engedélyezése a webes kliensben", + "Enable desktop notifications": "Asztali értesítések engedélyezése", + "Enable email notifications": "E-mail értesítések engedélyezése", + "Enable notifications for this account": "Értesítések engedélyezése a fiókhoz", + "Enable them now": "Engedélyezés most", + "Enter keywords separated by a comma:": "Kulcsszavak vesszővel elválasztva:", + "Error": "Hiba", + "Error saving email notification preferences": "Hiba email értesítés beállításának mentésénél", + "#example": "#példa", + "Failed to": "Nem lehet", + "Failed to add tag %(tagName)s to room": "Nem lehet a címkét hozzáadni a szobához: %(tagName)s", + "Failed to change settings": "Nem lehet a beállítást megváltoztatni", + "Failed to forget room %(errCode)s": "Nem lehet eltávolítani a szobát: %(errCode)s", + "Failed to update keywords": "Nem lehet a kulcsszavakat frissíteni", + "Failed to get protocol list from Home Server": "Nem lehet a protokoll listát lekérni a Saját szerverről", + "Failed to get public room list": "Nem lehet lekérdezni a nyílt szobák listáját", + "Failed to join the room": "Nem lehet csatlakozni a szobához", + "Failed to remove tag %(tagName)s from room": "Nem lehet törölni a(z) %(tagName)s címkét a szobáról", + "Failed to set direct chat tag": "Nem lehet a címkét beállítani a közvetlen beszélgetéshez", + "Failed to set Direct Message status of room": "Nem lehet beállítani a Közvetlen beszélgetés státuszt a szobához", + "Favourite": "Kedvenc", + "Fetching third party location failed": "Nem sikerült lekérdezni a harmadik felet", + "Files": "Fájlok", + "Filter room names": "Szoba nevek szűrése", + "Forget": "Elfelejt", + " from room": " szobából", + "Guests can join": "Vendégek csatlakozhatnak", + "Guest users can't invite users. Please register to invite": "Vendég felhasználó nem küldhet meghívót. Kérlek regisztrálj meghívó küldéshez", + "Invite to this room": "Meghívás a szobába", + "Keywords": "Kulcsszavak", + "Leave": "Elhagy", + "Low Priority": "Alacsony priorítás", + "Members": "Résztvevők", + "Mentions only": "Csak ha megemlítenek", + "Messages containing my display name": "Az üzenet tartalmazza a nevem", + "Messages containing my user name": "Az üzenet tartalmazza a felhasználói nevem", + "Messages in group chats": "Üzenetek a csoportszobában", + "Messages in one-to-one chats": "Üzenetek közvetlen beszélgetésekben", + "Messages sent by bot": "Botok által küldött üzenetek", + "more": "további", + "Mute": "Elnémít", + "No rooms to show": "Nincs megjeleníthető szoba", + "Noisy": "Hangos", + "Notification targets": "Értesítések célpontja", + "Notifications": "Értesítések", + "Notify for all other messages/rooms": "Értesítés minden más üzenethez/szobához" +} diff --git a/src/i18n/strings/ml.json b/src/i18n/strings/ml.json new file mode 100644 index 0000000000..e67ece484c --- /dev/null +++ b/src/i18n/strings/ml.json @@ -0,0 +1,5 @@ +{ + "Add an email address above to configure email notifications": "ഇ മെയില്‍ അറിയിപ്പുകൾ ലഭിക്കാന്‍ മുകളില്‍ ഇ-മെയില്‍ വിലാസം നല്‍കൂ", + "All messages": "എല്ലാ സന്ദേശങ്ങളും", + "All messages (loud)": "എല്ലാ സന്ദേശങ്ങളും (ഉച്ചത്തിൽ)" +} \ No newline at end of file diff --git a/src/i18n/strings/nb_NO.json b/src/i18n/strings/nb_NO.json new file mode 100644 index 0000000000..ed503025b3 --- /dev/null +++ b/src/i18n/strings/nb_NO.json @@ -0,0 +1,13 @@ +{ + "Add an email address above to configure email notifications": "Legg til en epost adresse for å sette opp epost varsling", + "Advanced notification settings": "Avanserte varslingsinnstillinger", + "All messages": "Alle meldinger", + "All messages (loud)": "Alle meldinger (høy)", + "All notifications are currently disabled for all targets.": "Alle varsler er deaktivert for alle mottakere.", + "An error occurred whilst saving your email notification preferences.": "En feil oppsto i forbindelse med lagring av epost varsel innstillinger.", + "Cancel Sending": "Avbryt sending", + "Can't update user notification settings": "Kan ikke oppdatere brukervarsel innstillinger", + "Close": "Lukk", + "Create new room": "Opprett nytt rom", + "Couldn't find a matching Matrix room": "Kunne ikke finne et samsvarende Matrix rom" +} diff --git a/src/i18n/strings/nl.json b/src/i18n/strings/nl.json new file mode 100644 index 0000000000..28e0ac3010 --- /dev/null +++ b/src/i18n/strings/nl.json @@ -0,0 +1,122 @@ +{ + "Add an email address above to configure email notifications": "Voeg een email adres toe om email notificaties te ontvangen", + "Advanced notification settings": "Geavanceerde notificatie instellingen", + "All messages": "Alle berichten", + "All messages (loud)": "Alle berichten (luid)", + "All notifications are currently disabled for all targets.": "Alle notificaties zijn op het moment uitgeschakeld voor alle doelen.", + "An error occurred whilst saving your email notification preferences.": "Er is een fout ontstaan tijdens het opslaan van jouw email notificatie voorkeuren.", + "Call invitation": "Audio gesprek uitnodiging", + "Cancel Sending": "Annuleren verzending", + "Can't update user notification settings": "Het is niet gelukt om de gebruiker notificatie instellingen bij te werken", + "Close": "Sluiten", + "Create new room": "Maak een nieuwe kamer", + "Couldn't find a matching Matrix room": "Het is niet gelukt om een bijbehorende Matrix kamer te vinden", + "Custom Server Options": "Aangepaste server instellingen", + "customServer_text": "Je kunt de aangepaste server instellingen gebruiken om in te loggen bij andere Matrix servers door een andere home server URL in te voeren.
    Dit maakt het mogelijk om Riot te gebruiken met een bestaand Matrix account op een andere home server.

    Je kunt ook een aangepaste identiteit server instellen, maar het is dan niet mogelijk om gebruikers uit te nodigen met behulp van een email adres of zelf uitgenodigt te worden met een email adres.", + "delete the alias": "verwijder de alias", + "Delete the room alias %(alias)s and remove %(name)s from the directory?": "Verwijder de alias %(alias)s en verwijder %(name)s uit de map?", + "Direct Chat": "Privé gesprek", + "Directory": "Kamer lijst", + "Dismiss": "Afwijzen", + "Download this file": "Download dit bestand", + "Enable audible notifications in web client": "Zet notificaties aan in de web client", + "Enable desktop notifications": "Zet desktop notificaties aan", + "Enable email notifications": "Zet email notificaties aan", + "Enable notifications for this account": "Zet notificaties aan voor dit account", + "Enable them now": "Zet ze nu aan", + "Enter keywords separated by a comma:": "Voeg trefwoorden toe, gesplitst door een komma:", + "Error": "Fout", + "Error saving email notification preferences": "Fout bij het opslaan van de email notificatie voorkeuren", + "#example": "#voorbeeld", + "Failed to": "Mislukt om", + "Failed to add tag %(tagName)s to room": "Mislukt om de label %(tagName)s aan de kamer toe te voegen", + "Failed to change settings": "Het is mislukt om de instellingen te wijzigen", + "Failed to forget room %(errCode)s": "Het is mislukt om de kamer te vergeten %(errCode)s", + "Failed to update keywords": "Het is mislukt om de trefwoorden bij te werken", + "Failed to get protocol list from Home Server": "Het is mislukt om de protocol lijst op te halen van de home server", + "Failed to get public room list": "Het is mislukt om de lijst van publieke kamers op te halen", + "Failed to join the room": "Het is mislukt om de kamer toe te treden", + "Failed to remove tag %(tagName)s from room": "Het is mislukt om de label %(tagName)s van de kamer te verwijderen", + "Failed to set direct chat tag": "Het is mislukt om de privé chat label weg te halen", + "Favourite": "Favoriet", + "Fetching third party location failed": "Het ophalen van de locatie van de derde partij is mislukt", + "Files": "Bestanden", + "Filter room names": "Filter kamer namen", + "Forget": "Vergeten", + " from room": " van kamer", + "Guests can join": "Gasten kunnen toe treden", + "Guest users can't invite users. Please register to invite": "Gasten kunnen geen gebruikers uitnodigen. Om anderen uit te nodigen zult u moeten registreren", + "Invite to this room": "Uitnodigen voor deze kamer", + "Keywords": "Trefwoorden", + "Leave": "Verlaten", + "Low Priority": "Lage prioriteit", + "Members": "Leden", + "Mentions only": "Alleen vermeldingen", + "Messages containing my display name": "Berichten die mijn weergavenaam bevatten", + "Messages containing my user name": "Berichten die mijn gebruikersnaam bevatten", + "Messages in group chats": "Berichten in groep gesprekken", + "Messages in one-to-one chats": "Berichten in één-op-één gesprekken", + "Messages sent by bot": "Berichten verzonden bij een bot", + "more": "meer", + "Mute": "Dempen", + "No rooms to show": "Geen kamers om te laten zien", + "Noisy": "Luidruchtig", + "Notification targets": "Notificatie doelen", + "Notifications": "Notificaties", + "Notifications on the following keywords follow rules which can’t be displayed here:": "Notificaties op de volgende trefwoorden volgen regels die hier niet kunnen worden laten zien:", + "Notify for all other messages/rooms": "Informeer mij voor alle andere berichten/kamers", + "Notify me for anything else": "Informeer mij voor al het andere", + "Off": "Uit", + "On": "Aan", + "Operation failed": "Actie mislukt", + "Permalink": "Permalink", + "Please Register": "Registreer alsjeblieft", + "powered by Matrix": "aangedreven door Matrix", + "Quote": "Quote", + "Reject": "Afwijzen", + "Remove %(name)s from the directory?": "Verwijder %(name)s uit de kamer lijst?", + "Remove": "Verwijder", + "remove %(name)s from the directory": "verwijder %(name)s uit de kamer lijst", + "Remove from Directory": "Verwijder uit de kamer lijst", + "Resend": "Opnieuw verzenden", + "Riot does not know how to join a room on this network": "Riot weet niet hoe het moet toetreden tot een kamer op dit netwerk", + "Room directory": "Kamer lijst", + "Room not found": "De kamer is niet gevonden", + "Search for a room": "Zoek naar een kamer", + "Settings": "Instellingen", + "Source URL": "Bron URL", + "Start chat": "Start gesprek", + "The Home Server may be too old to support third party networks": "De home server is misschien te oud om netwerken van derde partijen te ondersteunen", + "There are advanced notifications which are not shown here": "Er zijn geavanceerde notificaties die hier niet worden laten zien", + "The server may be unavailable or overloaded": "De server is misschien niet beschikbaar of overbeladen", + "This room is inaccessible to guests. You may be able to join if you register": "Deze kamer is niet toegankelijk voor gasten. Je zou misschien toe kunnen treden als je geregistreerd bent", + " to room": " naar kamer", + "Unable to fetch notification target list": "Het is mislukt om de lijst van notificatie doelen op te halen", + "Unable to join network": "Het is mislukt om toe te treden tot dit netwerk", + "Unable to look up room ID from server": "Het is mislukt om de kamer ID op te halen van de server", + "Unhide Preview": "Zichtbaar maken preview", + "unknown error code": "niet bekende foutcode", + "Unnamed room": "Kamer zonder naam", + "Uploaded on %(date)s by %(user)s": "Geüpload op %(date)s door %(user)s", + "View Decrypted Source": "Bekijk gedecodeerde bron", + "View Source": "Bekijk bron", + "When I'm invited to a room": "Wanneer ik uitgenodigt wordt naar een kamer", + "World readable": "Door iedereen leesbaar", + "You cannot delete this image. (%(code)s)": "Je kunt deze afbeelding niet verwijderen. (%code)s)", + "You cannot delete this message. (%(code)s)": "Je kunt dit bericht niet verwijderen. (%(code)s)", + "You are not receiving desktop notifications": "Je ontvangt momenteel geen desktop notificaties", + "You might have configured them in a client other than Riot. You cannot tune them in Riot but they still apply": "Je hebt ze mogelijk ingesteld in een andere client dan Riot. Je kunt ze niet aanpassen in Riot maar ze zijn wel actief", + "Sunday": "Zondag", + "Monday": "Maandag", + "Tuesday": "Dinsdag", + "Wednesday": "Woensdag", + "Thursday": "Donderdag", + "Friday": "Vrijdag", + "Saturday": "Zaterdag", + "Today": "Vandaag", + "Yesterday": "Gisteren", + "Welcome page": "Welkom pagina", + "Drop here %(toAction)s": "%(toAction)s hier naar toe verplaatsen", + "Failed to set Direct Message status of room": "Het is mislukt om de directe berichten status van de kamer in te stellen", + "Redact": "Redigeren" +} diff --git a/src/i18n/strings/pl.json b/src/i18n/strings/pl.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/i18n/strings/pl.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/i18n/strings/pt.json b/src/i18n/strings/pt.json new file mode 100644 index 0000000000..d55488059c --- /dev/null +++ b/src/i18n/strings/pt.json @@ -0,0 +1,115 @@ +{ + "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)", + "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 %(name)s da lista pública?", + "Direct Chat": "Conversa pessoal", + "Directory": "Diretório", + "Dismiss": "Encerrar", + "Download this file": "Baixar este arquivo", + "Drop here %(toAction)s": "Arraste aqui para %(toAction)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 can’t 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 %(tagName)s from room": "Não foi possível remover a marcação %(tagName)s desta sala", + "Notifications on the following keywords follow rules which can’t 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" +} diff --git a/src/i18n/strings/pt_BR.json b/src/i18n/strings/pt_BR.json new file mode 100644 index 0000000000..f535bf0e4e --- /dev/null +++ b/src/i18n/strings/pt_BR.json @@ -0,0 +1,122 @@ +{ + "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)", + "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 %(name)s da lista pública?", + "Direct Chat": "Conversa pessoal", + "Directory": "Diretório", + "Dismiss": "Encerrar", + "Download this file": "Baixar este arquivo", + "Drop here %(toAction)s": "Arraste aqui para %(toAction)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 can’t 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 %(tagName)s from room": "Não foi possível remover a marcação %(tagName)s desta sala", + "Welcome page": "Página de boas vindas" +} diff --git a/src/i18n/strings/ru.json b/src/i18n/strings/ru.json new file mode 100644 index 0000000000..f2f2dbdf36 --- /dev/null +++ b/src/i18n/strings/ru.json @@ -0,0 +1,129 @@ +{ + "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.": "Возникла ошибка при сохранении настроек оповещения по электронной почте.", + "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": "Включить оповещения по электронной почте", + "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 ": "Не удалось добавить тег ", + "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 can’t 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": "Здесь расширенные уведомления, которые здесь не показаны", + "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 %(toAction)s": "Вставить сюда для %(toAction)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 %(tagName)s from room": "Не удалось убрать пометку %(tagName)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": "Домашняя страница", + "Advanced notification settings": "Настройки уведомлений", + "Call invitation": "Звонок", + "customServer_text": "Вы можете войти с помощью вашего сервера.
    Это позволяет вам использовать Riot с уже существующей учетной записью на другом сервере.

    Вы также можете задать свой сервер идентификации, но тогда вы не можете приглашать пользователей с помощью email-адреса и не можете быть приглашены по нему.", + "Messages containing my display name": "Сообщения, содержащие мое отображаемое имя", + "Messages containing my user name": "Сообщение, содержащие мое имя пользователя", + "Messages in group chats": "Сообщения в групповых чатах", + "Messages in one-to-one chats": "Сообщения в приватных чатах", + "Messages sent by bot": "Сообщения, отправленные ботом", + "more": "больше", + "When I'm invited to a room": "Когда я приглашен в комнату" +} diff --git a/src/i18n/strings/sv.json b/src/i18n/strings/sv.json new file mode 100644 index 0000000000..0d03a87806 --- /dev/null +++ b/src/i18n/strings/sv.json @@ -0,0 +1,40 @@ +{ + "Add an email address above to configure email notifications": "Lägg till en epostadress här för att konfigurera epostaviseringar", + "Advanced notification settings": "Avancerade aviseringsinställingar", + "All messages": "Alla meddelanden", + "All messages (loud)": "Alla meddelanden (högljudd)", + "All notifications are currently disabled for all targets.": "Alla aviseringar är för tillfället avstängda för alla mål.", + "An error occurred whilst saving your email notification preferences.": "Ett fel uppstod då epostaviseringsinställningarna sparades.", + "Call invitation": "Inbjudan till samtal", + "Cancel Sending": "Avbryt sändning", + "Can't update user notification settings": "Kan inte uppdatera aviseringsinställningarna", + "Close": "Stäng", + "Create new room": "Nytt rum", + "Couldn't find a matching Matrix room": "Kunde inte hitta ett matchande Matrix-rum", + "Custom Server Options": "Egna serverinställningar", + "customServer_text": "Du kan använda serverinställningarna för att logga in i en annan Matrix-server genom att specifiera en URL till en annan hemserver.
    Så här kan du använda Riot med ett existerande Matrix-konto på en annan hemserver.

    Du kan också specifiera en egen identitetsserver, men du kommer inte att kunna bjuda in andra via epostadress, eller bli inbjuden via epostadress.", + "delete the alias": "radera adressen", + "Direct Chat": "Direkt chatt", + "Directory": "Katalog", + "Dismiss": "Avvisa", + "Download this file": "Ladda ner filen", + "Drop here %(toAction)s": "Dra hit för att %(toAction)s", + "Enable audible notifications in web client": "Sätt på högljudda aviseringar i webbklienten", + "Enable desktop notifications": "Sätt på skrivbordsaviseringar", + "Enable email notifications": "Sätt på epostaviseringar", + "Enable notifications for this account": "Sätt på aviseringar för det här kontot", + "Enable them now": "Sätt på nu", + "Enter keywords separated by a comma:": "Skriv in nyckelord, separerade med kommatecken", + "Error": "Fel", + "Error saving email notification preferences": "Ett fel uppstod då epostaviseringsinställningarna sparades", + "Failed to": "Det gick inte att", + "Failed to add tag %(tagName)s to room": "Det gick inte att lägga till \"%(tagName)s\" till rummet", + "Failed to change settings": "Det gick inte att spara inställningarna", + "Failed to forget room %(errCode)s": "Det gick inte att glömma bort rummet: %(errCode)s", + "Failed to update keywords": "Det gick inte att uppdatera nyckelorden", + "Failed to get protocol list from Home Server": "Det gick inte att hämta protokollistan från hemservern", + "Failed to get public room list": "Det gick inte att hämta listan över offentliga rum", + "Failed to join the room": "Det gick inte att ansluta till rummet", + "Failed to remove tag %(tagName)s from room": "Det gick inte att radera taggen %(tagName)s från rummet", + "Failed to set direct chat tag": "Det gick inte att markera rummet som direkt chatt" +} diff --git a/src/i18n/strings/zh_Hant.json b/src/i18n/strings/zh_Hant.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/src/i18n/strings/zh_Hant.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/src/skins/vector/css/matrix-react-sdk/structures/_FilePanel.scss b/src/skins/vector/css/matrix-react-sdk/structures/_FilePanel.scss index 872085b66b..58e090645f 100644 --- a/src/skins/vector/css/matrix-react-sdk/structures/_FilePanel.scss +++ b/src/skins/vector/css/matrix-react-sdk/structures/_FilePanel.scss @@ -112,4 +112,3 @@ limitations under the License. .mx_FilePanel .mx_EventTile_selected .mx_EventTile_line { padding-left: 0px; } - diff --git a/src/skins/vector/css/matrix-react-sdk/structures/_UserSettings.scss b/src/skins/vector/css/matrix-react-sdk/structures/_UserSettings.scss index fe60aacb9f..f72a6f0858 100644 --- a/src/skins/vector/css/matrix-react-sdk/structures/_UserSettings.scss +++ b/src/skins/vector/css/matrix-react-sdk/structures/_UserSettings.scss @@ -131,6 +131,10 @@ limitations under the License. position: absolute; } +.mx_UserSettings_language { + width: 200px; +} + .mx_UserSettings_profileTable { display: table; diff --git a/src/skins/vector/css/matrix-react-sdk/structures/login/_Login.scss b/src/skins/vector/css/matrix-react-sdk/structures/login/_Login.scss index ebd59a1c24..b81f3979a9 100644 --- a/src/skins/vector/css/matrix-react-sdk/structures/login/_Login.scss +++ b/src/skins/vector/css/matrix-react-sdk/structures/login/_Login.scss @@ -175,7 +175,8 @@ limitations under the License. } .mx_Login_type_dropdown { - width: 125px; + display: inline-block; + min-width: 125px; align-self: flex-end; } diff --git a/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss b/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss index abd4e9c164..d12bcd3712 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/dialogs/_ConfirmUserActionDialog.scss @@ -37,6 +37,7 @@ limitations under the License. font-family: 'Open Sans', Arial, Helvetica, Sans-Serif; font-size: 14px; color: $primary-fg-color; + background-color: $primary-bg-color; border-radius: 3px; border: solid 1px $input-border-color; diff --git a/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss b/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss index cbd7142285..9d970ad454 100644 --- a/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss +++ b/src/skins/vector/css/matrix-react-sdk/views/rooms/_EventTile.scss @@ -183,6 +183,10 @@ limitations under the License. visibility: visible; } +.mx_MessagePanel_alwaysShowTimestamps .mx_MessageTimestamp { + visibility: visible; +} + .mx_EventTile_selected .mx_MessageTimestamp { left: 3px; } @@ -263,6 +267,14 @@ limitations under the License. cursor: pointer; } +.mx_EventTile_12hr .mx_EventTile_e2eIcon { + padding-left: 5px; +} + +.mx_EventTile_12hr .mx_MessageTimestamp { + text-align: center; +} + .mx_EventTile:hover.mx_EventTile_verified .mx_EventTile_line, .mx_EventTile:hover.mx_EventTile_unverified .mx_EventTile_line { padding-left: 60px; diff --git a/src/skins/vector/css/vector-web/structures/_RightPanel.scss b/src/skins/vector/css/vector-web/structures/_RightPanel.scss index bb60fa1e7e..70cb2cb9be 100644 --- a/src/skins/vector/css/vector-web/structures/_RightPanel.scss +++ b/src/skins/vector/css/vector-web/structures/_RightPanel.scss @@ -30,6 +30,21 @@ limitations under the License. flex: 0 0 70px; } +.mx_RightPanel_loginButton { + margin-top: 15px; + width: 100%; + height: 40px; + border: 0px; + border-radius: 40px; + + background-color: $accent-color; + color: $primary-bg-color; + + cursor: pointer; + + font-size: 15px; +} + /** Fixme - factor this out with the main header **/ .mx_RightPanel_headerButtonGroup { diff --git a/src/vector/index.js b/src/vector/index.js index 02713afca7..14f8bb4b36 100644 --- a/src/vector/index.js +++ b/src/vector/index.js @@ -62,6 +62,8 @@ var VectorConferenceHandler = require('../VectorConferenceHandler'); var UpdateChecker = require("./updater"); var q = require('q'); var request = require('browser-request'); +import * as UserSettingsStore from 'matrix-react-sdk/lib/UserSettingsStore'; +import * as languageHandler from 'matrix-react-sdk/lib/languageHandler'; import url from 'url'; @@ -228,8 +230,9 @@ function onLoadCompleted() { } } - async function loadApp() { + await loadLanguage(); + const fragparts = parseQsFromFragment(window.location); const params = parseQs(window.location); @@ -309,4 +312,22 @@ async function loadApp() { } } +async function loadLanguage() { + const prefLang = UserSettingsStore.getLocalSetting('language'); + let langs = []; + + if (!prefLang) { + languageHandler.getLanguagesFromBrowser().forEach((l) => { + langs.push(...languageHandler.getNormalizedLanguageKeys(l)); + }); + } else { + langs = [prefLang]; + } + try { + await languageHandler.setLanguage(langs); + } catch (e) { + console.error("Unable to set language", e); + } +} + loadApp(); diff --git a/src/vector/platform/ElectronPlatform.js b/src/vector/platform/ElectronPlatform.js index 5710e66e4a..bf930a674f 100644 --- a/src/vector/platform/ElectronPlatform.js +++ b/src/vector/platform/ElectronPlatform.js @@ -54,7 +54,19 @@ function platformFriendlyName(): string { } } +function _onAction(payload: Object) { + // Whitelist payload actions, no point sending most across + if (['call_state'].includes(payload.action)) { + ipcRenderer.send('app_onAction', payload); + } +} + export default class ElectronPlatform extends VectorBasePlatform { + constructor() { + super(); + dis.register(_onAction); + } + setNotificationCount(count: number) { if (this.notificationCount === count) return; super.setNotificationCount(count); @@ -71,7 +83,6 @@ export default class ElectronPlatform extends VectorBasePlatform { } displayNotification(title: string, msg: string, avatarUrl: string, room: Object): Notification { - // GNOME notification spec parses HTML tags for styling... // Electron Docs state all supported linux notification systems follow this markup spec // https://github.com/electron/electron/blob/master/docs/tutorial/desktop-environment-integration.md#linux diff --git a/test/app-tests/loading.js b/test/app-tests/loading.js index d3844522b9..86fad11866 100644 --- a/test/app-tests/loading.js +++ b/test/app-tests/loading.js @@ -28,6 +28,7 @@ import jssdk from 'matrix-js-sdk'; import sdk from 'matrix-react-sdk'; import MatrixClientPeg from 'matrix-react-sdk/lib/MatrixClientPeg'; +import * as languageHandler from 'matrix-react-sdk/lib/languageHandler'; import test_utils from '../test-utils'; import MockHttpBackend from '../mock-request'; @@ -61,6 +62,10 @@ describe('loading:', function () { windowLocation = null; matrixChat = null; + + languageHandler.setMissingEntryGenerator(function(key) { + return key.split('|', 2)[1]; + }); }); afterEach(function() { diff --git a/test/skin-sdk.js b/test/skin-sdk.js index a5a7233c31..3421d5d07d 100644 --- a/test/skin-sdk.js +++ b/test/skin-sdk.js @@ -5,4 +5,4 @@ */ var sdk = require('matrix-react-sdk'); -sdk.loadSkin(require('component-index')); +sdk.loadSkin(require('../src/component-index')); diff --git a/test/unit-tests/notifications/ContentRules-test.js b/test/unit-tests/notifications/ContentRules-test.js index e7928147f6..c1cdc40a8b 100644 --- a/test/unit-tests/notifications/ContentRules-test.js +++ b/test/unit-tests/notifications/ContentRules-test.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -var notifications = require('notifications'); +var notifications = require('../../../src/notifications'); var ContentRules = notifications.ContentRules; var PushRuleVectorState = notifications.PushRuleVectorState; diff --git a/test/unit-tests/notifications/PushRuleVectorState-test.js b/test/unit-tests/notifications/PushRuleVectorState-test.js index 6b0f81c60c..68e7044f60 100644 --- a/test/unit-tests/notifications/PushRuleVectorState-test.js +++ b/test/unit-tests/notifications/PushRuleVectorState-test.js @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -var notifications = require('notifications'); +var notifications = require('../../../src/notifications'); var prvs = notifications.PushRuleVectorState;
    OffOnNoisy{ _t('Off') }{ _t('On') }{ _t('Noisy') }