chore: i18n

This commit is contained in:
zhom
2026-04-28 23:50:56 +04:00
parent 97d01e4b54
commit f8ce56481f
62 changed files with 6520 additions and 1322 deletions
+32 -27
View File
@@ -3,12 +3,14 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { toast } from "sonner";
import { AppUpdateToast } from "@/components/app-update-toast";
import { showToast } from "@/lib/toast-utils";
import type { AppUpdateInfo, AppUpdateProgress } from "@/types";
export function useAppUpdateNotifications() {
const { t } = useTranslation();
const [updateInfo, setUpdateInfo] = useState<AppUpdateInfo | null>(null);
const [isUpdating, setIsUpdating] = useState(false);
const [updateProgress, setUpdateProgress] =
@@ -60,32 +62,35 @@ export function useAppUpdateNotifications() {
}
}, [isClient]);
const handleAppUpdate = useCallback(async (appUpdateInfo: AppUpdateInfo) => {
try {
setIsUpdating(true);
setUpdateProgress({
stage: "downloading",
percentage: 0,
speed: undefined,
eta: undefined,
message: "Starting update...",
});
const handleAppUpdate = useCallback(
async (appUpdateInfo: AppUpdateInfo) => {
try {
setIsUpdating(true);
setUpdateProgress({
stage: "downloading",
percentage: 0,
speed: undefined,
eta: undefined,
message: "Starting update...",
});
await invoke("download_and_prepare_app_update", {
updateInfo: appUpdateInfo,
});
} catch (error) {
console.error("Failed to update app:", error);
showToast({
type: "error",
title: "Failed to update Donut Browser",
description: String(error),
duration: 6000,
});
setIsUpdating(false);
setUpdateProgress(null);
}
}, []);
await invoke("download_and_prepare_app_update", {
updateInfo: appUpdateInfo,
});
} catch (error) {
console.error("Failed to update app:", error);
showToast({
type: "error",
title: t("appUpdate.toast.updateFailed"),
description: String(error),
duration: 6000,
});
setIsUpdating(false);
setUpdateProgress(null);
}
},
[t],
);
const handleRestart = useCallback(async () => {
try {
@@ -94,12 +99,12 @@ export function useAppUpdateNotifications() {
console.error("Failed to restart app:", error);
showToast({
type: "error",
title: "Failed to restart",
title: t("appUpdate.toast.restartFailed"),
description: String(error),
duration: 6000,
});
}
}, []);
}, [t]);
const dismissAppUpdate = useCallback(() => {
if (!isClient) return;
+52 -21
View File
@@ -2,6 +2,7 @@ import { invoke } from "@tauri-apps/api/core";
import type { Event as TauriEvent } from "@tauri-apps/api/event";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import i18n from "@/i18n";
import { getBrowserDisplayName } from "@/lib/browser-utils";
import {
dismissToast,
@@ -106,11 +107,18 @@ export function useBrowserDownload() {
return githubReleases;
} catch (error) {
console.error("Failed to load versions:", error);
showErrorToast(`Failed to fetch ${browserName} versions`, {
description:
error instanceof Error ? error.message : "Unknown error occurred",
duration: 4000,
});
showErrorToast(
i18n.t("browserDownload.toast.fetchVersionsFailed", {
browser: browserName,
}),
{
description:
error instanceof Error
? error.message
: i18n.t("common.errors.unknown"),
duration: 4000,
},
);
throw error;
}
}, []);
@@ -146,10 +154,16 @@ export function useBrowserDownload() {
// Show notification about new versions if any were found
if (result.new_versions_count && result.new_versions_count > 0) {
showSuccessToast(
`Found ${result.new_versions_count} new ${browserName} versions!`,
i18n.t("browserDownload.toast.foundNewVersions", {
count: result.new_versions_count,
browser: browserName,
}),
{
duration: 3000,
description: `Total available: ${result.total_versions_count} versions`,
description: i18n.t(
"browserDownload.toast.totalAvailableVersions",
{ count: result.total_versions_count },
),
},
);
}
@@ -157,11 +171,18 @@ export function useBrowserDownload() {
return githubReleases;
} catch (error) {
console.error("Failed to load versions:", error);
showErrorToast(`Failed to fetch ${browserName} versions`, {
description:
error instanceof Error ? error.message : "Unknown error occurred",
duration: 4000,
});
showErrorToast(
i18n.t("browserDownload.toast.fetchVersionsFailed", {
browser: browserName,
}),
{
description:
error instanceof Error
? error.message
: i18n.t("common.errors.unknown"),
duration: 4000,
},
);
throw error;
}
}, []);
@@ -215,7 +236,7 @@ export function useBrowserDownload() {
// Dismiss any existing download toast and show error
dismissToast(`download-${browserStr}-${version}`);
let errorMessage = "Unknown error occurred";
let errorMessage = i18n.t("common.errors.unknown");
if (error instanceof Error) {
errorMessage = error.message;
} else if (typeof error === "string") {
@@ -226,10 +247,16 @@ export function useBrowserDownload() {
// Ensure the long-running download toast is dismissed, and show a finite error toast
dismissToast(`download-${browserStr}-${version}`);
showErrorToast(`Failed to download ${browserName} ${version}`, {
description: errorMessage,
duration: 8000,
});
showErrorToast(
i18n.t("browserDownload.toast.downloadFailed", {
browser: browserName,
version,
}),
{
description: errorMessage,
duration: 8000,
},
);
}
throw error;
} finally {
@@ -297,7 +324,7 @@ export function useBrowserDownload() {
).toFixed(1);
const etaText = progress.eta_seconds
? formatTime(progress.eta_seconds)
: "calculating...";
: i18n.t("browserDownload.toast.calculating");
const toastId = `download-${browserName.toLowerCase()}-${progress.version}`;
showDownloadToast(
@@ -346,10 +373,14 @@ export function useBrowserDownload() {
);
setDownloadProgress(null);
showErrorToast(
`${browserName} ${progress.version}: extraction failed`,
i18n.t("browserDownload.toast.extractionFailed", {
browser: browserName,
version: progress.version,
}),
{
description:
"The corrupt file was deleted. It will be re-downloaded on next attempt.",
description: i18n.t(
"browserDownload.toast.extractionFailedDescription",
),
},
);
} else if (progress.stage === "completed") {
+2 -1
View File
@@ -1,5 +1,6 @@
import { invoke } from "@tauri-apps/api/core";
import { useEffect, useState } from "react";
import i18n from "@/i18n";
export function useBrowserSupport() {
const [supportedBrowsers, setSupportedBrowsers] = useState<string[]>([]);
@@ -18,7 +19,7 @@ export function useBrowserSupport() {
setError(
err instanceof Error
? err.message
: "Failed to load supported browsers",
: i18n.t("errors.loadSupportedBrowsersFailed"),
);
} finally {
setIsLoading(false);
+4 -1
View File
@@ -1,6 +1,7 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import i18n from "@/i18n";
import type { Extension, ExtensionGroup } from "@/types";
export function useExtensionEvents() {
@@ -47,7 +48,9 @@ export function useExtensionEvents() {
} catch (err) {
console.error("Failed to setup extension event listeners:", err);
setError(
`Failed to setup extension event listeners: ${JSON.stringify(err)}`,
i18n.t("errors.setupExtensionListenersFailed", {
error: JSON.stringify(err),
}),
);
} finally {
setIsLoading(false);
+7 -2
View File
@@ -1,6 +1,7 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import i18n from "@/i18n";
import type { GroupWithCount } from "@/types";
/**
@@ -23,7 +24,9 @@ export function useGroupEvents() {
setError(null);
} catch (err: unknown) {
console.error("Failed to load groups:", err);
setError(`Failed to load groups: ${JSON.stringify(err)}`);
setError(
i18n.t("errors.loadGroupsFailed", { error: JSON.stringify(err) }),
);
}
}, []);
@@ -65,7 +68,9 @@ export function useGroupEvents() {
} catch (err) {
console.error("Failed to setup group event listeners:", err);
setError(
`Failed to setup group event listeners: ${JSON.stringify(err)}`,
i18n.t("errors.setupGroupListenersFailed", {
error: JSON.stringify(err),
}),
);
} finally {
setIsLoading(false);
+7 -2
View File
@@ -1,6 +1,7 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import i18n from "@/i18n";
import type { BrowserProfile, GroupWithCount } from "@/types";
interface UseProfileEventsReturn {
@@ -38,7 +39,9 @@ export function useProfileEvents(): UseProfileEventsReturn {
setError(null);
} catch (err: unknown) {
console.error("Failed to load profiles:", err);
setError(`Failed to load profiles: ${JSON.stringify(err)}`);
setError(
i18n.t("errors.loadProfilesFailed", { error: JSON.stringify(err) }),
);
}
}, []);
@@ -101,7 +104,9 @@ export function useProfileEvents(): UseProfileEventsReturn {
} catch (err) {
console.error("Failed to setup profile event listeners:", err);
setError(
`Failed to setup profile event listeners: ${JSON.stringify(err)}`,
i18n.t("errors.setupProfileListenersFailed", {
error: JSON.stringify(err),
}),
);
} finally {
setIsLoading(false);
+7 -2
View File
@@ -1,6 +1,7 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import i18n from "@/i18n";
import type { StoredProxy } from "@/types";
/**
@@ -40,7 +41,9 @@ export function useProxyEvents() {
setError(null);
} catch (err: unknown) {
console.error("Failed to load proxies:", err);
setError(`Failed to load proxies: ${JSON.stringify(err)}`);
setError(
i18n.t("errors.loadProxiesFailed", { error: JSON.stringify(err) }),
);
}
}, [loadProxyUsage]);
@@ -84,7 +87,9 @@ export function useProxyEvents() {
} catch (err) {
console.error("Failed to setup proxy event listeners:", err);
setError(
`Failed to setup proxy event listeners: ${JSON.stringify(err)}`,
i18n.t("errors.setupProxyListenersFailed", {
error: JSON.stringify(err),
}),
);
} finally {
setIsLoading(false);
+5 -1
View File
@@ -1,5 +1,6 @@
import { invoke } from "@tauri-apps/api/core";
import { useCallback, useRef, useState } from "react";
import i18n from "@/i18n";
import { getBrowserDisplayName } from "@/lib/browser-utils";
import { dismissToast, showToast } from "@/lib/toast-utils";
@@ -147,7 +148,10 @@ export function useUpdateNotifications(
showToast({
id: `auto-update-error-${browser}-${newVersion}`,
type: "error",
title: `Failed to download ${browserDisplayName} ${newVersion}`,
title: i18n.t("browserDownload.toast.downloadFailed", {
browser: browserDisplayName,
version: newVersion,
}),
description: String(downloadError),
duration: 8000,
});
+73 -28
View File
@@ -1,6 +1,7 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useRef, useState } from "react";
import i18n from "@/i18n";
import { getBrowserDisplayName } from "@/lib/browser-utils";
import {
showAutoUpdateToast,
@@ -162,9 +163,14 @@ export function useVersionUpdater() {
);
showSuccessToast(
`${browserDisplayName} ${new_version} already available`,
i18n.t("versionUpdater.toast.alreadyAvailable", {
browser: browserDisplayName,
version: new_version,
}),
{
description: "Updating profile configurations...",
description: i18n.t(
"versionUpdater.toast.updatingProfiles",
),
duration: 3000,
},
);
@@ -187,25 +193,44 @@ export function useVersionUpdater() {
// Show success message based on whether profiles were updated
if (updatedProfiles.length > 0) {
const profileText =
const description =
updatedProfiles.length === 1
? `Profile "${updatedProfiles[0]}" has been updated`
: `${updatedProfiles.length} profiles have been updated`;
? i18n.t("versionUpdater.toast.singleProfileUpdated", {
name: updatedProfiles[0],
version: new_version,
})
: i18n.t("versionUpdater.toast.multipleProfilesUpdated", {
count: updatedProfiles.length,
version: new_version,
});
showSuccessToast(`${browserDisplayName} update completed`, {
description: `${profileText} to version ${new_version}. You can now launch your browsers with the latest version.`,
duration: 6000,
});
showSuccessToast(
i18n.t("versionUpdater.toast.updateCompleted", {
browser: browserDisplayName,
}),
{
description,
duration: 6000,
},
);
} else {
showSuccessToast(`${browserDisplayName} update completed`, {
description: `Version ${new_version} is now available. Running profiles will use the new version when restarted.`,
duration: 6000,
});
showSuccessToast(
i18n.t("versionUpdater.toast.updateCompleted", {
browser: browserDisplayName,
}),
{
description: i18n.t(
"versionUpdater.toast.versionAvailable",
{ version: new_version },
),
duration: 6000,
},
);
}
} catch (error) {
console.error("Failed to handle browser auto-update:", error);
let errorMessage = "Unknown error occurred";
let errorMessage = i18n.t("common.errors.unknown");
if (error instanceof Error) {
errorMessage = error.message;
} else if (typeof error === "string") {
@@ -218,10 +243,15 @@ export function useVersionUpdater() {
errorMessage = String(error.message);
}
showErrorToast(`Failed to auto-update ${browserDisplayName}`, {
description: errorMessage,
duration: 8000,
});
showErrorToast(
i18n.t("versionUpdater.toast.autoUpdateFailed", {
browser: browserDisplayName,
}),
{
description: errorMessage,
duration: 8000,
},
);
} finally {
// Remove from active downloads
activeDownloads.current.delete(downloadKey);
@@ -286,18 +316,27 @@ export function useVersionUpdater() {
).length;
if (failedUpdates > 0) {
showErrorToast("Update completed with some errors", {
description: `${totalNewVersions} new versions found, ${failedUpdates} browsers failed to update`,
showErrorToast(i18n.t("versionUpdater.toast.updateWithErrors"), {
description: i18n.t(
"versionUpdater.toast.updateWithErrorsDescription",
{
newVersions: totalNewVersions,
failedUpdates,
},
),
duration: 5000,
});
} else if (totalNewVersions > 0) {
showSuccessToast("Browser versions updated successfully", {
description: `Found ${totalNewVersions} new versions across ${successfulUpdates} browsers. Auto-downloads will start shortly.`,
showSuccessToast(i18n.t("versionUpdater.toast.updateSuccess"), {
description: i18n.t("versionUpdater.toast.updateSuccessDescription", {
newVersions: totalNewVersions,
successfulUpdates,
}),
duration: 4000,
});
} else {
showSuccessToast("No new browser versions found", {
description: "All browser versions are up to date",
showSuccessToast(i18n.t("versionUpdater.toast.upToDate"), {
description: i18n.t("versionUpdater.toast.upToDateDescription"),
duration: 3000,
});
}
@@ -306,7 +345,7 @@ export function useVersionUpdater() {
return results;
} catch (error) {
console.error("Failed to trigger manual update:", error);
let errorMessage = "Unknown error occurred";
let errorMessage = i18n.t("common.errors.unknown");
if (error instanceof Error) {
errorMessage = error.message;
} else if (typeof error === "string") {
@@ -315,7 +354,7 @@ export function useVersionUpdater() {
errorMessage = String(error.message);
}
showErrorToast("Failed to update browser versions", {
showErrorToast(i18n.t("versionUpdater.toast.updateAllFailed"), {
description: errorMessage,
duration: 4000,
});
@@ -337,10 +376,16 @@ export function useVersionUpdater() {
if (result.new_versions_count && result.new_versions_count > 0) {
const browserName = getBrowserDisplayName(browserStr);
showSuccessToast(
`Found ${result.new_versions_count} new ${browserName} versions!`,
i18n.t("browserDownload.toast.foundNewVersions", {
count: result.new_versions_count,
browser: browserName,
}),
{
duration: 3000,
description: `Total available: ${result.total_versions_count} versions`,
description: i18n.t(
"browserDownload.toast.totalAvailableVersions",
{ count: result.total_versions_count },
),
},
);
}
+9 -2
View File
@@ -1,6 +1,7 @@
import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event";
import { useCallback, useEffect, useState } from "react";
import i18n from "@/i18n";
import type { VpnConfig } from "@/types";
/**
@@ -37,7 +38,9 @@ export function useVpnEvents() {
setError(null);
} catch (err: unknown) {
console.error("Failed to load VPN configs:", err);
setError(`Failed to load VPN configs: ${JSON.stringify(err)}`);
setError(
i18n.t("errors.loadVpnConfigsFailed", { error: JSON.stringify(err) }),
);
}
}, [loadVpnUsage]);
@@ -62,7 +65,11 @@ export function useVpnEvents() {
});
} catch (err) {
console.error("Failed to setup VPN event listeners:", err);
setError(`Failed to setup VPN event listeners: ${JSON.stringify(err)}`);
setError(
i18n.t("errors.setupVpnListenersFailed", {
error: JSON.stringify(err),
}),
);
} finally {
setIsLoading(false);
}