commit
f6b8bdcb3b
129
app/index.html
129
app/index.html
|
@ -27,29 +27,29 @@
|
||||||
css: { minimal: minimalView }">
|
css: { minimal: minimalView }">
|
||||||
<!-- ko with: connectDialog -->
|
<!-- ko with: connectDialog -->
|
||||||
<div class="connect-dialog dialog" data-bind="visible: visible() && !joinOnly()">
|
<div class="connect-dialog dialog" data-bind="visible: visible() && !joinOnly()">
|
||||||
<div class="dialog-header">
|
<div id="connect-dialog_title" class="dialog-header">
|
||||||
Connect to Server
|
Connect to Server
|
||||||
</div>
|
</div>
|
||||||
<form data-bind="submit: connect">
|
<form data-bind="submit: connect">
|
||||||
<table>
|
<table>
|
||||||
<tr data-bind="if: $root.config.connectDialog.address">
|
<tr data-bind="if: $root.config.connectDialog.address">
|
||||||
<td>Address</td>
|
<td id="connect-dialog_input_address">Address</td>
|
||||||
<td><input id="address" type="text" data-bind="value: address" required></td>
|
<td><input id="address" type="text" data-bind="value: address" required></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: $root.config.connectDialog.port">
|
<tr data-bind="if: $root.config.connectDialog.port">
|
||||||
<td>Port</td>
|
<td id="connect-dialog_input_port">Port</td>
|
||||||
<td><input id="port" type="text" data-bind="value: port" required></td>
|
<td><input id="port" type="text" data-bind="value: port" required></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: $root.config.connectDialog.username">
|
<tr data-bind="if: $root.config.connectDialog.username">
|
||||||
<td>Username</td>
|
<td id="connect-dialog_input_username">Username</td>
|
||||||
<td><input id="username" type="text" data-bind="value: username" required></td>
|
<td><input id="username" type="text" data-bind="value: username" required></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: $root.config.connectDialog.password">
|
<tr data-bind="if: $root.config.connectDialog.password">
|
||||||
<td>Password</td>
|
<td id="connect-dialog_input_password">Password</td>
|
||||||
<td><input id="password" type="password" data-bind="value: password"></td>
|
<td><input id="password" type="password" data-bind="value: password"></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: $root.config.connectDialog.token">
|
<tr data-bind="if: $root.config.connectDialog.token">
|
||||||
<td>Tokens</td>
|
<td id="connect-dialog_input_tokens">Tokens</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="text" data-bind='value: tokenToAdd, valueUpdate: "afterkeydown"'>
|
<input type="text" data-bind='value: tokenToAdd, valueUpdate: "afterkeydown"'>
|
||||||
</td>
|
</td>
|
||||||
|
@ -57,8 +57,8 @@
|
||||||
<tr data-bind="if: $root.config.connectDialog.token">
|
<tr data-bind="if: $root.config.connectDialog.token">
|
||||||
<td></td>
|
<td></td>
|
||||||
<td>
|
<td>
|
||||||
<button class="dialog-submit" type="button" data-bind="enable: selectedTokens().length > 0, click: removeSelectedTokens()">Remove</button>
|
<button id="connect-dialog_controls_remove" class="dialog-submit" type="button" data-bind="enable: selectedTokens().length > 0, click: removeSelectedTokens()">Remove</button>
|
||||||
<button class="dialog-submit" type="button" data-bind="enable: tokenToAdd().length > 0, click: addToken()">Add</button>
|
<button id="connect-dialog_controls_add" class="dialog-submit" type="button" data-bind="enable: tokenToAdd().length > 0, click: addToken()">Add</button>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: $root.config.connectDialog.token, visible: tokens().length > 0">
|
<tr data-bind="if: $root.config.connectDialog.token, visible: tokens().length > 0">
|
||||||
|
@ -71,8 +71,8 @@
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
<div class="dialog-footer">
|
<div class="dialog-footer">
|
||||||
<input class="dialog-close" type="button" data-bind="click: hide" value="Cancel">
|
<input id="connect-dialog_controls_cancel" class="dialog-close" type="button" data-bind="click: hide" value="Cancel">
|
||||||
<input class="dialog-submit" type="submit" value="Connect">
|
<input id="connect-dialog_controls_connect" class="dialog-submit" type="submit" value="Connect">
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -94,46 +94,64 @@
|
||||||
</div>
|
</div>
|
||||||
<form data-bind="submit: connect">
|
<form data-bind="submit: connect">
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr class="reason">
|
||||||
<td colspan=2>
|
<td colspan=2>
|
||||||
<!-- ko if: type() == 0 || type() == 8 -->
|
<!-- ko if: type() == 0 || type() == 8 -->
|
||||||
|
<span class="refused">
|
||||||
The connection has been refused.
|
The connection has been refused.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 1 -->
|
<!-- ko if: type() == 1 -->
|
||||||
|
<span class="version">
|
||||||
The server uses an incompatible version.
|
The server uses an incompatible version.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 2 -->
|
<!-- ko if: type() == 2 -->
|
||||||
|
<span class="username">
|
||||||
Your user name was rejected. Maybe try a different one?
|
Your user name was rejected. Maybe try a different one?
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 3 -->
|
<!-- ko if: type() == 3 -->
|
||||||
|
<span class="userpassword">
|
||||||
The given password is incorrect.
|
The given password is incorrect.
|
||||||
The user name you have chosen requires a special one.
|
The user name you have chosen requires a special one.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 4 -->
|
<!-- ko if: type() == 4 -->
|
||||||
|
<span class="serverpassword">
|
||||||
The given password is incorrect.
|
The given password is incorrect.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 5 -->
|
<!-- ko if: type() == 5 -->
|
||||||
|
<span class="username-in-use">
|
||||||
The user name you have chosen is already in use.
|
The user name you have chosen is already in use.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 6 -->
|
<!-- ko if: type() == 6 -->
|
||||||
|
<span class="full">
|
||||||
The server is full.
|
The server is full.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: type() == 7 -->
|
<!-- ko if: type() == 7 -->
|
||||||
|
<span class="clientcert">
|
||||||
The server requires you to provide a client certificate
|
The server requires you to provide a client certificate
|
||||||
which is not supported by this web application.
|
which is not supported by this web application.
|
||||||
|
</span>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<br>
|
<br>
|
||||||
|
<span class="server">
|
||||||
The server reports:
|
The server reports:
|
||||||
|
</span>
|
||||||
<br>
|
<br>
|
||||||
"<span class="connect-error-reason" data-bind="text: reason"></span>"
|
"<span class="connect-error-reason" data-bind="text: reason"></span>"
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: type() == 2 || type() == 3 || type() == 5">
|
<tr data-bind="if: type() == 2 || type() == 3 || type() == 5">
|
||||||
<td>Username</td>
|
<td class="alternate-username">Username</td>
|
||||||
<td><input id="username" type="text" data-bind="value: username" required></td>
|
<td><input id="username" type="text" data-bind="value: username" required></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr data-bind="if: type() == 3 || type() == 4">
|
<tr data-bind="if: type() == 3 || type() == 4">
|
||||||
<td>Password</td>
|
<td class="alternate-password">Password</td>
|
||||||
<td><input id="password" type="password" data-bind="value: password" required></td>
|
<td><input id="password" type="password" data-bind="value: password" required></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
@ -284,80 +302,97 @@
|
||||||
<img class="avatar-view" data-bind="visible: avatarView, attr: { src: avatarView },
|
<img class="avatar-view" data-bind="visible: avatarView, attr: { src: avatarView },
|
||||||
click: function () { avatarView(null) }"></img>
|
click: function () { avatarView(null) }"></img>
|
||||||
<!-- ko with: userContextMenu -->
|
<!-- ko with: userContextMenu -->
|
||||||
<ul class="context-menu" data-bind="if: target,
|
<ul class="context-menu user-context-menu" data-bind="if: target,
|
||||||
style: { left: posX() + 'px',
|
style: { left: posX() + 'px',
|
||||||
top: posY() + 'px' }">
|
top: posY() + 'px' }">
|
||||||
|
|
||||||
<!-- ko with: target -->
|
<!-- ko with: target -->
|
||||||
<li data-bind="css: { disabled: !canChangeMute() }">
|
<li data-bind="css: { disabled: !canChangeMute() }"
|
||||||
|
class="mute">
|
||||||
Mute
|
Mute
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canChangeDeafen() }">
|
<li data-bind="css: { disabled: !canChangeDeafen() }"
|
||||||
|
class="deafen">
|
||||||
Deafen
|
Deafen
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canChangePrioritySpeaker() }">
|
<li data-bind="css: { disabled: !canChangePrioritySpeaker() }"
|
||||||
|
class="priority-speaker">
|
||||||
Priority Speaker
|
Priority Speaker
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-bind="css: { disabled: !canLocalMute() }">
|
<li data-bind="css: { disabled: !canLocalMute() }"
|
||||||
|
class="local-mute">
|
||||||
Local Mute
|
Local Mute
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canIgnoreMessages() }">
|
<li data-bind="css: { disabled: !canIgnoreMessages() }"
|
||||||
|
class="ignore-messages">
|
||||||
Ignore Messages
|
Ignore Messages
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-bind="css: { disabled: !canChangeComment() }, visible: comment">
|
<li data-bind="css: { disabled: !canChangeComment() }, visible: comment"
|
||||||
|
class="view-comment">
|
||||||
View Comment
|
View Comment
|
||||||
</li>
|
</li>
|
||||||
<!-- ko if: $data === $root.thisUser() -->
|
<!-- ko if: $data === $root.thisUser() -->
|
||||||
<li data-bind="css: { disabled: !canChangeComment() }, visible: true">
|
<li data-bind="css: { disabled: !canChangeComment() }, visible: true"
|
||||||
|
class="change-comment">
|
||||||
Change Comment
|
Change Comment
|
||||||
</li>
|
</li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko if: $data !== $root.thisUser() -->
|
<!-- ko if: $data !== $root.thisUser() -->
|
||||||
<li data-bind="css: { disabled: !canChangeComment() }, visible: comment">
|
<li data-bind="css: { disabled: !canChangeComment() }, visible: comment"
|
||||||
|
class="reset-comment">
|
||||||
Reset Comment
|
Reset Comment
|
||||||
</li>
|
</li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
|
|
||||||
<li data-bind="css: { disabled: !canChangeAvatar() }, visible: texture,
|
<li data-bind="css: { disabled: !canChangeAvatar() }, visible: texture,
|
||||||
click: viewAvatar">
|
click: viewAvatar"
|
||||||
|
class="view-avatar">
|
||||||
View Avatar
|
View Avatar
|
||||||
</li>
|
</li>
|
||||||
<!-- ko if: $data === $root.thisUser() -->
|
<!-- ko if: $data === $root.thisUser() -->
|
||||||
<li data-bind="css: { disabled: !canChangeAvatar() }, visible: true,
|
<li data-bind="css: { disabled: !canChangeAvatar() }, visible: true,
|
||||||
click: changeAvatar">
|
click: changeAvatar"
|
||||||
|
class="change-avatar">
|
||||||
Change Avatar
|
Change Avatar
|
||||||
</li>
|
</li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<li data-bind="css: { disabled: !canChangeAvatar() }, visible: texture,
|
<li data-bind="css: { disabled: !canChangeAvatar() }, visible: texture,
|
||||||
click: removeAvatar">
|
click: removeAvatar",
|
||||||
|
class="reset-avatar">
|
||||||
Reset Avatar
|
Reset Avatar
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-bind="css: { disabled: true }, visible: true">
|
<li data-bind="css: { disabled: true }, visible: true"
|
||||||
|
class="send-message">
|
||||||
Send Message
|
Send Message
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: true }, visible: true">
|
<li data-bind="css: { disabled: true }, visible: true"
|
||||||
|
class="information">
|
||||||
Information
|
Information
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-bind="visible: $data === $root.thisUser(),
|
<li data-bind="visible: $data === $root.thisUser(),
|
||||||
css: { checked: selfMute },
|
css: { checked: selfMute },
|
||||||
click: toggleMute">
|
click: toggleMute"
|
||||||
|
class="self-mute">
|
||||||
Self Mute
|
Self Mute
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="visible: $data === $root.thisUser(),
|
<li data-bind="visible: $data === $root.thisUser(),
|
||||||
css: { checked: selfDeaf },
|
css: { checked: selfDeaf },
|
||||||
click: toggleDeaf">
|
click: toggleDeaf"
|
||||||
|
class="self-deafen">
|
||||||
Self Deafen
|
Self Deafen
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<!-- ko if: $data !== $root.thisUser() -->
|
<!-- ko if: $data !== $root.thisUser() -->
|
||||||
<li data-bind="css: { disabled: true }, visible: true">
|
<li data-bind="css: { disabled: true }, visible: true"
|
||||||
|
class="add-friend">
|
||||||
Add Friend
|
Add Friend
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: true }, visible: false">
|
<li data-bind="css: { disabled: true }, visible: false"
|
||||||
|
class="remove-friend">
|
||||||
Remove Friend
|
Remove Friend
|
||||||
</li>
|
</li>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
|
@ -366,43 +401,53 @@
|
||||||
</ul>
|
</ul>
|
||||||
<!-- /ko -->
|
<!-- /ko -->
|
||||||
<!-- ko with: channelContextMenu -->
|
<!-- ko with: channelContextMenu -->
|
||||||
<ul class="context-menu" data-bind="if: target,
|
<ul class="context-menu channel-context-menu" data-bind="if: target,
|
||||||
style: { left: posX() + 'px',
|
style: { left: posX() + 'px',
|
||||||
top: posY() + 'px' }">
|
top: posY() + 'px' }">
|
||||||
|
|
||||||
<!-- ko with: target -->
|
<!-- ko with: target -->
|
||||||
<li data-bind="visible: users.indexOf($root.thisUser()) === -1,
|
<li data-bind="visible: users.indexOf($root.thisUser()) === -1,
|
||||||
css: { disabled: !canJoin() },
|
css: { disabled: !canJoin() },
|
||||||
click: $root.requestMove.bind($root, $root.thisUser())">
|
click: $root.requestMove.bind($root, $root.thisUser())"
|
||||||
|
class="join">
|
||||||
Join Channel
|
Join Channel
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canAdd() }">
|
<li data-bind="css: { disabled: !canAdd() }"
|
||||||
|
class="add">
|
||||||
Add
|
Add
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canEdit() }">
|
<li data-bind="css: { disabled: !canEdit() }"
|
||||||
|
class="edit">
|
||||||
Edit
|
Edit
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canRemove() }">
|
<li data-bind="css: { disabled: !canRemove() }"
|
||||||
|
class="remove">
|
||||||
Remove
|
Remove
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-bind="css: { disabled: !canLink() }">
|
<li data-bind="css: { disabled: !canLink() }"
|
||||||
|
class="link">
|
||||||
Link
|
Link
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canUnlink() }">
|
<li data-bind="css: { disabled: !canUnlink() }"
|
||||||
|
class="unlink">
|
||||||
Unlink
|
Unlink
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canUnlink() }">
|
<li data-bind="css: { disabled: !canUnlink() }"
|
||||||
|
class="unlink-all">
|
||||||
Unlink All
|
Unlink All
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<li data-bind="css: { disabled: true }">
|
<li data-bind="css: { disabled: true }"
|
||||||
|
class="copy-mumble-url">
|
||||||
Copy Mumble URL
|
Copy Mumble URL
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: true }">
|
<li data-bind="css: { disabled: true }"
|
||||||
|
class="copy-mumble-web-url">
|
||||||
Copy Mumble-Web URL
|
Copy Mumble-Web URL
|
||||||
</li>
|
</li>
|
||||||
<li data-bind="css: { disabled: !canSendMessage() }">
|
<li data-bind="css: { disabled: !canSendMessage() }"
|
||||||
|
class="send-message">
|
||||||
Send Message
|
Send Message
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
|
95
app/index.js
95
app/index.js
|
@ -11,6 +11,7 @@ import _dompurify from 'dompurify'
|
||||||
import keyboardjs from 'keyboardjs'
|
import keyboardjs from 'keyboardjs'
|
||||||
|
|
||||||
import { ContinuousVoiceHandler, PushToTalkVoiceHandler, VADVoiceHandler, initVoice } from './voice'
|
import { ContinuousVoiceHandler, PushToTalkVoiceHandler, VADVoiceHandler, initVoice } from './voice'
|
||||||
|
import {initialize as localizationInitialize, translate} from './loc';
|
||||||
|
|
||||||
const dompurify = _dompurify(window)
|
const dompurify = _dompurify(window)
|
||||||
|
|
||||||
|
@ -923,7 +924,7 @@ var ui = new GlobalBindings(window.mumbleWebConfig)
|
||||||
// Used only for debugging
|
// Used only for debugging
|
||||||
window.mumbleUi = ui
|
window.mumbleUi = ui
|
||||||
|
|
||||||
window.onload = function () {
|
function initializeUI () {
|
||||||
var queryParams = url.parse(document.location.href, true).query
|
var queryParams = url.parse(document.location.href, true).query
|
||||||
queryParams = Object.assign({}, window.mumbleWebConfig.defaults, queryParams)
|
queryParams = Object.assign({}, window.mumbleWebConfig.defaults, queryParams)
|
||||||
var useJoinDialog = queryParams.joinDialog
|
var useJoinDialog = queryParams.joinDialog
|
||||||
|
@ -987,10 +988,10 @@ window.onload = function () {
|
||||||
}
|
}
|
||||||
ui.connectDialog.joinOnly(useJoinDialog)
|
ui.connectDialog.joinOnly(useJoinDialog)
|
||||||
ko.applyBindings(ui)
|
ko.applyBindings(ui)
|
||||||
}
|
|
||||||
|
|
||||||
window.onresize = () => ui.updateSize()
|
window.onresize = () => ui.updateSize()
|
||||||
ui.updateSize()
|
ui.updateSize()
|
||||||
|
}
|
||||||
|
|
||||||
function log () {
|
function log () {
|
||||||
console.log.apply(console, arguments)
|
console.log.apply(console, arguments)
|
||||||
|
@ -1041,6 +1042,92 @@ function userToState () {
|
||||||
var voiceHandler
|
var voiceHandler
|
||||||
var testVoiceHandler
|
var testVoiceHandler
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
function translatePiece(selector, kind, parameters, key) {
|
||||||
|
let element = document.querySelector(selector);
|
||||||
|
if (element !== null) {
|
||||||
|
const translation = translate(key);
|
||||||
|
switch (kind) {
|
||||||
|
default:
|
||||||
|
console.warn('unhandled dom translation kind "' + kind + '"');
|
||||||
|
break;
|
||||||
|
case 'textcontent':
|
||||||
|
element.textContent = translation;
|
||||||
|
break;
|
||||||
|
case 'attribute':
|
||||||
|
element.setAttribute(parameters.name || 'value', translation);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn(`translation selector "${selector}" for "${key}" did not match any element`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
function translateEverything() {
|
||||||
|
translatePiece('#connect-dialog_title', 'textcontent', {}, 'connectdialog.title');
|
||||||
|
translatePiece('#connect-dialog_input_address', 'textcontent', {}, 'connectdialog.address');
|
||||||
|
translatePiece('#connect-dialog_input_port', 'textcontent', {}, 'connectdialog.port');
|
||||||
|
translatePiece('#connect-dialog_input_username', 'textcontent', {}, 'connectdialog.username');
|
||||||
|
translatePiece('#connect-dialog_input_password', 'textcontent', {}, 'connectdialog.password');
|
||||||
|
translatePiece('#connect-dialog_input_tokens', 'textcontent', {}, 'connectdialog.tokens');
|
||||||
|
translatePiece('#connect-dialog_controls_remove', 'textcontent', {}, 'connectdialog.remove');
|
||||||
|
translatePiece('#connect-dialog_controls_add', 'textcontent', {}, 'connectdialog.add');
|
||||||
|
translatePiece('#connect-dialog_controls_cancel', 'attribute', {'name': 'value'}, 'connectdialog.cancel');
|
||||||
|
translatePiece('#connect-dialog_controls_connect', 'attribute', {'name': 'value'}, 'connectdialog.connect');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .dialog-header', 'textcontent', {}, 'connectdialog.error.title');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .refused', 'textcontent', {}, 'connectdialog.error.reason.refused');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .version', 'textcontent', {}, 'connectdialog.error.reason.version');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .username', 'textcontent', {}, 'connectdialog.error.reason.username');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .userpassword', 'textcontent', {}, 'connectdialog.error.reason.userpassword');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .serverpassword', 'textcontent', {}, 'connectdialog.error.reason.serverpassword');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .username-in-use', 'textcontent', {}, 'connectdialog.error.reason.username_in_use');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .full', 'textcontent', {}, 'connectdialog.error.reason.full');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .clientcert', 'textcontent', {}, 'connectdialog.error.reason.clientcert');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .reason .server', 'textcontent', {}, 'connectdialog.error.reason.server');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .alternate-username', 'textcontent', {}, 'connectdialog.username');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .alternate-password', 'textcontent', {}, 'connectdialog.password');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .dialog-submit', 'attribute', {'name': 'value'}, 'connectdialog.error.retry');
|
||||||
|
translatePiece('.connect-dialog.error-dialog .dialog-close', 'attribute', {'name': 'value'}, 'connectdialog.error.cancel');
|
||||||
|
translatePiece('.join-dialog .dialog-header', 'textcontent', {}, 'joindialog.title');
|
||||||
|
translatePiece('.join-dialog .dialog-submit', 'attribute', {'name': 'value'}, 'joindialog.connect');
|
||||||
|
translatePiece('.user-context-menu .mute', 'textcontent', {}, 'contextmenu.mute');
|
||||||
|
translatePiece('.user-context-menu .deafen', 'textcontent', {}, 'contextmenu.deafen');
|
||||||
|
translatePiece('.user-context-menu .priority-speaker', 'textcontent', {}, 'usercontextmenu.priority_speaker');
|
||||||
|
translatePiece('.user-context-menu .local-mute', 'textcontent', {}, 'usercontextmenu.local_mute');
|
||||||
|
translatePiece('.user-context-menu .ignore-messages', 'textcontent', {}, 'usercontextmenu.ignore_messages');
|
||||||
|
translatePiece('.user-context-menu .view-comment', 'textcontent', {}, 'usercontextmenu.view_comment');
|
||||||
|
translatePiece('.user-context-menu .change-comment', 'textcontent', {}, 'usercontextmenu.change_comment');
|
||||||
|
translatePiece('.user-context-menu .reset-comment', 'textcontent', {}, 'usercontextmenu.reset_comment');
|
||||||
|
translatePiece('.user-context-menu .view-avatar', 'textcontent', {}, 'usercontextmenu.view_avatar');
|
||||||
|
translatePiece('.user-context-menu .change-avatar', 'textcontent', {}, 'usercontextmenu.change_avatar');
|
||||||
|
translatePiece('.user-context-menu .reset-avatar', 'textcontent', {}, 'usercontextmenu.reset_avatar');
|
||||||
|
translatePiece('.user-context-menu .send-message', 'textcontent', {}, 'usercontextmenu.send_message');
|
||||||
|
translatePiece('.user-context-menu .information', 'textcontent', {}, 'usercontextmenu.information');
|
||||||
|
translatePiece('.user-context-menu .self-mute', 'textcontent', {}, 'usercontextmenu.self_mute');
|
||||||
|
translatePiece('.user-context-menu .self-deafen', 'textcontent', {}, 'usercontextmenu.self_deafen');
|
||||||
|
translatePiece('.user-context-menu .add-friend', 'textcontent', {}, 'usercontextmenu.add_friend');
|
||||||
|
translatePiece('.user-context-menu .remove-friend', 'textcontent', {}, 'usercontextmenu.remove_friend');
|
||||||
|
translatePiece('.channel-context-menu .join', 'textcontent', {}, 'channelcontextmenu.join');
|
||||||
|
translatePiece('.channel-context-menu .add', 'textcontent', {}, 'channelcontextmenu.add');
|
||||||
|
translatePiece('.channel-context-menu .edit', 'textcontent', {}, 'channelcontextmenu.edit');
|
||||||
|
translatePiece('.channel-context-menu .remove', 'textcontent', {}, 'channelcontextmenu.remove');
|
||||||
|
translatePiece('.channel-context-menu .link', 'textcontent', {}, 'channelcontextmenu.link');
|
||||||
|
translatePiece('.channel-context-menu .unlink', 'textcontent', {}, 'channelcontextmenu.unlink');
|
||||||
|
translatePiece('.channel-context-menu .unlink-all', 'textcontent', {}, 'channelcontextmenu.unlink_all');
|
||||||
|
translatePiece('.channel-context-menu .copy-mumble-url', 'textcontent', {}, 'channelcontextmenu.copy_mumble_url');
|
||||||
|
translatePiece('.channel-context-menu .copy-mumble-web-url', 'textcontent', {}, 'channelcontextmenu.copy_mumble_web_url');
|
||||||
|
translatePiece('.channel-context-menu .send-message', 'textcontent', {}, 'channelcontextmenu.send_message');
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
await localizationInitialize(navigator.language);
|
||||||
|
translateEverything();
|
||||||
|
initializeUI();
|
||||||
initVoice(data => {
|
initVoice(data => {
|
||||||
if (testVoiceHandler) {
|
if (testVoiceHandler) {
|
||||||
testVoiceHandler.write(data)
|
testVoiceHandler.write(data)
|
||||||
|
@ -1056,3 +1143,7 @@ initVoice(data => {
|
||||||
}, err => {
|
}, err => {
|
||||||
log('Cannot initialize user media. Microphone will not work:', err)
|
log('Cannot initialize user media. Microphone will not work:', err)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = main
|
||||||
|
|
||||||
|
|
99
app/loc.js
Normal file
99
app/loc.js
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
/**
|
||||||
|
* the default language to use
|
||||||
|
*
|
||||||
|
* @var {string}
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
var _languageDefault = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the fallback language to use
|
||||||
|
*
|
||||||
|
* @var {string}
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
var _languageFallback = null;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* two level map with ISO-639-1 code as first key and translation id as second key
|
||||||
|
*
|
||||||
|
* @var {Map<string,Map<string,string>>}
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
var _data = {};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} language
|
||||||
|
* @return Promise<Map<string,string>>
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
async function retrieveData (language) {
|
||||||
|
let json
|
||||||
|
try {
|
||||||
|
json = (await import(`../loc/${language}.json`)).default
|
||||||
|
} catch (exception) {
|
||||||
|
json = (await import(`../loc/${language.substr(0, language.indexOf('-'))}.json`)).default
|
||||||
|
}
|
||||||
|
const map = {}
|
||||||
|
flatten(json, '', map)
|
||||||
|
return map
|
||||||
|
}
|
||||||
|
|
||||||
|
function flatten (tree, prefix, result) {
|
||||||
|
for (const [key, value] of Object.entries(tree)) {
|
||||||
|
if (typeof value === 'string') {
|
||||||
|
result[prefix + key] = value
|
||||||
|
} else {
|
||||||
|
flatten(value, prefix + key + '.', result)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} languageDefault
|
||||||
|
* @param {string} [languageFallback]
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
export async function initialize (languageDefault, languageFallback = 'en') {
|
||||||
|
_languageFallback = languageFallback;
|
||||||
|
_languageDefault = languageDefault;
|
||||||
|
for (const language of [_languageFallback, _languageDefault]) {
|
||||||
|
if (_data.hasOwnProperty(language)) continue;
|
||||||
|
console.log('--', 'loading localization data for language "' + language + '" ...');
|
||||||
|
let data;
|
||||||
|
try {
|
||||||
|
data = await retrieveData(language);
|
||||||
|
} catch (exception) {
|
||||||
|
console.warn(exception.toString());
|
||||||
|
}
|
||||||
|
_data[language] = data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* gets a translation by its key for a specific language
|
||||||
|
*
|
||||||
|
* @param {string} key
|
||||||
|
* @param {string} [languageChosen]
|
||||||
|
* @return {string}
|
||||||
|
* @author svartoyg
|
||||||
|
*/
|
||||||
|
export function translate (key, languageChosen = _languageDefault) {
|
||||||
|
let result = undefined;
|
||||||
|
for (const language of [languageChosen, _languageFallback]) {
|
||||||
|
if (_data.hasOwnProperty(language) && (_data[language] !== undefined) && _data[language].hasOwnProperty(key)) {
|
||||||
|
result = _data[language][key];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result === undefined) {
|
||||||
|
result = ('{{' + key + '}}');
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
15
loc/de.json
Normal file
15
loc/de.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"connectdialog": {
|
||||||
|
"title": "Verbindung herstellen",
|
||||||
|
"address": "Adresse",
|
||||||
|
"port": "Port",
|
||||||
|
"username": "Nutzername",
|
||||||
|
"password": "Passwort",
|
||||||
|
"tokens": "Tokens",
|
||||||
|
"remove": "Entfernen",
|
||||||
|
"add": "Hinzufügen",
|
||||||
|
"cancel": "Abbrechen",
|
||||||
|
"connect": "Verbinden"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
66
loc/en.json
Normal file
66
loc/en.json
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"connectdialog": {
|
||||||
|
"title": "Connect to Server",
|
||||||
|
"address": "Address",
|
||||||
|
"port": "Port",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password",
|
||||||
|
"tokens": "Tokens",
|
||||||
|
"remove": "Remove",
|
||||||
|
"add": "Add",
|
||||||
|
"cancel": "Cancel",
|
||||||
|
"connect": "Connect",
|
||||||
|
"error": {
|
||||||
|
"title": "Failed to connect",
|
||||||
|
"reason": {
|
||||||
|
"refused": "The connection has been refused.",
|
||||||
|
"version": "The server uses an incompatible version.",
|
||||||
|
"username": "Your user name was rejected. Maybe try a different one?",
|
||||||
|
"userpassword": "The given password is incorrect.\nThe user name you have chosen requires a special one.",
|
||||||
|
"serverpassword": "The given password is incorrect.",
|
||||||
|
"username_in_use": "The user name you have chosen is already in use.",
|
||||||
|
"full": "The server is full.",
|
||||||
|
"clientcert": "The server requires you to provide a client certificate which is not supported by this web application.",
|
||||||
|
"server": "The server reports:"
|
||||||
|
},
|
||||||
|
"retry": "Retry",
|
||||||
|
"cancel": "Cancel"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"joindialog": {
|
||||||
|
"title": "Mumble Voice Conference",
|
||||||
|
"connect": "Join Conference"
|
||||||
|
},
|
||||||
|
"usercontextmenu": {
|
||||||
|
"mute": "Mute",
|
||||||
|
"deafen": "Deafen",
|
||||||
|
"priority_speaker": "Priority Speaker",
|
||||||
|
"local_mute": "Local Mute",
|
||||||
|
"ignore_messages": "Ignore Messages",
|
||||||
|
"view_comment": "View Comment",
|
||||||
|
"change_comment": "Change Comment",
|
||||||
|
"reset_comment": "Reset Comment",
|
||||||
|
"view_avatar": "View Avatar",
|
||||||
|
"change_avatar": "Change Avatar",
|
||||||
|
"reset_avatar": "Reset Avatar",
|
||||||
|
"send_message": "Send Message",
|
||||||
|
"information": "Information",
|
||||||
|
"self_mute": "Self Mute",
|
||||||
|
"self_deafen": "Self Deafen",
|
||||||
|
"add_friend": "Add Friend",
|
||||||
|
"remove_friend": "Remove Friend"
|
||||||
|
},
|
||||||
|
"channelcontextmenu": {
|
||||||
|
"channelcontextmenu.join": "Join Channel",
|
||||||
|
"channelcontextmenu.add": "Add",
|
||||||
|
"channelcontextmenu.edit": "Edit",
|
||||||
|
"channelcontextmenu.remove": "Remove",
|
||||||
|
"channelcontextmenu.link": "Link",
|
||||||
|
"channelcontextmenu.unlink": "Unlink",
|
||||||
|
"channelcontextmenu.unlink_all": "Unlink All",
|
||||||
|
"channelcontextmenu.copy_mumble_url": "Copy Mumble URL",
|
||||||
|
"channelcontextmenu.copy_mumble_web_url": "Copy Mumble-Web URL",
|
||||||
|
"channelcontextmenu.send_message": "Send Message"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
15
loc/eo.json
Normal file
15
loc/eo.json
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"connectdialog": {
|
||||||
|
"title": "Konektado",
|
||||||
|
"address": "Adreso",
|
||||||
|
"port": "Pordo",
|
||||||
|
"username": "Uzantnomo",
|
||||||
|
"password": "Pasvorto",
|
||||||
|
"tokens": "Ĵetonoj",
|
||||||
|
"remove": "Forigi",
|
||||||
|
"add": "Aldoni",
|
||||||
|
"cancel": "Nuligi",
|
||||||
|
"connect": "Konekti"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ module.exports = {
|
||||||
devtool: "cheap-source-map",
|
devtool: "cheap-source-map",
|
||||||
output: {
|
output: {
|
||||||
path: path.join(__dirname, 'dist'),
|
path: path.join(__dirname, 'dist'),
|
||||||
|
chunkFilename: '[chunkhash].js',
|
||||||
filename: '[name].js'
|
filename: '[name].js'
|
||||||
},
|
},
|
||||||
module: {
|
module: {
|
||||||
|
|
Loading…
Reference in a new issue