mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-08-14 23:20:41 +02:00
chore: i18n
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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") {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
});
|
||||
|
||||
@@ -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 },
|
||||
),
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user