diff --git a/src-tauri/src/cmd/clash.rs b/src-tauri/src/cmd/clash.rs index efebb1c4a..c32c08d92 100644 --- a/src-tauri/src/cmd/clash.rs +++ b/src-tauri/src/cmd/clash.rs @@ -1,4 +1,4 @@ -use super::CmdResult; +use super::{CmdResult, WithErrorCode as _, coded_error}; use crate::feat; use crate::utils::{dirs, yaml_emitter}; use crate::{ @@ -32,7 +32,9 @@ pub async fn get_clash_info() -> CmdResult { /// 修改Clash配置 #[tauri::command] pub async fn patch_clash_config(payload: Mapping) -> CmdResult { - feat::patch_clash(&payload).await.stringify_err() + feat::patch_clash(&payload) + .await + .with_error_code("CLASH_CONFIG_UPDATE_FAILED") } /// 修改Clash模式 @@ -41,7 +43,9 @@ pub async fn patch_clash_config(payload: Mapping) -> CmdResult { /// 并提示用户(此前命令始终返回 `Ok(())`,吞掉了后端错误)。 #[tauri::command] pub async fn patch_clash_mode(payload: String) -> CmdResult { - feat::change_clash_mode(payload).await + feat::change_clash_mode(payload) + .await + .with_error_code("CLASH_MODE_UPDATE_FAILED") } /// 获取当前 Clash 模式(容错读取) @@ -74,7 +78,7 @@ pub async fn change_clash_core(clash_core: String) -> CmdResult> let error_msg: String = format!("Core changed but failed to restart: {err}").into(); handle::Handle::notice_message("config_core::change_error", error_msg.clone()); logging!(error, Type::Core, "{error_msg}"); - Ok(Some(error_msg)) + Ok(Some(coded_error("CORE_CHANGE_FAILED", error_msg))) } } } @@ -82,7 +86,7 @@ pub async fn change_clash_core(clash_core: String) -> CmdResult> let error_msg: String = err; logging!(error, Type::Core, "failed to change core: {error_msg}"); handle::Handle::notice_message("config_core::change_error", error_msg.clone()); - Ok(Some(error_msg)) + Ok(Some(coded_error("CORE_CHANGE_FAILED", error_msg))) } } } @@ -90,7 +94,10 @@ pub async fn change_clash_core(clash_core: String) -> CmdResult> /// 启动核心 #[tauri::command] pub async fn start_core() -> CmdResult { - let result = CoreManager::global().start_core().await.stringify_err(); + let result = CoreManager::global() + .start_core() + .await + .with_error_code("CORE_START_FAILED"); if result.is_ok() { handle::Handle::refresh_clash(); } @@ -101,7 +108,10 @@ pub async fn start_core() -> CmdResult { #[tauri::command] pub async fn stop_core() -> CmdResult { logging_error!(Type::Core, Config::profiles().await.data_arc().save_file().await); - let result = CoreManager::global().stop_core().await.stringify_err(); + let result = CoreManager::global() + .stop_core() + .await + .with_error_code("CORE_STOP_FAILED"); if result.is_ok() { handle::Handle::refresh_clash(); } @@ -112,7 +122,10 @@ pub async fn stop_core() -> CmdResult { #[tauri::command] pub async fn restart_core() -> CmdResult { logging_error!(Type::Core, Config::profiles().await.data_arc().save_file().await); - let result = CoreManager::global().restart_core().await.stringify_err(); + let result = CoreManager::global() + .restart_core() + .await + .with_error_code("CORE_RESTART_FAILED"); if result.is_ok() { handle::Handle::refresh_clash(); } diff --git a/src-tauri/src/cmd/mod.rs b/src-tauri/src/cmd/mod.rs index 6c7486873..606c47f69 100644 --- a/src-tauri/src/cmd/mod.rs +++ b/src-tauri/src/cmd/mod.rs @@ -3,6 +3,12 @@ use smartstring::alias::String; pub type CmdResult = Result; +const USER_ERROR_PREFIX: &str = "CVR_ERROR:"; + +pub fn coded_error(code: &str, detail: impl std::fmt::Display) -> String { + format!("{USER_ERROR_PREFIX}{code}\n{detail}").into() +} + // Command modules pub mod app; pub mod backup; @@ -46,6 +52,10 @@ pub trait StringifyErr { F: Fn(&str); } +pub trait WithErrorCode { + fn with_error_code(self, code: &str) -> CmdResult; +} + impl StringifyErr for Result { fn stringify_err(self) -> CmdResult { self.map_err(|e| e.to_string().into()) @@ -62,3 +72,22 @@ impl StringifyErr for Result { }) } } + +impl WithErrorCode for Result { + fn with_error_code(self, code: &str) -> CmdResult { + self.map_err(|error| coded_error(code, error)) + } +} + +#[cfg(test)] +mod tests { + use super::coded_error; + + #[test] + fn coded_error_preserves_stable_code_and_diagnostic_detail() { + assert_eq!( + coded_error("CORE_RESTART_FAILED", "connection refused"), + "CVR_ERROR:CORE_RESTART_FAILED\nconnection refused" + ); + } +} diff --git a/src-tauri/src/cmd/profile.rs b/src-tauri/src/cmd/profile.rs index f6a4b2a06..88aa7ad49 100644 --- a/src-tauri/src/cmd/profile.rs +++ b/src-tauri/src/cmd/profile.rs @@ -1,5 +1,4 @@ -use super::CmdResult; -use super::StringifyErr as _; +use super::{CmdResult, StringifyErr as _, WithErrorCode as _, coded_error}; use crate::cmd::validate::{ValidationNoticeTarget, handle_validation_notice}; use crate::config::profiles; use crate::utils::window_manager::WindowManager; @@ -60,7 +59,7 @@ pub async fn enhance_profiles() -> CmdResult { } Err(e) => { logging!(error, Type::Cmd, "{}", e); - Err(e.to_string().into()) + Err(coded_error("PROFILE_ENHANCE_FAILED", e)) } } } @@ -78,18 +77,18 @@ pub async fn import_profile(url: std::string::String, option: Option) } Err(e) => { logging!(error, Type::Cmd, "[导入订阅] 下载失败: {}", e); - return Err(profile_import_error(&e).into()); + return Err(coded_error("PROFILE_IMPORT_FAILED", profile_import_error(&e))); } }; if let Err(e) = profiles_append_item_safe(item).await { logging!(error, Type::Cmd, "[导入订阅] 保存配置失败: {}", e); - return Err(format!("导入订阅失败: {}", e).into()); + return Err(coded_error("PROFILE_IMPORT_FAILED", e)); } if let Err(e) = profiles_save_file_safe().await { logging!(error, Type::Cmd, "[导入订阅] 保存配置文件失败: {}", e); - return Err(format!("导入订阅失败: {}", e).into()); + return Err(coded_error("PROFILE_IMPORT_FAILED", e)); } logging!(info, Type::Cmd, "[导入订阅] 配置文件保存成功"); logging_error!(Type::Timer, Timer::global().refresh().await); @@ -113,7 +112,7 @@ pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult { } Err(err) => { logging!(error, Type::Cmd, "重新排序配置文件失败: {}", err); - Err(format!("重新排序配置文件失败: {}", err).into()) + Err(coded_error("PROFILE_REORDER_FAILED", err)) } } } @@ -124,7 +123,9 @@ pub async fn reorder_profile(active_id: String, over_id: String) -> CmdResult { pub async fn create_profile(item: PrfItem, file_data: Option) -> CmdResult { match profiles_append_item_with_filedata_safe(&item, file_data).await { Ok(_) => { - profiles_save_file_safe().await.stringify_err()?; + profiles_save_file_safe() + .await + .with_error_code("PROFILE_CREATE_FAILED")?; logging_error!(Type::Timer, Timer::global().refresh().await); // 发送配置变更通知 if let Some(uid) = &item.uid { @@ -133,10 +134,7 @@ pub async fn create_profile(item: PrfItem, file_data: Option) -> CmdResu } Ok(()) } - Err(err) => match err.to_string().as_str() { - "the file already exists" => Err("the file already exists".into()), - _ => Err(format!("add profile error: {err}").into()), - }, + Err(err) => Err(coded_error("PROFILE_CREATE_FAILED", err)), } } @@ -147,7 +145,7 @@ pub async fn update_profile(index: String, option: Option) -> CmdResu Ok(_) => Ok(()), Err(e) => { logging!(error, Type::Cmd, "{}", e); - Err(e.to_string().into()) + Err(coded_error("PROFILE_UPDATE_FAILED", e)) } } } @@ -156,8 +154,12 @@ pub async fn update_profile(index: String, option: Option) -> CmdResu #[tauri::command] pub async fn delete_profile(index: String) -> CmdResult { // 使用Send-safe helper函数 - let should_update = profiles_delete_item_safe(&index).await.stringify_err()?; - profiles_save_file_safe().await.stringify_err()?; + let should_update = profiles_delete_item_safe(&index) + .await + .with_error_code("PROFILE_DELETE_FAILED")?; + profiles_save_file_safe() + .await + .with_error_code("PROFILE_DELETE_FAILED")?; if let Err(e) = Tray::global().update_tooltip().await { logging!(warn, Type::Cmd, "Warning: 异步更新托盘提示失败: {e}"); } @@ -176,15 +178,18 @@ pub async fn delete_profile(index: String) -> CmdResult { Ok(outcome) => { logging!(warn, Type::Cmd, "删除订阅后更新配置失败: {}", outcome); handle_validation_notice(&outcome, ValidationNoticeTarget::Runtime, "运行时配置"); - return Err(outcome.to_string().into()); + return Err(coded_error("PROFILE_DELETE_FAILED", outcome)); } Err(e) => { logging!(error, Type::Cmd, "{}", e); - return Err(e.to_string().into()); + return Err(coded_error("PROFILE_DELETE_FAILED", e)); } } } - Timer::global().refresh().await.stringify_err()?; + Timer::global() + .refresh() + .await + .with_error_code("PROFILE_DELETE_FAILED")?; Ok(()) } @@ -322,7 +327,9 @@ pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult CmdResult { false }; - profiles_patch_item_safe(&index, &profile).await.stringify_err()?; + profiles_patch_item_safe(&index, &profile) + .await + .with_error_code("PROFILE_UPDATE_FAILED")?; // 如果更新间隔或允许自动更新变更,异步刷新定时器 if should_refresh_timer { @@ -379,17 +388,22 @@ pub async fn view_profile(index: String) -> CmdResult { let profiles_ref = profiles.latest_arc(); let file = profiles_ref .get_item(&index) - .stringify_err()? + .with_error_code("PROFILE_OPEN_FAILED")? .file .as_ref() - .ok_or("the file field is null")?; + .ok_or_else(|| coded_error("PROFILE_OPEN_FAILED", "the file field is null"))?; - let path = dirs::app_profiles_dir().stringify_err()?.join(file.as_str()); + let path = dirs::app_profiles_dir() + .with_error_code("PROFILE_OPEN_FAILED")? + .join(file.as_str()); if !path.exists() { - return CmdResult::Err(format!("file not found \"{}\"", path.display()).into()); + return CmdResult::Err(coded_error( + "PROFILE_OPEN_FAILED", + format!("file not found \"{}\"", path.display()), + )); } - help::open_file(path).stringify_err() + help::open_file(path).with_error_code("PROFILE_OPEN_FAILED") } /// 读取配置文件内容 @@ -399,23 +413,32 @@ pub async fn read_profile_file(index: String) -> CmdResult { let profiles = Config::profiles().await; let profiles_ref = profiles.latest_arc(); PrfItem { - file: profiles_ref.get_item(&index).stringify_err()?.file.to_owned(), + file: profiles_ref + .get_item(&index) + .with_error_code("PROFILE_READ_FAILED")? + .file + .to_owned(), ..Default::default() } }; if let Some(file) = item.file.as_ref() { - let path = dirs::app_profiles_dir().stringify_err()?.join(file.as_str()); + let path = dirs::app_profiles_dir() + .with_error_code("PROFILE_READ_FAILED")? + .join(file.as_str()); match tokio::fs::try_exists(&path).await { Ok(true) => {} Ok(false) => return Ok(String::new()), Err(err) => { - return Err(format!("failed to check profile file \"{}\": {err}", path.display()).into()); + return Err(coded_error( + "PROFILE_READ_FAILED", + format!("failed to check profile file \"{}\": {err}", path.display()), + )); } } } - let data = item.read_file().await.stringify_err()?; + let data = item.read_file().await.with_error_code("PROFILE_READ_FAILED")?; Ok(data) } diff --git a/src-tauri/src/cmd/service.rs b/src-tauri/src/cmd/service.rs index 29530f28a..d0ee60d85 100644 --- a/src-tauri/src/cmd/service.rs +++ b/src-tauri/src/cmd/service.rs @@ -1,30 +1,27 @@ -use super::{CmdResult, StringifyErr as _}; +use super::{CmdResult, WithErrorCode as _}; use crate::core::{ CoreManager, service::{self, SERVICE_MANAGER, ServiceStatus}, }; -async fn execute_service_operation_sync(status: ServiceStatus, op_type: &str) -> CmdResult { +async fn execute_service_operation_sync(status: ServiceStatus, error_code: &str) -> CmdResult { let manager = CoreManager::global(); let _lifecycle = manager.lifecycle_lock.lock().await; if matches!( &status, ServiceStatus::ReinstallRequired | ServiceStatus::ForceReinstallRequired ) { - manager - .controlled_stop_core_inner() - .await - .map_err(|error| format!("{op_type} Service failed: {error:#}"))?; + manager.controlled_stop_core_inner().await.with_error_code(error_code)?; } SERVICE_MANAGER .handle_service_status(status) .await - .map_err(|e| format!("{op_type} Service failed: {e}").into()) + .with_error_code(error_code) } #[tauri::command] pub async fn install_service() -> CmdResult { - execute_service_operation_sync(ServiceStatus::InstallRequired, "Install").await + execute_service_operation_sync(ServiceStatus::InstallRequired, "SERVICE_INSTALL_FAILED").await } #[tauri::command] @@ -32,17 +29,17 @@ pub async fn uninstall_service() -> CmdResult { CoreManager::global() .uninstall_service_and_start_sidecar() .await - .map_err(|error| format!("Uninstall Service failed: {error:#}").into()) + .with_error_code("SERVICE_UNINSTALL_FAILED") } #[tauri::command] pub async fn reinstall_service() -> CmdResult { - execute_service_operation_sync(ServiceStatus::ReinstallRequired, "Reinstall").await + execute_service_operation_sync(ServiceStatus::ReinstallRequired, "SERVICE_REINSTALL_FAILED").await } #[tauri::command] pub async fn repair_service() -> CmdResult { - execute_service_operation_sync(ServiceStatus::ForceReinstallRequired, "Repair").await + execute_service_operation_sync(ServiceStatus::ForceReinstallRequired, "SERVICE_REPAIR_FAILED").await } #[tauri::command] @@ -60,5 +57,5 @@ pub async fn continue_with_sidecar() -> CmdResult { crate::core::CoreManager::global() .continue_with_sidecar() .await - .stringify_err() + .with_error_code("SERVICE_SIDECAR_FAILED") } diff --git a/src-tauri/src/feat/clash.rs b/src-tauri/src/feat/clash.rs index 0a4a8cd44..1c34c2948 100644 --- a/src-tauri/src/feat/clash.rs +++ b/src-tauri/src/feat/clash.rs @@ -57,10 +57,7 @@ pub async fn restart_app() { if !cleanup_result.core_stopped { handle::Handle::global().clear_is_exiting(); - handle::Handle::notice_message( - "set_config::error", - "Failed to stop the core safely; restart was cancelled", - ); + handle::Handle::notice_message("app_restart::core_stop_failed", ""); return; } diff --git a/src-tauri/src/feat/window.rs b/src-tauri/src/feat/window.rs index 7c5cf4f6b..af03ee58d 100644 --- a/src-tauri/src/feat/window.rs +++ b/src-tauri/src/feat/window.rs @@ -128,10 +128,7 @@ pub async fn quit() -> clash_verge_signal::ShutdownOutcome { if should_abort_exit_after_cleanup(cleanup_result.core_stopped) { handle::Handle::global().clear_is_exiting(); - handle::Handle::notice_message( - "set_config::error", - "Failed to stop the core safely; quit was cancelled", - ); + handle::Handle::notice_message("app_quit::core_stop_failed", ""); return clash_verge_signal::ShutdownOutcome::Canceled; } diff --git a/src/components/base/base-error-boundary.tsx b/src/components/base/base-error-boundary.tsx index 635f02361..7af9ba4f7 100644 --- a/src/components/base/base-error-boundary.tsx +++ b/src/components/base/base-error-boundary.tsx @@ -1,18 +1,20 @@ import { ReactNode } from 'react' import { ErrorBoundary, FallbackProps } from 'react-error-boundary' +import { useTranslation } from 'react-i18next' function ErrorFallback({ error }: FallbackProps) { + const { t } = useTranslation() const errorMessage = error instanceof Error ? error.message : String(error) const errorStack = error instanceof Error ? error.stack : undefined return (
-

Something went wrong:(

+

{t('shared.feedback.errors.unexpected')}

{errorMessage}
-
- Error Stack +
+ {t('shared.feedback.errors.stack')}
{errorStack}
diff --git a/src/components/home/current-proxy-card.tsx b/src/components/home/current-proxy-card.tsx index b14ba9e3a..cb2f34210 100644 --- a/src/components/home/current-proxy-card.tsx +++ b/src/components/home/current-proxy-card.tsx @@ -92,26 +92,61 @@ function convertDelayColor( } } -function getSignalIcon(delay: number): { +function getSignalIcon( + delay: number, + translate: (key: string) => string, +): { icon: React.ReactElement text: string color: string } { if (delay === -2) - return { icon: , text: '测试中', color: 'text.secondary' } + return { + icon: , + text: translate('home.components.currentProxy.status.testing'), + color: 'text.secondary', + } if (delay === -1) - return { icon: , text: '未测试', color: 'text.secondary' } + return { + icon: , + text: translate('home.components.currentProxy.status.untested'), + color: 'text.secondary', + } if (delay > 1e5) - return { icon: , text: '错误', color: 'error.main' } + return { + icon: , + text: translate('home.components.currentProxy.status.error'), + color: 'error.main', + } if (delay === 0 || delay >= 10000) - return { icon: , text: '超时', color: 'error.main' } + return { + icon: , + text: translate('home.components.currentProxy.status.timeout'), + color: 'error.main', + } if (delay >= 500) - return { icon: , text: '延迟较高', color: 'error.main' } + return { + icon: , + text: translate('home.components.currentProxy.status.latencyHigh'), + color: 'error.main', + } if (delay >= 300) - return { icon: , text: '延迟中等', color: 'warning.main' } + return { + icon: , + text: translate('home.components.currentProxy.status.latencyMedium'), + color: 'warning.main', + } if (delay >= 200) - return { icon: , text: '延迟良好', color: 'info.main' } - return { icon: , text: '延迟极佳', color: 'success.main' } + return { + icon: , + text: translate('home.components.currentProxy.status.latencyGood'), + color: 'info.main', + } + return { + icon: , + text: translate('home.components.currentProxy.status.latencyExcellent'), + color: 'success.main', + } } export const CurrentProxyCard = () => { @@ -378,8 +413,12 @@ export const CurrentProxyCard = () => { // 信号图标(增加非空校验) const signalInfo = currentProxy && selectedGroupName - ? getSignalIcon(currentDelay) - : { icon: , text: '未初始化', color: 'text.secondary' } + ? getSignalIcon(currentDelay, t) + : { + icon: , + text: t('home.components.currentProxy.status.uninitialized'), + color: 'text.secondary', + } const checkCurrentProxyDelay = useCallback(async () => { if (autoCheckInProgressRef.current) return @@ -617,7 +656,7 @@ export const CurrentProxyCard = () => { title={ currentProxy ? `${signalInfo.text}: ${delayManager.formatDelay(currentDelay)}` - : '无代理节点' + : t('home.components.currentProxy.status.noProxyNode') } > diff --git a/src/components/home/enhanced-canvas-traffic-graph.tsx b/src/components/home/enhanced-canvas-traffic-graph.tsx index ae9248f53..8c9eccc1d 100644 --- a/src/components/home/enhanced-canvas-traffic-graph.tsx +++ b/src/components/home/enhanced-canvas-traffic-graph.tsx @@ -380,7 +380,7 @@ export const EnhancedCanvasTrafficGraph = memo( // 格式化时间戳 const timeStr = dataPoint.timestamp ? formatTrafficName(dataPoint.timestamp) - : '未知时间' + : t('home.components.traffic.unknownTime') // 计算数据点对应的Y坐标位置(用于高亮) const { topValue: tvH, bottomValue: bvH } = yScale @@ -420,7 +420,7 @@ export const EnhancedCanvasTrafficGraph = memo( }) }) }, - [displayData, calculateY, yScale], + [displayData, calculateY, yScale, t], ) // 鼠标离开处理 @@ -1205,7 +1205,11 @@ export const EnhancedCanvasTrafficGraph = memo( opacity: 0.7, }} > - {chartStyle === 'bezier' ? 'Smooth' : 'Linear'} + {t( + chartStyle === 'bezier' + ? 'home.components.traffic.chartStyles.smooth' + : 'home.components.traffic.chartStyles.linear', + )} {/* 数据统计指示器(左下角) */} @@ -1220,8 +1224,11 @@ export const EnhancedCanvasTrafficGraph = memo( lineHeight: 1.2, }} > - Points: {displayData.length} | Compressed:{' '} - {samplerStats.compressedBufferSize} | FPS: {currentFPS} + {t('home.components.traffic.diagnostics', { + points: displayData.length, + compressed: samplerStats.compressedBufferSize, + fps: currentFPS, + })} {/* 悬浮提示框 */} diff --git a/src/components/layout/service-migration-dialog.tsx b/src/components/layout/service-migration-dialog.tsx index 5ca4ec6a7..32253936f 100644 --- a/src/components/layout/service-migration-dialog.tsx +++ b/src/components/layout/service-migration-dialog.tsx @@ -86,7 +86,10 @@ export const ServiceMigrationDialog = () => { } actionSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.actionFailed', + error, + ) } let initialRefreshSucceeded = false @@ -94,7 +97,10 @@ export const ServiceMigrationDialog = () => { await refreshInstallState() initialRefreshSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.stateRefreshFailed', + error, + ) } if (!actionSucceeded || !initialRefreshSucceeded) { setLoading(false) @@ -106,7 +112,10 @@ export const ServiceMigrationDialog = () => { await restartCore() restartSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.restartFailed', + error, + ) } let finalRefreshSucceeded = false @@ -114,14 +123,20 @@ export const ServiceMigrationDialog = () => { await refreshInstallState() finalRefreshSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.stateRefreshFailed', + error, + ) } let revalidationSucceeded = false try { await refreshSystemAndRunning() revalidationSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.revalidationFailed', + error, + ) } if (restartSucceeded && finalRefreshSucceeded && revalidationSucceeded) { setWorkflowIncomplete(false) @@ -145,17 +160,26 @@ export const ServiceMigrationDialog = () => { await refreshInstallState() installRefreshSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.stateRefreshFailed', + error, + ) } let revalidationSucceeded = false try { await refreshSystemAndRunning() revalidationSucceeded = true } catch (error) { - showNotice.error(error) + showNotice.error( + 'layout.components.serviceMigration.errors.revalidationFailed', + error, + ) } if (startupError) { - showNotice.error(startupError) + showNotice.error( + 'layout.components.serviceMigration.errors.sidecarFailed', + startupError, + ) } else if (installRefreshSucceeded && revalidationSucceeded) { setWorkflowIncomplete(false) } diff --git a/src/components/layout/update-button.tsx b/src/components/layout/update-button.tsx index 67e4c1100..8cfe36afc 100644 --- a/src/components/layout/update-button.tsx +++ b/src/components/layout/update-button.tsx @@ -1,5 +1,6 @@ import { Button } from '@mui/material' import { useRef } from 'react' +import { useTranslation } from 'react-i18next' import { DialogRef } from '@/components/base' import { useUpdate } from '@/hooks/use-update' @@ -12,6 +13,7 @@ interface Props { export const UpdateButton = (props: Props) => { const { className } = props + const { t } = useTranslation() const viewerRef = useRef(null) const { updateInfo } = useUpdate() @@ -29,7 +31,7 @@ export const UpdateButton = (props: Props) => { className={className} onClick={() => viewerRef.current?.open()} > - New + {t('shared.actions.new')} ) diff --git a/src/components/profile/file-input.tsx b/src/components/profile/file-input.tsx index 4215a031e..6124a9754 100644 --- a/src/components/profile/file-input.tsx +++ b/src/components/profile/file-input.tsx @@ -54,7 +54,7 @@ export const FileInput = (props: Props) => { /> - {loading ? 'Loading...' : fileName} + {loading ? t('shared.statuses.loading') : fileName} ) diff --git a/src/components/profile/profile-viewer.tsx b/src/components/profile/profile-viewer.tsx index 0fcf1ed84..c55928577 100644 --- a/src/components/profile/profile-viewer.tsx +++ b/src/components/profile/profile-viewer.tsx @@ -91,9 +91,11 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { setLoading(true) try { // 基本验证 - if (!form.type) throw new Error('`Type` should not be null') + if (!form.type) { + throw new Error(t('profiles.modals.profileForm.errors.typeRequired')) + } if (form.type === 'remote' && !form.url) { - throw new Error('The URL should not be null') + throw new Error(t('profiles.modals.profileForm.errors.urlRequired')) } // 处理表单数据 @@ -131,7 +133,11 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { if (openType === 'new') { await createProfile(item, fileDataRef.current) } else { - if (!form.uid) throw new Error('UID not found') + if (!form.uid) { + throw new Error( + t('profiles.modals.profileForm.errors.uidMissing'), + ) + } await patchProfile(form.uid, item) } } else { @@ -141,7 +147,11 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { if (openType === 'new') { await createProfile(item, fileDataRef.current) } else { - if (!form.uid) throw new Error('UID not found') + if (!form.uid) { + throw new Error( + t('profiles.modals.profileForm.errors.uidMissing'), + ) + } await patchProfile(form.uid, item) } } catch { @@ -164,7 +174,11 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { if (openType === 'new') { await createProfile(retryItem, fileDataRef.current) } else { - if (!form.uid) throw new Error('UID not found') + if (!form.uid) { + throw new Error( + t('profiles.modals.profileForm.errors.uidMissing'), + ) + } await patchProfile(form.uid, retryItem) // 编辑模式下恢复原始代理设置 @@ -187,7 +201,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { onChange(isActivating) }, 0) } catch (err) { - showNotice.error(err) + showNotice.error('profiles.modals.profileForm.errors.saveFailed', err) } finally { setLoading(false) } @@ -246,8 +260,12 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { autoFocus label={t('profiles.modals.profileForm.fields.type')} > - Remote - Local + + {t('profiles.modals.profileForm.types.remote')} + + + {t('profiles.modals.profileForm.types.local')} + )} @@ -305,7 +323,7 @@ export function ProfileViewer({ onChange, ref }: ProfileViewerProps) { {...text} {...field} placeholder={`clash-verge/v${version}`} - label="User Agent" + label={t('profiles.modals.profileForm.fields.userAgent')} /> )} /> diff --git a/src/components/proxy/proxy-chain.tsx b/src/components/proxy/proxy-chain.tsx index a96eaa63d..602d1529e 100644 --- a/src/components/proxy/proxy-chain.tsx +++ b/src/components/proxy/proxy-chain.tsx @@ -214,9 +214,7 @@ const SortableItem = ({ {proxy.delay !== undefined && ( 0 - ? `${proxy.delay}ms` - : t('shared.labels.timeout') || '超时' + proxy.delay > 0 ? `${proxy.delay}ms` : t('shared.labels.timeout') } size="small" color={ @@ -402,7 +400,7 @@ export const ProxyChain = ({ onUpdateChain([]) } catch (error) { console.error('Failed to disconnect from proxy chain:', error) - alert(t('proxies.page.chain.disconnectFailed') || '断开链式代理失败') + alert(t('proxies.page.chain.disconnectFailed')) } finally { setIsConnecting(false) } @@ -410,7 +408,7 @@ export const ProxyChain = ({ } if (mode === 'global' && proxyView?.global === null) { - alert(t('proxies.page.chain.connectFailed') || '连接链式代理失败') + alert(t('proxies.page.chain.connectFailed')) return } @@ -418,7 +416,7 @@ export const ProxyChain = ({ currentProxyChain.length < 2 || currentProxyChain.some(({ recordId }) => !recordId) ) { - alert(t('proxies.page.chain.minimumNodes') || '链式代理至少需要2个节点') + alert(t('proxies.page.chain.minimumNodes')) return } @@ -450,7 +448,7 @@ export const ProxyChain = ({ debugLog('Successfully connected to proxy chain') } catch (error) { console.error('Failed to connect to proxy chain:', error) - alert(t('proxies.page.chain.connectFailed') || '连接链式代理失败') + alert(t('proxies.page.chain.connectFailed')) } finally { setIsConnecting(false) } @@ -526,9 +524,7 @@ export const ProxyChain = ({ backgroundColor: theme.palette.error.light + '20', }, }} - title={ - t('proxies.page.actions.clearChainConfig') || '删除链式配置' - } + title={t('proxies.page.actions.clearChainConfig')} > @@ -554,16 +550,15 @@ export const ProxyChain = ({ }} title={ !isConnected && currentProxyChain.length < 2 - ? t('proxies.page.chain.minimumNodes') || - '链式代理至少需要2个节点' + ? t('proxies.page.chain.minimumNodes') : undefined } > {isConnecting - ? t('proxies.page.actions.connecting') || '连接中...' + ? t('proxies.page.actions.connecting') : isConnected - ? t('proxies.page.actions.disconnect') || '断开' - : t('proxies.page.actions.connect') || '连接'} + ? t('proxies.page.actions.disconnect') + : t('proxies.page.actions.connect')} @@ -573,10 +568,8 @@ export const ProxyChain = ({ sx={{ mb: 2 }} > {currentProxyChain.length === 1 - ? t('proxies.page.chain.minimumNodesHint') || - '链式代理至少需要2个节点,请再添加一个节点。' - : t('proxies.page.chain.instruction') || - '按顺序点击节点添加到代理链中'} + ? t('proxies.page.chain.minimumNodesHint') + : t('proxies.page.chain.instruction')} diff --git a/src/components/proxy/proxy-groups-chain.tsx b/src/components/proxy/proxy-groups-chain.tsx index a3467f272..2b405e1a9 100644 --- a/src/components/proxy/proxy-groups-chain.tsx +++ b/src/components/proxy/proxy-groups-chain.tsx @@ -63,6 +63,7 @@ interface GroupSelectMenuProps { groups: ProxyGroupOption[] selectedGroup: string | null emptyText: string + nodeCountLabel: (count: number) => string onClose: () => void onSelect: (groupName: string) => void } @@ -162,6 +163,7 @@ function GroupSelectMenu({ groups, selectedGroup, emptyText, + nodeCountLabel, onClose, onSelect, }: GroupSelectMenuProps) { @@ -197,7 +199,7 @@ function GroupSelectMenu({ {group.name} - {group.type} · {group.members.length} 节点 + {group.type} · {nodeCountLabel(group.members.length)} @@ -521,7 +523,10 @@ export function ProxyGroupsChain(props: ProxyGroupsChainProps) { anchorEl={ruleMenuAnchor} groups={availableGroups} selectedGroup={activeSelectedGroup} - emptyText="暂无可用代理组" + emptyText={t('proxies.page.empty.noAvailableGroups')} + nodeCountLabel={(count) => + t('proxies.page.labels.nodeCount', { count }) + } onClose={handleGroupMenuClose} onSelect={handleGroupSelect} /> diff --git a/src/components/proxy/proxy-item-mini.tsx b/src/components/proxy/proxy-item-mini.tsx index ea3ab097b..2108c8272 100644 --- a/src/components/proxy/proxy-item-mini.tsx +++ b/src/components/proxy/proxy-item-mini.tsx @@ -183,7 +183,7 @@ export const ProxyItemMini = (props: Props) => { ':hover': { bgcolor: alpha(palette.primary.main, 0.15) }, })} > - Check + {t('shared.actions.check')} )} diff --git a/src/components/proxy/proxy-item.tsx b/src/components/proxy/proxy-item.tsx index 0f0a98282..75b1a2bb1 100644 --- a/src/components/proxy/proxy-item.tsx +++ b/src/components/proxy/proxy-item.tsx @@ -10,6 +10,7 @@ import { type SxProps, type Theme, } from '@mui/material' +import { useTranslation } from 'react-i18next' import { BaseLoading } from '@/components/base' import { useProxyDelayState } from '@/hooks/use-proxy-delay-state' @@ -49,6 +50,7 @@ const TypeBox = styled('span')(({ theme }) => ({ })) export const ProxyItem = (props: Props) => { + const { t } = useTranslation() const { group, member, selected, showType = true, sx, onClick } = props const details = memberDetails(member) const unresolved = member.kind === 'unresolved' @@ -160,7 +162,7 @@ export const ProxyItem = (props: Props) => { ':hover': { bgcolor: alpha(palette.primary.main, 0.15) }, })} > - Check + {t('shared.actions.check')} )} diff --git a/src/components/proxy/proxy-render.tsx b/src/components/proxy/proxy-render.tsx index 5afaeb963..3f4b08b20 100644 --- a/src/components/proxy/proxy-render.tsx +++ b/src/components/proxy/proxy-render.tsx @@ -262,7 +262,9 @@ export const ProxyRender = memo(function ProxyRender(props: RenderProps) { }} > - No Proxies + + {t('proxies.page.empty.noProxies')} + ) } diff --git a/src/components/setting/mods/dns-viewer.tsx b/src/components/setting/mods/dns-viewer.tsx index 099a53393..b90d7b53f 100644 --- a/src/components/setting/mods/dns-viewer.tsx +++ b/src/components/setting/mods/dns-viewer.tsx @@ -583,7 +583,7 @@ export function DnsViewer({ ref }: { ref?: Ref }) { setOpen(false) showNotice.success('settings.modals.dns.messages.saved') } catch (err) { - showNotice.error(err) + showNotice.error('settings.modals.dns.messages.configError', err) } }) diff --git a/src/components/setting/mods/update-viewer.tsx b/src/components/setting/mods/update-viewer.tsx index aa7c9c077..019efc89a 100644 --- a/src/components/setting/mods/update-viewer.tsx +++ b/src/components/setting/mods/update-viewer.tsx @@ -30,11 +30,26 @@ type MarkdownNode = { } const GITHUB_ALERTS = { - note: { label: 'Note', color: '#0969da' }, - tip: { label: 'Tip', color: '#1a7f37' }, - important: { label: 'Important', color: '#8250df' }, - warning: { label: 'Warning', color: '#9a6700' }, - caution: { label: 'Caution', color: '#cf222e' }, + note: { + labelKey: 'settings.modals.update.alerts.note', + color: '#0969da', + }, + tip: { + labelKey: 'settings.modals.update.alerts.tip', + color: '#1a7f37', + }, + important: { + labelKey: 'settings.modals.update.alerts.important', + color: '#8250df', + }, + warning: { + labelKey: 'settings.modals.update.alerts.warning', + color: '#9a6700', + }, + caution: { + labelKey: 'settings.modals.update.alerts.caution', + color: '#cf222e', + }, } as const type GitHubAlertType = keyof typeof GITHUB_ALERTS @@ -76,7 +91,7 @@ const findFirstTextNode = (node: MarkdownNode): MarkdownNode | null => { return null } -const remarkGitHubAlerts = () => { +const remarkGitHubAlerts = (labels: Record) => { const visit = (node: MarkdownNode) => { for (const child of node.children ?? []) { visit(child) @@ -111,7 +126,7 @@ const remarkGitHubAlerts = () => { children: [ { type: 'text', - value: GITHUB_ALERTS[alertType].label, + value: labels[alertType], }, ], }) @@ -144,12 +159,27 @@ export function UpdateViewer({ ref }: { ref?: Ref }) { close: () => setOpen(false), })) + const githubAlertLabels = useMemo( + () => + Object.fromEntries( + Object.entries(GITHUB_ALERTS).map(([type, alert]) => [ + type, + t(alert.labelKey), + ]), + ) as Record, + [t], + ) + const remarkGitHubAlertsPlugin = useMemo( + () => () => remarkGitHubAlerts(githubAlertLabels), + [githubAlertLabels], + ) + const markdownContent = useMemo(() => { if (!updateInfo?.body) { - return 'New Version is available' + return t('settings.modals.update.messages.available') } return updateInfo?.body - }, [updateInfo]) + }, [t, updateInfo]) const breakChangeFlag = useMemo(() => { if (!updateInfo?.body) { @@ -382,7 +412,7 @@ export function UpdateViewer({ ref }: { ref?: Ref }) { {open && ( }> { const { children } = props diff --git a/src/components/setting/mods/web-ui-viewer.tsx b/src/components/setting/mods/web-ui-viewer.tsx index 1f90676f5..1920e81b8 100644 --- a/src/components/setting/mods/web-ui-viewer.tsx +++ b/src/components/setting/mods/web-ui-viewer.tsx @@ -74,9 +74,17 @@ export function WebUIViewer({ ref }: { ref?: Ref }) { let url = value.trim().replaceAll('%host', '127.0.0.1') if (url.includes('%port') || url.includes('%secret')) { - if (!clashInfo) throw new Error('failed to get clash info') + if (!clashInfo) { + throw new Error( + t('settings.modals.webUI.errors.clashInfoUnavailable'), + ) + } if (!clashInfo.server?.includes(':')) { - throw new Error(`failed to parse the server "${clashInfo.server}"`) + throw new Error( + t('settings.modals.webUI.errors.invalidServer', { + server: clashInfo.server, + }), + ) } const port = clashInfo.server @@ -92,7 +100,7 @@ export function WebUIViewer({ ref }: { ref?: Ref }) { await openWebUrl(url) } catch (e: any) { - showNotice.error(e) + showNotice.error('settings.modals.webUI.errors.openFailed', e) } }) diff --git a/src/components/shared/traffic-error-boundary.tsx b/src/components/shared/traffic-error-boundary.tsx index 5d5c0ad43..0cdfedc7b 100644 --- a/src/components/shared/traffic-error-boundary.tsx +++ b/src/components/shared/traffic-error-boundary.tsx @@ -189,8 +189,10 @@ const TrafficErrorFallback: React.FC = ({ - Error:{' '} - {error instanceof Error ? error.message : 'Unknown error'} + {t('shared.feedback.errors.label')}:{' '} + {error instanceof Error + ? error.message + : t('shared.feedback.errors.unknown')} {retryCount > 0 && ( @@ -239,7 +241,7 @@ const TrafficErrorFallback: React.FC = ({ }} > - Error Details: + {t('shared.feedback.errors.details')}: = ({ {errorInfo?.componentStack && ( <> - Component Stack: + {t('shared.feedback.errors.componentStack')}: = ({ export const LightweightTrafficErrorBoundary: React.FC<{ children: ReactNode }> = ({ children }) => { + const { t } = useTranslation() + return ( - Traffic data unavailable + + {t('shared.feedback.errors.trafficUnavailable')} + } > diff --git a/src/components/test/test-item.tsx b/src/components/test/test-item.tsx index a208d7d7c..965a80c55 100644 --- a/src/components/test/test-item.tsx +++ b/src/components/test/test-item.tsx @@ -70,8 +70,8 @@ export const TestItem = ({ }) const menu = [ - { label: 'Edit', handler: onEditTest }, - { label: 'Delete', handler: onDelete }, + { label: t('shared.actions.edit'), handler: onEditTest }, + { label: t('shared.actions.delete'), handler: onDelete }, ] useEffect(() => { @@ -220,7 +220,7 @@ export const TestItem = ({ sx={{ minWidth: 120 }} dense > - {t(item.label)} + {item.label} ))} diff --git a/src/components/test/test-viewer.tsx b/src/components/test/test-viewer.tsx index 236b3fbbc..398aa3091 100644 --- a/src/components/test/test-viewer.tsx +++ b/src/components/test/test-viewer.tsx @@ -68,8 +68,12 @@ export const TestViewer = forwardRef( formIns.handleSubmit(async (form) => { setLoading(true) try { - if (!form.name) throw new Error('`Name` should not be null') - if (!form.url) throw new Error('`Url` should not be null') + if (!form.name) { + throw new Error(t('tests.modals.test.errors.nameRequired')) + } + if (!form.url) { + throw new Error(t('tests.modals.test.errors.urlRequired')) + } let newList let uid @@ -84,7 +88,7 @@ export const TestViewer = forwardRef( 'image/svg+xml', ) if (doc.querySelector('parsererror')) { - throw new Error('`Icon`svg format error') + throw new Error(t('tests.modals.test.errors.invalidSvg')) } } @@ -95,7 +99,9 @@ export const TestViewer = forwardRef( await patchVerge({ test_list: newList }) onChange(uid) } else { - if (!form.uid) throw new Error('UID not found') + if (!form.uid) { + throw new Error(t('tests.modals.test.errors.uidMissing')) + } uid = form.uid await patchTestList(uid, form) @@ -105,7 +111,7 @@ export const TestViewer = forwardRef( setLoading(false) setTimeout(() => formIns.reset(), 500) } catch (err: any) { - showNotice.error(err) + showNotice.error('tests.modals.test.errors.saveFailed', err) setLoading(false) } }), diff --git a/src/hooks/use-clash.ts b/src/hooks/use-clash.ts index 027c89628..d099cc086 100644 --- a/src/hooks/use-clash.ts +++ b/src/hooks/use-clash.ts @@ -1,4 +1,5 @@ import { useLockFn } from 'ahooks' +import i18n from 'i18next' import { getVersion } from 'tauri-plugin-mihomo-api' import { @@ -47,10 +48,14 @@ const hasClashInfoPayload = (patch: ClashInfoPatch) => const validatePortRange = (port: number) => { if (port < 1000) { - throw new Error('The port should not < 1000') + throw new Error( + i18n.t(($) => $.settings.modals.clashPort.messages.portTooLow), + ) } if (port > 65535) { - throw new Error('The port should not > 65536') + throw new Error( + i18n.t(($) => $.settings.modals.clashPort.messages.portTooHigh), + ) } } diff --git a/src/locales/ar/home.json b/src/locales/ar/home.json index f2c93b82d..9048e69d6 100644 --- a/src/locales/ar/home.json +++ b/src/locales/ar/home.json @@ -82,7 +82,9 @@ "unknown": "Unknown" }, "errors": { - "load": "فشل الحصول على معلومات الـ IP" + "load": "فشل الحصول على معلومات الـ IP", + "loadWithDetails": "تعذّر الحصول على معلومات IP: {{message}}", + "noServices": "لا توجد خدمات كشف IP متاحة" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Group", "proxy": "Proxy", "noActiveNode": "No active proxy node" + }, + "status": { + "testing": "جارٍ الاختبار", + "untested": "لم يُختبر", + "error": "خطأ", + "timeout": "انتهت المهلة", + "latencyHigh": "زمن استجابة مرتفع", + "latencyMedium": "زمن استجابة متوسط", + "latencyGood": "زمن استجابة جيد", + "latencyExcellent": "زمن استجابة ممتاز", + "uninitialized": "غير مُهيأ", + "noProxyNode": "لا توجد عقدة وكيل" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "وقت غير معروف", + "chartStyles": { + "smooth": "ناعم", + "linear": "خطي" + }, + "diagnostics": "النقاط: {{points}} | مضغوط: {{compressed}} | الإطارات/ث: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/ar/layout.json b/src/locales/ar/layout.json index 3a6cdb1e8..a3881e18e 100644 --- a/src/locales/ar/layout.json +++ b/src/locales/ar/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "فشلت عملية الخدمة", + "stateRefreshFailed": "تعذّر تحديث حالة الخدمة", + "restartFailed": "تعذّر إعادة تشغيل النواة", + "revalidationFailed": "تعذّر تحديث حالة التشغيل", + "sidecarFailed": "تعذّر المتابعة باستخدام Sidecar" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "تعذّر إيقاف النواة بأمان، لذا أُلغيت إعادة التشغيل", + "quitCoreStopFailed": "تعذّر إيقاف النواة بأمان، لذا أُلغي الخروج" } } } diff --git a/src/locales/ar/profiles.json b/src/locales/ar/profiles.json index 8e8cbd0a5..b9a84928f 100644 --- a/src/locales/ar/profiles.json +++ b/src/locales/ar/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "لا يتم دعم سوى ملفات YAML" + "onlyYaml": "لا يتم دعم سوى ملفات YAML", + "createFailed": "تعذّر إنشاء الملف الشخصي", + "deleteFailed": "تعذّر حذف الملف الشخصي", + "enhanceFailed": "تعذّر إعادة تفعيل الملفات الشخصية", + "importFailed": "تعذّر استيراد الملف الشخصي", + "openFailed": "تعذّر فتح الملف الشخصي", + "readFailed": "تعذّر قراءة الملف الشخصي", + "reorderFailed": "تعذّر إعادة ترتيب الملفات الشخصية", + "switchFailed": "تعذّر تبديل الملف الشخصي", + "updateFailed": "تعذّر تحديث الملف الشخصي" }, "notifications": { "importRetry": "Import failed, retrying with Clash proxy...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "بيانات الملف الشخصي غير متاحة؛ انقر للتحديث القسري" } }, "title": "الملفات الشخصية" @@ -105,6 +117,7 @@ "type": "النوع", "description": "الوصف", "subscriptionUrl": "رابط الاشتراك", + "userAgent": "وكيل المستخدم", "httpTimeout": "HTTP Request Timeout", "updateInterval": "فاصل التحديث", "useSystemProxy": "استخدام وكيل النظام", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "قبول الشهادات غير الصالحة (خطر)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "بعيد", + "local": "محلي" + }, + "errors": { + "typeRequired": "اختر نوع الملف الشخصي", + "urlRequired": "أدخل رابط الاشتراك", + "uidMissing": "مُعرّف الملف الشخصي مفقود", + "saveFailed": "تعذّر حفظ الملف الشخصي" + }, "feedback": { "notifications": { "creationRetry": "Profile creation failed, retrying with Clash proxy...", diff --git a/src/locales/ar/proxies.json b/src/locales/ar/proxies.json index 7b9a0663e..ae7eb24c4 100644 --- a/src/locales/ar/proxies.json +++ b/src/locales/ar/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Proxy Count", - "delayCheckReset": "فحص التأخير لإلغاء الثابت" + "delayCheckReset": "فحص التأخير لإلغاء الثابت", + "nodeCount": "{{count}} عقدة" }, "tooltips": { "locate": "الموقع", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "رابط فحص التأخير" }, + "empty": { + "noAvailableGroups": "لا توجد مجموعات وكيل متاحة", + "noProxies": "لا توجد وكلاء" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/ar/settings.json b/src/locales/ar/settings.json index 807cf5861..d28c05aaf 100644 --- a/src/locales/ar/settings.json +++ b/src/locales/ar/settings.json @@ -5,6 +5,7 @@ "telegram": "قناة تيليجرام", "github": "مستودع Github" }, + "actionsGroupLabel": "روابط الإعدادات", "title": "الإعدادات" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "يجب ألا يقل المنفذ عن 1000", + "portTooHigh": "يجب ألا يزيد المنفذ عن 65535" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "تحديث" }, "messages": { - "breakChangeError": "هذا الإصدار هو تحديث رئيسي ولا يدعم التحديث داخل التطبيق. يرجى إلغاء التثبيت وتنزيل الإصدار الجديد وتثبيته يدويًا" + "breakChangeError": "هذا الإصدار هو تحديث رئيسي ولا يدعم التحديث داخل التطبيق. يرجى إلغاء التثبيت وتنزيل الإصدار الجديد وتثبيته يدويًا", + "available": "يتوفّر إصدار جديد" + }, + "alerts": { + "note": "ملاحظة", + "tip": "نصيحة", + "important": "مهم", + "warning": "تحذير", + "caution": "تنبيه" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "يدعم %host و%port و%secret", "placeholderInstruction": "استبدل المضيف والمنفذ والمفتاح بـ %host و%port و%secret" + }, + "errors": { + "clashInfoUnavailable": "معلومات اتصال النواة غير متاحة", + "invalidServer": "عنوان خادم النواة \"{{server}}\" غير صالح", + "openFailed": "تعذّر فتح واجهة الويب" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "تعذّر تحديث إعدادات النواة", + "modeUpdateFailed": "تعذّر تغيير وضع الوكيل", + "restartFailed": "تعذّر إعادة تشغيل النواة", + "startFailed": "تعذّر تشغيل النواة", + "stopFailed": "تعذّر إيقاف النواة" + }, + "clashService": { + "installFailed": "تعذّر تثبيت الخدمة", + "uninstallFailed": "تعذّر إلغاء تثبيت الخدمة", + "reinstallFailed": "تعذّر إعادة تثبيت الخدمة", + "repairFailed": "تعذّر إصلاح الخدمة", + "sidecarFailed": "تعذّر المتابعة باستخدام Sidecar" + } + }, "notifications": { "clash": { "restartSuccess": "تم إعادة تشغيل نواة Clash", diff --git a/src/locales/ar/shared.json b/src/locales/ar/shared.json index a12f77995..62b9373b5 100644 --- a/src/locales/ar/shared.json +++ b/src/locales/ar/shared.json @@ -23,7 +23,8 @@ "closeAll": "إغلاق الكل", "clear": "مسح", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "فحص" }, "labels": { "updateAt": "التحديث عند", @@ -44,7 +45,8 @@ "enabled": "ممكّن", "disabled": "معطّل", "saving": "Saving...", - "empty": "فارغ" + "empty": "فارغ", + "loading": "جارٍ التحميل..." }, "units": { "milliseconds": "ميلي ثانية", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "حدث خطأ ما", + "label": "خطأ", + "unknown": "خطأ غير معروف", + "details": "تفاصيل الخطأ", + "stack": "تتبّع الخطأ", + "componentStack": "تتبّع المكوّن", + "trafficUnavailable": "بيانات حركة المرور غير متاحة", + "operationFailed": "فشلت العملية", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/ar/tests.json b/src/locales/ar/tests.json index 3f4d17072..31b740623 100644 --- a/src/locales/ar/tests.json +++ b/src/locales/ar/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "رابط الاختبار" + }, + "errors": { + "nameRequired": "أدخل اسمًا", + "urlRequired": "أدخل رابط الاختبار", + "invalidSvg": "الأيقونة ليست بصيغة SVG صالحة", + "uidMissing": "مُعرّف عنصر الاختبار مفقود", + "saveFailed": "تعذّر حفظ عنصر الاختبار" } } }, diff --git a/src/locales/de/home.json b/src/locales/de/home.json index 70c6549e3..ad0476ac9 100644 --- a/src/locales/de/home.json +++ b/src/locales/de/home.json @@ -82,7 +82,9 @@ "unknown": "Unbekannt" }, "errors": { - "load": "IP-Informationen konnten nicht abgerufen werden" + "load": "IP-Informationen konnten nicht abgerufen werden", + "loadWithDetails": "IP-Informationen konnten nicht abgerufen werden: {{message}}", + "noServices": "Keine IP-Erkennungsdienste verfügbar" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Proxy-Gruppe", "proxy": "Knoten", "noActiveNode": "Kein aktiver Proxy-Knoten" + }, + "status": { + "testing": "Wird getestet", + "untested": "Nicht getestet", + "error": "Fehler", + "timeout": "Zeitüberschreitung", + "latencyHigh": "Hohe Latenz", + "latencyMedium": "Mittlere Latenz", + "latencyGood": "Gute Latenz", + "latencyExcellent": "Ausgezeichnete Latenz", + "uninitialized": "Nicht initialisiert", + "noProxyNode": "Kein Proxy-Knoten" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "Unbekannte Zeit", + "chartStyles": { + "smooth": "Weich", + "linear": "Linear" + }, + "diagnostics": "Punkte: {{points}} | Komprimiert: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/de/layout.json b/src/locales/de/layout.json index 2684b705d..095890074 100644 --- a/src/locales/de/layout.json +++ b/src/locales/de/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "Der Dienstvorgang ist fehlgeschlagen", + "stateRefreshFailed": "Dienststatus konnte nicht aktualisiert werden", + "restartFailed": "Kern konnte nicht neu gestartet werden", + "revalidationFailed": "Laufstatus konnte nicht aktualisiert werden", + "sidecarFailed": "Fortsetzung mit Sidecar fehlgeschlagen" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "Der Kern konnte nicht sicher gestoppt werden, daher wurde der Neustart abgebrochen", + "quitCoreStopFailed": "Der Kern konnte nicht sicher gestoppt werden, daher wurde das Beenden abgebrochen" } } } diff --git a/src/locales/de/profiles.json b/src/locales/de/profiles.json index 1a18f04c1..a8783fa76 100644 --- a/src/locales/de/profiles.json +++ b/src/locales/de/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "Nur YAML-Dateien werden unterstützt" + "onlyYaml": "Nur YAML-Dateien werden unterstützt", + "createFailed": "Abonnement konnte nicht erstellt werden", + "deleteFailed": "Abonnement konnte nicht gelöscht werden", + "enhanceFailed": "Abonnements konnten nicht erneut aktiviert werden", + "importFailed": "Abonnement konnte nicht importiert werden", + "openFailed": "Abonnement konnte nicht geöffnet werden", + "readFailed": "Abonnement konnte nicht gelesen werden", + "reorderFailed": "Abonnements konnten nicht neu angeordnet werden", + "switchFailed": "Abonnement konnte nicht gewechselt werden", + "updateFailed": "Abonnement konnte nicht aktualisiert werden" }, "notifications": { "importRetry": "Import des Abonnements fehlgeschlagen. Versuche es mit dem Clash-Proxy erneut...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Abonnementdaten sind nicht verfügbar; zum erzwungenen Aktualisieren klicken" } }, "title": "Abonnement" @@ -105,6 +117,7 @@ "type": "Typ", "description": "Beschreibung", "subscriptionUrl": "Abonnement-Link", + "userAgent": "User Agent", "httpTimeout": "HTTP Request Timeout", "updateInterval": "Aktualisierungsintervall", "useSystemProxy": "Systemproxy zur Aktualisierung verwenden", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Allows Invalid Certificates (Danger)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "Remote", + "local": "Lokal" + }, + "errors": { + "typeRequired": "Abonnementtyp auswählen", + "urlRequired": "Abonnement-URL eingeben", + "uidMissing": "Die Abonnement-Kennung fehlt", + "saveFailed": "Abonnement konnte nicht gespeichert werden" + }, "feedback": { "notifications": { "creationRetry": "Erstellung des Abonnements fehlgeschlagen. Versuche es mit dem Clash-Proxy erneut...", diff --git a/src/locales/de/proxies.json b/src/locales/de/proxies.json index 3381c3ccf..f71289018 100644 --- a/src/locales/de/proxies.json +++ b/src/locales/de/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Anzahl der Knoten", - "delayCheckReset": "Latenztest durchführen, um Fixierung aufzuheben" + "delayCheckReset": "Latenztest durchführen, um Fixierung aufzuheben", + "nodeCount": "{{count}} Knoten" }, "tooltips": { "locate": "Aktueller Knoten", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "Latenztest-URL" }, + "empty": { + "noAvailableGroups": "Keine Proxy-Gruppen verfügbar", + "noProxies": "Keine Proxys" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/de/settings.json b/src/locales/de/settings.json index e423e62e3..7171450a8 100644 --- a/src/locales/de/settings.json +++ b/src/locales/de/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram-Kanal", "github": "GitHub-Projektadresse" }, + "actionsGroupLabel": "Einstellungslinks", "title": "Einstellungen" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "Der Port muss mindestens 1000 sein", + "portTooHigh": "Der Port darf höchstens 65535 sein" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Aktualisieren" }, "messages": { - "breakChangeError": "Dies ist eine wichtige Aktualisierung. Die In-App-Aktualisierung wird nicht unterstützt. Bitte deinstallieren Sie die Software und laden Sie die neue Version manuell herunter und installieren Sie sie." + "breakChangeError": "Dies ist eine wichtige Aktualisierung. Die In-App-Aktualisierung wird nicht unterstützt. Bitte deinstallieren Sie die Software und laden Sie die neue Version manuell herunter und installieren Sie sie.", + "available": "Eine neue Version ist verfügbar" + }, + "alerts": { + "note": "Hinweis", + "tip": "Tipp", + "important": "Wichtig", + "warning": "Warnung", + "caution": "Achtung" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "Unterstützt %host, %port, %secret", "placeholderInstruction": "Verwenden Sie %host, %port, %secret für Host, Port und Zugangsschlüssel" + }, + "errors": { + "clashInfoUnavailable": "Verbindungsinformationen des Kerns sind nicht verfügbar", + "invalidServer": "Die Kern-Serveradresse „{{server}}“ ist ungültig", + "openFailed": "Web-UI konnte nicht geöffnet werden" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "Kernkonfiguration konnte nicht aktualisiert werden", + "modeUpdateFailed": "Proxy-Modus konnte nicht geändert werden", + "restartFailed": "Kern konnte nicht neu gestartet werden", + "startFailed": "Kern konnte nicht gestartet werden", + "stopFailed": "Kern konnte nicht gestoppt werden" + }, + "clashService": { + "installFailed": "Dienst konnte nicht installiert werden", + "uninstallFailed": "Dienst konnte nicht deinstalliert werden", + "reinstallFailed": "Dienst konnte nicht neu installiert werden", + "repairFailed": "Dienst konnte nicht repariert werden", + "sidecarFailed": "Fortsetzung mit Sidecar fehlgeschlagen" + } + }, "notifications": { "clash": { "restartSuccess": "Clash-Kern wurde neu gestartet", diff --git a/src/locales/de/shared.json b/src/locales/de/shared.json index fa62dbb55..cdb18280d 100644 --- a/src/locales/de/shared.json +++ b/src/locales/de/shared.json @@ -23,7 +23,8 @@ "closeAll": "Alle schließen", "clear": "Löschen", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "Prüfen" }, "labels": { "updateAt": "Aktualisiert am", @@ -44,7 +45,8 @@ "enabled": "Aktiviert", "disabled": "Deaktiviert", "saving": "Saving...", - "empty": "Leer" + "empty": "Leer", + "loading": "Wird geladen..." }, "units": { "milliseconds": "Millisekunden", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Etwas ist schiefgelaufen", + "label": "Fehler", + "unknown": "Unbekannter Fehler", + "details": "Fehlerdetails", + "stack": "Fehler-Stack", + "componentStack": "Komponenten-Stack", + "trafficUnavailable": "Traffic-Daten nicht verfügbar", + "operationFailed": "Der Vorgang ist fehlgeschlagen", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/de/tests.json b/src/locales/de/tests.json index 49b92211b..665a1a03f 100644 --- a/src/locales/de/tests.json +++ b/src/locales/de/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "Test-URL" + }, + "errors": { + "nameRequired": "Namen eingeben", + "urlRequired": "Test-URL eingeben", + "invalidSvg": "Das Symbol ist kein gültiges SVG", + "uidMissing": "Die Kennung des Testelements fehlt", + "saveFailed": "Testelement konnte nicht gespeichert werden" } } }, diff --git a/src/locales/en/home.json b/src/locales/en/home.json index 8a8309fb3..7aa2eab33 100644 --- a/src/locales/en/home.json +++ b/src/locales/en/home.json @@ -82,7 +82,9 @@ "unknown": "Unknown" }, "errors": { - "load": "Failed to get IP info" + "load": "Failed to get IP info", + "loadWithDetails": "Failed to get IP info: {{message}}", + "noServices": "No IP detection services are available" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Group", "proxy": "Proxy", "noActiveNode": "No active proxy node" + }, + "status": { + "testing": "Testing", + "untested": "Not tested", + "error": "Error", + "timeout": "Timeout", + "latencyHigh": "High latency", + "latencyMedium": "Moderate latency", + "latencyGood": "Good latency", + "latencyExcellent": "Excellent latency", + "uninitialized": "Not initialized", + "noProxyNode": "No proxy node" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "Unknown time", + "chartStyles": { + "smooth": "Smooth", + "linear": "Linear" + }, + "diagnostics": "Points: {{points}} | Compressed: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/en/layout.json b/src/locales/en/layout.json index 49762e8b6..bea0ecce2 100644 --- a/src/locales/en/layout.json +++ b/src/locales/en/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "The service operation failed", + "stateRefreshFailed": "Failed to refresh the service state", + "restartFailed": "Failed to restart the core", + "revalidationFailed": "Failed to refresh the running state", + "sidecarFailed": "Failed to continue with Sidecar" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "The core could not be stopped safely, so the restart was cancelled", + "quitCoreStopFailed": "The core could not be stopped safely, so quitting was cancelled" } } } diff --git a/src/locales/en/profiles.json b/src/locales/en/profiles.json index 130519774..6205574d0 100644 --- a/src/locales/en/profiles.json +++ b/src/locales/en/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "Only YAML Files Supported" + "onlyYaml": "Only YAML Files Supported", + "createFailed": "Failed to create profile", + "deleteFailed": "Failed to delete profile", + "enhanceFailed": "Failed to reactivate profiles", + "importFailed": "Failed to import profile", + "openFailed": "Failed to open profile", + "readFailed": "Failed to read profile", + "reorderFailed": "Failed to reorder profiles", + "switchFailed": "Failed to switch profile", + "updateFailed": "Failed to update profile" }, "notifications": { "importRetry": "Import failed, retrying with Clash proxy...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Profile data is unavailable; click to force a refresh" } }, "title": "Profiles" @@ -105,6 +117,7 @@ "type": "Type", "description": "Descriptions", "subscriptionUrl": "Subscription URL", + "userAgent": "User Agent", "httpTimeout": "HTTP Request Timeout", "updateInterval": "Update Interval", "useSystemProxy": "Use System Proxy", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Allows Invalid Certificates (Danger)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "Remote", + "local": "Local" + }, + "errors": { + "typeRequired": "Select a profile type", + "urlRequired": "Enter a subscription URL", + "uidMissing": "The profile identifier is missing", + "saveFailed": "Failed to save profile" + }, "feedback": { "notifications": { "creationRetry": "Profile creation failed, retrying with Clash proxy...", diff --git a/src/locales/en/proxies.json b/src/locales/en/proxies.json index 19b00eb58..0d6a8f36f 100644 --- a/src/locales/en/proxies.json +++ b/src/locales/en/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Proxy Count", - "delayCheckReset": "Delay check to cancel fixed" + "delayCheckReset": "Delay check to cancel fixed", + "nodeCount": "{{count}} nodes" }, "tooltips": { "locate": "locate", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "Delay check URL" }, + "empty": { + "noAvailableGroups": "No proxy groups are available", + "noProxies": "No proxies" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/en/settings.json b/src/locales/en/settings.json index 2ddf9c14c..cffe9fa59 100644 --- a/src/locales/en/settings.json +++ b/src/locales/en/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram Channel", "github": "Github Repo" }, + "actionsGroupLabel": "Settings links", "title": "Settings" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "The port must be 1000 or higher", + "portTooHigh": "The port must be 65535 or lower" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Update" }, "messages": { - "breakChangeError": "This version is a major update and does not support in-app updates. Please uninstall it and manually download and install the new version" + "breakChangeError": "This version is a major update and does not support in-app updates. Please uninstall it and manually download and install the new version", + "available": "A new version is available" + }, + "alerts": { + "note": "Note", + "tip": "Tip", + "important": "Important", + "warning": "Warning", + "caution": "Caution" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "Support %host, %port, %secret", "placeholderInstruction": "Replace host, port, secret with %host, %port, %secret" + }, + "errors": { + "clashInfoUnavailable": "Core connection information is unavailable", + "invalidServer": "The core server address \"{{server}}\" is invalid", + "openFailed": "Failed to open Web UI" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "Failed to update core configuration", + "modeUpdateFailed": "Failed to change proxy mode", + "restartFailed": "Failed to restart the core", + "startFailed": "Failed to start the core", + "stopFailed": "Failed to stop the core" + }, + "clashService": { + "installFailed": "Failed to install the service", + "uninstallFailed": "Failed to uninstall the service", + "reinstallFailed": "Failed to reinstall the service", + "repairFailed": "Failed to repair the service", + "sidecarFailed": "Failed to continue with Sidecar" + } + }, "notifications": { "clash": { "restartSuccess": "Clash Core Restarted", diff --git a/src/locales/en/shared.json b/src/locales/en/shared.json index 2ac1743b6..27e7b7e24 100644 --- a/src/locales/en/shared.json +++ b/src/locales/en/shared.json @@ -23,7 +23,8 @@ "closeAll": "Close All", "clear": "Clear", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "Check" }, "labels": { "updateAt": "Update At", @@ -44,7 +45,8 @@ "enabled": "Enabled", "disabled": "Disabled", "saving": "Saving...", - "empty": "Empty" + "empty": "Empty", + "loading": "Loading..." }, "units": { "milliseconds": "ms", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Something went wrong", + "label": "Error", + "unknown": "Unknown error", + "details": "Error details", + "stack": "Error stack", + "componentStack": "Component stack", + "trafficUnavailable": "Traffic data unavailable", + "operationFailed": "The operation failed", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/en/tests.json b/src/locales/en/tests.json index 22c585591..627bdbb1c 100644 --- a/src/locales/en/tests.json +++ b/src/locales/en/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "Test URL" + }, + "errors": { + "nameRequired": "Enter a name", + "urlRequired": "Enter a test URL", + "invalidSvg": "The icon is not valid SVG", + "uidMissing": "The test item identifier is missing", + "saveFailed": "Failed to save test item" } } }, diff --git a/src/locales/es/home.json b/src/locales/es/home.json index 75e68bd5e..c0660e749 100644 --- a/src/locales/es/home.json +++ b/src/locales/es/home.json @@ -82,7 +82,9 @@ "unknown": "Desconocido" }, "errors": { - "load": "Error al obtener la información de IP" + "load": "Error al obtener la información de IP", + "loadWithDetails": "No se pudo obtener la información de IP: {{message}}", + "noServices": "No hay servicios de detección de IP disponibles" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Grupo de proxy", "proxy": "Nodo", "noActiveNode": "No hay nodos de proxy activos" + }, + "status": { + "testing": "Probando", + "untested": "Sin probar", + "error": "Error", + "timeout": "Tiempo agotado", + "latencyHigh": "Latencia alta", + "latencyMedium": "Latencia moderada", + "latencyGood": "Latencia buena", + "latencyExcellent": "Latencia excelente", + "uninitialized": "Sin inicializar", + "noProxyNode": "Sin nodo proxy" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "Hora desconocida", + "chartStyles": { + "smooth": "Suave", + "linear": "Lineal" + }, + "diagnostics": "Puntos: {{points}} | Comprimido: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/es/layout.json b/src/locales/es/layout.json index d1ec64481..ece0d655f 100644 --- a/src/locales/es/layout.json +++ b/src/locales/es/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "La operación del servicio falló", + "stateRefreshFailed": "No se pudo actualizar el estado del servicio", + "restartFailed": "No se pudo reiniciar el núcleo", + "revalidationFailed": "No se pudo actualizar el estado de ejecución", + "sidecarFailed": "No se pudo continuar con Sidecar" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "No se pudo detener el núcleo de forma segura, por lo que se canceló el reinicio", + "quitCoreStopFailed": "No se pudo detener el núcleo de forma segura, por lo que se canceló la salida" } } } diff --git a/src/locales/es/profiles.json b/src/locales/es/profiles.json index 3044e89c7..feb419649 100644 --- a/src/locales/es/profiles.json +++ b/src/locales/es/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "Solo se admiten archivos YAML" + "onlyYaml": "Solo se admiten archivos YAML", + "createFailed": "No se pudo crear la suscripción", + "deleteFailed": "No se pudo eliminar la suscripción", + "enhanceFailed": "No se pudieron reactivar las suscripciones", + "importFailed": "No se pudo importar la suscripción", + "openFailed": "No se pudo abrir la suscripción", + "readFailed": "No se pudo leer la suscripción", + "reorderFailed": "No se pudo reordenar las suscripciones", + "switchFailed": "No se pudo cambiar de suscripción", + "updateFailed": "No se pudo actualizar la suscripción" }, "notifications": { "importRetry": "Error al importar la suscripción. Intentando con el proxy de Clash...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Los datos de la suscripción no están disponibles; haz clic para forzar una actualización" } }, "title": "Suscripciones" @@ -105,6 +117,7 @@ "type": "Tipo", "description": "Descripción", "subscriptionUrl": "Enlace de suscripción", + "userAgent": "Agente de usuario", "httpTimeout": "HTTP Request Timeout", "updateInterval": "Intervalo de actualización", "useSystemProxy": "Usar proxy del sistema para actualizar", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Allows Invalid Certificates (Danger)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "Remoto", + "local": "Local" + }, + "errors": { + "typeRequired": "Selecciona un tipo de suscripción", + "urlRequired": "Introduce una URL de suscripción", + "uidMissing": "Falta el identificador de la suscripción", + "saveFailed": "No se pudo guardar la suscripción" + }, "feedback": { "notifications": { "creationRetry": "Error al crear la suscripción. Intentando con el proxy de Clash...", diff --git a/src/locales/es/proxies.json b/src/locales/es/proxies.json index 83743fd66..e7eb9bc4b 100644 --- a/src/locales/es/proxies.json +++ b/src/locales/es/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Número de nodos", - "delayCheckReset": "Realizar prueba de latencia para cancelar la fijación" + "delayCheckReset": "Realizar prueba de latencia para cancelar la fijación", + "nodeCount": "{{count}} nodos" }, "tooltips": { "locate": "Nodo actual", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "URL de prueba de latencia" }, + "empty": { + "noAvailableGroups": "No hay grupos de proxy disponibles", + "noProxies": "Sin proxies" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/es/settings.json b/src/locales/es/settings.json index ef894c890..935e7d357 100644 --- a/src/locales/es/settings.json +++ b/src/locales/es/settings.json @@ -5,6 +5,7 @@ "telegram": "Canal de Telegram", "github": "Dirección del proyecto en GitHub" }, + "actionsGroupLabel": "Enlaces de configuración", "title": "Ajustes" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "El puerto debe ser 1000 o superior", + "portTooHigh": "El puerto debe ser 65535 o inferior" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Actualizar" }, "messages": { - "breakChangeError": "Esta es una actualización importante y no se admite la actualización desde dentro de la aplicación. Desinstale e instale manualmente la nueva versión." + "breakChangeError": "Esta es una actualización importante y no se admite la actualización desde dentro de la aplicación. Desinstale e instale manualmente la nueva versión.", + "available": "Hay una nueva versión disponible" + }, + "alerts": { + "note": "Nota", + "tip": "Consejo", + "important": "Importante", + "warning": "Advertencia", + "caution": "Precaución" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "Soporta %host, %port, %secret", "placeholderInstruction": "Utilice %host, %port, %secret para representar el host, el puerto y la clave de acceso." + }, + "errors": { + "clashInfoUnavailable": "La información de conexión del núcleo no está disponible", + "invalidServer": "La dirección del servidor del núcleo «{{server}}» no es válida", + "openFailed": "No se pudo abrir la interfaz web" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "No se pudo actualizar la configuración del núcleo", + "modeUpdateFailed": "No se pudo cambiar el modo de proxy", + "restartFailed": "No se pudo reiniciar el núcleo", + "startFailed": "No se pudo iniciar el núcleo", + "stopFailed": "No se pudo detener el núcleo" + }, + "clashService": { + "installFailed": "No se pudo instalar el servicio", + "uninstallFailed": "No se pudo desinstalar el servicio", + "reinstallFailed": "No se pudo reinstalar el servicio", + "repairFailed": "No se pudo reparar el servicio", + "sidecarFailed": "No se pudo continuar con Sidecar" + } + }, "notifications": { "clash": { "restartSuccess": "Núcleo de Clash reiniciado", diff --git a/src/locales/es/shared.json b/src/locales/es/shared.json index bdea93304..a77002484 100644 --- a/src/locales/es/shared.json +++ b/src/locales/es/shared.json @@ -23,7 +23,8 @@ "closeAll": "Cerrar todas", "clear": "Limpiar", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "Comprobar" }, "labels": { "updateAt": "Actualizado el", @@ -44,7 +45,8 @@ "enabled": "Habilitado", "disabled": "Deshabilitado", "saving": "Saving...", - "empty": "Vacío" + "empty": "Vacío", + "loading": "Cargando..." }, "units": { "milliseconds": "Milisegundos", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Algo salió mal", + "label": "Error", + "unknown": "Error desconocido", + "details": "Detalles del error", + "stack": "Pila de errores", + "componentStack": "Pila de componentes", + "trafficUnavailable": "Datos de tráfico no disponibles", + "operationFailed": "La operación falló", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/es/tests.json b/src/locales/es/tests.json index 43bc028b0..8e17072ad 100644 --- a/src/locales/es/tests.json +++ b/src/locales/es/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "URL de prueba" + }, + "errors": { + "nameRequired": "Introduce un nombre", + "urlRequired": "Introduce una URL de prueba", + "invalidSvg": "El icono no es un SVG válido", + "uidMissing": "Falta el identificador del elemento de prueba", + "saveFailed": "No se pudo guardar el elemento de prueba" } } }, diff --git a/src/locales/fa/home.json b/src/locales/fa/home.json index ebaeea7f2..388bf4d44 100644 --- a/src/locales/fa/home.json +++ b/src/locales/fa/home.json @@ -82,7 +82,9 @@ "unknown": "Unknown" }, "errors": { - "load": "دریافت اطلاعات IP با خطا مواجه شد" + "load": "دریافت اطلاعات IP با خطا مواجه شد", + "loadWithDetails": "دریافت اطلاعات IP ناموفق بود: {{message}}", + "noServices": "هیچ سرویس تشخیص IP در دسترس نیست" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Group", "proxy": "Proxy", "noActiveNode": "No active proxy node" + }, + "status": { + "testing": "در حال آزمایش", + "untested": "آزمایش‌نشده", + "error": "خطا", + "timeout": "مهلت تمام شد", + "latencyHigh": "تأخیر زیاد", + "latencyMedium": "تأخیر متوسط", + "latencyGood": "تأخیر خوب", + "latencyExcellent": "تأخیر عالی", + "uninitialized": "مقداردهی نشده", + "noProxyNode": "نود پروکسی وجود ندارد" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "زمان نامشخص", + "chartStyles": { + "smooth": "نرم", + "linear": "خطی" + }, + "diagnostics": "نقاط: {{points}} | فشرده: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/fa/layout.json b/src/locales/fa/layout.json index be65e60b2..1969364f0 100644 --- a/src/locales/fa/layout.json +++ b/src/locales/fa/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "عملیات سرویس ناموفق بود", + "stateRefreshFailed": "به‌روزرسانی وضعیت سرویس ناموفق بود", + "restartFailed": "راه‌اندازی مجدد هسته ناموفق بود", + "revalidationFailed": "به‌روزرسانی وضعیت اجرا ناموفق بود", + "sidecarFailed": "ادامه با Sidecar ناموفق بود" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "هسته را نمی‌توان با ایمنی متوقف کرد، بنابراین راه‌اندازی مجدد لغو شد", + "quitCoreStopFailed": "هسته را نمی‌توان با ایمنی متوقف کرد، بنابراین خروج لغو شد" } } } diff --git a/src/locales/fa/profiles.json b/src/locales/fa/profiles.json index 18743f819..acf5a25c7 100644 --- a/src/locales/fa/profiles.json +++ b/src/locales/fa/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "فقط فایل‌های YAML پشتیبانی می‌شوند" + "onlyYaml": "فقط فایل‌های YAML پشتیبانی می‌شوند", + "createFailed": "ایجاد پروفایل ناموفق بود", + "deleteFailed": "حذف پروفایل ناموفق بود", + "enhanceFailed": "فعال‌سازی مجدد پروفایل‌ها ناموفق بود", + "importFailed": "وارد کردن پروفایل ناموفق بود", + "openFailed": "باز کردن پروفایل ناموفق بود", + "readFailed": "خواندن پروفایل ناموفق بود", + "reorderFailed": "تغییر ترتیب پروفایل‌ها ناموفق بود", + "switchFailed": "تعویض پروفایل ناموفق بود", + "updateFailed": "به‌روزرسانی پروفایل ناموفق بود" }, "notifications": { "importRetry": "Import failed, retrying with Clash proxy...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "داده‌های پروفایل در دسترس نیست؛ برای به‌روزرسانی اجباری کلیک کنید" } }, "title": "پروفایل‌ها" @@ -105,6 +117,7 @@ "type": "نوع", "description": "توضیحات", "subscriptionUrl": "آدرس اشتراک", + "userAgent": "عامل کاربر", "httpTimeout": "HTTP Request Timeout", "updateInterval": "فاصله زمانی به‌روزرسانی", "useSystemProxy": "استفاده از پراکسی سیستم", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "پذیرش گواهی‌نامه‌های نامعتبر (خطرناک)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "از راه دور", + "local": "محلی" + }, + "errors": { + "typeRequired": "نوع پروفایل را انتخاب کنید", + "urlRequired": "نشانی اشتراک را وارد کنید", + "uidMissing": "شناسه پروفایل موجود نیست", + "saveFailed": "ذخیره پروفایل ناموفق بود" + }, "feedback": { "notifications": { "creationRetry": "Profile creation failed, retrying with Clash proxy...", diff --git a/src/locales/fa/proxies.json b/src/locales/fa/proxies.json index 9d33c6a4a..ee5e4c2f6 100644 --- a/src/locales/fa/proxies.json +++ b/src/locales/fa/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Proxy Count", - "delayCheckReset": "بررسی تأخیر برای لغو ثابت" + "delayCheckReset": "بررسی تأخیر برای لغو ثابت", + "nodeCount": "{{count}} نود" }, "tooltips": { "locate": "موقعیت", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "آدرس بررسی تأخیر" }, + "empty": { + "noAvailableGroups": "هیچ گروه پروکسی در دسترس نیست", + "noProxies": "پروکسی‌ای وجود ندارد" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/fa/settings.json b/src/locales/fa/settings.json index 11c6dda55..50a3a79d1 100644 --- a/src/locales/fa/settings.json +++ b/src/locales/fa/settings.json @@ -5,6 +5,7 @@ "telegram": "کانال تلگرام", "github": "مخزن GitHub" }, + "actionsGroupLabel": "پیوندهای تنظیمات", "title": "تنظیمات" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "پورت باید ۱۰۰۰ یا بیشتر باشد", + "portTooHigh": "پورت باید ۶۵۵۳۵ یا کمتر باشد" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "به‌روزرسانی" }, "messages": { - "breakChangeError": "این نسخه یک به‌روزرسانی اساسی است و پشتیبانی از به‌روزرسانی درون برنامه را پشتیبانی نمی‌کند. لطفاً پس از حذف، دستی دانلود و نصب کنید." + "breakChangeError": "این نسخه یک به‌روزرسانی اساسی است و پشتیبانی از به‌روزرسانی درون برنامه را پشتیبانی نمی‌کند. لطفاً پس از حذف، دستی دانلود و نصب کنید.", + "available": "نسخه جدیدی در دسترس است" + }, + "alerts": { + "note": "یادداشت", + "tip": "نکته", + "important": "مهم", + "warning": "هشدار", + "caution": "احتیاط" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "پشتیبانی از %host، %port و %secret", "placeholderInstruction": "جایگزین کردن میزبان، پورت و رمز با %host، %port، %secret" + }, + "errors": { + "clashInfoUnavailable": "اطلاعات اتصال هسته در دسترس نیست", + "invalidServer": "نشانی سرور هسته «{{server}}» نامعتبر است", + "openFailed": "باز کردن رابط وب ناموفق بود" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "به‌روزرسانی پیکربندی هسته ناموفق بود", + "modeUpdateFailed": "تغییر حالت پروکسی ناموفق بود", + "restartFailed": "راه‌اندازی مجدد هسته ناموفق بود", + "startFailed": "راه‌اندازی هسته ناموفق بود", + "stopFailed": "توقف هسته ناموفق بود" + }, + "clashService": { + "installFailed": "نصب سرویس ناموفق بود", + "uninstallFailed": "حذف سرویس ناموفق بود", + "reinstallFailed": "نصب مجدد سرویس ناموفق بود", + "repairFailed": "تعمیر سرویس ناموفق بود", + "sidecarFailed": "ادامه با Sidecar ناموفق بود" + } + }, "notifications": { "clash": { "restartSuccess": "هسته Clash مجدداً راه‌اندازی شد", diff --git a/src/locales/fa/shared.json b/src/locales/fa/shared.json index 409c4a69b..03cba2df4 100644 --- a/src/locales/fa/shared.json +++ b/src/locales/fa/shared.json @@ -23,7 +23,8 @@ "closeAll": "بستن همه", "clear": "پاک کردن", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "بررسی" }, "labels": { "updateAt": "به‌روزرسانی در", @@ -44,7 +45,8 @@ "enabled": "توانایی فعال شد", "disabled": "غیرفعال شد", "saving": "Saving...", - "empty": "خالی خالی" + "empty": "خالی خالی", + "loading": "در حال بارگذاری..." }, "units": { "milliseconds": "میلی‌ثانیه", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "مشکلی پیش آمد", + "label": "خطا", + "unknown": "خطای نامشخص", + "details": "جزئیات خطا", + "stack": "پشته خطا", + "componentStack": "پشته مؤلفه", + "trafficUnavailable": "داده‌های ترافیک در دسترس نیست", + "operationFailed": "عملیات ناموفق بود", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/fa/tests.json b/src/locales/fa/tests.json index 9068ea338..5ed5b3774 100644 --- a/src/locales/fa/tests.json +++ b/src/locales/fa/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "آدرس آزمون" + }, + "errors": { + "nameRequired": "یک نام وارد کنید", + "urlRequired": "نشانی آزمایش را وارد کنید", + "invalidSvg": "آیکون یک SVG معتبر نیست", + "uidMissing": "شناسه مورد آزمایش موجود نیست", + "saveFailed": "ذخیره مورد آزمایش ناموفق بود" } } }, diff --git a/src/locales/id/home.json b/src/locales/id/home.json index 968717b32..aa9459475 100644 --- a/src/locales/id/home.json +++ b/src/locales/id/home.json @@ -82,7 +82,9 @@ "unknown": "Unknown" }, "errors": { - "load": "Gagal mendapatkan informasi IP" + "load": "Gagal mendapatkan informasi IP", + "loadWithDetails": "Gagal mendapatkan info IP: {{message}}", + "noServices": "Tidak ada layanan deteksi IP yang tersedia" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Group", "proxy": "Proxy", "noActiveNode": "No active proxy node" + }, + "status": { + "testing": "Menguji", + "untested": "Belum diuji", + "error": "Kesalahan", + "timeout": "Waktu habis", + "latencyHigh": "Latensi tinggi", + "latencyMedium": "Latensi sedang", + "latencyGood": "Latensi baik", + "latencyExcellent": "Latensi sangat baik", + "uninitialized": "Belum diinisialisasi", + "noProxyNode": "Tidak ada node proxy" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "Waktu tidak diketahui", + "chartStyles": { + "smooth": "Halus", + "linear": "Linier" + }, + "diagnostics": "Titik: {{points}} | Terkompresi: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/id/layout.json b/src/locales/id/layout.json index 94e38a0ce..b93f6ccaa 100644 --- a/src/locales/id/layout.json +++ b/src/locales/id/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "Operasi layanan gagal", + "stateRefreshFailed": "Gagal menyegarkan status layanan", + "restartFailed": "Gagal memulai ulang core", + "revalidationFailed": "Gagal menyegarkan status berjalan", + "sidecarFailed": "Gagal melanjutkan dengan Sidecar" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "Core tidak dapat dihentikan dengan aman, sehingga mulai ulang dibatalkan", + "quitCoreStopFailed": "Core tidak dapat dihentikan dengan aman, sehingga keluar dibatalkan" } } } diff --git a/src/locales/id/profiles.json b/src/locales/id/profiles.json index ffb4d3ae2..a040859ed 100644 --- a/src/locales/id/profiles.json +++ b/src/locales/id/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "Hanya File YAML yang Didukung" + "onlyYaml": "Hanya File YAML yang Didukung", + "createFailed": "Gagal membuat profil", + "deleteFailed": "Gagal menghapus profil", + "enhanceFailed": "Gagal mengaktifkan ulang profil", + "importFailed": "Gagal mengimpor profil", + "openFailed": "Gagal membuka profil", + "readFailed": "Gagal membaca profil", + "reorderFailed": "Gagal mengurutkan ulang profil", + "switchFailed": "Gagal beralih profil", + "updateFailed": "Gagal memperbarui profil" }, "notifications": { "importRetry": "Import failed, retrying with Clash proxy...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Data profil tidak tersedia; klik untuk menyegarkan paksa" } }, "title": "Profil" @@ -105,6 +117,7 @@ "type": "Jenis", "description": "Deskripsi", "subscriptionUrl": "URL Langganan", + "userAgent": "User Agent", "httpTimeout": "HTTP Request Timeout", "updateInterval": "Interval Pembaruan", "useSystemProxy": "Gunakan Proksi Sistem", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Terima Sertifikat Tidak Valid (Bahaya)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "Jarak jauh", + "local": "Lokal" + }, + "errors": { + "typeRequired": "Pilih jenis profil", + "urlRequired": "Masukkan URL langganan", + "uidMissing": "Pengenal profil tidak ada", + "saveFailed": "Gagal menyimpan profil" + }, "feedback": { "notifications": { "creationRetry": "Profile creation failed, retrying with Clash proxy...", diff --git a/src/locales/id/proxies.json b/src/locales/id/proxies.json index 9f052cbd5..473984537 100644 --- a/src/locales/id/proxies.json +++ b/src/locales/id/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Proxy Count", - "delayCheckReset": "Periksa keterlambatan untuk membatalkan tetap" + "delayCheckReset": "Periksa keterlambatan untuk membatalkan tetap", + "nodeCount": "{{count}} node" }, "tooltips": { "locate": "Lokasi", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "URL Periksa Keterlambatan" }, + "empty": { + "noAvailableGroups": "Tidak ada grup proxy yang tersedia", + "noProxies": "Tidak ada proxy" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/id/settings.json b/src/locales/id/settings.json index bbb7039b7..88c2217d0 100644 --- a/src/locales/id/settings.json +++ b/src/locales/id/settings.json @@ -5,6 +5,7 @@ "telegram": "Saluran Telegram", "github": "Repositori Github" }, + "actionsGroupLabel": "Tautan pengaturan", "title": "Pengaturan" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "Port harus 1000 atau lebih tinggi", + "portTooHigh": "Port harus 65535 atau lebih rendah" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Perbarui" }, "messages": { - "breakChangeError": "Versi ini adalah pembaruan besar dan tidak mendukung pembaruan dalam aplikasi. Harap hapus instalasi dan unduh serta instal versi baru secara manual" + "breakChangeError": "Versi ini adalah pembaruan besar dan tidak mendukung pembaruan dalam aplikasi. Harap hapus instalasi dan unduh serta instal versi baru secara manual", + "available": "Versi baru tersedia" + }, + "alerts": { + "note": "Catatan", + "tip": "Tips", + "important": "Penting", + "warning": "Peringatan", + "caution": "Perhatian" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "Dukung %host, %port, %secret", "placeholderInstruction": "Ganti host, port, rahasia dengan %host, %port, %secret" + }, + "errors": { + "clashInfoUnavailable": "Informasi koneksi core tidak tersedia", + "invalidServer": "Alamat server core \"{{server}}\" tidak valid", + "openFailed": "Gagal membuka Web UI" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "Gagal memperbarui konfigurasi core", + "modeUpdateFailed": "Gagal mengubah mode proxy", + "restartFailed": "Gagal memulai ulang core", + "startFailed": "Gagal memulai core", + "stopFailed": "Gagal menghentikan core" + }, + "clashService": { + "installFailed": "Gagal memasang layanan", + "uninstallFailed": "Gagal mencopot layanan", + "reinstallFailed": "Gagal memasang ulang layanan", + "repairFailed": "Gagal memperbaiki layanan", + "sidecarFailed": "Gagal melanjutkan dengan Sidecar" + } + }, "notifications": { "clash": { "restartSuccess": "Core Clash Dimulai Ulang", diff --git a/src/locales/id/shared.json b/src/locales/id/shared.json index d6763964d..11072caaa 100644 --- a/src/locales/id/shared.json +++ b/src/locales/id/shared.json @@ -23,7 +23,8 @@ "closeAll": "Tutup Semua", "clear": "Bersihkan", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "Periksa" }, "labels": { "updateAt": "Diperbarui Pada", @@ -44,7 +45,8 @@ "enabled": "Diaktifkan", "disabled": "Dinonaktifkan", "saving": "Saving...", - "empty": "Kosong" + "empty": "Kosong", + "loading": "Memuat..." }, "units": { "milliseconds": "milidetik", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Terjadi kesalahan", + "label": "Kesalahan", + "unknown": "Kesalahan tidak diketahui", + "details": "Detail kesalahan", + "stack": "Tumpukan kesalahan", + "componentStack": "Tumpukan komponen", + "trafficUnavailable": "Data lalu lintas tidak tersedia", + "operationFailed": "Operasi gagal", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/id/tests.json b/src/locales/id/tests.json index 95cfa598d..88c7e0c21 100644 --- a/src/locales/id/tests.json +++ b/src/locales/id/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "URL Tes" + }, + "errors": { + "nameRequired": "Masukkan nama", + "urlRequired": "Masukkan URL pengujian", + "invalidSvg": "Ikon bukan SVG yang valid", + "uidMissing": "Pengenal item pengujian tidak ada", + "saveFailed": "Gagal menyimpan item pengujian" } } }, diff --git a/src/locales/jp/home.json b/src/locales/jp/home.json index 4b037df68..0cf3ff964 100644 --- a/src/locales/jp/home.json +++ b/src/locales/jp/home.json @@ -82,7 +82,9 @@ "unknown": "不明" }, "errors": { - "load": "IP情報の取得に失敗しました" + "load": "IP情報の取得に失敗しました", + "loadWithDetails": "IP情報の取得に失敗しました: {{message}}", + "noServices": "利用可能なIP検出サービスがありません" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "プロキシグループ", "proxy": "ノード", "noActiveNode": "アクティブなプロキシノードがありません。" + }, + "status": { + "testing": "テスト中", + "untested": "未テスト", + "error": "エラー", + "timeout": "タイムアウト", + "latencyHigh": "遅延が高い", + "latencyMedium": "遅延が中程度", + "latencyGood": "遅延が良好", + "latencyExcellent": "遅延が非常に良好", + "uninitialized": "未初期化", + "noProxyNode": "プロキシノードがありません" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "不明な時刻", + "chartStyles": { + "smooth": "スムーズ", + "linear": "リニア" + }, + "diagnostics": "データ点: {{points}} | 圧縮後: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/jp/layout.json b/src/locales/jp/layout.json index b18b4d625..dd7d242e1 100644 --- a/src/locales/jp/layout.json +++ b/src/locales/jp/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "サービス操作に失敗しました", + "stateRefreshFailed": "サービス状態の更新に失敗しました", + "restartFailed": "コアの再起動に失敗しました", + "revalidationFailed": "実行状態の更新に失敗しました", + "sidecarFailed": "Sidecar での続行に失敗しました" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "コアを安全に停止できなかったため、再起動をキャンセルしました", + "quitCoreStopFailed": "コアを安全に停止できなかったため、終了をキャンセルしました" } } } diff --git a/src/locales/jp/profiles.json b/src/locales/jp/profiles.json index 8304e2519..f99070ff7 100644 --- a/src/locales/jp/profiles.json +++ b/src/locales/jp/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "YAMLファイルのみサポートされています。" + "onlyYaml": "YAMLファイルのみサポートされています。", + "createFailed": "プロファイルの作成に失敗しました", + "deleteFailed": "プロファイルの削除に失敗しました", + "enhanceFailed": "プロファイルの再適用に失敗しました", + "importFailed": "プロファイルのインポートに失敗しました", + "openFailed": "プロファイルを開けませんでした", + "readFailed": "プロファイルの読み込みに失敗しました", + "reorderFailed": "プロファイルの並べ替えに失敗しました", + "switchFailed": "プロファイルの切り替えに失敗しました", + "updateFailed": "プロファイルの更新に失敗しました" }, "notifications": { "importRetry": "インポートに失敗しました。Clashプロキシを使用して再試行します...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "プロファイルデータが利用できません。クリックして強制的に更新します" } }, "title": "プロファイル" @@ -105,6 +117,7 @@ "type": "タイプ", "description": "説明", "subscriptionUrl": "サブスクリプションURL", + "userAgent": "ユーザーエージェント", "httpTimeout": "HTTP Request Timeout", "updateInterval": "更新間隔", "useSystemProxy": "システムプロキシを使用して更新", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Allows Invalid Certificates (Danger)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "リモート", + "local": "ローカル" + }, + "errors": { + "typeRequired": "プロファイルの種類を選択してください", + "urlRequired": "サブスクリプションURLを入力してください", + "uidMissing": "プロファイル識別子がありません", + "saveFailed": "プロファイルの保存に失敗しました" + }, "feedback": { "notifications": { "creationRetry": "プロファイルの作成に失敗しました。Clashプロキシを使用して再試行します...", diff --git a/src/locales/jp/proxies.json b/src/locales/jp/proxies.json index ba6eb1248..1e345dd49 100644 --- a/src/locales/jp/proxies.json +++ b/src/locales/jp/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "ノード数", - "delayCheckReset": "遅延テストを実行して固定を解除する" + "delayCheckReset": "遅延テストを実行して固定を解除する", + "nodeCount": "{{count}} ノード" }, "tooltips": { "locate": "現在のノード", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "遅延テストURL" }, + "empty": { + "noAvailableGroups": "利用可能なプロキシグループがありません", + "noProxies": "プロキシがありません" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/jp/settings.json b/src/locales/jp/settings.json index f9c1e1ba0..b7b958d13 100644 --- a/src/locales/jp/settings.json +++ b/src/locales/jp/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegramチャンネル", "github": "GitHubリポジトリ" }, + "actionsGroupLabel": "設定リンク", "title": "設定" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "ポート番号は 1000 以上である必要があります", + "portTooHigh": "ポート番号は 65535 以下である必要があります" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "更新" }, "messages": { - "breakChangeError": "このバージョンは重大な更新であり、アプリケーション内での更新はサポートされていません。アンインストールしてから手動でダウンロードしてインストールしてください。" + "breakChangeError": "このバージョンは重大な更新であり、アプリケーション内での更新はサポートされていません。アンインストールしてから手動でダウンロードしてインストールしてください。", + "available": "新しいバージョンが利用可能です" + }, + "alerts": { + "note": "メモ", + "tip": "ヒント", + "important": "重要", + "warning": "警告", + "caution": "注意" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "%host, %port, %secretをサポートします。", "placeholderInstruction": "%host, %port, %secretを使用してホスト、ポート、アクセスキーを表します。" + }, + "errors": { + "clashInfoUnavailable": "コアの接続情報を取得できません", + "invalidServer": "コアサーバーアドレス「{{server}}」が無効です", + "openFailed": "Web UI を開けませんでした" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "コア設定の更新に失敗しました", + "modeUpdateFailed": "プロキシモードの変更に失敗しました", + "restartFailed": "コアの再起動に失敗しました", + "startFailed": "コアの起動に失敗しました", + "stopFailed": "コアの停止に失敗しました" + }, + "clashService": { + "installFailed": "サービスのインストールに失敗しました", + "uninstallFailed": "サービスのアンインストールに失敗しました", + "reinstallFailed": "サービスの再インストールに失敗しました", + "repairFailed": "サービスの修復に失敗しました", + "sidecarFailed": "Sidecar での続行に失敗しました" + } + }, "notifications": { "clash": { "restartSuccess": "Clashコアが再起動されました。", diff --git a/src/locales/jp/shared.json b/src/locales/jp/shared.json index 06cb62e22..e67de92d7 100644 --- a/src/locales/jp/shared.json +++ b/src/locales/jp/shared.json @@ -23,7 +23,8 @@ "closeAll": "すべて閉じる", "clear": "クリア", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "検査" }, "labels": { "updateAt": "更新日時", @@ -44,7 +45,8 @@ "enabled": "有効", "disabled": "無効", "saving": "Saving...", - "empty": "空っぽ" + "empty": "空っぽ", + "loading": "読み込み中..." }, "units": { "milliseconds": "ミリ秒", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "問題が発生しました", + "label": "エラー", + "unknown": "不明なエラー", + "details": "エラーの詳細", + "stack": "エラースタック", + "componentStack": "コンポーネントスタック", + "trafficUnavailable": "トラフィックデータを利用できません", + "operationFailed": "操作に失敗しました", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/jp/tests.json b/src/locales/jp/tests.json index 0640382d6..5df0b5302 100644 --- a/src/locales/jp/tests.json +++ b/src/locales/jp/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "テストURL" + }, + "errors": { + "nameRequired": "名前を入力してください", + "urlRequired": "テストURLを入力してください", + "invalidSvg": "アイコンが有効なSVGではありません", + "uidMissing": "テスト項目の識別子がありません", + "saveFailed": "テスト項目の保存に失敗しました" } } }, diff --git a/src/locales/ko/home.json b/src/locales/ko/home.json index cbcf926c7..b921e99ba 100644 --- a/src/locales/ko/home.json +++ b/src/locales/ko/home.json @@ -82,7 +82,9 @@ "unknown": "알 수 없음" }, "errors": { - "load": "IP 정보를 가져오지 못했습니다" + "load": "IP 정보를 가져오지 못했습니다", + "loadWithDetails": "IP 정보를 가져오지 못했습니다: {{message}}", + "noServices": "사용 가능한 IP 감지 서비스가 없습니다" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "그룹", "proxy": "프록시", "noActiveNode": "활성 프록시 노드 없음" + }, + "status": { + "testing": "테스트 중", + "untested": "테스트 안 함", + "error": "오류", + "timeout": "시간 초과", + "latencyHigh": "지연 높음", + "latencyMedium": "지연 보통", + "latencyGood": "지연 양호", + "latencyExcellent": "지연 매우 우수", + "uninitialized": "초기화되지 않음", + "noProxyNode": "프록시 노드 없음" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}}분" - } + }, + "unknownTime": "알 수 없는 시간", + "chartStyles": { + "smooth": "부드럽게", + "linear": "선형" + }, + "diagnostics": "데이터 점: {{points}} | 압축됨: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/ko/layout.json b/src/locales/ko/layout.json index 2caa7d921..169c73373 100644 --- a/src/locales/ko/layout.json +++ b/src/locales/ko/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "서비스 작업에 실패했습니다", + "stateRefreshFailed": "서비스 상태를 새로 고치지 못했습니다", + "restartFailed": "코어를 재시작하지 못했습니다", + "revalidationFailed": "실행 상태를 새로 고치지 못했습니다", + "sidecarFailed": "Sidecar로 계속하지 못했습니다" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "코어를 안전하게 중지할 수 없어 재시작이 취소되었습니다", + "quitCoreStopFailed": "코어를 안전하게 중지할 수 없어 종료가 취소되었습니다" } } } diff --git a/src/locales/ko/profiles.json b/src/locales/ko/profiles.json index ded11350b..52e1f92bd 100644 --- a/src/locales/ko/profiles.json +++ b/src/locales/ko/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "잘못된 프로필 URL입니다. http:// 또는 https://로 시작하는 URL을 입력하세요", - "onlyYaml": "YAML 파일만 지원됩니다" + "onlyYaml": "YAML 파일만 지원됩니다", + "createFailed": "프로필을 만들지 못했습니다", + "deleteFailed": "프로필을 삭제하지 못했습니다", + "enhanceFailed": "프로필을 다시 활성화하지 못했습니다", + "importFailed": "프로필을 가져오지 못했습니다", + "openFailed": "프로필을 열지 못했습니다", + "readFailed": "프로필을 읽지 못했습니다", + "reorderFailed": "프로필 순서를 변경하지 못했습니다", + "switchFailed": "프로필을 전환하지 못했습니다", + "updateFailed": "프로필을 업데이트하지 못했습니다" }, "notifications": { "importRetry": "가져오기에 실패했습니다. Clash 프록시로 다시 시도 중...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "강제 새로고침 완료", "emergencyRefreshFailed": "긴급 새로고침 실패: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "프로필 데이터를 사용할 수 없습니다. 클릭하여 강제로 새로 고칩니다" } }, "title": "프로필" @@ -105,6 +117,7 @@ "type": "유형", "description": "설명", "subscriptionUrl": "구독 URL", + "userAgent": "사용자 에이전트", "httpTimeout": "HTTP 요청 시간 초과", "updateInterval": "업데이트 간격", "useSystemProxy": "시스템 프록시 사용", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "잘못된 인증서 허용(위험)", "allowAutoUpdate": "자동 업데이트 허용" }, + "types": { + "remote": "원격", + "local": "로컬" + }, + "errors": { + "typeRequired": "프로필 유형을 선택하세요", + "urlRequired": "구독 URL을 입력하세요", + "uidMissing": "프로필 식별자가 없습니다", + "saveFailed": "프로필을 저장하지 못했습니다" + }, "feedback": { "notifications": { "creationRetry": "프로필 생성 실패, Clash 프록시로 다시 시도 중...", diff --git a/src/locales/ko/proxies.json b/src/locales/ko/proxies.json index 14840e97e..43b5b18c2 100644 --- a/src/locales/ko/proxies.json +++ b/src/locales/ko/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "프록시 개수", - "delayCheckReset": "고정 취소를 위한 지연 확인" + "delayCheckReset": "고정 취소를 위한 지연 확인", + "nodeCount": "노드 {{count}}개" }, "tooltips": { "locate": "위치 찾기", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "지연 확인 URL" }, + "empty": { + "noAvailableGroups": "사용 가능한 프록시 그룹이 없습니다", + "noProxies": "프록시 없음" + }, "chain": { "header": "체인 프록시 구성", "warning": "체인 프록시는 네트워크 속도를 크게 저하시킬 수 있습니다. 명확한 업무상 필요가 없거나 이 구성을 이해하지 못한다면 비활성화 상태로 두세요.", diff --git a/src/locales/ko/settings.json b/src/locales/ko/settings.json index 3021b5cd7..947ceed4f 100644 --- a/src/locales/ko/settings.json +++ b/src/locales/ko/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram 채널", "github": "GitHub 저장소" }, + "actionsGroupLabel": "설정 링크", "title": "설정" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "포트 설정이 저장되었습니다", - "saveFailed": "포트 설정 저장에 실패했습니다" + "saveFailed": "포트 설정 저장에 실패했습니다", + "portTooLow": "포트는 1000 이상이어야 합니다", + "portTooHigh": "포트는 65535 이하여야 합니다" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "업데이트" }, "messages": { - "breakChangeError": "이 버전은 메이저 업데이트로 앱 내 업데이트를 지원하지 않습니다. 프로그램을 제거한 뒤 새 버전을 수동으로 설치하세요" + "breakChangeError": "이 버전은 메이저 업데이트로 앱 내 업데이트를 지원하지 않습니다. 프로그램을 제거한 뒤 새 버전을 수동으로 설치하세요", + "available": "새 버전을 사용할 수 있습니다" + }, + "alerts": { + "note": "참고", + "tip": "팁", + "important": "중요", + "warning": "경고", + "caution": "주의" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "지원되는 자리표시자: %host, %port, %secret", "placeholderInstruction": "host, port, secret을 %host, %port, %secret로 바꿔 입력하세요" + }, + "errors": { + "clashInfoUnavailable": "코어 연결 정보를 사용할 수 없습니다", + "invalidServer": "코어 서버 주소 \"{{server}}\"이(가) 잘못되었습니다", + "openFailed": "Web UI를 열지 못했습니다" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "코어 구성을 업데이트하지 못했습니다", + "modeUpdateFailed": "프록시 모드를 변경하지 못했습니다", + "restartFailed": "코어를 재시작하지 못했습니다", + "startFailed": "코어를 시작하지 못했습니다", + "stopFailed": "코어를 중지하지 못했습니다" + }, + "clashService": { + "installFailed": "서비스를 설치하지 못했습니다", + "uninstallFailed": "서비스를 제거하지 못했습니다", + "reinstallFailed": "서비스를 다시 설치하지 못했습니다", + "repairFailed": "서비스를 복구하지 못했습니다", + "sidecarFailed": "Sidecar로 계속하지 못했습니다" + } + }, "notifications": { "clash": { "restartSuccess": "Clash 코어가 재시작되었습니다", diff --git a/src/locales/ko/shared.json b/src/locales/ko/shared.json index b386c234c..6f08eb747 100644 --- a/src/locales/ko/shared.json +++ b/src/locales/ko/shared.json @@ -23,7 +23,8 @@ "closeAll": "모두 닫기", "clear": "지우기", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "검사" }, "labels": { "updateAt": "업데이트 시간", @@ -44,7 +45,8 @@ "enabled": "사용", "disabled": "비활성화", "saving": "저장 중...", - "empty": "비어있음" + "empty": "비어있음", + "loading": "로드 중..." }, "units": { "milliseconds": "밀리초", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "문제가 발생했습니다", + "label": "오류", + "unknown": "알 수 없는 오류", + "details": "오류 세부 정보", + "stack": "오류 스택", + "componentStack": "컴포넌트 스택", + "trafficUnavailable": "트래픽 데이터를 사용할 수 없습니다", + "operationFailed": "작업에 실패했습니다", "trafficStats": "트래픽 통계 오류", "trafficStatsDescription": "트래픽 통계 구성 요소에서 오류가 발생하여 충돌을 방지하기 위해 비활성화되었습니다." }, diff --git a/src/locales/ko/tests.json b/src/locales/ko/tests.json index b4d5c8832..9e92684c6 100644 --- a/src/locales/ko/tests.json +++ b/src/locales/ko/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "테스트 URL" + }, + "errors": { + "nameRequired": "이름을 입력하세요", + "urlRequired": "테스트 URL을 입력하세요", + "invalidSvg": "아이콘이 유효한 SVG가 아닙니다", + "uidMissing": "테스트 항목 식별자가 없습니다", + "saveFailed": "테스트 항목을 저장하지 못했습니다" } } }, diff --git a/src/locales/ru/home.json b/src/locales/ru/home.json index a904e15e3..a77e603e8 100644 --- a/src/locales/ru/home.json +++ b/src/locales/ru/home.json @@ -82,7 +82,9 @@ "unknown": "Неизвестно" }, "errors": { - "load": "Не удалось получить информацию об IP" + "load": "Не удалось получить информацию об IP", + "loadWithDetails": "Не удалось получить сведения об IP: {{message}}", + "noServices": "Нет доступных сервисов определения IP" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Группа", "proxy": "Прокси", "noActiveNode": "Нет активного прокси" + }, + "status": { + "testing": "Проверка", + "untested": "Не проверено", + "error": "Ошибка", + "timeout": "Тайм-аут", + "latencyHigh": "Высокая задержка", + "latencyMedium": "Средняя задержка", + "latencyGood": "Хорошая задержка", + "latencyExcellent": "Отличная задержка", + "uninitialized": "Не инициализировано", + "noProxyNode": "Нет прокси-узла" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} мин" - } + }, + "unknownTime": "Неизвестное время", + "chartStyles": { + "smooth": "Плавный", + "linear": "Линейный" + }, + "diagnostics": "Точки: {{points}} | Сжато: {{compressed}} | Кадры/с: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/ru/layout.json b/src/locales/ru/layout.json index aa9f92603..95ddf5100 100644 --- a/src/locales/ru/layout.json +++ b/src/locales/ru/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "Не удалось выполнить операцию со службой", + "stateRefreshFailed": "Не удалось обновить состояние службы", + "restartFailed": "Не удалось перезапустить ядро", + "revalidationFailed": "Не удалось обновить состояние выполнения", + "sidecarFailed": "Не удалось продолжить в режиме Sidecar" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "Не удалось безопасно остановить ядро, поэтому перезапуск отменён", + "quitCoreStopFailed": "Не удалось безопасно остановить ядро, поэтому выход отменён" } } } diff --git a/src/locales/ru/profiles.json b/src/locales/ru/profiles.json index 71dde696d..eb5be3f92 100644 --- a/src/locales/ru/profiles.json +++ b/src/locales/ru/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Недопустимый URL профиля. Укажите адрес, начинающийся с http:// или https://", - "onlyYaml": "Поддерживаются только файлы YAML" + "onlyYaml": "Поддерживаются только файлы YAML", + "createFailed": "Не удалось создать профиль", + "deleteFailed": "Не удалось удалить профиль", + "enhanceFailed": "Не удалось повторно активировать профили", + "importFailed": "Не удалось импортировать профиль", + "openFailed": "Не удалось открыть профиль", + "readFailed": "Не удалось прочитать профиль", + "reorderFailed": "Не удалось изменить порядок профилей", + "switchFailed": "Не удалось переключить профиль", + "updateFailed": "Не удалось обновить профиль" }, "notifications": { "importRetry": "Не удалось импортировать, повторная попытка через Clash proxy...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Принудительное обновление завершено", "emergencyRefreshFailed": "Экстренное обновление не удалось: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Данные профиля недоступны; нажмите для принудительного обновления" } }, "title": "Профили" @@ -105,6 +117,7 @@ "type": "Тип", "description": "Описание", "subscriptionUrl": "URL подписки", + "userAgent": "User Agent", "httpTimeout": "Тайм-аут HTTP-запроса", "updateInterval": "Интервал обновления", "useSystemProxy": "Использовать системный прокси для обновления", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Принимать недействительные сертификаты (ОПАСНО)", "allowAutoUpdate": "Разрешить автообновление" }, + "types": { + "remote": "Удалённый", + "local": "Локальный" + }, + "errors": { + "typeRequired": "Выберите тип профиля", + "urlRequired": "Введите URL подписки", + "uidMissing": "Отсутствует идентификатор профиля", + "saveFailed": "Не удалось сохранить профиль" + }, "feedback": { "notifications": { "creationRetry": "Не удалось создать профиль, повторная попытка через Clash proxy...", diff --git a/src/locales/ru/proxies.json b/src/locales/ru/proxies.json index 24159aeb4..a9e5a1538 100644 --- a/src/locales/ru/proxies.json +++ b/src/locales/ru/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Количество прокси", - "delayCheckReset": "Сброс проверки задержки" + "delayCheckReset": "Сброс проверки задержки", + "nodeCount": "Узлов: {{count}}" }, "tooltips": { "locate": "Местоположение", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "URL для проверки задержки" }, + "empty": { + "noAvailableGroups": "Нет доступных групп прокси", + "noProxies": "Нет прокси" + }, "chain": { "header": "Цепочка прокси", "warning": "Цепочка прокси может значительно снизить скорость сети. Если у вас нет явной рабочей необходимости или вы не понимаете эту настройку, оставьте ее отключенной.", diff --git a/src/locales/ru/settings.json b/src/locales/ru/settings.json index ea9d340d5..05159a280 100644 --- a/src/locales/ru/settings.json +++ b/src/locales/ru/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram-канал", "github": "GitHub репозиторий" }, + "actionsGroupLabel": "Ссылки настроек", "title": "Настройки" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Порт {{port}} уже используется", "saved": "Настройки портов сохранены", - "saveFailed": "Не удалось сохранить настройки портов" + "saveFailed": "Не удалось сохранить настройки портов", + "portTooLow": "Порт должен быть не меньше 1000", + "portTooHigh": "Порт должен быть не больше 65535" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Обновить" }, "messages": { - "breakChangeError": "Это крупное обновление, которое не поддерживает обновление внутри приложения. Пожалуйста, удалите текущую версию и загрузите установочный файл вручную." + "breakChangeError": "Это крупное обновление, которое не поддерживает обновление внутри приложения. Пожалуйста, удалите текущую версию и загрузите установочный файл вручную.", + "available": "Доступна новая версия" + }, + "alerts": { + "note": "Примечание", + "tip": "Совет", + "important": "Важно", + "warning": "Предупреждение", + "caution": "Осторожно" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "Поддерживаются %host, %port, %secret", "placeholderInstruction": "Замените хост, порт и секрет на %host, %port, %secret" + }, + "errors": { + "clashInfoUnavailable": "Сведения о подключении к ядру недоступны", + "invalidServer": "Адрес сервера ядра «{{server}}» недействителен", + "openFailed": "Не удалось открыть веб-интерфейс" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "Не удалось обновить конфигурацию ядра", + "modeUpdateFailed": "Не удалось изменить режим прокси", + "restartFailed": "Не удалось перезапустить ядро", + "startFailed": "Не удалось запустить ядро", + "stopFailed": "Не удалось остановить ядро" + }, + "clashService": { + "installFailed": "Не удалось установить службу", + "uninstallFailed": "Не удалось удалить службу", + "reinstallFailed": "Не удалось переустановить службу", + "repairFailed": "Не удалось восстановить службу", + "sidecarFailed": "Не удалось продолжить в режиме Sidecar" + } + }, "notifications": { "clash": { "restartSuccess": "Ядро перезапущено", diff --git a/src/locales/ru/shared.json b/src/locales/ru/shared.json index 1b072a496..a330a7ff3 100644 --- a/src/locales/ru/shared.json +++ b/src/locales/ru/shared.json @@ -23,7 +23,8 @@ "closeAll": "Закрыть всё", "clear": "Очистить", "previous": "Назад", - "next": "Далее" + "next": "Далее", + "check": "Проверить" }, "labels": { "updateAt": "Обновлено в", @@ -44,7 +45,8 @@ "enabled": "Включено", "disabled": "Отключено", "saving": "Сохранение...", - "empty": "Пусто" + "empty": "Пусто", + "loading": "Загрузка..." }, "units": { "milliseconds": "миллисекунды", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Что-то пошло не так", + "label": "Ошибка", + "unknown": "Неизвестная ошибка", + "details": "Сведения об ошибке", + "stack": "Стек ошибки", + "componentStack": "Стек компонентов", + "trafficUnavailable": "Данные трафика недоступны", + "operationFailed": "Не удалось выполнить операцию", "trafficStats": "Ошибка статистики трафика", "trafficStatsDescription": "Компонент статистики трафика столкнулся с ошибкой и был отключён во избежание сбоев." }, diff --git a/src/locales/ru/tests.json b/src/locales/ru/tests.json index df0b11981..d8fbb5f37 100644 --- a/src/locales/ru/tests.json +++ b/src/locales/ru/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "URL для проверки" + }, + "errors": { + "nameRequired": "Введите название", + "urlRequired": "Введите URL для теста", + "invalidSvg": "Значок не является допустимым SVG", + "uidMissing": "Отсутствует идентификатор тестового элемента", + "saveFailed": "Не удалось сохранить тестовый элемент" } } }, diff --git a/src/locales/tr/home.json b/src/locales/tr/home.json index 1237e3e1f..70785c065 100644 --- a/src/locales/tr/home.json +++ b/src/locales/tr/home.json @@ -82,7 +82,9 @@ "unknown": "Bilinmiyor" }, "errors": { - "load": "IP bilgisi alınamadı" + "load": "IP bilgisi alınamadı", + "loadWithDetails": "IP bilgisi alınamadı: {{message}}", + "noServices": "Kullanılabilir IP algılama hizmeti yok" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Grup", "proxy": "Vekil", "noActiveNode": "Aktif vekil düğümü yok" + }, + "status": { + "testing": "Test ediliyor", + "untested": "Test edilmedi", + "error": "Hata", + "timeout": "Zaman aşımı", + "latencyHigh": "Yüksek gecikme", + "latencyMedium": "Orta gecikme", + "latencyGood": "İyi gecikme", + "latencyExcellent": "Mükemmel gecikme", + "uninitialized": "Başlatılmadı", + "noProxyNode": "Proxy düğümü yok" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "Bilinmeyen zaman", + "chartStyles": { + "smooth": "Yumuşak", + "linear": "Doğrusal" + }, + "diagnostics": "Nokta: {{points}} | Sıkıştırılmış: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/tr/layout.json b/src/locales/tr/layout.json index 048e3149c..7a9fc8719 100644 --- a/src/locales/tr/layout.json +++ b/src/locales/tr/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "Hizmet işlemi başarısız oldu", + "stateRefreshFailed": "Hizmet durumu yenilenemedi", + "restartFailed": "Çekirdek yeniden başlatılamadı", + "revalidationFailed": "Çalışma durumu yenilenemedi", + "sidecarFailed": "Sidecar ile devam edilemedi" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "Çekirdek güvenli biçimde durdurulamadı, bu nedenle yeniden başlatma iptal edildi", + "quitCoreStopFailed": "Çekirdek güvenli biçimde durdurulamadı, bu nedenle çıkış iptal edildi" } } } diff --git a/src/locales/tr/profiles.json b/src/locales/tr/profiles.json index 3ad749750..5dba41d43 100644 --- a/src/locales/tr/profiles.json +++ b/src/locales/tr/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "Yalnızca YAML Dosyaları Desteklenir" + "onlyYaml": "Yalnızca YAML Dosyaları Desteklenir", + "createFailed": "Profil oluşturulamadı", + "deleteFailed": "Profil silinemedi", + "enhanceFailed": "Profiller yeniden etkinleştirilemedi", + "importFailed": "Profil içe aktarılamadı", + "openFailed": "Profil açılamadı", + "readFailed": "Profil okunamadı", + "reorderFailed": "Profiller yeniden sıralanamadı", + "switchFailed": "Profil değiştirilemedi", + "updateFailed": "Profil güncellenemedi" }, "notifications": { "importRetry": "İçe aktarma başarısız oldu, Clash vekil ile yeniden deneniyor...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Profil verileri kullanılamıyor; zorla yenilemek için tıklayın" } }, "title": "Profiller" @@ -105,6 +117,7 @@ "type": "Tip", "description": "Açıklamalar", "subscriptionUrl": "Abonelik URL'si", + "userAgent": "Kullanıcı Aracısı", "httpTimeout": "HTTP Request Timeout", "updateInterval": "Güncelleme Aralığı", "useSystemProxy": "Sistem Vekil'ini Kullan", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Geçersiz Sertifikalara İzin Ver (Tehlikeli)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "Uzak", + "local": "Yerel" + }, + "errors": { + "typeRequired": "Bir profil türü seçin", + "urlRequired": "Bir abonelik URL’si girin", + "uidMissing": "Profil tanımlayıcısı eksik", + "saveFailed": "Profil kaydedilemedi" + }, "feedback": { "notifications": { "creationRetry": "Profil oluşturma başarısız oldu, Clash vekil ile yeniden deneniyor...", diff --git a/src/locales/tr/proxies.json b/src/locales/tr/proxies.json index 865c93f83..2849f21b6 100644 --- a/src/locales/tr/proxies.json +++ b/src/locales/tr/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Vekil Sayısı", - "delayCheckReset": "Sabit iptali için gecikme kontrolü" + "delayCheckReset": "Sabit iptali için gecikme kontrolü", + "nodeCount": "{{count}} düğüm" }, "tooltips": { "locate": "konum", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "Gecikme kontrol URL'si" }, + "empty": { + "noAvailableGroups": "Kullanılabilir proxy grubu yok", + "noProxies": "Proxy yok" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/tr/settings.json b/src/locales/tr/settings.json index bd1e52216..a73e81693 100644 --- a/src/locales/tr/settings.json +++ b/src/locales/tr/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram Kanalı", "github": "Github Repo" }, + "actionsGroupLabel": "Ayar bağlantıları", "title": "Ayarlar" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "Bağlantı noktası 1000 veya daha yüksek olmalıdır", + "portTooHigh": "Bağlantı noktası 65535 veya daha düşük olmalıdır" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Güncelle" }, "messages": { - "breakChangeError": "Bu sürüm büyük bir güncellemedir ve uygulama içi güncellemeleri desteklemez. Lütfen kaldırın ve yeni sürümü manuel olarak indirip kurun" + "breakChangeError": "Bu sürüm büyük bir güncellemedir ve uygulama içi güncellemeleri desteklemez. Lütfen kaldırın ve yeni sürümü manuel olarak indirip kurun", + "available": "Yeni bir sürüm mevcut" + }, + "alerts": { + "note": "Not", + "tip": "İpucu", + "important": "Önemli", + "warning": "Uyarı", + "caution": "Dikkat" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "%host, %port, %secret destekler", "placeholderInstruction": "Ana bilgisayar, port, sırrı %host, %port, %secret ile değiştirin" + }, + "errors": { + "clashInfoUnavailable": "Çekirdek bağlantı bilgisi kullanılamıyor", + "invalidServer": "Çekirdek sunucu adresi \"{{server}}\" geçersiz", + "openFailed": "Web UI açılamadı" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "Çekirdek yapılandırması güncellenemedi", + "modeUpdateFailed": "Proxy modu değiştirilemedi", + "restartFailed": "Çekirdek yeniden başlatılamadı", + "startFailed": "Çekirdek başlatılamadı", + "stopFailed": "Çekirdek durdurulamadı" + }, + "clashService": { + "installFailed": "Hizmet kurulamadı", + "uninstallFailed": "Hizmet kaldırılamadı", + "reinstallFailed": "Hizmet yeniden kurulamadı", + "repairFailed": "Hizmet onarılamadı", + "sidecarFailed": "Sidecar ile devam edilemedi" + } + }, "notifications": { "clash": { "restartSuccess": "Clash Çekirdeği Yeniden Başlatıldı", diff --git a/src/locales/tr/shared.json b/src/locales/tr/shared.json index 225d24e3c..d88ab771c 100644 --- a/src/locales/tr/shared.json +++ b/src/locales/tr/shared.json @@ -23,7 +23,8 @@ "closeAll": "Tümünü Kapat", "clear": "Temizle", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "Denetle" }, "labels": { "updateAt": "Güncelleme Zamanı", @@ -44,7 +45,8 @@ "enabled": "Etkin", "disabled": "Devre Dışı", "saving": "Saving...", - "empty": "Boş" + "empty": "Boş", + "loading": "Yükleniyor..." }, "units": { "milliseconds": "ms", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Bir şeyler ters gitti", + "label": "Hata", + "unknown": "Bilinmeyen hata", + "details": "Hata ayrıntıları", + "stack": "Hata yığını", + "componentStack": "Bileşen yığını", + "trafficUnavailable": "Trafik verileri kullanılamıyor", + "operationFailed": "İşlem başarısız oldu", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/tr/tests.json b/src/locales/tr/tests.json index 41d0e3032..27a7f60ec 100644 --- a/src/locales/tr/tests.json +++ b/src/locales/tr/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "Test URL'si" + }, + "errors": { + "nameRequired": "Bir ad girin", + "urlRequired": "Bir test URL’si girin", + "invalidSvg": "Simge geçerli bir SVG değil", + "uidMissing": "Test öğesi tanımlayıcısı eksik", + "saveFailed": "Test öğesi kaydedilemedi" } } }, diff --git a/src/locales/tt/home.json b/src/locales/tt/home.json index e68b27612..6939efc57 100644 --- a/src/locales/tt/home.json +++ b/src/locales/tt/home.json @@ -82,7 +82,9 @@ "unknown": "Unknown" }, "errors": { - "load": "IP мәгълүматын алу мөмкин булмады" + "load": "IP мәгълүматын алу мөмкин булмады", + "loadWithDetails": "IP мәгълүматын алып булмады: {{message}}", + "noServices": "IP ачыклау хезмәтләре юк" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "Group", "proxy": "Proxy", "noActiveNode": "No active proxy node" + }, + "status": { + "testing": "Тикшерелә", + "untested": "Тикшерелмәгән", + "error": "Хата", + "timeout": "Вакыт узды", + "latencyHigh": "Зур тоткарлык", + "latencyMedium": "Урта тоткарлык", + "latencyGood": "Яхшы тоткарлык", + "latencyExcellent": "Бик яхшы тоткарлык", + "uninitialized": "Әзерләнмәгән", + "noProxyNode": "Прокси төене юк" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} Minutes" - } + }, + "unknownTime": "Билгесез вакыт", + "chartStyles": { + "smooth": "Шома", + "linear": "Сызыклы" + }, + "diagnostics": "Нокталар: {{points}} | Кысылган: {{compressed}} | FPS: {{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/tt/layout.json b/src/locales/tt/layout.json index 3a879ce55..fe962a3a9 100644 --- a/src/locales/tt/layout.json +++ b/src/locales/tt/layout.json @@ -28,7 +28,20 @@ "reinstall": "Reinstall service", "repair": "Repair service", "continueSidecar": "Continue with Sidecar", - "success": "The Clash Verge service was updated successfully" + "success": "The Clash Verge service was updated successfully", + "errors": { + "actionFailed": "Хезмәт операциясе башкарылмады", + "stateRefreshFailed": "Хезмәт халәтен яңартып булмады", + "restartFailed": "Ядрону яңадан башлап булмады", + "revalidationFailed": "Эшләү халәтен яңартып булмады", + "sidecarFailed": "Sidecar белән дәвам итеп булмады" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "Ядрону иминлек белән туктатып булмады, шуңа күрә яңадан башлау кире кагылды", + "quitCoreStopFailed": "Ядрону иминлек белән туктатып булмады, шуңа күрә чыгу кире кагылды" } } } diff --git a/src/locales/tt/profiles.json b/src/locales/tt/profiles.json index aa92f1aa4..d1356cd8a 100644 --- a/src/locales/tt/profiles.json +++ b/src/locales/tt/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "Invalid profile URL. Please enter a URL starting with http:// or https://", - "onlyYaml": "Фәкать YAML-файллар гына хуплана" + "onlyYaml": "Фәкать YAML-файллар гына хуплана", + "createFailed": "Профиль төзеп булмады", + "deleteFailed": "Профильне бетереп булмады", + "enhanceFailed": "Профильләрне яңадан эшкә җибәреп булмады", + "importFailed": "Профильне кертеп булмады", + "openFailed": "Профильне ачып булмады", + "readFailed": "Профильне укып булмады", + "reorderFailed": "Профильләр тәртибен үзгәртеп булмады", + "switchFailed": "Профильне алыштырып булмады", + "updateFailed": "Профильне яңартып булмады" }, "notifications": { "importRetry": "Import failed, retrying with Clash proxy...", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "Профиль мәгълүматы юк; көчләп яңарту өчен басыгыз" } }, "title": "Профильләр" @@ -105,6 +117,7 @@ "type": "Төр", "description": "Тасвирламалар", "subscriptionUrl": "Подписка URL-ы", + "userAgent": "Кулланучы агенты", "httpTimeout": "HTTP Request Timeout", "updateInterval": "Яңарту интервалы", "useSystemProxy": "Системалы проксины кулланып яңарту", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "Дөрес булмаган сертификатларны кабул итү (Куркыныч)", "allowAutoUpdate": "Allow Auto Update" }, + "types": { + "remote": "Ерактагы", + "local": "Җирле" + }, + "errors": { + "typeRequired": "Профиль төрен сайлагыз", + "urlRequired": "Язылу сылтамасын кертегез", + "uidMissing": "Профиль билгесе юк", + "saveFailed": "Профильне саклап булмады" + }, "feedback": { "notifications": { "creationRetry": "Profile creation failed, retrying with Clash proxy...", diff --git a/src/locales/tt/proxies.json b/src/locales/tt/proxies.json index bd04efca1..e20331ffd 100644 --- a/src/locales/tt/proxies.json +++ b/src/locales/tt/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "Proxy Count", - "delayCheckReset": "Беркетелгәнне гамәлдән чыгару өчен задержканы тикшерү" + "delayCheckReset": "Беркетелгәнне гамәлдән чыгару өчен задержканы тикшерү", + "nodeCount": "{{count}} төен" }, "tooltips": { "locate": "Урын", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "Задержканы тикшерү URL-ы" }, + "empty": { + "noAvailableGroups": "Кулланырлык прокси төркемнәре юк", + "noProxies": "Проксилар юк" + }, "chain": { "header": "Chain Proxy Config", "warning": "Chain proxy will significantly reduce network speed. If you do not have a clear business need, or do not understand this configuration, keep it disabled.", diff --git a/src/locales/tt/settings.json b/src/locales/tt/settings.json index d6193d4b0..916d1eba1 100644 --- a/src/locales/tt/settings.json +++ b/src/locales/tt/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram каналы", "github": "GitHub репозиториясе" }, + "actionsGroupLabel": "Көйләү сылтамалары", "title": "Көйләүләр" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "Port settings saved", - "saveFailed": "Failed to save port settings" + "saveFailed": "Failed to save port settings", + "portTooLow": "Порт 1000 дән ким булмаска тиеш", + "portTooHigh": "Порт 65535 тән артмаска тиеш" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "Яңарту" }, "messages": { - "breakChangeError": "Бу зур яңарту, ул кушымта эчендә яңартылмый. Борып алып ташлап, яңадан урнаштыру сорала." + "breakChangeError": "Бу зур яңарту, ул кушымта эчендә яңартылмый. Борып алып ташлап, яңадан урнаштыру сорала.", + "available": "Яңа версия бар" + }, + "alerts": { + "note": "Искәрмә", + "tip": "Киңәш", + "important": "Мөһим", + "warning": "Кисәтү", + "caution": "Игътибар" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "%host, %port, %secret макросларын хуплау", "placeholderInstruction": "Хост, порт, серсүзне %host, %port, %secret белән алмаштырыгыз" + }, + "errors": { + "clashInfoUnavailable": "Ядро тоташу мәгълүматы юк", + "invalidServer": "Ядро сервер адресы «{{server}}» дөрес түгел", + "openFailed": "Web UI ачып булмады" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "Ядро көйләүләрен яңартып булмады", + "modeUpdateFailed": "Прокси режимын үзгәртеп булмады", + "restartFailed": "Ядрону яңадан башлап булмады", + "startFailed": "Ядрону башлап булмады", + "stopFailed": "Ядрону туктатып булмады" + }, + "clashService": { + "installFailed": "Хезмәтне урнаштырып булмады", + "uninstallFailed": "Хезмәтне бетереп булмады", + "reinstallFailed": "Хезмәтне яңадан урнаштырып булмады", + "repairFailed": "Хезмәтне төзәтеп булмады", + "sidecarFailed": "Sidecar белән дәвам итеп булмады" + } + }, "notifications": { "clash": { "restartSuccess": "Clash ядросы яңадан башланды", diff --git a/src/locales/tt/shared.json b/src/locales/tt/shared.json index 38f9939fb..a10ad6b75 100644 --- a/src/locales/tt/shared.json +++ b/src/locales/tt/shared.json @@ -23,7 +23,8 @@ "closeAll": "Барысын да ябу", "clear": "Чистарту", "previous": "Previous", - "next": "Next" + "next": "Next", + "check": "Тикшерү" }, "labels": { "updateAt": "Яңартылган вакыт", @@ -44,7 +45,8 @@ "enabled": "Кушылган", "disabled": "Сүнгән", "saving": "Saving...", - "empty": "Буш" + "empty": "Буш", + "loading": "Йөкләнә..." }, "units": { "milliseconds": "Миллисекундлар", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "Нәрсәдер дөрес булмады", + "label": "Хата", + "unknown": "Билгесез хата", + "details": "Хата тәфсилатлары", + "stack": "Хата стегы", + "componentStack": "Компонент стегы", + "trafficUnavailable": "Трафик мәгълүматы юк", + "operationFailed": "Операция башкарылмады", "trafficStats": "Traffic Statistics Error", "trafficStatsDescription": "The traffic statistics component encountered an error and has been disabled to prevent crashes." }, diff --git a/src/locales/tt/tests.json b/src/locales/tt/tests.json index efc03a9ad..445776f93 100644 --- a/src/locales/tt/tests.json +++ b/src/locales/tt/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "Тест URL-ы" + }, + "errors": { + "nameRequired": "Исем кертегез", + "urlRequired": "Тест сылтамасын кертегез", + "invalidSvg": "Билгә дөрес SVG түгел", + "uidMissing": "Тест элементы билгесе юк", + "saveFailed": "Тест элементын саклап булмады" } } }, diff --git a/src/locales/zh/home.json b/src/locales/zh/home.json index 1a74e45ad..d9421744e 100644 --- a/src/locales/zh/home.json +++ b/src/locales/zh/home.json @@ -82,7 +82,9 @@ "unknown": "未知" }, "errors": { - "load": "获取 IP 信息失败" + "load": "获取 IP 信息失败", + "loadWithDetails": "获取 IP 信息失败:{{message}}", + "noServices": "暂无可用的 IP 检测服务" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "代理组", "proxy": "节点", "noActiveNode": "暂无激活的代理节点" + }, + "status": { + "testing": "测试中", + "untested": "未测试", + "error": "错误", + "timeout": "超时", + "latencyHigh": "延迟较高", + "latencyMedium": "延迟中等", + "latencyGood": "延迟良好", + "latencyExcellent": "延迟极佳", + "uninitialized": "未初始化", + "noProxyNode": "无代理节点" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} 分钟" - } + }, + "unknownTime": "未知时间", + "chartStyles": { + "smooth": "平滑", + "linear": "线性" + }, + "diagnostics": "数据点:{{points}} | 压缩后:{{compressed}} | 帧率:{{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/zh/layout.json b/src/locales/zh/layout.json index 12984f766..177ae7eb3 100644 --- a/src/locales/zh/layout.json +++ b/src/locales/zh/layout.json @@ -28,7 +28,20 @@ "reinstall": "重新安装服务", "repair": "修复服务", "continueSidecar": "继续使用 Sidecar", - "success": "Clash Verge 系统服务已更新" + "success": "Clash Verge 系统服务已更新", + "errors": { + "actionFailed": "服务操作失败", + "stateRefreshFailed": "刷新服务状态失败", + "restartFailed": "重启内核失败", + "revalidationFailed": "刷新运行状态失败", + "sidecarFailed": "继续使用 Sidecar 失败" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "无法安全停止内核,已取消重启", + "quitCoreStopFailed": "无法安全停止内核,已取消退出" } } } diff --git a/src/locales/zh/profiles.json b/src/locales/zh/profiles.json index 0bd22903f..3c920e809 100644 --- a/src/locales/zh/profiles.json +++ b/src/locales/zh/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "无效的订阅链接,请输入以 http:// 或 https:// 开头的地址", - "onlyYaml": "仅支持 YAML 文件" + "onlyYaml": "仅支持 YAML 文件", + "createFailed": "创建订阅失败", + "deleteFailed": "删除订阅失败", + "enhanceFailed": "重新激活订阅失败", + "importFailed": "导入订阅失败", + "openFailed": "打开订阅失败", + "readFailed": "读取订阅失败", + "reorderFailed": "调整订阅顺序失败", + "switchFailed": "切换订阅失败", + "updateFailed": "更新订阅失败" }, "notifications": { "importRetry": "订阅导入失败,尝试使用 Clash 代理导入", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "数据已强制刷新", "emergencyRefreshFailed": "紧急刷新失败: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "订阅数据异常,点击强制刷新" } }, "title": "订阅" @@ -105,6 +117,7 @@ "type": "类型", "description": "描述", "subscriptionUrl": "订阅链接", + "userAgent": "用户代理", "httpTimeout": "HTTP 请求超时", "updateInterval": "更新间隔", "useSystemProxy": "使用系统代理更新", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "允许无效证书(危险)", "allowAutoUpdate": "允许自动更新" }, + "types": { + "remote": "远程", + "local": "本地" + }, + "errors": { + "typeRequired": "请选择订阅类型", + "urlRequired": "请输入订阅链接", + "uidMissing": "缺少订阅标识", + "saveFailed": "保存订阅失败" + }, "feedback": { "notifications": { "creationRetry": "订阅创建失败,尝试使用 Clash 代理创建", diff --git a/src/locales/zh/proxies.json b/src/locales/zh/proxies.json index ed9fab6fd..54c2dd3c1 100644 --- a/src/locales/zh/proxies.json +++ b/src/locales/zh/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "节点数量", - "delayCheckReset": "进行延迟测试,以取消固定" + "delayCheckReset": "进行延迟测试,以取消固定", + "nodeCount": "{{count}} 个节点" }, "tooltips": { "locate": "当前节点", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "延迟测试链接" }, + "empty": { + "noAvailableGroups": "暂无可用代理组", + "noProxies": "暂无代理" + }, "chain": { "header": "代理链配置", "warning": "链式代理会显著降低网速。如果您没有明确的业务需求,或不了解此项配置,请保持关闭", diff --git a/src/locales/zh/settings.json b/src/locales/zh/settings.json index c834dbb23..940667365 100644 --- a/src/locales/zh/settings.json +++ b/src/locales/zh/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram 频道", "github": "GitHub 项目地址" }, + "actionsGroupLabel": "设置相关链接", "title": "设置" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "端口 {{port}} 已被占用", "saved": "端口设置已保存", - "saveFailed": "端口设置保存失败" + "saveFailed": "端口设置保存失败", + "portTooLow": "端口号不能小于 1000", + "portTooHigh": "端口号不能大于 65535" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "更新" }, "messages": { - "breakChangeError": "此版本为重大更新,不支持应用内更新,请卸载后手动下载安装" + "breakChangeError": "此版本为重大更新,不支持应用内更新,请卸载后手动下载安装", + "available": "有新版本可用" + }, + "alerts": { + "note": "备注", + "tip": "提示", + "important": "重要", + "warning": "警告", + "caution": "注意" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "支持 %host, %port, %secret", "placeholderInstruction": "使用 %host, %port, %secret 表示 主机, 端口, 访问密钥" + }, + "errors": { + "clashInfoUnavailable": "内核连接信息暂不可用", + "invalidServer": "内核服务地址“{{server}}”无效", + "openFailed": "打开 Web UI 失败" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "更新内核配置失败", + "modeUpdateFailed": "切换代理模式失败", + "restartFailed": "重启内核失败", + "startFailed": "启动内核失败", + "stopFailed": "停止内核失败" + }, + "clashService": { + "installFailed": "安装服务失败", + "uninstallFailed": "卸载服务失败", + "reinstallFailed": "重新安装服务失败", + "repairFailed": "修复服务失败", + "sidecarFailed": "继续使用 Sidecar 失败" + } + }, "notifications": { "clash": { "restartSuccess": "已重启 Clash 内核", diff --git a/src/locales/zh/shared.json b/src/locales/zh/shared.json index 9648bb316..0f3023356 100644 --- a/src/locales/zh/shared.json +++ b/src/locales/zh/shared.json @@ -23,7 +23,8 @@ "closeAll": "关闭全部", "clear": "清除", "previous": "上一页", - "next": "下一页" + "next": "下一页", + "check": "检测" }, "labels": { "updateAt": "更新于", @@ -44,7 +45,8 @@ "enabled": "已启用", "disabled": "未启用", "saving": "保存中...", - "empty": "空空如也" + "empty": "空空如也", + "loading": "加载中..." }, "units": { "milliseconds": "毫秒", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "出现了一些问题", + "label": "错误", + "unknown": "未知错误", + "details": "错误详情", + "stack": "错误堆栈", + "componentStack": "组件堆栈", + "trafficUnavailable": "流量数据暂不可用", + "operationFailed": "操作失败", "trafficStats": "流量统计错误", "trafficStatsDescription": "流量统计组件发生错误,为防止崩溃已暂时停用。" }, diff --git a/src/locales/zh/tests.json b/src/locales/zh/tests.json index a39a4c076..a48820e7c 100644 --- a/src/locales/zh/tests.json +++ b/src/locales/zh/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "测试地址" + }, + "errors": { + "nameRequired": "请输入名称", + "urlRequired": "请输入测试链接", + "invalidSvg": "图标不是有效的 SVG", + "uidMissing": "缺少测试项标识", + "saveFailed": "保存测试项失败" } } }, diff --git a/src/locales/zhtw/home.json b/src/locales/zhtw/home.json index 46ba8c522..86029aa88 100644 --- a/src/locales/zhtw/home.json +++ b/src/locales/zhtw/home.json @@ -82,7 +82,9 @@ "unknown": "未知" }, "errors": { - "load": "取得 IP 資訊失敗" + "load": "取得 IP 資訊失敗", + "loadWithDetails": "取得 IP 資訊失敗:{{message}}", + "noServices": "目前沒有可用的 IP 偵測服務" } }, "currentProxy": { @@ -96,6 +98,18 @@ "group": "代理組", "proxy": "節點", "noActiveNode": "暫無作用中的代理節點" + }, + "status": { + "testing": "測試中", + "untested": "未測試", + "error": "錯誤", + "timeout": "逾時", + "latencyHigh": "延遲較高", + "latencyMedium": "延遲中等", + "latencyGood": "延遲良好", + "latencyExcellent": "延遲極佳", + "uninitialized": "未初始化", + "noProxyNode": "無代理節點" } }, "tests": { @@ -114,7 +128,13 @@ }, "patterns": { "minutes": "{{time}} 分" - } + }, + "unknownTime": "未知時間", + "chartStyles": { + "smooth": "平滑", + "linear": "線性" + }, + "diagnostics": "資料點:{{points}} | 壓縮後:{{compressed}} | 影格率:{{fps}}" }, "clashMode": { "errors": { diff --git a/src/locales/zhtw/layout.json b/src/locales/zhtw/layout.json index 2dc7a7845..5be24de85 100644 --- a/src/locales/zhtw/layout.json +++ b/src/locales/zhtw/layout.json @@ -28,7 +28,20 @@ "reinstall": "重新安裝服務", "repair": "修復服務", "continueSidecar": "繼續使用 Sidecar", - "success": "Clash Verge 系統服務已更新" + "success": "Clash Verge 系統服務已更新", + "errors": { + "actionFailed": "服務操作失敗", + "stateRefreshFailed": "重新整理服務狀態失敗", + "restartFailed": "重啟內核失敗", + "revalidationFailed": "重新整理執行狀態失敗", + "sidecarFailed": "繼續使用 Sidecar 失敗" + } + } + }, + "feedback": { + "errors": { + "restartCoreStopFailed": "無法安全停止內核,已取消重啟", + "quitCoreStopFailed": "無法安全停止內核,已取消結束" } } } diff --git a/src/locales/zhtw/profiles.json b/src/locales/zhtw/profiles.json index b282ecb72..f94707834 100644 --- a/src/locales/zhtw/profiles.json +++ b/src/locales/zhtw/profiles.json @@ -28,7 +28,16 @@ "feedback": { "errors": { "invalidUrl": "無效的訂閱網址,請輸入以 http:// 或 https:// 開頭的位址", - "onlyYaml": "僅支援 YAML 檔案" + "onlyYaml": "僅支援 YAML 檔案", + "createFailed": "建立訂閱失敗", + "deleteFailed": "刪除訂閱失敗", + "enhanceFailed": "重新啟用訂閱失敗", + "importFailed": "匯入訂閱失敗", + "openFailed": "開啟訂閱失敗", + "readFailed": "讀取訂閱失敗", + "reorderFailed": "調整訂閱順序失敗", + "switchFailed": "切換訂閱失敗", + "updateFailed": "更新訂閱失敗" }, "notifications": { "importRetry": "訂閱匯入失敗,嘗試使用 Clash 代理匯入", @@ -43,6 +52,9 @@ "notices": { "forceRefreshCompleted": "Force refresh completed", "emergencyRefreshFailed": "Emergency refresh failed: {{message}}" + }, + "tooltips": { + "forceRefreshStaleData": "訂閱資料異常,點擊強制重新整理" } }, "title": "訂閱" @@ -105,6 +117,7 @@ "type": "類型", "description": "描述", "subscriptionUrl": "訂閱網址", + "userAgent": "使用者代理", "httpTimeout": "HTTP Request Timeout", "updateInterval": "更新間隔", "useSystemProxy": "使用系統代理更新", @@ -112,6 +125,16 @@ "acceptInvalidCerts": "允許無效憑證(危險)", "allowAutoUpdate": "允許自動更新" }, + "types": { + "remote": "遠端", + "local": "本機" + }, + "errors": { + "typeRequired": "請選擇訂閱類型", + "urlRequired": "請輸入訂閱連結", + "uidMissing": "缺少訂閱識別碼", + "saveFailed": "儲存訂閱失敗" + }, "feedback": { "notifications": { "creationRetry": "訂閱建立失敗,嘗試使用 Clash 代理建立", diff --git a/src/locales/zhtw/proxies.json b/src/locales/zhtw/proxies.json index 8863581eb..74b9bdced 100644 --- a/src/locales/zhtw/proxies.json +++ b/src/locales/zhtw/proxies.json @@ -25,7 +25,8 @@ }, "labels": { "proxyCount": "節點數量", - "delayCheckReset": "測試延遲以取消固定" + "delayCheckReset": "測試延遲以取消固定", + "nodeCount": "{{count}} 個節點" }, "tooltips": { "locate": "目前節點", @@ -41,6 +42,10 @@ "placeholders": { "delayCheckUrl": "延遲測試網址" }, + "empty": { + "noAvailableGroups": "目前沒有可用的代理群組", + "noProxies": "目前沒有代理" + }, "chain": { "header": "鏈式代理設定", "warning": "鏈式代理會顯著降低網速。如果您沒有明確的業務需求,或不了解此項設定,請保持關閉", diff --git a/src/locales/zhtw/settings.json b/src/locales/zhtw/settings.json index 7976de291..76eda5055 100644 --- a/src/locales/zhtw/settings.json +++ b/src/locales/zhtw/settings.json @@ -5,6 +5,7 @@ "telegram": "Telegram 頻道", "github": "GitHub 專案位址" }, + "actionsGroupLabel": "設定相關連結", "title": "設定" }, "sections": { @@ -284,7 +285,9 @@ "messages": { "portInUse": "Port {{port}} is already in use", "saved": "連結埠設定已儲存", - "saveFailed": "連結埠設定儲存失敗" + "saveFailed": "連結埠設定儲存失敗", + "portTooLow": "連結埠不能小於 1000", + "portTooHigh": "連結埠不能大於 65535" } }, "clashCore": { @@ -429,7 +432,15 @@ "update": "更新" }, "messages": { - "breakChangeError": "此版本為重大更新,不支援應用程式內更新,請解除安裝後手動下載安裝" + "breakChangeError": "此版本為重大更新,不支援應用程式內更新,請解除安裝後手動下載安裝", + "available": "有新版本可用" + }, + "alerts": { + "note": "備註", + "tip": "提示", + "important": "重要", + "warning": "警告", + "caution": "注意" } }, "sysproxy": { @@ -590,6 +601,11 @@ "messages": { "supportedPlaceholders": "支援 %host, %port, %secret", "placeholderInstruction": "使用 %host, %port, %secret 表示 主機, 連接埠, 存取金鑰" + }, + "errors": { + "clashInfoUnavailable": "內核連線資訊暫時無法取得", + "invalidServer": "內核伺服器位址「{{server}}」無效", + "openFailed": "開啟 Web UI 失敗" } }, "hotkey": { @@ -617,6 +633,22 @@ } }, "feedback": { + "errors": { + "clash": { + "configUpdateFailed": "更新內核設定失敗", + "modeUpdateFailed": "切換代理模式失敗", + "restartFailed": "重啟內核失敗", + "startFailed": "啟動內核失敗", + "stopFailed": "停止內核失敗" + }, + "clashService": { + "installFailed": "安裝服務失敗", + "uninstallFailed": "解除安裝服務失敗", + "reinstallFailed": "重新安裝服務失敗", + "repairFailed": "修復服務失敗", + "sidecarFailed": "繼續使用 Sidecar 失敗" + } + }, "notifications": { "clash": { "restartSuccess": "已重啟 Clash 內核", diff --git a/src/locales/zhtw/shared.json b/src/locales/zhtw/shared.json index 49ad200c2..1bde03631 100644 --- a/src/locales/zhtw/shared.json +++ b/src/locales/zhtw/shared.json @@ -23,7 +23,8 @@ "closeAll": "關閉全部", "clear": "清除", "previous": "上一頁", - "next": "下一頁" + "next": "下一頁", + "check": "檢測" }, "labels": { "updateAt": "更新於", @@ -44,7 +45,8 @@ "enabled": "已啟用", "disabled": "已停用", "saving": "儲存中...", - "empty": "空空如也" + "empty": "空空如也", + "loading": "載入中..." }, "units": { "milliseconds": "毫秒", @@ -74,6 +76,14 @@ }, "feedback": { "errors": { + "unexpected": "發生了一些問題", + "label": "錯誤", + "unknown": "未知錯誤", + "details": "錯誤詳情", + "stack": "錯誤堆疊", + "componentStack": "元件堆疊", + "trafficUnavailable": "流量資料暫時無法使用", + "operationFailed": "操作失敗", "trafficStats": "流量統計錯誤", "trafficStatsDescription": "流量統計元件發生錯誤,已停用以避免當機。" }, diff --git a/src/locales/zhtw/tests.json b/src/locales/zhtw/tests.json index dbdc26944..9a846caf2 100644 --- a/src/locales/zhtw/tests.json +++ b/src/locales/zhtw/tests.json @@ -20,6 +20,13 @@ }, "fields": { "url": "測試網址" + }, + "errors": { + "nameRequired": "請輸入名稱", + "urlRequired": "請輸入測試連結", + "invalidSvg": "圖示不是有效的 SVG", + "uidMissing": "缺少測試項目識別碼", + "saveFailed": "儲存測試項目失敗" } } }, diff --git a/src/pages/_layout/utils/notification-handlers.ts b/src/pages/_layout/utils/notification-handlers.ts index e452af879..d0d8530fa 100644 --- a/src/pages/_layout/utils/notification-handlers.ts +++ b/src/pages/_layout/utils/notification-handlers.ts @@ -24,6 +24,10 @@ export const handleNoticeMessage = ( showNotice.error(msg) }, 'set_config::error': () => showNotice.error(msg), + 'app_restart::core_stop_failed': () => + showNotice.error('layout.feedback.errors.restartCoreStopFailed'), + 'app_quit::core_stop_failed': () => + showNotice.error('layout.feedback.errors.quitCoreStopFailed'), update_with_clash_proxy: () => showNotice.success( 'settings.feedback.notifications.updater.withClashProxySuccess', diff --git a/src/pages/profiles.tsx b/src/pages/profiles.tsx index e4d8ea26f..7299640a5 100644 --- a/src/pages/profiles.tsx +++ b/src/pages/profiles.tsx @@ -835,7 +835,9 @@ const ProfilePage = () => { { + $.home.components.ipInfo.errors.loadWithDetails, { + message: + extractErrorMessage(lastError) || + i18n.t(($) => $.shared.feedback.errors.unknown), + }), ) } else { - throw new Error('没有可用的IP检测服务') + throw new Error(i18n.t(($) => $.home.components.ipInfo.errors.noServices)) } } diff --git a/src/services/notice-service.ts b/src/services/notice-service.ts index 6cc502152..050e95069 100644 --- a/src/services/notice-service.ts +++ b/src/services/notice-service.ts @@ -45,6 +45,32 @@ const DEFAULT_DURATIONS: Readonly> = { } const TRANSLATION_KEY_PATTERN = /^[A-Za-z0-9_-]+(?:\.[A-Za-z0-9_-]+)+$/ +const CODED_ERROR_PATTERN = /^CVR_ERROR:([A-Z0-9_]+)(?:\n([\s\S]*))?$/ +const CODED_ERROR_TRANSLATION_KEYS: Readonly> = { + CLASH_CONFIG_UPDATE_FAILED: + 'settings.feedback.errors.clash.configUpdateFailed', + CLASH_MODE_UPDATE_FAILED: 'settings.feedback.errors.clash.modeUpdateFailed', + CORE_CHANGE_FAILED: 'settings.feedback.notifications.clash.changeFailed', + CORE_RESTART_FAILED: 'settings.feedback.errors.clash.restartFailed', + CORE_START_FAILED: 'settings.feedback.errors.clash.startFailed', + CORE_STOP_FAILED: 'settings.feedback.errors.clash.stopFailed', + PROFILE_CREATE_FAILED: 'profiles.page.feedback.errors.createFailed', + PROFILE_DELETE_FAILED: 'profiles.page.feedback.errors.deleteFailed', + PROFILE_ENHANCE_FAILED: 'profiles.page.feedback.errors.enhanceFailed', + PROFILE_IMPORT_FAILED: 'profiles.page.feedback.errors.importFailed', + PROFILE_OPEN_FAILED: 'profiles.page.feedback.errors.openFailed', + PROFILE_READ_FAILED: 'profiles.page.feedback.errors.readFailed', + PROFILE_REORDER_FAILED: 'profiles.page.feedback.errors.reorderFailed', + PROFILE_SWITCH_FAILED: 'profiles.page.feedback.errors.switchFailed', + PROFILE_UPDATE_FAILED: 'profiles.page.feedback.errors.updateFailed', + SERVICE_INSTALL_FAILED: 'settings.feedback.errors.clashService.installFailed', + SERVICE_REINSTALL_FAILED: + 'settings.feedback.errors.clashService.reinstallFailed', + SERVICE_REPAIR_FAILED: 'settings.feedback.errors.clashService.repairFailed', + SERVICE_SIDECAR_FAILED: 'settings.feedback.errors.clashService.sidecarFailed', + SERVICE_UNINSTALL_FAILED: + 'settings.feedback.errors.clashService.uninstallFailed', +} let nextId = 0 let notices: NoticeItem[] = [] @@ -195,12 +221,27 @@ function extractDisplayText(input: unknown): string | undefined { } } +function parseCodedError(input?: string) { + if (!input) return undefined + const match = input.match(CODED_ERROR_PATTERN) + if (!match) return undefined + + return { + translationKey: + CODED_ERROR_TRANSLATION_KEYS[match[1]] ?? + 'shared.feedback.errors.operationFailed', + detail: match[2]?.trim(), + } +} + function normalizeNoticeMessage( message: NoticeContent, params?: Record, raw?: unknown, ): { message?: ReactNode; i18n?: NoticeTranslationDescriptor } { const rawText = raw !== undefined ? extractDisplayText(raw) : undefined + const parsedRawError = parseCodedError(rawText) + const rawDetail = parsedRawError?.detail ?? rawText if (isValidElement(message)) { return { message } @@ -212,7 +253,7 @@ function normalizeNoticeMessage( ? { ...originalParams, ...params } : { ...originalParams } - if (rawText !== undefined) { + if (rawDetail !== undefined) { return { i18n: { key: 'shared.feedback.notices.prefixedRaw', @@ -220,7 +261,7 @@ function normalizeNoticeMessage( ...mergedParams, prefixKey: message.key, prefixParams: originalParams, - message: rawText, + message: rawDetail, }, }, } @@ -234,8 +275,28 @@ function normalizeNoticeMessage( } } + const parsedMessageError = parseCodedError(extractDisplayText(message)) + if (parsedMessageError) { + if (!parsedMessageError.detail) { + return { + i18n: { + key: parsedMessageError.translationKey, + }, + } + } + return { + i18n: { + key: 'shared.feedback.notices.prefixedRaw', + params: { + prefixKey: parsedMessageError.translationKey, + message: parsedMessageError.detail, + }, + }, + } + } + if (typeof message === 'string') { - if (rawText !== undefined) { + if (rawDetail !== undefined) { if (shouldUseTranslationKey(message, params)) { return { i18n: { @@ -243,7 +304,7 @@ function normalizeNoticeMessage( params: { ...(params ?? {}), prefixKey: message, - message: rawText, + message: rawDetail, }, }, } @@ -255,7 +316,7 @@ function normalizeNoticeMessage( params: { ...(params ?? {}), prefix: message, - message: rawText, + message: rawDetail, }, }, } @@ -272,8 +333,8 @@ function normalizeNoticeMessage( return { i18n: createRawDescriptor(message) } } - if (rawText !== undefined) { - return { i18n: createRawDescriptor(rawText) } + if (rawDetail !== undefined) { + return { i18n: createRawDescriptor(rawDetail) } } const extracted = extractDisplayText(message) diff --git a/src/types/generated/i18n-keys.ts b/src/types/generated/i18n-keys.ts index ceb8312c9..de14429a7 100644 --- a/src/types/generated/i18n-keys.ts +++ b/src/types/generated/i18n-keys.ts @@ -73,6 +73,8 @@ export const translationKeys = [ 'home.components.ipInfo.labels.autoRefresh', 'home.components.ipInfo.labels.unknown', 'home.components.ipInfo.errors.load', + 'home.components.ipInfo.errors.loadWithDetails', + 'home.components.ipInfo.errors.noServices', 'home.components.currentProxy.title', 'home.components.currentProxy.actions.refreshDelay', 'home.components.currentProxy.labels.globalMode', @@ -80,6 +82,16 @@ export const translationKeys = [ 'home.components.currentProxy.labels.group', 'home.components.currentProxy.labels.proxy', 'home.components.currentProxy.labels.noActiveNode', + 'home.components.currentProxy.status.testing', + 'home.components.currentProxy.status.untested', + 'home.components.currentProxy.status.error', + 'home.components.currentProxy.status.timeout', + 'home.components.currentProxy.status.latencyHigh', + 'home.components.currentProxy.status.latencyMedium', + 'home.components.currentProxy.status.latencyGood', + 'home.components.currentProxy.status.latencyExcellent', + 'home.components.currentProxy.status.uninitialized', + 'home.components.currentProxy.status.noProxyNode', 'home.components.tests.title', 'home.components.traffic.metrics.uploadSpeed', 'home.components.traffic.metrics.downloadSpeed', @@ -88,6 +100,10 @@ export const translationKeys = [ 'home.components.traffic.legends.upload', 'home.components.traffic.legends.download', 'home.components.traffic.patterns.minutes', + 'home.components.traffic.unknownTime', + 'home.components.traffic.chartStyles.smooth', + 'home.components.traffic.chartStyles.linear', + 'home.components.traffic.diagnostics', 'home.components.clashMode.errors.communication', 'home.components.clashMode.labels.rule', 'home.components.clashMode.labels.global', @@ -117,6 +133,13 @@ export const translationKeys = [ 'layout.components.serviceMigration.repair', 'layout.components.serviceMigration.continueSidecar', 'layout.components.serviceMigration.success', + 'layout.components.serviceMigration.errors.actionFailed', + 'layout.components.serviceMigration.errors.stateRefreshFailed', + 'layout.components.serviceMigration.errors.restartFailed', + 'layout.components.serviceMigration.errors.revalidationFailed', + 'layout.components.serviceMigration.errors.sidecarFailed', + 'layout.feedback.errors.restartCoreStopFailed', + 'layout.feedback.errors.quitCoreStopFailed', 'logs.page.title', 'logs.actions.showDescending', 'logs.actions.showAscending', @@ -135,6 +158,15 @@ export const translationKeys = [ 'profiles.page.importForm.actions.paste', 'profiles.page.feedback.errors.invalidUrl', 'profiles.page.feedback.errors.onlyYaml', + 'profiles.page.feedback.errors.createFailed', + 'profiles.page.feedback.errors.deleteFailed', + 'profiles.page.feedback.errors.enhanceFailed', + 'profiles.page.feedback.errors.importFailed', + 'profiles.page.feedback.errors.openFailed', + 'profiles.page.feedback.errors.readFailed', + 'profiles.page.feedback.errors.reorderFailed', + 'profiles.page.feedback.errors.switchFailed', + 'profiles.page.feedback.errors.updateFailed', 'profiles.page.feedback.notifications.importRetry', 'profiles.page.feedback.notifications.importFail', 'profiles.page.feedback.notifications.importNeedsRefresh', @@ -145,6 +177,7 @@ export const translationKeys = [ 'profiles.page.feedback.notifications.batchDeleted', 'profiles.page.feedback.notices.forceRefreshCompleted', 'profiles.page.feedback.notices.emergencyRefreshFailed', + 'profiles.page.feedback.tooltips.forceRefreshStaleData', 'profiles.page.title', 'profiles.components.card.labels.clickToImport', 'profiles.components.fileInput.chooseFile', @@ -177,12 +210,19 @@ export const translationKeys = [ 'profiles.modals.profileForm.fields.type', 'profiles.modals.profileForm.fields.description', 'profiles.modals.profileForm.fields.subscriptionUrl', + 'profiles.modals.profileForm.fields.userAgent', 'profiles.modals.profileForm.fields.httpTimeout', 'profiles.modals.profileForm.fields.updateInterval', 'profiles.modals.profileForm.fields.useSystemProxy', 'profiles.modals.profileForm.fields.useClashProxy', 'profiles.modals.profileForm.fields.acceptInvalidCerts', 'profiles.modals.profileForm.fields.allowAutoUpdate', + 'profiles.modals.profileForm.types.remote', + 'profiles.modals.profileForm.types.local', + 'profiles.modals.profileForm.errors.typeRequired', + 'profiles.modals.profileForm.errors.urlRequired', + 'profiles.modals.profileForm.errors.uidMissing', + 'profiles.modals.profileForm.errors.saveFailed', 'profiles.modals.profileForm.feedback.notifications.creationRetry', 'profiles.modals.profileForm.feedback.notifications.creationSuccess', 'profiles.modals.proxiesEditor.title', @@ -235,6 +275,7 @@ export const translationKeys = [ 'proxies.page.rules.select', 'proxies.page.labels.proxyCount', 'proxies.page.labels.delayCheckReset', + 'proxies.page.labels.nodeCount', 'proxies.page.tooltips.locate', 'proxies.page.tooltips.delayCheck', 'proxies.page.tooltips.sortDefault', @@ -245,6 +286,8 @@ export const translationKeys = [ 'proxies.page.tooltips.showDetail', 'proxies.page.tooltips.filter', 'proxies.page.placeholders.delayCheckUrl', + 'proxies.page.empty.noAvailableGroups', + 'proxies.page.empty.noProxies', 'proxies.page.chain.header', 'proxies.page.chain.warning', 'proxies.page.chain.empty', @@ -328,6 +371,7 @@ export const translationKeys = [ 'settings.page.actions.manual', 'settings.page.actions.telegram', 'settings.page.actions.github', + 'settings.page.actionsGroupLabel', 'settings.page.title', 'settings.sections.system.title', 'settings.sections.system.toggles.tunMode', @@ -492,6 +536,8 @@ export const translationKeys = [ 'settings.modals.clashPort.messages.portInUse', 'settings.modals.clashPort.messages.saved', 'settings.modals.clashPort.messages.saveFailed', + 'settings.modals.clashPort.messages.portTooLow', + 'settings.modals.clashPort.messages.portTooHigh', 'settings.modals.clashCore.variants.release', 'settings.modals.clashCore.variants.alpha', 'settings.modals.liteMode.title', @@ -581,6 +627,12 @@ export const translationKeys = [ 'settings.modals.update.actions.goToRelease', 'settings.modals.update.actions.update', 'settings.modals.update.messages.breakChangeError', + 'settings.modals.update.messages.available', + 'settings.modals.update.alerts.note', + 'settings.modals.update.alerts.tip', + 'settings.modals.update.alerts.important', + 'settings.modals.update.alerts.warning', + 'settings.modals.update.alerts.caution', 'settings.modals.sysproxy.title', 'settings.modals.sysproxy.fieldsets.currentStatus', 'settings.modals.sysproxy.fields.enableStatus', @@ -669,6 +721,9 @@ export const translationKeys = [ 'settings.modals.webUI.title', 'settings.modals.webUI.messages.supportedPlaceholders', 'settings.modals.webUI.messages.placeholderInstruction', + 'settings.modals.webUI.errors.clashInfoUnavailable', + 'settings.modals.webUI.errors.invalidServer', + 'settings.modals.webUI.errors.openFailed', 'settings.modals.hotkey.toggles.enableGlobal', 'settings.modals.hotkey.title', 'settings.modals.hotkey.functions.rule', @@ -682,6 +737,16 @@ export const translationKeys = [ 'settings.modals.networkInterface.title', 'settings.modals.networkInterface.fields.ipAddress', 'settings.modals.networkInterface.fields.macAddress', + 'settings.feedback.errors.clash.configUpdateFailed', + 'settings.feedback.errors.clash.modeUpdateFailed', + 'settings.feedback.errors.clash.restartFailed', + 'settings.feedback.errors.clash.startFailed', + 'settings.feedback.errors.clash.stopFailed', + 'settings.feedback.errors.clashService.installFailed', + 'settings.feedback.errors.clashService.uninstallFailed', + 'settings.feedback.errors.clashService.reinstallFailed', + 'settings.feedback.errors.clashService.repairFailed', + 'settings.feedback.errors.clashService.sidecarFailed', 'settings.feedback.notifications.clash.restartSuccess', 'settings.feedback.notifications.clash.versionUpdated', 'settings.feedback.notifications.clash.alreadyLatestVersion', @@ -720,6 +785,7 @@ export const translationKeys = [ 'shared.actions.clear', 'shared.actions.previous', 'shared.actions.next', + 'shared.actions.check', 'shared.labels.updateAt', 'shared.labels.timeout', 'shared.labels.icon', @@ -737,6 +803,7 @@ export const translationKeys = [ 'shared.statuses.disabled', 'shared.statuses.saving', 'shared.statuses.empty', + 'shared.statuses.loading', 'shared.units.milliseconds', 'shared.units.seconds', 'shared.units.minutes', @@ -753,6 +820,14 @@ export const translationKeys = [ 'shared.window.minimize', 'shared.editorModes.visualization', 'shared.editorModes.advanced', + 'shared.feedback.errors.unexpected', + 'shared.feedback.errors.label', + 'shared.feedback.errors.unknown', + 'shared.feedback.errors.details', + 'shared.feedback.errors.stack', + 'shared.feedback.errors.componentStack', + 'shared.feedback.errors.trafficUnavailable', + 'shared.feedback.errors.operationFailed', 'shared.feedback.errors.trafficStats', 'shared.feedback.errors.trafficStatsDescription', 'shared.feedback.notices.raw', @@ -794,6 +869,11 @@ export const translationKeys = [ 'tests.modals.test.title.create', 'tests.modals.test.title.edit', 'tests.modals.test.fields.url', + 'tests.modals.test.errors.nameRequired', + 'tests.modals.test.errors.urlRequired', + 'tests.modals.test.errors.invalidSvg', + 'tests.modals.test.errors.uidMissing', + 'tests.modals.test.errors.saveFailed', 'tests.statuses.test.pending', 'tests.statuses.test.yes', 'tests.statuses.test.no', diff --git a/src/types/generated/i18n-resources.ts b/src/types/generated/i18n-resources.ts index 3c822e777..bbd064bfe 100644 --- a/src/types/generated/i18n-resources.ts +++ b/src/types/generated/i18n-resources.ts @@ -75,11 +75,25 @@ export interface TranslationResources { noActiveNode: string proxy: string } + status: { + error: string + latencyExcellent: string + latencyGood: string + latencyHigh: string + latencyMedium: string + noProxyNode: string + testing: string + timeout: string + uninitialized: string + untested: string + } title: string } ipInfo: { errors: { load: string + loadWithDetails: string + noServices: string } labels: { asn: string @@ -129,6 +143,11 @@ export interface TranslationResources { title: string } traffic: { + chartStyles: { + linear: string + smooth: string + } + diagnostics: string legends: { download: string upload: string @@ -142,6 +161,7 @@ export interface TranslationResources { patterns: { minutes: string } + unknownTime: string } } page: { @@ -197,6 +217,13 @@ export interface TranslationResources { serviceMigration: { checkingMessage: string continueSidecar: string + errors: { + actionFailed: string + restartFailed: string + revalidationFailed: string + sidecarFailed: string + stateRefreshFailed: string + } message: string reinstall: string repair: string @@ -205,6 +232,12 @@ export interface TranslationResources { unavailableMessage: string } } + feedback: { + errors: { + quitCoreStopFailed: string + restartCoreStopFailed: string + } + } } logs: { actions: { @@ -316,6 +349,12 @@ export interface TranslationResources { title: string } profileForm: { + errors: { + saveFailed: string + typeRequired: string + uidMissing: string + urlRequired: string + } feedback: { notifications: { creationRetry: string @@ -331,12 +370,17 @@ export interface TranslationResources { type: string updateInterval: string useClashProxy: string + userAgent: string useSystemProxy: string } title: { create: string edit: string } + types: { + local: string + remote: string + } } proxiesEditor: { actions: { @@ -374,8 +418,17 @@ export interface TranslationResources { } feedback: { errors: { + createFailed: string + deleteFailed: string + enhanceFailed: string + importFailed: string invalidUrl: string onlyYaml: string + openFailed: string + readFailed: string + reorderFailed: string + switchFailed: string + updateFailed: string } notices: { emergencyRefreshFailed: string @@ -391,6 +444,9 @@ export interface TranslationResources { profileSwitched: string switchBusy: string } + tooltips: { + forceRefreshStaleData: string + } } importForm: { actions: { @@ -451,8 +507,13 @@ export interface TranslationResources { minimumNodesHint: string warning: string } + empty: { + noAvailableGroups: string + noProxies: string + } labels: { delayCheckReset: string + nodeCount: string proxyCount: string } messages: { @@ -699,6 +760,22 @@ export interface TranslationResources { } } feedback: { + errors: { + clash: { + configUpdateFailed: string + modeUpdateFailed: string + restartFailed: string + startFailed: string + stopFailed: string + } + clashService: { + installFailed: string + reinstallFailed: string + repairFailed: string + sidecarFailed: string + uninstallFailed: string + } + } notifications: { clash: { alreadyLatestVersion: string @@ -817,6 +894,8 @@ export interface TranslationResources { } messages: { portInUse: string + portTooHigh: string + portTooLow: string saved: string saveFailed: string } @@ -1050,7 +1129,15 @@ export interface TranslationResources { goToRelease: string update: string } + alerts: { + caution: string + important: string + note: string + tip: string + warning: string + } messages: { + available: string breakChangeError: string } title: string @@ -1059,6 +1146,11 @@ export interface TranslationResources { actions: { openUrl: string } + errors: { + clashInfoUnavailable: string + invalidServer: string + openFailed: string + } messages: { placeholderInstruction: string supportedPlaceholders: string @@ -1072,6 +1164,7 @@ export interface TranslationResources { manual: string telegram: string } + actionsGroupLabel: string title: string } sections: { @@ -1228,6 +1321,7 @@ export interface TranslationResources { shared: { actions: { cancel: string + check: string clear: string close: string closeAll: string @@ -1258,8 +1352,16 @@ export interface TranslationResources { } feedback: { errors: { + componentStack: string + details: string + label: string + operationFailed: string + stack: string trafficStats: string trafficStatsDescription: string + trafficUnavailable: string + unexpected: string + unknown: string } notices: { prefixedRaw: string @@ -1341,6 +1443,7 @@ export interface TranslationResources { disabled: string empty: string enabled: string + loading: string saving: string } units: { @@ -1369,6 +1472,13 @@ export interface TranslationResources { } modals: { test: { + errors: { + invalidSvg: string + nameRequired: string + saveFailed: string + uidMissing: string + urlRequired: string + } fields: { url: string }