Removed the whole `{:br:}` syntax and removed jQuery from the `tra` method

master
WolverinDEV 2021-04-24 13:59:49 +02:00
parent 0faa33581d
commit 29c168ece0
36 changed files with 102 additions and 256 deletions

View File

@ -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"]}) :
"",

View File

@ -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;

View File

@ -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:

View File

@ -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";

View File

@ -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();
});
}

View File

@ -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,

View File

@ -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;

View File

@ -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 {

View File

@ -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",

View File

@ -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();

View File

@ -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})$/;

View File

@ -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("");
}

View File

@ -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>;

View File

@ -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");

View File

@ -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",

View File

@ -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);

View File

@ -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>;

View File

@ -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";

View File

@ -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;
}

View File

@ -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();

View File

@ -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();

View File

@ -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);
}
});
}

View File

@ -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();

View File

@ -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;

View File

@ -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();
})
}

View File

@ -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();
}

View File

@ -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]} = {

View File

@ -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));
}
}
}

View File

@ -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);

View File

@ -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();
}
});
}

View File

@ -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();
}
}

View File

@ -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;
}

View File

@ -1,4 +1,5 @@
import * as React from "react";
import {tra} from "tc-shared/i18n/localize";
const cssStyle = require("./Tab.scss");

View File

@ -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";

View File

@ -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;

View File

@ -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);