diff --git a/application/src/components/services/LastCheckedTime.tsx b/application/src/components/services/LastCheckedTime.tsx
index 3757f12..85756a3 100644
--- a/application/src/components/services/LastCheckedTime.tsx
+++ b/application/src/components/services/LastCheckedTime.tsx
@@ -2,6 +2,7 @@
import React from "react";
import { Clock, TimerOff } from "lucide-react";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
+import { useLanguage } from "@/contexts/LanguageContext";
interface LastCheckedTimeProps {
lastCheckedTime: string;
@@ -10,6 +11,7 @@ interface LastCheckedTimeProps {
}
export const LastCheckedTime = ({ lastCheckedTime, status, interval }: LastCheckedTimeProps) => {
+ const { t } = useLanguage();
// Format the time without seconds to display a static time
const formatTimeWithoutSeconds = (timeString: string) => {
try {
@@ -55,7 +57,7 @@ export const LastCheckedTime = ({ lastCheckedTime, status, interval }: LastCheck
)}
- {isPaused ? "Paused at " : ""}
+ {isPaused ? t("pausedAt") : ""}
{formattedTime}
@@ -66,14 +68,14 @@ export const LastCheckedTime = ({ lastCheckedTime, status, interval }: LastCheck
>
- {isPaused ? "Monitoring Paused" : "Last Check Details"}
+ {isPaused ? t("monitoringPaused") : t("lastCheckDetails")}
- {isPaused ? "No automatic checks" : `Checked at ${formattedTime}`}
+ {isPaused ? t("noAutomaticChecks") : t("checkedAt") + `${formattedTime}`}
{interval && !isPaused && (
- Check interval: {formatInterval(interval)}
+ {t("checkInterval")}: {formatInterval(interval)}
)}
diff --git a/application/src/components/services/ServiceEditDialog.tsx b/application/src/components/services/ServiceEditDialog.tsx
index 8603398..d020d56 100644
--- a/application/src/components/services/ServiceEditDialog.tsx
+++ b/application/src/components/services/ServiceEditDialog.tsx
@@ -11,6 +11,7 @@ import { Service } from "@/types/service.types";
import { useQueryClient } from "@tanstack/react-query";
import { useState, useEffect } from "react";
import { ScrollArea } from "@/components/ui/scroll-area";
+import { useLanguage } from "@/contexts/LanguageContext";
interface ServiceEditDialogProps {
open: boolean;
@@ -19,6 +20,7 @@ interface ServiceEditDialogProps {
}
export function ServiceEditDialog({ open, onOpenChange, service }: ServiceEditDialogProps) {
+ const { t } = useLanguage();
const queryClient = useQueryClient();
const [isSubmitting, setIsSubmitting] = useState(false);
@@ -53,9 +55,9 @@ export function ServiceEditDialog({ open, onOpenChange, service }: ServiceEditDi
}}>
- Edit Service
+ {t("editService")}
- Update the details of your monitored service.
+ {t("editServiceDesc")}
{open && service && (
diff --git a/application/src/components/services/ServiceStatsCards.tsx b/application/src/components/services/ServiceStatsCards.tsx
index db469e1..4d84708 100644
--- a/application/src/components/services/ServiceStatsCards.tsx
+++ b/application/src/components/services/ServiceStatsCards.tsx
@@ -4,6 +4,7 @@ import { Service, UptimeData } from "@/types/service.types";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { useMemo } from "react";
import { formatDistanceStrict } from "date-fns";
+import {useLanguage} from "@/contexts/LanguageContext.tsx";
interface ServiceStatsCardsProps {
service: Service;
@@ -11,6 +12,8 @@ interface ServiceStatsCardsProps {
}
export function ServiceStatsCards({ service, uptimeData }: ServiceStatsCardsProps) {
+
+ const { t } = useLanguage();
// Calculate uptime percentage
const calculateUptimePercentage = () => {
if (uptimeData.length === 0) return 100;
@@ -109,41 +112,46 @@ export function ServiceStatsCards({ service, uptimeData }: ServiceStatsCardsProp
- Response Time
+ {t('responseTime')}
{service.responseTime}ms
- Last checked at {service.lastChecked}
+ {t('lastCheckedAt').replace('{datetime}', service.lastChecked)}
{avgResponseTime > 0 && avgResponseTime !== service.responseTime && (
- Avg: {avgResponseTime}ms (last {upChecks.length} up checks)
+ {t('avg')}: {avgResponseTime}ms ({t('lastUpChecksCount').replace('{count}', String(upChecks.length))})
)}
- Uptime
+ {t('uptime')}
{uptimePercentage}%
- Based on last {uptimeData.length} checks
+ {t('basedOnlastChecksCount').replace('{count}', String(uptimeData.length))}
-
Total uptime: {uptimeStats.totalUptimeFormatted}
+
{t("totalUptime")}: {uptimeStats.totalUptimeFormatted}
-
Total downtime: {uptimeStats.totalDowntimeFormatted}
+
{t("totalDowntime")}: {uptimeStats.totalDowntimeFormatted}
{service.status !== "paused" && (
- {service.status === "up" ? "Up" : "Down"} for {uptimeStats.currentStatusDuration}
+ {
+ service.status === "up" ?
+ t('upStatusDuration').replace("{duration}", uptimeStats.currentStatusDuration)
+ :
+ t('downStatusDuration').replace("{duration}", uptimeStats.currentStatusDuration)
+ }
)}
@@ -153,16 +161,16 @@ export function ServiceStatsCards({ service, uptimeData }: ServiceStatsCardsProp
- Monitoring Settings
+ {t('monitoringSettings')}
- Checked every {service.interval} seconds
+ {t('monitoringSettingsInterval').replace('{interval}', String(service.interval))}
- {service.type} monitoring
+ {service.type} {t('monitoringSettingsType')}
diff --git a/application/src/components/services/UptimeBar.tsx b/application/src/components/services/UptimeBar.tsx
index 642e35e..7a85f05 100644
--- a/application/src/components/services/UptimeBar.tsx
+++ b/application/src/components/services/UptimeBar.tsx
@@ -5,6 +5,7 @@ import { TooltipProvider } from '@/components/ui/tooltip';
import { UptimeStatusItem } from './uptime/UptimeStatusItem';
import { uptimeService } from '@/services/uptimeService';
import { UptimeData } from '@/types/service.types';
+import {useLanguage} from "@/contexts/LanguageContext.tsx";
interface UptimeBarProps {
uptime: number;
@@ -15,6 +16,7 @@ interface UptimeBarProps {
}
const UptimeBarComponent = ({ uptime, status, serviceId, interval, serviceType = "HTTP" }: UptimeBarProps) => {
+ const { t } = useLanguage();
// Calculate date range for last 20 checks with much more aggressive caching
const endDate = useMemo(() => new Date(), []);
const startDate = useMemo(() => {
@@ -84,7 +86,7 @@ const UptimeBarComponent = ({ uptime, status, serviceId, interval, serviceType =
- Last 20 checks
+ {t('last20Checks')}
);
diff --git a/application/src/components/services/add-service/ServiceFormActions.tsx b/application/src/components/services/add-service/ServiceFormActions.tsx
index 4f6ad59..e9a5552 100644
--- a/application/src/components/services/add-service/ServiceFormActions.tsx
+++ b/application/src/components/services/add-service/ServiceFormActions.tsx
@@ -2,6 +2,7 @@
import { Button } from "@/components/ui/button";
import { Loader2 } from "lucide-react";
import { MouseEvent } from "react";
+import {useLanguage} from "@/contexts/LanguageContext.tsx";
interface ServiceFormActionsProps {
isSubmitting: boolean;
@@ -14,6 +15,8 @@ export function ServiceFormActions({
onCancel,
submitLabel = "Create Service"
}: ServiceFormActionsProps) {
+
+ const {t} = useLanguage();
const handleCancel = (e: MouseEvent) => {
e.preventDefault();
if (!isSubmitting) {
@@ -29,7 +32,7 @@ export function ServiceFormActions({
variant="outline"
disabled={isSubmitting}
>
- Cancel
+ {t("cancel")}
{
? 'text-green-700 dark:text-green-300'
: 'text-red-700 dark:text-red-300'
}`}>
- {importResult.created > 0 && `${importResult.created} collections created`}
- {importResult.updated > 0 && (importResult.created > 0 ? ', ' : '') + `${importResult.updated} collections updated`}
- {importResult.skipped > 0 && ((importResult.created > 0 || importResult.updated > 0) ? ', ' : '') + `${importResult.skipped} collections skipped`}
+ {importResult.created > 0 && t('collectionsCreatedCount').replace('{count}', String(importResult.created))}
+ {importResult.updated > 0 && (importResult.created > 0 ? ', ' : '') + t('collectionsUpdatedCount').replace('{count}', String(importResult.updated))}
+ {importResult.skipped > 0 && ((importResult.created > 0 || importResult.updated > 0) ? ', ' : '') + t('collectionsSkippedCount').replace('{count}', String(importResult.skipped))}
)}
- Instructions:
+ {t('instructions')}:
- - Merge fields: Safely add new fields to existing collections, preserves all data
- - System collections (starting with _) and users collection will be skipped automatically
- - Only authenticated admins can perform schema imports
+ - {t('mergeFields')}: {t('instructionsMergeFields')}
+ - {t('instructionsCollections')}
+ - {t('instructionsImportAuth')}
diff --git a/application/src/components/settings/alerts-templates/TemplateDialog.tsx b/application/src/components/settings/alerts-templates/TemplateDialog.tsx
index fb547d6..fc7f26a 100644
--- a/application/src/components/settings/alerts-templates/TemplateDialog.tsx
+++ b/application/src/components/settings/alerts-templates/TemplateDialog.tsx
@@ -16,6 +16,7 @@ import { ScrollArea } from "@/components/ui/scroll-area";
import { TemplateType, templateTypeConfigs } from "@/services/templateService";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Textarea } from "@/components/ui/textarea";
+import {z} from "zod";
interface TemplateDialogProps {
open: boolean;
@@ -81,6 +82,7 @@ export const TemplateDialog: React.FC
= ({
};
const renderPlaceholderGuide = () => {
+
const config = templateTypeConfigs[selectedTemplateType];
if (!config) return null;
diff --git a/application/src/components/settings/notification-settings/NotificationChannelDialog.tsx b/application/src/components/settings/notification-settings/NotificationChannelDialog.tsx
index 0b1d3e1..ef0591d 100644
--- a/application/src/components/settings/notification-settings/NotificationChannelDialog.tsx
+++ b/application/src/components/settings/notification-settings/NotificationChannelDialog.tsx
@@ -27,6 +27,7 @@ import { Switch } from "@/components/ui/switch";
import { Loader2, Copy } from "lucide-react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { toast } from "@/hooks/use-toast";
+import { useLanguage } from "@/contexts/LanguageContext";
interface NotificationChannelDialogProps {
open: boolean;
@@ -34,6 +35,7 @@ interface NotificationChannelDialogProps {
editingConfig: AlertConfiguration | null;
}
+
const baseSchema = z.object({
notify_name: z.string().min(1, "Name is required"),
notification_type: z.enum(["telegram", "discord", "slack", "signal", "google_chat", "email", "ntfy", "pushover", "notifiarr", "gotify", "webhook"]),
diff --git a/application/src/translations/en/about.ts b/application/src/translations/en/about.ts
index ef6ddcc..3e399ac 100644
--- a/application/src/translations/en/about.ts
+++ b/application/src/translations/en/about.ts
@@ -16,4 +16,19 @@ export const aboutTranslations: AboutTranslations = {
quickActionsDescription: "Access common monitoring operations and features quickly. Select an action below to get started.",
quickTips: "Quick Tips",
releasedOn: "Released On",
+ updateSchema: "Update Schema",
+ updateSchemaDesc: "Automatic import collections schema",
+ mergeFieldsLabel: "Merge fields with existing collections (safe - preserves data)",
+ importing: "Importing...",
+ clickToUpdateSchema: "Click to update Schema",
+ importSuccessful: "Import Successful",
+ importFailed: "Import Failed",
+ instructions: "Instructions",
+ mergeFields: "Merge fields",
+ instructionsMergeFields: "Safely add new fields to existing collections, preserves all data",
+ instructionsCollections: "System collections (starting with _) and users collection will be skipped automatically",
+ instructionsImportAuth: "Only authenticated admins can perform schema imports",
+ collectionsUpdatedCount: "{count} collections updated",
+ collectionsCreatedCount: "{count} collections created",
+ collectionsSkippedCount: "{count} collections created",
};
diff --git a/application/src/translations/en/services.ts b/application/src/translations/en/services.ts
index 3058a85..9204fe2 100644
--- a/application/src/translations/en/services.ts
+++ b/application/src/translations/en/services.ts
@@ -3,7 +3,6 @@ import { ServicesTranslations } from '../types/services';
export const servicesTranslations: ServicesTranslations = {
serviceStatus: "Service Status",
- responseTime: "Response Time",
uptime: "Uptime",
lastChecked: "Last Checked",
noServices: "No services match your filter criteria.",
@@ -95,4 +94,46 @@ export const servicesTranslations: ServicesTranslations = {
downServices: "DOWN SERVICES",
pausedServices: "PAUSED SERVICES",
warningServices: "WARNING SERVICES",
+
+ // ServiceRowActions.tsx
+ viewDetail: "View Detail",
+ resumeMonitoring: "Resume Monitoring",
+ pauseMonitoring: "Pause Monitoring",
+
+
+ //IncidentTable.tsx
+ responseTime: "Response Time",
+ errorMessage: "Error Message",
+ details: "Details",
+ unmuteAlerts: "Unmute Alerts",
+ muteAlerts: "Mute Alerts",
+
+ //LastCheckedTime.tsx
+ pausedAt: "Paused at ",
+ lastCheckDetails: "Last Check Details",
+ checkedAt: "Checked at ",
+ monitoringPaused: "Monitoring Paused",
+ noAutomaticChecks: "No automatic checks",
+
+ //ServiveEditDialog.tsx
+ editService: "Edit Service",
+ editServiceDesc: "Update the details of your monitored service.",
+
+ //ServiceStatsCards.tsx
+ lastCheckedAt: "Last checked at {datetime}",
+ avg: "Avg",
+ lastUpChecksCount: "last {count} up checks",
+ basedOnlastChecksCount: "Based on last {count} checks",
+ totalUptime: "Total Uptime",
+ totalDowntime: "Total Downtime",
+ monitoringSettings: "Monitoring Settings",
+ monitoringSettingsInterval: "Checked every {interval} seconds",
+ monitoringSettingsType: "monitoring",
+ upStatusDuration: "Up for {duration}",
+ downStatusDuration: "Down for {duration}",
+
+ incidentHistory: "Incident History",
+ processing: "Processing",
+ back: "Back",
+ last20Checks: "Last 20 checks",
};
\ No newline at end of file
diff --git a/application/src/translations/types/about.ts b/application/src/translations/types/about.ts
index 9d8a1f6..e2972c1 100644
--- a/application/src/translations/types/about.ts
+++ b/application/src/translations/types/about.ts
@@ -14,4 +14,19 @@ export interface AboutTranslations {
quickActionsDescription: string;
quickTips: string;
releasedOn: string;
+ updateSchema: string;
+ updateSchemaDesc: string;
+ mergeFieldsLabel: string;
+ importing: string;
+ clickToUpdateSchema: string;
+ importSuccessful: string;
+ importFailed: string;
+ instructions: string;
+ mergeFields: string;
+ instructionsMergeFields: string;
+ instructionsCollections: string;
+ instructionsImportAuth: string;
+ collectionsUpdatedCount: string;
+ collectionsCreatedCount: string;
+ collectionsSkippedCount: string;
}
diff --git a/application/src/translations/types/incident.ts b/application/src/translations/types/incident.ts
index 4ad5ccf..8df2f92 100644
--- a/application/src/translations/types/incident.ts
+++ b/application/src/translations/types/incident.ts
@@ -59,4 +59,5 @@ export interface IncidentTranslations {
affectedSystems: string;
enterAffectedSystems: string;
separateSystemsWithComma: string;
+
}
diff --git a/application/src/translations/types/services.ts b/application/src/translations/types/services.ts
index bd9e7a9..cda603a 100644
--- a/application/src/translations/types/services.ts
+++ b/application/src/translations/types/services.ts
@@ -2,7 +2,6 @@
export interface ServicesTranslations {
serviceStatus: string;
- responseTime: string;
uptime: string;
lastChecked: string;
noServices: string;
@@ -93,5 +92,46 @@ export interface ServicesTranslations {
upServices: string;
downServices: string;
pausedServices: string;
- warningServices: string;
+ warningServices: string;
+
+ // ServiceRowActions.tsx
+ viewDetail: string;
+ resumeMonitoring: string;
+ pauseMonitoring: string;
+ unmuteAlerts: string;
+ muteAlerts: string;
+
+ //IncidentTable.tsx
+ responseTime: string;
+ errorMessage: string;
+ details: string;
+
+ //LastCheckedTime.tsx
+ pausedAt: string;
+ lastCheckDetails: string;
+ checkedAt: string;
+ monitoringPaused: string;
+ noAutomaticChecks: string;
+
+ //ServiveEditDialog.tsx
+ editService: string;
+ editServiceDesc: string;
+
+ //ServiceStatsCards.tsx
+ lastCheckedAt: string;
+ avg: string;
+ lastUpChecksCount: string;
+ basedOnlastChecksCount: string;
+ totalUptime: string;
+ totalDowntime: string;
+ monitoringSettings: string;
+ monitoringSettingsInterval: string;
+ monitoringSettingsType: string;
+ upStatusDuration: string;
+ downStatusDuration: string;
+
+ incidentHistory: string;
+ processing: string;
+ back: string;
+ last20Checks: string;
}
diff --git a/application/src/translations/zhcn/about.ts b/application/src/translations/zhcn/about.ts
index f8eb611..5e0d3de 100644
--- a/application/src/translations/zhcn/about.ts
+++ b/application/src/translations/zhcn/about.ts
@@ -16,4 +16,19 @@ export const aboutTranslations: AboutTranslations = {
quickActionsDescription: "快速访问常用的监控操作和功能。选择下面的操作开始。",
quickTips: "快速提示",
releasedOn: "发布于",
+ updateSchema: "更新架构",
+ updateSchemaDesc: "自动导入集合架构",
+ mergeFieldsLabel: "合并字段到现有集合(安全 - 保留数据)",
+ importing: "导入中...",
+ clickToUpdateSchema: "点击更新架构",
+ importSuccessful: "导入成功",
+ importFailed: "导入失败",
+ instructions: "说明",
+ mergeFields: "合并字段",
+ instructionsMergeFields: "安全地向现有集合添加新字段,保留所有数据",
+ instructionsCollections: "系统集合(以_开头的)和用户集合将被自动跳过",
+ instructionsImportAuth: "只有经过身份验证的管理员才能执行架构导入",
+ collectionsUpdatedCount: "已更新 {count} 个集合",
+ collectionsCreatedCount: "已创建 {count} 个集合",
+ collectionsSkippedCount: "已跳过 {count} 个集合",
};
diff --git a/application/src/translations/zhcn/services.ts b/application/src/translations/zhcn/services.ts
index 4e9cc95..f7ba25a 100644
--- a/application/src/translations/zhcn/services.ts
+++ b/application/src/translations/zhcn/services.ts
@@ -3,7 +3,6 @@ import { ServicesTranslations } from '../types/services';
export const servicesTranslations: ServicesTranslations = {
serviceStatus: "服务状态",
- responseTime: "响应时间",
uptime: "在线时间",
lastChecked: "最后检查时间",
noServices: "没有符合您筛选条件的服务。",
@@ -95,4 +94,45 @@ export const servicesTranslations: ServicesTranslations = {
downServices: "下线服务",
pausedServices: "暂停服务",
warningServices: "告警服务",
+
+ // ServiceRowActions.tsx
+ viewDetail: "查看详情",
+ resumeMonitoring: "恢复监控",
+ pauseMonitoring: "暂停监控",
+ unmuteAlerts: "取消静音警报",
+ muteAlerts: "静音警报",
+
+ //IncidentTable.tsx
+ responseTime: "响应时间",
+ errorMessage: "错误信息",
+ details: "详情",
+
+ //LastCheckedTime.tsx
+ pausedAt: "暂停于 ",
+ lastCheckDetails: "最近检查详情",
+ checkedAt: "检查于 ",
+ monitoringPaused: "监控已暂停",
+ noAutomaticChecks: "无自动检查",
+
+ //ServiveEditDialog.tsx
+ editService: "编辑服务",
+ editServiceDesc: "更新您所监控服务的详细信息。",
+
+ //ServiceStatsCards.tsx
+ lastCheckedAt: "最新检查时间 {datetime}",
+ avg: "平均",
+ lastUpChecksCount: "最近 {count} 次检查",
+ basedOnlastChecksCount: "基于最近的 {count} 次检查",
+ totalUptime: "总在线时间",
+ totalDowntime: "总宕机时间",
+ monitoringSettings: "监控设置",
+ monitoringSettingsInterval: "每 {interval} 秒检查一次",
+ monitoringSettingsType: "监控",
+ upStatusDuration: "已在线 {duration}",
+ downStatusDuration: "已宕机 {duration}",
+
+ incidentHistory: "事件历史",
+ processing: "处理中",
+ back: "返回",
+ last20Checks: "最近 20 次检查",
};
\ No newline at end of file