feat(i18n): localize frontend components and add missing translations
- Replaced hardcoded UI strings with translation keys across frontend files - Added and updated English(en) and Khmer(km) translation files for settings, notifications, and server components - Improved localization and multi-language support throughout the frontend
This commit is contained in:
@@ -10,6 +10,7 @@ import { Copy, Download, Terminal, CheckCircle, Zap, Play } from "lucide-react";
|
||||
import { regionalService } from "@/services/regionalService";
|
||||
import { InstallCommand } from "@/types/regional.types";
|
||||
import { useToast } from "@/hooks/use-toast";
|
||||
import { useLanguage } from "@/contexts/LanguageContext";
|
||||
|
||||
interface AddRegionalAgentDialogProps {
|
||||
open: boolean;
|
||||
@@ -22,6 +23,7 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
onOpenChange,
|
||||
onAgentAdded
|
||||
}) => {
|
||||
const { t } = useLanguage();
|
||||
const [step, setStep] = useState(1);
|
||||
const [regionName, setRegionName] = useState("");
|
||||
const [agentIp, setAgentIp] = useState("");
|
||||
@@ -44,8 +46,8 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
setStep(2);
|
||||
} catch (error) {
|
||||
toast({
|
||||
title: "Error",
|
||||
description: "Failed to create regional agent configuration.",
|
||||
title: t('error'),
|
||||
description: t('failedToCreateAgent'),
|
||||
variant: "destructive",
|
||||
});
|
||||
} finally {
|
||||
@@ -59,7 +61,7 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
if (navigator.clipboard && window.isSecureContext) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
toast({
|
||||
title: "Copied!",
|
||||
title: t('copied'),
|
||||
description: `${description} copied to clipboard.`,
|
||||
});
|
||||
return;
|
||||
@@ -80,8 +82,9 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
|
||||
if (successful) {
|
||||
toast({
|
||||
title: "Copied!",
|
||||
title: t('copied'),
|
||||
description: `${description} copied to clipboard.`,
|
||||
//description: t('copiedDescription', { description }),
|
||||
});
|
||||
} else {
|
||||
throw new Error('execCommand failed');
|
||||
@@ -93,15 +96,15 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
const userAgent = navigator.userAgent.toLowerCase();
|
||||
const isLocalhost = window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1';
|
||||
|
||||
let errorMessage = "Failed to copy to clipboard.";
|
||||
let errorMessage = t('copyFailedDescription');
|
||||
if (isLocalhost) {
|
||||
errorMessage += " This is common in local development. Please manually copy the text.";
|
||||
errorMessage += " " + t('copyFailedLocalhost');
|
||||
} else if (userAgent.includes('chrome')) {
|
||||
errorMessage += " Try using HTTPS or enable clipboard permissions.";
|
||||
errorMessage += " " + t('copyFailedChrome');
|
||||
}
|
||||
|
||||
toast({
|
||||
title: "Copy failed",
|
||||
title: t('copyFailed'),
|
||||
description: errorMessage,
|
||||
variant: "destructive",
|
||||
});
|
||||
@@ -133,8 +136,8 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
URL.revokeObjectURL(url);
|
||||
|
||||
toast({
|
||||
title: "Downloaded!",
|
||||
description: "Installation script downloaded successfully.",
|
||||
title: t('downloaded'),
|
||||
description: t('downloadedDescription'),
|
||||
});
|
||||
};
|
||||
|
||||
@@ -158,9 +161,9 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="sm:max-w-[900px] max-h-[90vh] overflow-auto">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Add Regional Monitoring Agent</DialogTitle>
|
||||
<DialogTitle>{t('addRegionalMonitoringAgent')}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Deploy a regional monitoring agent with automatic one-click installation.
|
||||
{t('deployRegionalMonitoringAgent')}
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
@@ -168,10 +171,10 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
<form onSubmit={handleCreateAgent} className="space-y-6">
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="regionName">Region Name</Label>
|
||||
<Label htmlFor="regionName">{t('regionName')}</Label>
|
||||
<Input
|
||||
id="regionName"
|
||||
placeholder="e.g., us-east-1, europe-west-1, asia-pacific-1"
|
||||
placeholder={t('regionNamePlaceholder')}
|
||||
value={regionName}
|
||||
onChange={(e) => setRegionName(e.target.value)}
|
||||
required
|
||||
@@ -179,10 +182,10 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label htmlFor="agentIp">Agent Server IP Address</Label>
|
||||
<Label htmlFor="agentIp">{t('agentServerIpAddress')}</Label>
|
||||
<Input
|
||||
id="agentIp"
|
||||
placeholder="e.g., 192.168.1.100 or your-server.example.com"
|
||||
placeholder={t('agentIpPlaceholder')}
|
||||
value={agentIp}
|
||||
onChange={(e) => setAgentIp(e.target.value)}
|
||||
required
|
||||
@@ -192,10 +195,10 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
|
||||
<div className="flex justify-end space-x-2">
|
||||
<Button type="button" variant="outline" onClick={() => onOpenChange(false)}>
|
||||
Cancel
|
||||
{t('cancel')}
|
||||
</Button>
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
{isSubmitting ? "Generating..." : "Generate Installation"}
|
||||
{isSubmitting ? t('generating') : t('generateInstallation')}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
@@ -205,17 +208,17 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
<div className="space-y-6">
|
||||
<div className="text-center space-y-2">
|
||||
<CheckCircle className="h-12 w-12 text-green-600 mx-auto" />
|
||||
<h3 className="text-lg font-semibold">Agent Configuration Ready!</h3>
|
||||
<h3 className="text-lg font-semibold">{t('agentConfigurationReady')}</h3>
|
||||
<p className="text-muted-foreground">
|
||||
One-click installation script generated with automatic configuration.
|
||||
{t('oneClickInstallScriptGenerated')}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<Tabs defaultValue="oneclicK" className="w-full">
|
||||
<TabsList className="grid w-full grid-cols-3">
|
||||
<TabsTrigger value="oneclicK">One-Click Install</TabsTrigger>
|
||||
<TabsTrigger value="details">Agent Details</TabsTrigger>
|
||||
<TabsTrigger value="manual">Manual Install</TabsTrigger>
|
||||
<TabsTrigger value="oneclicK">{t('oneClickInstallTab')}</TabsTrigger>
|
||||
<TabsTrigger value="details">{t('agentDetailsTab')}</TabsTrigger>
|
||||
<TabsTrigger value="manual">{t('manualInstallTab')}</TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
<TabsContent value="oneclicK" className="space-y-4">
|
||||
@@ -223,29 +226,29 @@ export const AddRegionalAgentDialog: React.FC<AddRegionalAgentDialogProps> = ({
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Zap className="h-5 w-5 text-yellow-500" />
|
||||
One-Click Automatic Installation
|
||||
{t('oneClickAutomaticInstallation')}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Complete installation, configuration, and service startup in one command
|
||||
{t('completeInstallationDescription')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="bg-green-50 border border-green-200 rounded-lg p-4">
|
||||
<div className="flex items-center gap-2 text-green-800 font-medium mb-2">
|
||||
<Play className="h-4 w-4" />
|
||||
What this script does automatically:
|
||||
{t('whatThisScriptDoes')}
|
||||
</div>
|
||||
<ul className="text-sm text-green-700 space-y-1 ml-6">
|
||||
<li>• Downloads the latest .deb package</li>
|
||||
<li>• Installs the regional monitoring agent</li>
|
||||
<li>• Creates configuration file with your settings</li>
|
||||
<li>• Starts and enables the service</li>
|
||||
<li>• Runs health checks</li>
|
||||
<li>• {t('scriptActionDownload')}</li>
|
||||
<li>• {t('scriptActionInstall')}</li>
|
||||
<li>• {t('scriptActionConfigure')}</li>
|
||||
<li>• {t('scriptActionStart')}</li>
|
||||
<li>• {t('scriptActionHealthChecks')}</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label>Run this command on your target server:</Label>
|
||||
<Label>{t('runCommandOnServer')}</Label>
|
||||
<div className="relative">
|
||||
<Textarea
|
||||
readOnly
|
||||
@@ -272,7 +275,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
<div className="flex gap-2">
|
||||
<Button onClick={downloadScript} variant="outline" className="flex-1">
|
||||
<Download className="mr-2 h-4 w-4" />
|
||||
Download Complete Script
|
||||
{t('downloadCompleteScript')}
|
||||
</Button>
|
||||
<Button
|
||||
onClick={() => copyToClipboard(installCommand.bash_script, "Installation script")}
|
||||
@@ -280,17 +283,14 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
className="flex-1"
|
||||
>
|
||||
<Copy className="mr-2 h-4 w-4" />
|
||||
Copy Full Script
|
||||
{t('copyFullScript')}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Local development notice */}
|
||||
{(window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') && (
|
||||
<div className="bg-yellow-50 border border-yellow-200 rounded-lg p-3">
|
||||
<p className="text-sm text-yellow-800">
|
||||
<strong>Local Development Notice:</strong> If clipboard copying fails, this is normal in local development.
|
||||
You can use the "Download Complete Script" button instead or manually copy the text.
|
||||
</p>
|
||||
<p className="text-sm text-yellow-800" dangerouslySetInnerHTML={{ __html: t('localDevelopmentNotice') }} />
|
||||
</div>
|
||||
)}
|
||||
</CardContent>
|
||||
@@ -300,15 +300,15 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
<TabsContent value="details" className="space-y-4">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Generated Agent Configuration</CardTitle>
|
||||
<CardTitle>{t('generatedAgentConfiguration')}</CardTitle>
|
||||
<CardDescription>
|
||||
These values will be automatically configured during installation
|
||||
{t('autoConfiguredDuringInstallation')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-3">
|
||||
<div className="grid grid-cols-2 gap-4">
|
||||
<div>
|
||||
<Label className="text-sm font-medium text-foreground">Agent ID</Label>
|
||||
<Label className="text-sm font-medium text-foreground">{t('agentId')}</Label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
value={installCommand.agent_id}
|
||||
@@ -319,14 +319,14 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="absolute right-1 top-1/2 -translate-y-1/2 h-8 w-8 p-0 hover:bg-muted"
|
||||
onClick={() => copyToClipboard(installCommand.agent_id, "Agent ID")}
|
||||
onClick={() => copyToClipboard(installCommand.agent_id, t('agentId'))}
|
||||
>
|
||||
<Copy className="h-3 w-3" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-medium text-foreground">Region Name</Label>
|
||||
<Label className="text-sm font-medium text-foreground">{t('regionNameDetail')}</Label>
|
||||
<Input
|
||||
value={regionName}
|
||||
readOnly
|
||||
@@ -334,7 +334,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-medium text-foreground">Server IP</Label>
|
||||
<Label className="text-sm font-medium text-foreground">{t('serverIp')}</Label>
|
||||
<Input
|
||||
value={agentIp}
|
||||
readOnly
|
||||
@@ -342,7 +342,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm font-medium text-foreground">API Endpoint</Label>
|
||||
<Label className="text-sm font-medium text-foreground">{t('apiEndpoint')}</Label>
|
||||
<Input
|
||||
value={installCommand.api_endpoint}
|
||||
readOnly
|
||||
@@ -352,7 +352,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Label className="text-sm font-medium text-foreground">Authentication Token</Label>
|
||||
<Label className="text-sm font-medium text-foreground">{t('authenticationToken')}</Label>
|
||||
<div className="relative">
|
||||
<Input
|
||||
value={installCommand.token}
|
||||
@@ -363,7 +363,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
size="sm"
|
||||
variant="ghost"
|
||||
className="absolute right-1 top-1/2 -translate-y-1/2 h-8 w-8 p-0 hover:bg-muted"
|
||||
onClick={() => copyToClipboard(installCommand.token, "Authentication token")}
|
||||
onClick={() => copyToClipboard(installCommand.token, t('authenticationToken'))}
|
||||
>
|
||||
<Copy className="h-3 w-3" />
|
||||
</Button>
|
||||
@@ -371,9 +371,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
</div>
|
||||
|
||||
<div className="mt-4 p-3 bg-blue-50 border border-blue-200 rounded-lg">
|
||||
<p className="text-sm text-blue-800">
|
||||
<strong>Configuration file location:</strong> /etc/regional-check-agent/regional-check-agent.env
|
||||
</p>
|
||||
<p className="text-sm text-blue-800" dangerouslySetInnerHTML={{ __html: t('configurationFileLocation') }} />
|
||||
</div>
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -384,28 +382,30 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center gap-2">
|
||||
<Terminal className="h-5 w-5" />
|
||||
Manual Installation Steps
|
||||
{t('manualInstallationSteps')}
|
||||
</CardTitle>
|
||||
<CardDescription>
|
||||
Step-by-step manual installation process
|
||||
{t('stepByStepManualInstallation')}
|
||||
</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="space-y-4">
|
||||
<div className="text-sm space-y-4">
|
||||
<div className="border-l-4 border-blue-500 pl-4">
|
||||
<p className="font-medium">Step 1: Download Package</p>
|
||||
<p className="font-medium">{t('step1DownloadPackage')}</p>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
<p className="text-xs text-muted-foreground mt-1">✅ If you’re using the amd64 architecture, please download this package. </p> <br/>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t('downloadAmd64Notice')}</p>
|
||||
<br/>
|
||||
wget https://github.com/operacle/Distributed-Regional-Monitoring/releases/download/V1.0.0/distributed-regional-check-agent_1.0.0_amd64.deb
|
||||
</code>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
<p className="text-xs text-muted-foreground mt-1">✅ If you’re using the arm64 architecture, please download this package. </p> <br/>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t('downloadArm64Notice')}</p>
|
||||
<br/>
|
||||
wget https://github.com/operacle/Distributed-Regional-Monitoring/releases/download/V1.0.0/distributed-regional-check-agent_1.0.0_arm64.deb
|
||||
</code>
|
||||
</div>
|
||||
|
||||
<div className="border-l-4 border-blue-500 pl-4">
|
||||
<p className="font-medium">Step 2: Install Package</p>
|
||||
<p className="font-medium">{t('step2InstallPackage')}</p>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
sudo dpkg -i distributed-regional-check-agent_1.0.0_amd64.deb<br/>
|
||||
sudo apt-get install -f
|
||||
@@ -413,18 +413,18 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
</div>
|
||||
|
||||
<div className="border-l-4 border-blue-500 pl-4">
|
||||
<p className="font-medium">Step 3: Configure Agent</p>
|
||||
<p className="font-medium">{t('step3ConfigureAgent')}</p>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
sudo nano /etc/regional-check-agent/regional-check-agent.env
|
||||
</code>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
Copy sample configuration from https://github.com/operacle/Distributed-Regional-Monitoring/blob/main/packaging/regional-check-agent.conf
|
||||
{t('copySampleConfiguration')}
|
||||
</code>
|
||||
<p className="text-xs text-muted-foreground mt-1">Add the configuration values shown in the Agent Details tab</p>
|
||||
<p className="text-xs text-muted-foreground mt-1">{t('addConfigurationValues')}</p>
|
||||
</div>
|
||||
|
||||
<div className="border-l-4 border-blue-500 pl-4">
|
||||
<p className="font-medium">Step 4: Start Service</p>
|
||||
<p className="font-medium">{t('step4StartService')}</p>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
sudo systemctl enable regional-check-agent<br/>
|
||||
sudo systemctl start regional-check-agent
|
||||
@@ -432,7 +432,7 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
</div>
|
||||
|
||||
<div className="border-l-4 border-green-500 pl-4">
|
||||
<p className="font-medium">Step 5: Verify Installation</p>
|
||||
<p className="font-medium">{t('step5VerifyInstallation')}</p>
|
||||
<code className="text-xs bg-muted p-2 rounded block mt-1">
|
||||
sudo systemctl status regional-check-agent<br/>
|
||||
curl http://localhost:8091/health
|
||||
@@ -446,10 +446,10 @@ curl -fsSL https://raw.githubusercontent.com/operacle/checkcle/refs/heads/main/s
|
||||
|
||||
<div className="flex justify-end space-x-2">
|
||||
<Button variant="outline" onClick={resetDialog}>
|
||||
Add Another Agent
|
||||
{t('addAnotherAgent')}
|
||||
</Button>
|
||||
<Button onClick={handleComplete}>
|
||||
Complete Setup
|
||||
{t('completeSetup')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user