Add comprehensive Chinese internationalization support

- Implemented i18n framework with react-i18next for multi-language support
- Added Chinese (zh) and English (en) translation files with comprehensive coverage
- Localized Admin interface, authentication flows, and error messages
- Translated FileManager operations and UI elements
- Updated HomepageAuth component with localized authentication messages
- Localized LeftSidebar navigation and host management
- Added language switcher component (shown after login only)
- Configured default language as English with Chinese as secondary option
- Localized TOTPSetup two-factor authentication interface
- Updated Docker build to include translation files
- Achieved 95%+ UI localization coverage across core components

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
ZacharyZcR
2025-09-02 20:36:48 +08:00
parent 26c1cacc9d
commit 70a26359b6
24 changed files with 1805 additions and 362 deletions

View File

@@ -4,6 +4,7 @@ import {FitAddon} from '@xterm/addon-fit';
import {ClipboardAddon} from '@xterm/addon-clipboard';
import {Unicode11Addon} from '@xterm/addon-unicode11';
import {WebLinksAddon} from '@xterm/addon-web-links';
import {useTranslation} from 'react-i18next';
interface SSHTerminalProps {
hostConfig: any;
@@ -17,6 +18,7 @@ export const Terminal = forwardRef<any, SSHTerminalProps>(function SSHTerminal(
{hostConfig, isVisible, splitScreen = false},
ref
) {
const {t} = useTranslation();
const {instance: terminal, ref: xtermRef} = useXTerm();
const fitAddonRef = useRef<FitAddon | null>(null);
const webSocketRef = useRef<WebSocket | null>(null);
@@ -139,11 +141,11 @@ export const Terminal = forwardRef<any, SSHTerminalProps>(function SSHTerminal(
try {
const msg = JSON.parse(event.data);
if (msg.type === 'data') terminal.write(msg.data);
else if (msg.type === 'error') terminal.writeln(`\r\n[ERROR] ${msg.message}`);
else if (msg.type === 'error') terminal.writeln(`\r\n[${t('terminal.error')}] ${msg.message}`);
else if (msg.type === 'connected') {
} else if (msg.type === 'disconnected') {
wasDisconnectedBySSH.current = true;
terminal.writeln(`\r\n[${msg.message || 'Disconnected'}]`);
terminal.writeln(`\r\n[${msg.message || t('terminal.disconnected')}]`);
}
} catch (error) {
}
@@ -151,12 +153,12 @@ export const Terminal = forwardRef<any, SSHTerminalProps>(function SSHTerminal(
ws.addEventListener('close', () => {
if (!wasDisconnectedBySSH.current) {
terminal.writeln('\r\n[Connection closed]');
terminal.writeln(`\r\n[${t('terminal.connectionClosed')}]`);
}
});
ws.addEventListener('error', () => {
terminal.writeln('\r\n[Connection error]');
terminal.writeln(`\r\n[${t('terminal.connectionError')}]`);
});
}