mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-28 06:05:24 +00:00
fix: translate leftover hardcoded ui text
This commit is contained in:
1 parent
1b342322dc
commit
20f19ff13b
26 files changed
+80
-41
No files matched your search
@@ -379,7 +379,11 @@
|
||||
"dragFilesToDesktop": "Dragging {{count}} files to the desktop",
|
||||
"folderDragUnsupported": "Dragging folders to the desktop is not supported yet",
|
||||
"saveToDesktopFailed": "Save failed: {{error}}",
|
||||
"dragFailedDetail": "Drag failed: {{error}}"
|
||||
"dragFailedDetail": "Drag failed: {{error}}",
|
||||
"videoUnsupported": "Your browser cannot play this video format.",
|
||||
"downloadToPlay": "Download to play it elsewhere",
|
||||
"cannotPreviewType": "Cannot preview this file type",
|
||||
"cannotPreviewTypeHint": "This file type has no preview. Download it to open it in another app."
|
||||
},
|
||||
"sftpTransfer": {
|
||||
"title": "SFTP",
|
||||
|
||||
@@ -790,10 +790,7 @@ export function FileViewer({
|
||||
<source src={videoUrl} type={mimeType} />
|
||||
<div className="text-center text-muted-foreground p-4">
|
||||
<AlertCircle className="w-8 h-8 mx-auto mb-2" />
|
||||
<p>
|
||||
Your browser does not support video playback for this
|
||||
format.
|
||||
</p>
|
||||
<p>{t("fileManager.videoUnsupported")}</p>
|
||||
{onDownload && (
|
||||
<Button
|
||||
variant="outline"
|
||||
@@ -801,7 +798,7 @@ export function FileViewer({
|
||||
className="mt-2 flex items-center gap-2 mx-auto"
|
||||
>
|
||||
<Download className="w-4 h-4" />
|
||||
Download to play externally
|
||||
{t("fileManager.downloadToPlay")}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
@@ -918,11 +915,10 @@ export function FileViewer({
|
||||
<div className="text-center text-muted-foreground">
|
||||
<AlertCircle className="w-16 h-16 mx-auto mb-4 text-muted-foreground/50" />
|
||||
<h3 className="text-lg font-medium mb-2">
|
||||
Cannot preview this file type
|
||||
{t("fileManager.cannotPreviewType")}
|
||||
</h3>
|
||||
<p className="text-sm mb-4">
|
||||
This file type is not supported for preview. You can download
|
||||
it to view in an external application.
|
||||
{t("fileManager.cannotPreviewTypeHint")}
|
||||
</p>
|
||||
{onDownload && (
|
||||
<Button
|
||||
|
||||
@@ -161,7 +161,15 @@
|
||||
"compactMode": "Compact Mode",
|
||||
"selectHosts": "Select Hosts",
|
||||
"listLayout": "List",
|
||||
"gridLayout": "Grid"
|
||||
"gridLayout": "Grid",
|
||||
"configureUrl": "Set a URL in the widget settings",
|
||||
"embeddedContent": "Embedded content",
|
||||
"noBookmarks": "No bookmarks",
|
||||
"noSections": "No sections set up",
|
||||
"noServices": "No services set up",
|
||||
"configureLocation": "Set a location in the widget settings",
|
||||
"bannerTextPlaceholder": "Banner text",
|
||||
"serviceNamePlaceholder": "My service"
|
||||
},
|
||||
"permissions": {
|
||||
"use": {
|
||||
|
||||
@@ -39,7 +39,7 @@ export function ServiceLinkEditForm({
|
||||
<Input
|
||||
value={config.description ?? ""}
|
||||
onChange={(e) => onChange({ ...config, description: e.target.value })}
|
||||
placeholder="My service"
|
||||
placeholder={t("homepage.serviceNamePlaceholder")}
|
||||
className="h-8 text-sm"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { Bookmark, ExternalLink } from "lucide-react";
|
||||
import { registerWidget } from "./WidgetRegistry";
|
||||
import type { BookmarkListConfig, WidgetComponentProps } from "../types.js";
|
||||
@@ -8,6 +9,7 @@ function BookmarkListWidget({
|
||||
widget,
|
||||
isReadOnly,
|
||||
}: WidgetComponentProps<BookmarkListConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { links } = config;
|
||||
|
||||
return (
|
||||
@@ -23,7 +25,7 @@ function BookmarkListWidget({
|
||||
<div className="flex-1 overflow-auto p-3 gap-1 flex flex-col">
|
||||
{links.length === 0 && (
|
||||
<span className="text-xs text-muted-foreground italic">
|
||||
No bookmarks
|
||||
{t("homepage.noBookmarks")}
|
||||
</span>
|
||||
)}
|
||||
{links.map((link, i) =>
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { Globe } from "lucide-react";
|
||||
import { registerWidget } from "./WidgetRegistry";
|
||||
import type { IframeConfig, WidgetComponentProps } from "../types.js";
|
||||
@@ -9,13 +10,14 @@ function IframeWidget({
|
||||
config,
|
||||
isReadOnly,
|
||||
}: WidgetComponentProps<IframeConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { url, scrolling } = config;
|
||||
|
||||
if (!url) {
|
||||
return (
|
||||
<div className="flex flex-col items-center justify-center w-full h-full gap-2 text-muted-foreground/50">
|
||||
<Globe size={24} />
|
||||
<span className="text-xs">Configure a URL in widget settings</span>
|
||||
<span className="text-xs">{t("homepage.configureUrl")}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -29,7 +31,7 @@ function IframeWidget({
|
||||
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
|
||||
scrolling={scrolling ? "yes" : "no"}
|
||||
className="w-full h-full border-0"
|
||||
title="Embedded content"
|
||||
title={t("homepage.embeddedContent")}
|
||||
/>
|
||||
{/* Block interaction in read-only mode so the canvas can still pan */}
|
||||
{isReadOnly && <div className="absolute inset-0 pointer-events-none" />}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { useRef } from "react";
|
||||
import { List, ExternalLink } from "lucide-react";
|
||||
import { registerWidget } from "./WidgetRegistry";
|
||||
@@ -72,12 +73,13 @@ function LinkTreeWidget({
|
||||
config,
|
||||
isReadOnly,
|
||||
}: WidgetComponentProps<LinkTreeConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { sections, compact } = config;
|
||||
|
||||
if (sections.length === 0) {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-full text-xs text-muted-foreground">
|
||||
No sections configured
|
||||
{t("homepage.noSections")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { useRef, useState, useEffect } from "react";
|
||||
import { Grid3x3, ExternalLink } from "lucide-react";
|
||||
import { registerWidget } from "./WidgetRegistry";
|
||||
@@ -107,12 +108,13 @@ function ServiceGridWidget({
|
||||
config,
|
||||
isReadOnly,
|
||||
}: WidgetComponentProps<ServiceGridConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { services, columns, showLabels, iconSize } = config;
|
||||
|
||||
if (services.length === 0) {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-full text-xs text-muted-foreground">
|
||||
No services configured
|
||||
{t("homepage.noServices")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { Type } from "lucide-react";
|
||||
import { registerWidget } from "./WidgetRegistry";
|
||||
import type { TextBannerConfig, WidgetComponentProps } from "../types.js";
|
||||
@@ -23,6 +24,7 @@ const TEXT_ALIGN_MAP = {
|
||||
};
|
||||
|
||||
function TextBannerWidget({ config }: WidgetComponentProps<TextBannerConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { text, fontSize, textAlign, fontWeight, backgroundColor } = config;
|
||||
|
||||
return (
|
||||
@@ -31,7 +33,7 @@ function TextBannerWidget({ config }: WidgetComponentProps<TextBannerConfig>) {
|
||||
style={backgroundColor ? { background: backgroundColor } : undefined}
|
||||
>
|
||||
<span className="whitespace-pre-wrap break-words w-full text-foreground leading-tight">
|
||||
{text || "Banner text"}
|
||||
{text || t("homepage.bannerTextPlaceholder")}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { useEffect, useState } from "react";
|
||||
import {
|
||||
Cloud,
|
||||
@@ -54,6 +55,7 @@ function WeatherWidget({
|
||||
widget,
|
||||
config,
|
||||
}: WidgetComponentProps<WeatherConfig>) {
|
||||
const { t } = useTranslation();
|
||||
const { location, unit, showForecast } = config;
|
||||
const [data, setData] = useState<WttrResponse | null>(null);
|
||||
const [error, setError] = useState(false);
|
||||
@@ -90,7 +92,7 @@ function WeatherWidget({
|
||||
if (!location) {
|
||||
return (
|
||||
<div className="flex items-center justify-center w-full h-full text-xs text-muted-foreground/60 p-3 text-center">
|
||||
Configure a location in widget settings
|
||||
{t("homepage.configureLocation")}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -177,7 +177,8 @@
|
||||
"wgAllowedIPs": "Allowed IPs",
|
||||
"wgLastHandshake": "Last handshake",
|
||||
"wgHandshakeNever": "Never",
|
||||
"wgTransfer": "Transfer"
|
||||
"wgTransfer": "Transfer",
|
||||
"wgNoPeers": "No peers"
|
||||
}
|
||||
},
|
||||
"metricsHistory": {
|
||||
|
||||
@@ -162,7 +162,7 @@ export function WireGuardManagerCard({ hostId }: { hostId: number | null }) {
|
||||
<div className="mb-1 ml-5 flex flex-col border-l border-border/50">
|
||||
{iface.peers.length === 0 ? (
|
||||
<span className="px-3 py-1 text-[10px] text-muted-foreground/50">
|
||||
No peers
|
||||
{t("hostMetrics.managers.wgNoPeers")}
|
||||
</span>
|
||||
) : (
|
||||
iface.peers.map((peer) => (
|
||||
|
||||
@@ -208,7 +208,8 @@
|
||||
"colorScheme": "Color Scheme",
|
||||
"backspaceKey": "Backspace Key",
|
||||
"colorDepth": "Color Depth",
|
||||
"resizeMethod": "Resize Method"
|
||||
"resizeMethod": "Resize Method",
|
||||
"driveNamePlaceholder": "Termix Drive"
|
||||
},
|
||||
"remoteDesktop": "Remote Desktop",
|
||||
"tabRdp": "RDP",
|
||||
|
||||
@@ -523,7 +523,7 @@ export function HostEditorRdpTab({
|
||||
{t("hosts.guac.driveName")}
|
||||
</label>
|
||||
<Input
|
||||
placeholder="Termix Drive"
|
||||
placeholder={t("hosts.guac.driveNamePlaceholder")}
|
||||
value={form.guacamoleConfig["drive-name"] ?? ""}
|
||||
onChange={(e) => setGuacField("drive-name", e.target.value)}
|
||||
/>
|
||||
|
||||
@@ -45,5 +45,9 @@
|
||||
"loadError": "Failed to load session logs",
|
||||
"deleteError": "Failed to delete session log",
|
||||
"filterByHost": "Filter by host..."
|
||||
},
|
||||
"player": {
|
||||
"timeline": "Recording timeline",
|
||||
"speed": "Playback speed"
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from "@termix/plugin-sdk/frontend";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { Pause, Play } from "lucide-react";
|
||||
import { Terminal } from "@xterm/xterm";
|
||||
@@ -36,6 +37,7 @@ function PlaybackControls({
|
||||
onSeek: (position: number) => void;
|
||||
onSpeed: (speed: number) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="flex items-center gap-2 border-t border-border/60 bg-muted/20 px-3 py-2">
|
||||
<button
|
||||
@@ -61,7 +63,7 @@ function PlaybackControls({
|
||||
value={Math.min(position, duration)}
|
||||
onChange={(event) => onSeek(Number(event.target.value))}
|
||||
className="min-w-0 flex-1 accent-primary"
|
||||
aria-label="Recording timeline"
|
||||
aria-label={t("player.timeline")}
|
||||
/>
|
||||
<span className="w-10 text-right text-[10px] tabular-nums text-muted-foreground">
|
||||
{formatPosition(duration)}
|
||||
@@ -70,7 +72,7 @@ function PlaybackControls({
|
||||
value={speed}
|
||||
onChange={(event) => onSpeed(Number(event.target.value))}
|
||||
className="h-7 border border-border bg-background px-1 text-[10px]"
|
||||
aria-label="Playback speed"
|
||||
aria-label={t("player.speed")}
|
||||
>
|
||||
{SPEEDS.map((value) => (
|
||||
<option key={value} value={value}>
|
||||
|
||||
@@ -85,7 +85,8 @@
|
||||
"imageChooseFile": "Choose an image file",
|
||||
"imageUploaded": "Image uploaded: {{path}}",
|
||||
"imageClipboardUnavailable": "This browser cannot read images from the clipboard",
|
||||
"imageClipboardEmpty": "No image found in the clipboard"
|
||||
"imageClipboardEmpty": "No image found in the clipboard",
|
||||
"localShell": "Local terminal shell"
|
||||
},
|
||||
"terminalToolbar": {
|
||||
"detachTmux": "Detach tmux",
|
||||
|
||||
@@ -185,7 +185,7 @@ export function LocalTerminal({
|
||||
{isWindows && (
|
||||
<div className="flex justify-end border-b border-border px-2 py-1">
|
||||
<select
|
||||
aria-label="Local terminal shell"
|
||||
aria-label={t("terminal.localShell")}
|
||||
className="rounded border border-border bg-background px-2 py-1 text-xs text-foreground"
|
||||
value={shell}
|
||||
onChange={(event) =>
|
||||
|
||||
Reference in new issue
Block a user