Removed the whole `{:br:}` syntax and removed jQuery from the `tra` method
parent
0faa33581d
commit
29c168ece0
|
@ -3,7 +3,6 @@ import {PermissionManager} from "./permission/PermissionManager";
|
|||
import {GroupManager} from "./permission/GroupManager";
|
||||
import {Settings, settings} from "./settings";
|
||||
import {Sound, SoundManager} from "./audio/Sounds";
|
||||
import {ConnectionProfile} from "./profiles/ConnectionProfile";
|
||||
import {LogCategory, logError, logInfo, logTrace, logWarn} from "./log";
|
||||
import {createErrorModal, createInputModal, Modal} from "./ui/elements/Modal";
|
||||
import {hashPassword} from "./utils/helpers";
|
||||
|
@ -13,7 +12,7 @@ import {defaultRecorder, RecorderProfile} from "./voice/RecorderProfile";
|
|||
import {formatMessage} from "./ui/frames/chat";
|
||||
import {EventHandler, Registry} from "./events";
|
||||
import {FileManager} from "./file/FileManager";
|
||||
import {tr} from "./i18n/localize";
|
||||
import {tr, tra} from "./i18n/localize";
|
||||
import {guid} from "./crypto/uid";
|
||||
import {PluginCmdRegistry} from "./connection/PluginCmdHandler";
|
||||
import {VoiceConnectionStatus, WhisperSessionInitializeData} from "./connection/VoiceConnection";
|
||||
|
@ -632,7 +631,7 @@ export class ConnectionHandler {
|
|||
case DisconnectReason.IDENTITY_TOO_LOW:
|
||||
createErrorModal(
|
||||
tr("Identity level is too low"),
|
||||
formatMessage(tr("You've been disconnected, because your Identity level is too low.{:br:}You need at least a level of {0}"), data["extra_message"])
|
||||
formatMessage(tr("You've been disconnected, because your Identity level is too low.\nYou need at least a level of {0}"), data["extra_message"])
|
||||
).open();
|
||||
this.sound.play(Sound.CONNECTION_DISCONNECTED);
|
||||
|
||||
|
@ -691,7 +690,7 @@ export class ConnectionHandler {
|
|||
const modal = createErrorModal(
|
||||
tr("You've been kicked"),
|
||||
formatMessage(
|
||||
have_invoker ? tr("You've been kicked from the server by {0}:{:br:}{1}") : tr("You've been kicked from the server:{:br:}{1}"),
|
||||
have_invoker ? tr("You've been kicked from the server by {0}:\n{1}") : tr("You've been kicked from the server:\n{1}"),
|
||||
have_invoker ?
|
||||
htmltags.generate_client_object({ client_id: parseInt(data["invokerid"]), client_unique_id: data["invokeruid"], client_name: data["invokername"]}) :
|
||||
"",
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import * as sdpTransform from "sdp-transform";
|
||||
import { tr } from "tc-shared/i18n/localize";
|
||||
import {tr, tra} from "tc-shared/i18n/localize";
|
||||
|
||||
interface SdpCodec {
|
||||
payload: number;
|
||||
|
|
|
@ -359,11 +359,11 @@ registerDispatcher(EventType.CLIENT_VIEW_LEAVE, (data, handlerId) => {
|
|||
break;
|
||||
|
||||
case ViewReasonId.VREASON_SERVER_KICK:
|
||||
message = tra("{0} was kicked from the server by {1}.{2}", data.client, data.invoker.client_name, data.message ? " (" + data.message + ")" : "");
|
||||
message = tra("{0} was kicked from the server by {1}.{2}", data.client.client_name, data.invoker.client_name, data.message ? " (" + data.message + ")" : "");
|
||||
break;
|
||||
|
||||
case ViewReasonId.VREASON_CHANNEL_KICK:
|
||||
message = tra("{0} was kicked from channel {1} by {2}.{3}", data.client, data.channel_from.channel_name, data.invoker.client_name, data.message ? " (" + data.message + ")" : "");
|
||||
message = tra("{0} was kicked from channel {1} by {2}.{3}", data.client.client_name, data.channel_from.channel_name, data.invoker.client_name, data.message ? " (" + data.message + ")" : "");
|
||||
break;
|
||||
|
||||
case ViewReasonId.VREASON_BAN:
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import {LogCategory, logError, logWarn} from "tc-shared/log";
|
||||
import {tr} from "tc-shared/i18n/localize";
|
||||
import {tr, tra} from "tc-shared/i18n/localize";
|
||||
import * as loader from "tc-loader";
|
||||
import {Stage} from "tc-loader";
|
||||
import {ConnectionHandler} from "tc-shared/ConnectionHandler";
|
||||
|
|
|
@ -11,7 +11,7 @@ import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
|||
import {ErrorCode} from "tc-shared/connection/ErrorCode";
|
||||
import {LogCategory, logError, logWarn} from "tc-shared/log";
|
||||
import {createErrorModal} from "tc-shared/ui/elements/Modal";
|
||||
import {traj} from "tc-shared/i18n/localize";
|
||||
import {trJQuery} from "tc-shared/i18n/localize";
|
||||
import {ConnectionHandler, ConnectionState} from "tc-shared/ConnectionHandler";
|
||||
import {LocalClientEntry} from "tc-shared/tree/Client";
|
||||
import {ServerCommand} from "tc-shared/connection/ConnectionBase";
|
||||
|
@ -281,7 +281,7 @@ export class ChannelConversation extends AbstractChat<ChannelConversationEvents>
|
|||
error = error.extra_message || error.message;
|
||||
}
|
||||
|
||||
createErrorModal(tr("Failed to delete message"), traj("Failed to delete conversation message{:br:}Error: {}", error)).open();
|
||||
createErrorModal(tr("Failed to delete message"), trJQuery("Failed to delete conversation message{:br:}Error: {}", error)).open();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,7 @@ import {LogCategory, logError, logWarn} from "tc-shared/log";
|
|||
import * as loader from "tc-loader";
|
||||
import {Stage} from "tc-loader";
|
||||
import * as crypto from "crypto-js";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
export type LocalAvatarInfo = {
|
||||
fileName: string,
|
||||
|
|
|
@ -75,9 +75,13 @@ export function tr(message: string, key?: string) : string {
|
|||
return translated;
|
||||
}
|
||||
|
||||
export function tra(message: string, ...args: (string | number | boolean)[]) : string;
|
||||
export function tra(message: string, ...args: any[]) : JQuery[];
|
||||
export function tra(message: string, ...args: any[]) : any {
|
||||
export function trJQuery(message: string, ...args: any[]) : JQuery[] {
|
||||
message = /* @tr-ignore */ tr(message);
|
||||
return formatMessage(message, ...args);
|
||||
}
|
||||
|
||||
/* We can remove our checks if we're sure that no call calls this with an object any more*/
|
||||
export function tra(message: string, ...args: (string | number | boolean)[]) : string {
|
||||
message = /* @tr-ignore */ tr(message);
|
||||
for(const element of args) {
|
||||
if(element === null) {
|
||||
|
@ -92,16 +96,18 @@ export function tra(message: string, ...args: any[]) : any {
|
|||
continue;
|
||||
|
||||
default:
|
||||
return formatMessage(message, ...args);
|
||||
debugger;
|
||||
logWarn(LogCategory.GENERAL, tr("Received tra argument which isn't a string"));
|
||||
}
|
||||
}
|
||||
if(message.indexOf("{:") !== -1)
|
||||
return formatMessage(message, ...args);
|
||||
return formatMessageString(message, ...args);
|
||||
}
|
||||
|
||||
export function traj(message: string, ...args: any[]) : JQuery[] {
|
||||
return tra(message, ...args, {});
|
||||
if(message.indexOf("{:") !== -1) {
|
||||
debugger;
|
||||
logWarn(LogCategory.GENERAL, tr("Received tra message which contains HTML elements"));
|
||||
message = message.replace(/{:br:}/g, "\n");
|
||||
}
|
||||
|
||||
return formatMessageString(message, ...args);
|
||||
}
|
||||
|
||||
async function load_translation_file(url: string, path: string) : Promise<TranslationFile> {
|
||||
|
@ -331,7 +337,7 @@ export async function initializeI18N() {
|
|||
logError(LogCategory.I18N, tr("Failed to initialize selected translation: %o"), error);
|
||||
const show_error = () => {
|
||||
import("../ui/elements/Modal").then(Modal => {
|
||||
Modal.createErrorModal(tr("Translation System"), tra("Failed to load current selected translation file.{:br:}File: {0}{:br:}Error: {1}{:br:}{:br:}Using default fallback translations.", cfg.current_translation_url, error)).open()
|
||||
Modal.createErrorModal(tr("Translation System"), tra("Failed to load current selected translation file.\nFile: {0}\nError: {1}\n\nUsing default fallback translations.", cfg.current_translation_url, error)).open()
|
||||
});
|
||||
};
|
||||
if(loader.running())
|
||||
|
@ -351,16 +357,12 @@ export async function initializeI18N() {
|
|||
declare global {
|
||||
interface Window {
|
||||
tr(message: string) : string;
|
||||
tra(message: string, ...args: (string | number | boolean | null | undefined)[]) : string;
|
||||
tra(message: string, ...args: any[]) : JQuery[];
|
||||
|
||||
log: any;
|
||||
StaticSettings: any;
|
||||
}
|
||||
|
||||
const tr: typeof window.tr;
|
||||
const tra: typeof window.tra;
|
||||
}
|
||||
|
||||
window.tr = tr;
|
||||
window.tra = tra;
|
||||
window.tr = tr;
|
|
@ -10,7 +10,7 @@ import {Registry} from "tc-shared/events";
|
|||
import {InputStartError} from "tc-shared/voice/RecorderBase";
|
||||
import {LogCategory, logDebug, logError, logWarn} from "tc-shared/log";
|
||||
import {queryMediaPermissions, requestMediaStream, stopMediaStream} from "tc-shared/media/Stream";
|
||||
import {tr} from "tc-shared/i18n/localize";
|
||||
import {tr, tra} from "tc-shared/i18n/localize";
|
||||
|
||||
declare global {
|
||||
interface MediaDevices {
|
||||
|
|
|
@ -4,6 +4,7 @@ import {Registry} from "tc-shared/events";
|
|||
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||
import {ErrorCode} from "tc-shared/connection/ErrorCode";
|
||||
import _ = require("lodash");
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
export type PlaylistEntry = {
|
||||
type: "song",
|
||||
|
|
|
@ -6,6 +6,7 @@ import {LogCategory, logError} from "tc-shared/log";
|
|||
import {clientServiceInvite, clientServices} from "tc-shared/clientservice";
|
||||
import {handleConnectRequest} from "tc-shared/main";
|
||||
import {assertMainApplication} from "tc-shared/ui/utils";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
assertMainApplication();
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import {useContext} from "react";
|
|||
import * as contextmenu from "tc-shared/ui/elements/ContextMenu";
|
||||
|
||||
import IconPlay from "./YoutubePlayButton.svg";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
const cssStyle = require("./YoutubeRenderer.scss");
|
||||
|
||||
const patternYtVideoId = /^(?:http(?:s)?:\/\/)?(?:www\.)?(?:m\.)?(?:youtu\.be\/|youtube\.com\/(?:(?:watch)?\?(?:.*&)?v(?:i)?=|(?:embed|v|vi|user)\/))([^?&"'>]{10,11})$/;
|
||||
|
|
|
@ -94,7 +94,7 @@ export function formatMessage(pattern: string, ...objects: any[]) : JQuery[] {
|
|||
return result;
|
||||
}
|
||||
|
||||
export function formatMessageString(pattern: string, ...args: string[]) : string {
|
||||
export function formatMessageString(pattern: string, ...args: (string | number | boolean)[]) : string {
|
||||
return parseMessageWithArguments(pattern, args.length).map(e => typeof e === "string" ? e : args[e]).join("");
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import {ClientGroupInfo, ClientInfoEvents, InheritedChannelInfo,} from "tc-share
|
|||
import {Registry} from "tc-shared/events";
|
||||
import {openClientInfo} from "tc-shared/ui/modal/ModalClientInfo";
|
||||
import {spawnAvatarUpload} from "tc-shared/ui/modal/avatar-upload/Controller";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
export class ClientInfoController {
|
||||
private readonly uiEvents: Registry<ClientInfoEvents>;
|
||||
|
|
|
@ -16,7 +16,7 @@ import {ClientAvatar, getGlobalAvatarManagerFactory} from "tc-shared/file/Avatar
|
|||
import {AvatarRenderer} from "tc-shared/ui/react-elements/Avatar";
|
||||
import {Translatable} from "tc-shared/ui/react-elements/i18n";
|
||||
import {LoadingDots} from "tc-shared/ui/react-elements/LoadingDots";
|
||||
import {ChannelTag, ClientTag} from "tc-shared/ui/tree/EntryTags";
|
||||
import {ClientTag} from "tc-shared/ui/tree/EntryTags";
|
||||
import {guid} from "tc-shared/crypto/uid";
|
||||
import {useDependentState} from "tc-shared/ui/react-elements/Helper";
|
||||
import {format_online_time} from "tc-shared/utils/TimeUtils";
|
||||
|
@ -25,7 +25,8 @@ import {ClientIconRenderer} from "tc-shared/ui/react-elements/Icons";
|
|||
import {getIconManager} from "tc-shared/file/Icons";
|
||||
import {RemoteIconRenderer} from "tc-shared/ui/react-elements/Icon";
|
||||
import {CountryCode} from "tc-shared/ui/react-elements/CountryCode";
|
||||
import {getKeyBoard, SpecialKey} from "tc-shared/PPTListener";
|
||||
import {getKeyBoard} from "tc-shared/PPTListener";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const cssStyle = require("./ClientInfoRenderer.scss");
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ import {openMusicManage} from "tc-shared/ui/modal/ModalMusicManage";
|
|||
import {createErrorModal, createInputModal} from "tc-shared/ui/elements/Modal";
|
||||
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||
import {LogCategory, logError} from "tc-shared/log";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const ChannelInfoUpdateProperties: (keyof ChannelProperties)[] = [
|
||||
"channel_name",
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
import {Translatable, VariadicTranslatable} from "tc-shared/ui/react-elements/i18n";
|
||||
import {RemoteIconRenderer} from "tc-shared/ui/react-elements/Icon";
|
||||
import {getIconManager} from "tc-shared/file/Icons";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const StateContext = React.createContext<SideHeaderState>(undefined);
|
||||
const EventsContext = React.createContext<Registry<SideHeaderEvents>>(undefined);
|
||||
|
|
|
@ -4,6 +4,7 @@ import {MusicPlaylistStatus, MusicPlaylistUiEvents} from "tc-shared/ui/frames/si
|
|||
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||
import {LogCategory, logError} from "tc-shared/log";
|
||||
import {createErrorModal} from "tc-shared/ui/elements/Modal";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
export class MusicPlaylistController {
|
||||
readonly uiEvents: Registry<MusicPlaylistUiEvents>;
|
||||
|
|
|
@ -18,7 +18,7 @@ import {
|
|||
} from "tc-shared/connection/VideoConnection";
|
||||
import {ClientEntry, ClientType, LocalClientEntry, MusicClientEntry} from "tc-shared/tree/Client";
|
||||
import {LogCategory, logError, logWarn} from "tc-shared/log";
|
||||
import {tr} from "tc-shared/i18n/localize";
|
||||
import {tr, tra} from "tc-shared/i18n/localize";
|
||||
import {Settings, settings} from "tc-shared/settings";
|
||||
import * as _ from "lodash";
|
||||
import PermissionType from "tc-shared/permission/PermissionType";
|
||||
|
|
|
@ -345,7 +345,7 @@ function initializeGroupCreateController(connection: ConnectionHandler, events:
|
|||
}).catch(error => {
|
||||
if(error instanceof CommandResult && error.id === ErrorCode.SERVER_INSUFFICIENT_PERMISSIONS) {
|
||||
createErrorModal(tr("Failed to create group"),
|
||||
tra("Failed to create group.\nMissing permission {}", connection.permissions.resolveInfo(parseInt(error.json["failed_permid"]))?.name || tr("unknwon"))).open();
|
||||
tra("Failed to create group.\nMissing permission {}", connection.permissions.getFailedPermission(error))).open();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ import PermissionType from "../../permission/PermissionType";
|
|||
import {createErrorModal, createModal} from "../../ui/elements/Modal";
|
||||
import {LogCategory, logError, logInfo, logWarn} from "../../log";
|
||||
import {CommandResult} from "../../connection/ServerConnectionDeclaration";
|
||||
import {tra, traj} from "../../i18n/localize";
|
||||
import {tra, trJQuery} from "../../i18n/localize";
|
||||
import {arrayBufferBase64} from "../../utils/buffers";
|
||||
import * as crc32 from "../../crypto/crc32";
|
||||
import {FileInfo} from "../../file/FileManager";
|
||||
|
@ -285,13 +285,13 @@ function handle_icon_upload(file: File, client: ConnectionHandler): UploadingIco
|
|||
} catch (error) {
|
||||
logInfo(LogCategory.GENERAL, "Image failed to load (%o)", error);
|
||||
logError(LogCategory.GENERAL, tr("Failed to load file %s: Image failed to load"), file.name);
|
||||
createErrorModal(tr("Icon upload failed"), tra("Failed to upload icon {}.{:br:}Failed to load image", file.name)).open();
|
||||
createErrorModal(tr("Icon upload failed"), tra("Failed to upload icon {}.\nFailed to load image", file.name)).open();
|
||||
icon.state = "error";
|
||||
}
|
||||
|
||||
const width_error = message => {
|
||||
logError(LogCategory.GENERAL, tr("Failed to load file %s: Invalid bounds: %s"), file.name, message);
|
||||
createErrorModal(tr("Icon upload failed"), tra("Failed to upload icon {}.{:br:}Image is too large ({})", file.name, message)).open();
|
||||
createErrorModal(tr("Icon upload failed"), tra("Failed to upload icon {}.\nImage is too large ({})", file.name, message)).open();
|
||||
icon.state = "error";
|
||||
};
|
||||
|
||||
|
@ -469,7 +469,7 @@ export function spawnIconUpload(client: ConnectionHandler) {
|
|||
const update_upload_button = () => {
|
||||
const icon_count = icons.filter(e => e.state === "valid").length;
|
||||
button_upload.empty();
|
||||
traj("Upload icons ({})", icon_count).forEach(e => e.appendTo(button_upload));
|
||||
trJQuery("Upload icons ({})", icon_count).forEach(e => e.appendTo(button_upload));
|
||||
button_upload.prop("disabled", icon_count == 0);
|
||||
};
|
||||
update_upload_button();
|
||||
|
|
|
@ -1619,7 +1619,7 @@ function build_permission_container(event_registry: Registry<music_manage>, tag:
|
|||
last_sync_value = event.value;
|
||||
} else if (event.status === "error") {
|
||||
if (typeof last_sync_value === "number") input.val(last_sync_value);
|
||||
createErrorModal(tr("Failed to change permission"), tra("Failed to change permission:{:br:}{}", event.error_msg)).open();
|
||||
createErrorModal(tr("Failed to change permission"), tra("Failed to change permission:\n{}", event.error_msg)).open();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1977,7 +1977,7 @@ function build_permission_container(event_registry: Registry<music_manage>, tag:
|
|||
last_sync_value = event.value;
|
||||
} else if (event.status === "error") {
|
||||
if (typeof last_sync_value === "number") input.val(last_sync_value);
|
||||
createErrorModal(tr("Failed to change permission"), tra("Failed to change permission:{:br:}{}", event.error_msg)).open();
|
||||
createErrorModal(tr("Failed to change permission"), tra("Failed to change permission:\n{}", event.error_msg)).open();
|
||||
}
|
||||
hide_indicator = false;
|
||||
update_indicator();
|
||||
|
|
|
@ -1,192 +0,0 @@
|
|||
import {ServerConnectionInfo, ServerEntry} from "../../tree/Server";
|
||||
import {createModal, Modal} from "../../ui/elements/Modal";
|
||||
import {CommandResult} from "../../connection/ServerConnectionDeclaration";
|
||||
import {Graph} from "../../ui/elements/NetGraph";
|
||||
import * as tooltip from "../../ui/elements/Tooltip";
|
||||
import {network} from "../../ui/frames/chat";
|
||||
import {ErrorCode} from "../../connection/ErrorCode";
|
||||
import {tr} from "tc-shared/i18n/localize";
|
||||
|
||||
export enum RequestInfoStatus {
|
||||
SUCCESS,
|
||||
UNKNOWN,
|
||||
NO_PERMISSION
|
||||
}
|
||||
export type ServerBandwidthInfoUpdateCallback = (status: RequestInfoStatus, info?: ServerConnectionInfo) => any;
|
||||
export function openServerInfoBandwidth(server: ServerEntry, update_callbacks?: ServerBandwidthInfoUpdateCallback[]) : Modal {
|
||||
let modal: Modal;
|
||||
let own_callbacks = !update_callbacks;
|
||||
update_callbacks = update_callbacks || [];
|
||||
|
||||
modal = createModal({
|
||||
header: tr("Server bandwidth data"),
|
||||
body: () => {
|
||||
const template = $("#tmpl_server_info_bandwidth").renderTag();
|
||||
|
||||
const children = template.children();
|
||||
initialize_current_bandwidth(modal, children.find(".statistic-bandwidth"), update_callbacks);
|
||||
initialize_ft_bandwidth(modal, children.find(".statistic-ft-bandwidth"), update_callbacks);
|
||||
initialize_general(template.find(".top"), update_callbacks);
|
||||
|
||||
tooltip.initialize(template);
|
||||
return template.children();
|
||||
},
|
||||
footer: null,
|
||||
min_width: "25em"
|
||||
});
|
||||
|
||||
if(own_callbacks) {
|
||||
const updater = setInterval(() => {
|
||||
server.request_connection_info().then(info => update_callbacks.forEach(e => e(RequestInfoStatus.SUCCESS, info))).catch(error => {
|
||||
if(error instanceof CommandResult && error.id == ErrorCode.SERVER_INSUFFICIENT_PERMISSIONS) {
|
||||
update_callbacks.forEach(e => e(RequestInfoStatus.NO_PERMISSION));
|
||||
return;
|
||||
}
|
||||
update_callbacks.forEach(e => e(RequestInfoStatus.UNKNOWN));
|
||||
});
|
||||
}, 1000);
|
||||
modal.close_listener.push(() => clearInterval(updater));
|
||||
}
|
||||
|
||||
|
||||
modal.htmlTag.find(".button-close").on('click', event => modal.close());
|
||||
modal.htmlTag.find(".modal-body").addClass("modal-server-info-bandwidth");
|
||||
modal.open();
|
||||
return modal;
|
||||
}
|
||||
|
||||
function initialize_graph(modal: Modal, tag: JQuery, callbacks: ServerBandwidthInfoUpdateCallback[], fields: {uplaod: string, download: string}) {
|
||||
const canvas = tag.find("canvas")[0] as HTMLCanvasElement;
|
||||
const label_upload = tag.find(".upload");
|
||||
const label_download = tag.find(".download");
|
||||
let last_info: { status: RequestInfoStatus, info: ServerConnectionInfo };
|
||||
let custom_info = false;
|
||||
|
||||
const show_info = (upload: number | undefined, download: number | undefined) => {
|
||||
let fallback_text = last_info && last_info.status === RequestInfoStatus.NO_PERMISSION ? tr("No permission") : tr("receiving...");
|
||||
|
||||
if(typeof upload !== "number")
|
||||
upload = last_info ? last_info[fields.uplaod] : undefined;
|
||||
|
||||
if(typeof download !== "number")
|
||||
download = last_info ? last_info[fields.download] : undefined;
|
||||
|
||||
if(typeof upload !== "number")
|
||||
label_upload.text(fallback_text);
|
||||
else
|
||||
label_upload.text(network.format_bytes(upload, {unit: "Bytes", time: "s", exact: false}));
|
||||
|
||||
if(typeof download !== "number")
|
||||
label_download.text(fallback_text);
|
||||
else
|
||||
label_download.text(network.format_bytes(download, {unit: "Bytes", time: "s", exact: false}));
|
||||
};
|
||||
show_info(undefined, undefined);
|
||||
|
||||
const graph = new Graph();
|
||||
graph.initializeCanvas(canvas);
|
||||
graph.pushEntry({ timestamp: Date.now(), upload: undefined, download: undefined});
|
||||
callbacks.push((status, values) => {
|
||||
last_info = {status: status, info: values};
|
||||
|
||||
if(!values) {
|
||||
graph.pushEntry({ timestamp: Date.now(), upload: undefined, download: undefined});
|
||||
} else {
|
||||
graph.pushEntry({
|
||||
timestamp: Date.now(),
|
||||
download: values[fields.download], //values.connection_bandwidth_received_last_second_total,
|
||||
upload: values[fields.uplaod], //values.connection_bandwidth_sent_last_second_total
|
||||
});
|
||||
}
|
||||
|
||||
/* set that we want to show the entry within one second */
|
||||
graph.timeSpan.origin = Object.assign(graph.calculateTimespan(), { time: Date.now() });
|
||||
graph.timeSpan.target = {
|
||||
begin: Date.now() - 120 * 1000,
|
||||
end: Date.now(),
|
||||
time: Date.now() + 200
|
||||
};
|
||||
|
||||
graph.cleanup();
|
||||
if(!custom_info) {
|
||||
show_info(undefined, undefined);
|
||||
graph.resize(); /* just to ensure (we have to rethink this maybe; cause it causes a recalculates the style */
|
||||
}
|
||||
});
|
||||
|
||||
graph.maxGapSize(0);
|
||||
graph.initialize();
|
||||
|
||||
graph.callbackDetailedHide = () => {
|
||||
custom_info = false;
|
||||
show_info(undefined, undefined);
|
||||
};
|
||||
|
||||
graph.callbackDetailedInfo = (upload, download, timestamp, event) => {
|
||||
custom_info = true;
|
||||
show_info(upload, download);
|
||||
};
|
||||
|
||||
modal.close_listener.push(() => graph.finalize());
|
||||
modal.open_listener.push(() => graph.resize());
|
||||
|
||||
tag.addClass("window-resize-listener").on('resize', event => graph.resize());
|
||||
}
|
||||
|
||||
function initialize_current_bandwidth(modal: Modal, tag: JQuery, callbacks: ServerBandwidthInfoUpdateCallback[]) {
|
||||
initialize_graph(modal, tag, callbacks, {
|
||||
uplaod: "connection_bandwidth_sent_last_second_total",
|
||||
download: "connection_bandwidth_received_last_second_total"
|
||||
});
|
||||
}
|
||||
|
||||
function initialize_ft_bandwidth(modal: Modal, tag: JQuery, callbacks: ServerBandwidthInfoUpdateCallback[]) {
|
||||
initialize_graph(modal, tag, callbacks, {
|
||||
uplaod: "connection_filetransfer_bandwidth_sent",
|
||||
download: "connection_filetransfer_bandwidth_received"
|
||||
});
|
||||
}
|
||||
|
||||
function initialize_general(tag: JQuery, callbacks: ServerBandwidthInfoUpdateCallback[]) {
|
||||
const tag_packets_upload = tag.find(".statistic-packets .upload");
|
||||
const tag_packets_download = tag.find(".statistic-packets .download");
|
||||
|
||||
const tag_bytes_upload = tag.find(".statistic-bytes .upload");
|
||||
const tag_bytes_download = tag.find(".statistic-bytes .download");
|
||||
|
||||
const tag_ft_bytes_upload = tag.find(".statistic-ft-bytes .upload");
|
||||
const tag_ft_bytes_download = tag.find(".statistic-ft-bytes .download");
|
||||
|
||||
const update = (tag, value: undefined | null | number) => {
|
||||
if(typeof value === "undefined")
|
||||
tag.text(tr("receiving..."));
|
||||
else if(value === null)
|
||||
tag.text(tr("no permissions"));
|
||||
else
|
||||
tag.text(network.format_bytes(value, {unit: "Bytes", exact: false}));
|
||||
};
|
||||
|
||||
const props = [
|
||||
{tag: tag_packets_download, property: "connection_packets_received_total"},
|
||||
{tag: tag_packets_upload, property: "connection_packets_sent_total"},
|
||||
|
||||
{tag: tag_bytes_download, property: "connection_bytes_received_total"},
|
||||
{tag: tag_bytes_upload, property: "connection_bytes_sent_total"},
|
||||
|
||||
{tag: tag_ft_bytes_upload, property: "connection_filetransfer_bytes_received_total"},
|
||||
{tag: tag_ft_bytes_download, property: "connection_filetransfer_bytes_sent_total"},
|
||||
];
|
||||
|
||||
callbacks.push((status, info) => {
|
||||
if(status === RequestInfoStatus.SUCCESS) {
|
||||
for(const entry of props)
|
||||
update(entry.tag, info[entry.property]);
|
||||
} else if(status === RequestInfoStatus.NO_PERMISSION) {
|
||||
for(const entry of props)
|
||||
update(entry.tag, null);
|
||||
} else {
|
||||
for(const entry of props)
|
||||
update(entry.tag, undefined);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -8,7 +8,7 @@ import PermissionType from "tc-shared/permission/PermissionType";
|
|||
import {getOwnAvatarStorage, LocalAvatarInfo} from "tc-shared/file/OwnAvatarStorage";
|
||||
import {LogCategory, logError, logInfo, logWarn} from "tc-shared/log";
|
||||
import {Mutex} from "tc-shared/Mutex";
|
||||
import {tr, traj} from "tc-shared/i18n/localize";
|
||||
import {tr, trJQuery} from "tc-shared/i18n/localize";
|
||||
import {createErrorModal, createInfoModal} from "tc-shared/ui/elements/Modal";
|
||||
import {CommandResult} from "tc-shared/connection/ServerConnectionDeclaration";
|
||||
import {formatMessage} from "tc-shared/ui/frames/chat";
|
||||
|
@ -211,11 +211,11 @@ class Controller {
|
|||
|
||||
let message;
|
||||
if(error instanceof CommandResult) {
|
||||
message = formatMessage(tr("Failed to delete avatar.{:br:}Error: {0}"), error.formattedMessage());
|
||||
message = formatMessage(tr("Failed to delete avatar.\nError: {0}"), error.formattedMessage());
|
||||
}
|
||||
|
||||
if(!message) {
|
||||
message = formatMessage(tr("Failed to delete avatar.{:br:}Lookup the console for more details"));
|
||||
message = formatMessage(tr("Failed to delete avatar.\nLookup the console for more details"));
|
||||
}
|
||||
|
||||
createErrorModal(tr("Failed to delete avatar"), message).open();
|
||||
|
@ -262,7 +262,7 @@ class Controller {
|
|||
if (transfer.transferState() !== FileTransferState.FINISHED) {
|
||||
if (transfer.transferState() === FileTransferState.ERRORED) {
|
||||
logWarn(LogCategory.FILE_TRANSFER, tr("Failed to upload clients avatar: %o"), transfer.currentError());
|
||||
createErrorModal(tr("Failed to upload avatar"), traj("Failed to upload avatar:{:br:}{0}", transfer.currentErrorMessage())).open();
|
||||
createErrorModal(tr("Failed to upload avatar"), tr("Failed to upload avatar:\n{0}", transfer.currentErrorMessage())).open();
|
||||
return;
|
||||
} else if (transfer.transferState() === FileTransferState.CANCELED) {
|
||||
createErrorModal(tr("Failed to upload avatar"), tr("Your avatar upload has been canceled.")).open();
|
||||
|
@ -287,11 +287,11 @@ class Controller {
|
|||
|
||||
let message;
|
||||
if(error instanceof CommandResult) {
|
||||
message = formatMessage(tr("Failed to update avatar flag.{:br:}Error: {0}"), error.formattedMessage());
|
||||
message = formatMessage(tr("Failed to update avatar flag.\nError: {0}"), error.formattedMessage());
|
||||
}
|
||||
|
||||
if(!message) {
|
||||
message = formatMessage(tr("Failed to update avatar flag.{:br:}Lookup the console for more details"));
|
||||
message = formatMessage(tr("Failed to update avatar flag.\nLookup the console for more details"));
|
||||
}
|
||||
|
||||
createErrorModal(tr("Failed to set avatar"), message).open();
|
||||
|
|
|
@ -19,6 +19,7 @@ import {joinClassList, useDependentState} from "tc-shared/ui/react-elements/Help
|
|||
|
||||
import kDefaultAvatarUrl from "../../../../img/style/avatar.png";
|
||||
import byteSizeToString = network.binarySizeToString;
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const ServerUniqueIdContext = React.createContext<string>(undefined);
|
||||
const EventContext = React.createContext<Registry<ModalAvatarUploadEvents>>(undefined);
|
||||
|
@ -294,7 +295,7 @@ class ModalAvatarUpload extends AbstractModal {
|
|||
createErrorModal(tr("Failed to load avatar"), tra("Failed to load avatar: {}", result.reason)).open();
|
||||
succeeded = false;
|
||||
} else if(result.status === "cache-unavailable") {
|
||||
createErrorModal(tr("Failed to load avatar"), tra("Failed to load avatar:{:br:}Own avatar cach unavailable.")).open();
|
||||
createErrorModal(tr("Failed to load avatar"), tra("Failed to load avatar:{:br:}Own avatar cache unavailable.")).open();
|
||||
succeeded = false;
|
||||
} else {
|
||||
succeeded = false;
|
||||
|
|
|
@ -10,7 +10,7 @@ import {joinClassList, useTr} from "tc-shared/ui/react-elements/Helper";
|
|||
import {Checkbox} from "tc-shared/ui/react-elements/Checkbox";
|
||||
import {ControlledBoxedInputField, ControlledSelect} from "tc-shared/ui/react-elements/InputField";
|
||||
import {createErrorModal} from "tc-shared/ui/elements/Modal";
|
||||
import {traj} from "tc-shared/i18n/localize";
|
||||
import {tr, tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const cssStyle = require("./Renderer.scss");
|
||||
const EventContext = React.createContext<Registry<ModalInputProcessorEvents>>(undefined);
|
||||
|
@ -382,7 +382,7 @@ class Modal extends AbstractModal {
|
|||
this.variables = createIpcUiVariableConsumer(variables);
|
||||
|
||||
this.events.on("notify_apply_error", event => {
|
||||
createErrorModal(tr("Failed to apply changes"), traj("Failed to apply changes:{:br:}{}", event.message)).open();
|
||||
createErrorModal(tr("Failed to apply changes"), tra("Failed to apply changes:\n{}", event.message)).open();
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ export function spawnPermissionEditorModal(connection: ConnectionHandler, defaul
|
|||
function initializePermissionModalResultHandlers(events: Registry<PermissionModalEvents>) {
|
||||
events.on("action_rename_group_result", event => {
|
||||
if (event.status === "error") {
|
||||
createErrorModal(tr("Failed to rename group"), formatMessage(tr("Failed to rename group:{:br:}"), event.error)).open();
|
||||
createErrorModal(tr("Failed to rename group"), formatMessage(tra("Failed to rename group:\n{}", event.error))).open();
|
||||
} else {
|
||||
createInfoModal(tr("Group renamed"), tr("The group has been renamed.")).open();
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import {CallOnce, ignorePromise} from "tc-shared/proto";
|
|||
import {spawnModal} from "tc-shared/ui/react-elements/modal";
|
||||
import {ServerConnectionInfoResult, ServerProperties} from "tc-shared/tree/Server";
|
||||
import {LogCategory, logWarn} from "tc-shared/log";
|
||||
import {openServerInfoBandwidth} from "tc-shared/ui/modal/ModalServerInfoBandwidth";
|
||||
import {spawnServerBandwidth} from "tc-shared/ui/modal/server-bandwidth/Controller";
|
||||
|
||||
const kPropertyUpdateMatrix: {[T in keyof ServerProperties]?: [keyof ModalServerInfoVariables]} = {
|
||||
|
|
|
@ -189,7 +189,7 @@ class KeyActionEntry extends ReactComponentBase<KeyActionEntryProperties, KeyAct
|
|||
});
|
||||
} else {
|
||||
this.setState({state: "loaded"});
|
||||
createErrorModal(tr("Failed to change key"), tra("Failed to change key for action \"{}\":{:br:}{}", this.props.action, event.status === "timeout" ? tr("timeout") : event.error));
|
||||
createErrorModal(tr("Failed to change key"), tra("Failed to change key for action \"{}\":\n{}", this.props.action, event.status === "timeout" ? tr("timeout") : event.error));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ import {InputDevice} from "tc-shared/audio/Recorder";
|
|||
import {joinClassList} from "tc-shared/ui/react-elements/Helper";
|
||||
import {IconTooltip} from "tc-shared/ui/react-elements/Tooltip";
|
||||
import _ from "lodash";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const cssStyle = require("./Microphone.scss");
|
||||
const EventContext = React.createContext<Registry<MicrophoneSettingsEvents>>(undefined);
|
||||
|
|
|
@ -7,7 +7,7 @@ import {LogCategory, logError, logTrace} from "../../../log";
|
|||
import {Entry, MenuEntry, MenuEntryType, spawn_context_menu} from "../../../ui/elements/ContextMenu";
|
||||
import {getKeyBoard, SpecialKey} from "../../../PPTListener";
|
||||
import {spawnYesNo} from "../../../ui/modal/ModalYesNo";
|
||||
import {tr, tra, traj} from "../../../i18n/localize";
|
||||
import {tr, tra} from "../../../i18n/localize";
|
||||
import {
|
||||
FileTransfer,
|
||||
FileTransferState,
|
||||
|
@ -708,7 +708,7 @@ export function initializeRemoteFileBrowserController(connection: ConnectionHand
|
|||
});
|
||||
transfer.awaitFinished().then(() => {
|
||||
if (transfer.transferState() === FileTransferState.ERRORED) {
|
||||
createErrorModal(tr("Failed to download file"), traj("Failed to download {0}:{:br:}{1}", fileName, transfer.currentErrorMessage())).open();
|
||||
createErrorModal(tr("Failed to download file"), tra("Failed to download {0}:\n{1}", fileName, transfer.currentErrorMessage())).open();
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
|
@ -739,7 +739,7 @@ export function initializeRemoteFileBrowserController(connection: ConnectionHand
|
|||
} else if (event.mode === "files") {
|
||||
const pathInfo = parsePath(event.path, connection);
|
||||
if (pathInfo.type !== "channel") {
|
||||
createErrorModal(tr("Failed to upload file(s)"), tra("Failed to upload files:{:br:}File uplaod is only supported in channel directories")).open();
|
||||
createErrorModal(tr("Failed to upload file(s)"), tra("Failed to upload files:\nFile uplaod is only supported in channel directories")).open();
|
||||
return;
|
||||
}
|
||||
for (const file of event.files) {
|
||||
|
@ -753,7 +753,7 @@ export function initializeRemoteFileBrowserController(connection: ConnectionHand
|
|||
});
|
||||
transfer.awaitFinished().then(() => {
|
||||
if (transfer.transferState() === FileTransferState.ERRORED) {
|
||||
createErrorModal(tr("Failed to upload file"), tra("Failed to upload {0}:{:br:}{1}", fileName, transfer.currentErrorMessage())).open();
|
||||
createErrorModal(tr("Failed to upload file"), tra("Failed to upload {0}:\n{1}", fileName, transfer.currentErrorMessage())).open();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -321,9 +321,9 @@ export class NavigationBar extends ReactComponentBase<NavigationBarProperties, N
|
|||
|
||||
if (event.status !== "success") {
|
||||
if (event.status === "timeout") {
|
||||
createErrorModal(tr("Failed to enter path"), tra("Failed to enter given path.{:br:}Action resulted in a timeout.")).open();
|
||||
createErrorModal(tr("Failed to enter path"), tra("Failed to enter given path.\nAction resulted in a timeout.")).open();
|
||||
} else {
|
||||
createErrorModal(tr("Failed to enter path"), tra("Failed to enter given path:{:br:}{0}", event.error)).open();
|
||||
createErrorModal(tr("Failed to enter path"), tra("Failed to enter given path:\n{0}", event.error)).open();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -457,9 +457,9 @@ const FileName = (props: { path: string, file: ListedFileInfo }) => {
|
|||
} else {
|
||||
setFileName(props.file.name);
|
||||
if (event.status === "timeout") {
|
||||
createErrorModal(tr("Failed to rename file"), tra("Failed to rename file.{:br:}Action resulted in a timeout.")).open();
|
||||
createErrorModal(tr("Failed to rename file"), tra("Failed to rename file.\nAction resulted in a timeout.")).open();
|
||||
} else {
|
||||
createErrorModal(tr("Failed to rename file"), tra("Failed to rename file:{:br:}{0}", event.error)).open();
|
||||
createErrorModal(tr("Failed to rename file"), tra("Failed to rename file:\n{0}", event.error)).open();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1306,7 +1306,7 @@ export class FileBrowserRenderer extends ReactComponentBase<FileListTablePropert
|
|||
if (e.status === "success")
|
||||
return;
|
||||
|
||||
createErrorModal(tr("Failed to delete entry"), tra("Failed to delete \"{0}\":{:br:}{1}", e.name, e.error || tr("Unknown error"))).open();
|
||||
createErrorModal(tr("Failed to delete entry"), tra("Failed to delete \"{0}\":\n{1}", e.name, e.error || tr("Unknown error"))).open();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -1358,9 +1358,9 @@ export class FileBrowserRenderer extends ReactComponentBase<FileListTablePropert
|
|||
this.forceUpdate();
|
||||
|
||||
if (event.status === "timeout") {
|
||||
createErrorModal(tr("Failed to create directory"), tra("Failed to create directory.{:br:}Action resulted in a timeout.")).open();
|
||||
createErrorModal(tr("Failed to create directory"), tra("Failed to create directory.\nAction resulted in a timeout.")).open();
|
||||
} else {
|
||||
createErrorModal(tr("Failed to create directory"), tra("Failed to create directory:{:br:}{0}", event.error)).open();
|
||||
createErrorModal(tr("Failed to create directory"), tra("Failed to create directory:\n{0}", event.error)).open();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
export interface YesNoParameters {
|
||||
title: string,
|
||||
question: string,
|
||||
|
||||
textYes?: string,
|
||||
textNo?: string,
|
||||
|
||||
closeable?: boolean
|
||||
}
|
||||
|
||||
export async function promptYesNo(properties: YesNoParameters) : Promise<boolean | undefined> {
|
||||
/* Having these checks because tra(..) still might return jQuery */
|
||||
if(typeof properties.title !== "string") {
|
||||
debugger;
|
||||
throw "yes-no title isn't a string";
|
||||
}
|
||||
|
||||
if(typeof properties.question !== "string") {
|
||||
debugger;
|
||||
throw "yes-no question isn't a string";
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import * as React from "react";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
const cssStyle = require("./Tab.scss");
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import * as loader from "tc-loader";
|
||||
import {setupIpcHandler} from "tc-shared/ipc/BrowserIPC";
|
||||
import {initializeI18N} from "tc-shared/i18n/localize";
|
||||
import {initializeI18N, tra} from "tc-shared/i18n/localize";
|
||||
import {Stage} from "tc-loader";
|
||||
import {AbstractModal, constructAbstractModalClass} from "tc-shared/ui/react-elements/modal/Definitions";
|
||||
import {AppParameters, Settings, settings} from "tc-shared/settings";
|
||||
|
|
|
@ -9,6 +9,7 @@ import {
|
|||
} from "svg-sprites/client-icons";
|
||||
import {LogCategory, logDebug} from "tc-shared/log";
|
||||
import {ChannelTreeDragData, ChannelTreeDragEntry} from "tc-shared/ui/tree/Definitions";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
let spriteImage: HTMLImageElement;
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import {useEffect, useState} from "react";
|
|||
import * as _ from "lodash";
|
||||
import {ReadonlyKeys, WritableKeys} from "tc-shared/proto";
|
||||
import {useDependentState} from "tc-shared/ui/react-elements/Helper";
|
||||
import {tra} from "tc-shared/i18n/localize";
|
||||
|
||||
/*
|
||||
* To deliver optimized performance, we only promisify the values we need.
|
||||
|
@ -71,7 +72,7 @@ export abstract class UiVariableProvider<Variables extends UiVariableMap> {
|
|||
sendVariable<T extends keyof Variables>(variable: T, customData?: any, forceSend?: boolean) : void | Promise<void> {
|
||||
const providers = this.variableProvider[variable as any];
|
||||
if(!providers) {
|
||||
throw tra("missing provider for {}", variable);
|
||||
throw tra("missing provider for {}", variable as string);
|
||||
}
|
||||
|
||||
const result = providers(customData);
|
||||
|
@ -98,7 +99,7 @@ export abstract class UiVariableProvider<Variables extends UiVariableMap> {
|
|||
async getVariable<T extends keyof Variables>(variable: T, customData?: any, ignoreCache?: boolean) : Promise<Variables[T]> {
|
||||
const providers = this.variableProvider[variable as any];
|
||||
if(!providers) {
|
||||
throw tra("missing provider for {}", variable);
|
||||
throw tra("missing provider for {}", variable as string);
|
||||
}
|
||||
|
||||
const result = providers(customData);
|
||||
|
|
Loading…
Reference in New Issue