fix: show OpenClaw in non-Chinese, 小龙虾 only in zh/zh_TW

Flutter app:
- app_zh.arb: OpenClaw → 小龙虾
- app_zh_TW.arb: OpenClaw → 小龍蝦
- app_en.arb: revert 小龙虾 back to OpenClaw

Web admin:
- Add serverPool/openclawInstances keys to en/zh sidebar.json
- en: "OpenClaw Instances", zh: "小龙虾实例"
- sidebar.tsx: use t() instead of hardcoded strings
- openclaw-instances + server-pool pages: use t('openclawInstances')

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
hailin 2026-03-08 01:48:25 -08:00
parent 0846452e8d
commit b666bed740
10 changed files with 40 additions and 32 deletions

View File

@ -5,6 +5,7 @@ import { useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { RefreshCw, Boxes, CheckCircle, AlertCircle, Clock, XCircle, StopCircle } from 'lucide-react'; import { RefreshCw, Boxes, CheckCircle, AlertCircle, Clock, XCircle, StopCircle } from 'lucide-react';
import { apiClient } from '@/infrastructure/api/api-client'; import { apiClient } from '@/infrastructure/api/api-client';
import { useTranslation } from 'react-i18next';
interface AgentInstance { interface AgentInstance {
id: string; id: string;
@ -60,6 +61,7 @@ function formatDate(iso: string) {
} }
export default function OpenClawInstancesPage() { export default function OpenClawInstancesPage() {
const { t } = useTranslation('sidebar');
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [statusFilter, setStatusFilter] = useState<AgentInstance['status'] | 'all'>('all'); const [statusFilter, setStatusFilter] = useState<AgentInstance['status'] | 'all'>('all');
@ -113,9 +115,9 @@ export default function OpenClawInstancesPage() {
{/* Header */} {/* Header */}
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h1 className="text-xl font-semibold text-foreground"></h1> <h1 className="text-xl font-semibold text-foreground">{t('openclawInstances')}</h1>
<p className="text-sm text-muted-foreground mt-0.5"> <p className="text-sm text-muted-foreground mt-0.5">
{t('openclawInstances')}
</p> </p>
</div> </div>
<button <button

View File

@ -4,6 +4,7 @@ import { useState } from 'react';
import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query';
import { toast } from 'sonner'; import { toast } from 'sonner';
import { RefreshCw, Plus, Trash2, Pencil, Server, CheckCircle, AlertCircle, WrenchIcon } from 'lucide-react'; import { RefreshCw, Plus, Trash2, Pencil, Server, CheckCircle, AlertCircle, WrenchIcon } from 'lucide-react';
import { useTranslation } from 'react-i18next';
interface PoolServer { interface PoolServer {
id: string; id: string;
@ -193,6 +194,7 @@ function ServerModal({
// ── Page ──────────────────────────────────────────────────────────────────── // ── Page ────────────────────────────────────────────────────────────────────
export default function ServerPoolPage() { export default function ServerPoolPage() {
const { t } = useTranslation('sidebar');
const queryClient = useQueryClient(); const queryClient = useQueryClient();
const [showModal, setShowModal] = useState(false); const [showModal, setShowModal] = useState(false);
const [editingServer, setEditingServer] = useState<PoolServer | undefined>(); const [editingServer, setEditingServer] = useState<PoolServer | undefined>();
@ -234,7 +236,7 @@ export default function ServerPoolPage() {
<div> <div>
<h1 className="text-xl font-semibold text-foreground"></h1> <h1 className="text-xl font-semibold text-foreground"></h1>
<p className="text-sm text-muted-foreground mt-0.5"> <p className="text-sm text-muted-foreground mt-0.5">
/ {t('openclawInstances')}/
</p> </p>
</div> </div>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@ -285,7 +287,7 @@ export default function ServerPoolPage() {
{servers.length === 0 ? ( {servers.length === 0 ? (
<div className="bg-card rounded-lg border p-12 text-center"> <div className="bg-card rounded-lg border p-12 text-center">
<Server className="w-10 h-10 text-muted-foreground mx-auto mb-3" /> <Server className="w-10 h-10 text-muted-foreground mx-auto mb-3" />
<p className="text-muted-foreground text-sm mb-4"></p> <p className="text-muted-foreground text-sm mb-4">{t('openclawInstances')}</p>
<button onClick={() => setShowModal(true)} className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:bg-primary/90"> <button onClick={() => setShowModal(true)} className="px-4 py-2 rounded-md text-sm bg-primary text-primary-foreground hover:bg-primary/90">
</button> </button>

View File

@ -41,5 +41,7 @@
"tenants": "Tenants", "tenants": "Tenants",
"users": "Users", "users": "Users",
"settings": "Settings", "settings": "Settings",
"collapse": "Collapse" "collapse": "Collapse",
"serverPool": "Server Pool",
"openclawInstances": "OpenClaw Instances"
} }

View File

@ -41,5 +41,7 @@
"tenants": "租户", "tenants": "租户",
"users": "用户", "users": "用户",
"settings": "设置", "settings": "设置",
"collapse": "折叠" "collapse": "折叠",
"serverPool": "服务器池",
"openclawInstances": "小龙虾实例"
} }

View File

@ -122,8 +122,8 @@ export function Sidebar() {
{ key: 'campaigns', label: t('campaigns'), href: '/campaigns', icon: <Megaphone className={iconClass} /> }, { key: 'campaigns', label: t('campaigns'), href: '/campaigns', icon: <Megaphone className={iconClass} /> },
{ key: 'segments', label: t('segments'), href: '/segments', icon: <Users2 className={iconClass} /> }, { key: 'segments', label: t('segments'), href: '/segments', icon: <Users2 className={iconClass} /> },
{ key: 'notifications', label: t('notifications'), href: '/notifications', icon: <Bell className={iconClass} /> }, { key: 'notifications', label: t('notifications'), href: '/notifications', icon: <Bell className={iconClass} /> },
{ key: 'serverPool', label: '服务器池', href: '/server-pool', icon: <Database className={iconClass} /> }, { key: 'serverPool', label: t('serverPool'), href: '/server-pool', icon: <Database className={iconClass} /> },
{ key: 'openclawInstances', label: '小龙虾实例', href: '/openclaw-instances', icon: <Boxes className={iconClass} /> }, { key: 'openclawInstances', label: t('openclawInstances'), href: '/openclaw-instances', icon: <Boxes className={iconClass} /> },
{ {
key: 'billing', key: 'billing',
label: t('billing'), label: t('billing'),

View File

@ -48,20 +48,20 @@
"officialAgent3Desc": "Slow query analysis, index optimization, backup verification", "officialAgent3Desc": "Slow query analysis, index optimization, backup verification",
"noOwnAgentsTitle": "No agents yet", "noOwnAgentsTitle": "No agents yet",
"noOwnAgentsDesc": "Tap the robot button below and tell iAgent:\n\"Recruit a 小龙虾 agent for me\"", "noOwnAgentsDesc": "Tap the robot button below and tell iAgent:\n\"Recruit an OpenClaw agent for me\"",
"quickTipsHeader": "You can say...", "quickTipsHeader": "You can say...",
"quickTip1": "💬 \"Recruit an agent to monitor GitHub Actions\"", "quickTip1": "💬 \"Recruit an agent to monitor GitHub Actions\"",
"quickTip2": "🔧 \"Export my 小龙虾 config as JSON\"", "quickTip2": "🔧 \"Export my OpenClaw config as JSON\"",
"quickTip3": "📊 \"Analyze server load for the past 7 days\"", "quickTip3": "📊 \"Analyze server load for the past 7 days\"",
"quickTip4": "🛡️ \"Set up automatic database backup at 2AM daily\"", "quickTip4": "🛡️ \"Set up automatic database backup at 2AM daily\"",
"myAgentsTitle": "My Agents", "myAgentsTitle": "My Agents",
"myAgentsEmptyTitle": "Recruit your own agent", "myAgentsEmptyTitle": "Recruit your own agent",
"myAgentsEmptyDesc": "Chat with iAgent to recruit various agents:\n小龙虾 coding assistant, ops bot, data analyst...", "myAgentsEmptyDesc": "Chat with iAgent to recruit various agents:\nOpenClaw coding assistant, ops bot, data analyst...",
"myAgentsStep1Title": "Tap the robot button", "myAgentsStep1Title": "Tap the robot button",
"myAgentsStep1Desc": "Open a conversation with iAgent", "myAgentsStep1Desc": "Open a conversation with iAgent",
"myAgentsStep2Title": "Describe the agent you want", "myAgentsStep2Title": "Describe the agent you want",
"myAgentsStep2Desc": "e.g. \"Recruit a 小龙虾 coding assistant for me\"", "myAgentsStep2Desc": "e.g. \"Recruit an OpenClaw coding assistant for me\"",
"myAgentsStep3Title": "iAgent auto-deploys", "myAgentsStep3Title": "iAgent auto-deploys",
"myAgentsStep3Desc": "It appears here after deployment. Chat via Telegram/WhatsApp.", "myAgentsStep3Desc": "It appears here after deployment. Chat via Telegram/WhatsApp.",
"myAgentsTemplatesHeader": "Popular templates (tell iAgent which one you want)", "myAgentsTemplatesHeader": "Popular templates (tell iAgent which one you want)",

View File

@ -120,7 +120,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get noOwnAgentsDesc => String get noOwnAgentsDesc =>
'Tap the robot button below and tell iAgent:\n\"Recruit a 小龙虾 agent for me\"'; 'Tap the robot button below and tell iAgent:\n\"Recruit an OpenClaw agent for me\"';
@override @override
String get quickTipsHeader => 'You can say...'; String get quickTipsHeader => 'You can say...';
@ -129,7 +129,7 @@ class AppLocalizationsEn extends AppLocalizations {
String get quickTip1 => '💬 \"Recruit an agent to monitor GitHub Actions\"'; String get quickTip1 => '💬 \"Recruit an agent to monitor GitHub Actions\"';
@override @override
String get quickTip2 => '🔧 \"Export my 小龙虾 config as JSON\"'; String get quickTip2 => '🔧 \"Export my OpenClaw config as JSON\"';
@override @override
String get quickTip3 => '📊 \"Analyze server load for the past 7 days\"'; String get quickTip3 => '📊 \"Analyze server load for the past 7 days\"';
@ -146,7 +146,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get myAgentsEmptyDesc => String get myAgentsEmptyDesc =>
'Chat with iAgent to recruit various agents:\n小龙虾 coding assistant, ops bot, data analyst...'; 'Chat with iAgent to recruit various agents:\nOpenClaw coding assistant, ops bot, data analyst...';
@override @override
String get myAgentsStep1Title => 'Tap the robot button'; String get myAgentsStep1Title => 'Tap the robot button';
@ -159,7 +159,7 @@ class AppLocalizationsEn extends AppLocalizations {
@override @override
String get myAgentsStep2Desc => String get myAgentsStep2Desc =>
'e.g. \"Recruit a 小龙虾 coding assistant for me\"'; 'e.g. \"Recruit an OpenClaw coding assistant for me\"';
@override @override
String get myAgentsStep3Title => 'iAgent auto-deploys'; String get myAgentsStep3Title => 'iAgent auto-deploys';

View File

@ -116,7 +116,7 @@ class AppLocalizationsZh extends AppLocalizations {
String get noOwnAgentsTitle => '还没有自己的智能体'; String get noOwnAgentsTitle => '还没有自己的智能体';
@override @override
String get noOwnAgentsDesc => '点击下方机器人按钮,告诉 我智能体\n\"帮我招募一个 OpenClaw 智能体\"'; String get noOwnAgentsDesc => '点击下方机器人按钮,告诉 我智能体\n\"帮我招募一个 小龙虾 智能体\"';
@override @override
String get quickTipsHeader => '你可以这样说...'; String get quickTipsHeader => '你可以这样说...';
@ -125,7 +125,7 @@ class AppLocalizationsZh extends AppLocalizations {
String get quickTip1 => '💬 \"帮我招募一个监控 GitHub Actions 的智能体\"'; String get quickTip1 => '💬 \"帮我招募一个监控 GitHub Actions 的智能体\"';
@override @override
String get quickTip2 => '🔧 \"把我的 OpenClaw 配置导出为 JSON\"'; String get quickTip2 => '🔧 \"把我的 小龙虾 配置导出为 JSON\"';
@override @override
String get quickTip3 => '📊 \"分析我的服务器最近7天的负载情况\"'; String get quickTip3 => '📊 \"分析我的服务器最近7天的负载情况\"';
@ -141,7 +141,7 @@ class AppLocalizationsZh extends AppLocalizations {
@override @override
String get myAgentsEmptyDesc => String get myAgentsEmptyDesc =>
'通过与 我智能体 对话,你可以招募各种智能体:\nOpenClaw 编程助手、运维机器人、数据分析师...'; '通过与 我智能体 对话,你可以招募各种智能体:\n小龙虾 编程助手、运维机器人、数据分析师...';
@override @override
String get myAgentsStep1Title => '点击下方机器人'; String get myAgentsStep1Title => '点击下方机器人';
@ -153,7 +153,7 @@ class AppLocalizationsZh extends AppLocalizations {
String get myAgentsStep2Title => '描述你想要的智能体'; String get myAgentsStep2Title => '描述你想要的智能体';
@override @override
String get myAgentsStep2Desc => '例如:\"帮我招募一个 OpenClaw 编程助手\"'; String get myAgentsStep2Desc => '例如:\"帮我招募一个 小龙虾 编程助手\"';
@override @override
String get myAgentsStep3Title => '我智能体 自动部署'; String get myAgentsStep3Title => '我智能体 自动部署';
@ -1139,7 +1139,7 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
String get noOwnAgentsTitle => '還沒有自己的智能體'; String get noOwnAgentsTitle => '還沒有自己的智能體';
@override @override
String get noOwnAgentsDesc => '點擊下方機器人按鈕,告訴 我智能體\n\"幫我招募一個 OpenClaw 智能體\"'; String get noOwnAgentsDesc => '點擊下方機器人按鈕,告訴 我智能體\n\"幫我招募一個 小龍蝦 智能體\"';
@override @override
String get quickTipsHeader => '你可以這樣說...'; String get quickTipsHeader => '你可以這樣說...';
@ -1148,7 +1148,7 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
String get quickTip1 => '💬 \"幫我招募一個監控 GitHub Actions 的智能體\"'; String get quickTip1 => '💬 \"幫我招募一個監控 GitHub Actions 的智能體\"';
@override @override
String get quickTip2 => '🔧 \"把我的 OpenClaw 配置匯出為 JSON\"'; String get quickTip2 => '🔧 \"把我的 小龍蝦 配置匯出為 JSON\"';
@override @override
String get quickTip3 => '📊 \"分析我的伺服器最近7天的負載情況\"'; String get quickTip3 => '📊 \"分析我的伺服器最近7天的負載情況\"';
@ -1164,13 +1164,13 @@ class AppLocalizationsZhTw extends AppLocalizationsZh {
@override @override
String get myAgentsEmptyDesc => String get myAgentsEmptyDesc =>
'透過與 我智能體 對話,你可以招募各種智能體:\nOpenClaw 程式助手、運維機器人、資料分析師...'; '透過與 我智能體 對話,你可以招募各種智能體:\n小龍蝦 程式助手、運維機器人、資料分析師...';
@override @override
String get myAgentsStep1Desc => '打開與 我智能體 的對話視窗'; String get myAgentsStep1Desc => '打開與 我智能體 的對話視窗';
@override @override
String get myAgentsStep2Desc => '例如:\"幫我招募一個 OpenClaw 程式助手\"'; String get myAgentsStep2Desc => '例如:\"幫我招募一個 小龍蝦 程式助手\"';
@override @override
String get myAgentsStep3Title => '我智能體 自動部署'; String get myAgentsStep3Title => '我智能體 自動部署';

View File

@ -48,20 +48,20 @@
"officialAgent3Desc": "慢查询分析、索引优化、备份验证", "officialAgent3Desc": "慢查询分析、索引优化、备份验证",
"noOwnAgentsTitle": "还没有自己的智能体", "noOwnAgentsTitle": "还没有自己的智能体",
"noOwnAgentsDesc": "点击下方机器人按钮,告诉 我智能体\n\"帮我招募一个 OpenClaw 智能体\"", "noOwnAgentsDesc": "点击下方机器人按钮,告诉 我智能体\n\"帮我招募一个 小龙虾 智能体\"",
"quickTipsHeader": "你可以这样说...", "quickTipsHeader": "你可以这样说...",
"quickTip1": "💬 \"帮我招募一个监控 GitHub Actions 的智能体\"", "quickTip1": "💬 \"帮我招募一个监控 GitHub Actions 的智能体\"",
"quickTip2": "🔧 \"把我的 OpenClaw 配置导出为 JSON\"", "quickTip2": "🔧 \"把我的 小龙虾 配置导出为 JSON\"",
"quickTip3": "📊 \"分析我的服务器最近7天的负载情况\"", "quickTip3": "📊 \"分析我的服务器最近7天的负载情况\"",
"quickTip4": "🛡️ \"帮我设置每天凌晨2点自动备份数据库\"", "quickTip4": "🛡️ \"帮我设置每天凌晨2点自动备份数据库\"",
"myAgentsTitle": "我的智能体", "myAgentsTitle": "我的智能体",
"myAgentsEmptyTitle": "招募你的专属智能体", "myAgentsEmptyTitle": "招募你的专属智能体",
"myAgentsEmptyDesc": "通过与 我智能体 对话,你可以招募各种智能体:\nOpenClaw 编程助手、运维机器人、数据分析师...", "myAgentsEmptyDesc": "通过与 我智能体 对话,你可以招募各种智能体:\n小龙虾 编程助手、运维机器人、数据分析师...",
"myAgentsStep1Title": "点击下方机器人", "myAgentsStep1Title": "点击下方机器人",
"myAgentsStep1Desc": "打开与 我智能体 的对话窗口", "myAgentsStep1Desc": "打开与 我智能体 的对话窗口",
"myAgentsStep2Title": "描述你想要的智能体", "myAgentsStep2Title": "描述你想要的智能体",
"myAgentsStep2Desc": "例如:\"帮我招募一个 OpenClaw 编程助手\"", "myAgentsStep2Desc": "例如:\"帮我招募一个 小龙虾 编程助手\"",
"myAgentsStep3Title": "我智能体 自动部署", "myAgentsStep3Title": "我智能体 自动部署",
"myAgentsStep3Desc": "部署完成后出现在这里,通过 Telegram/WhatsApp 等渠道与它对话", "myAgentsStep3Desc": "部署完成后出现在这里,通过 Telegram/WhatsApp 等渠道与它对话",
"myAgentsTemplatesHeader": "热门模板(告诉 我智能体 你想要哪种)", "myAgentsTemplatesHeader": "热门模板(告诉 我智能体 你想要哪种)",

View File

@ -11,18 +11,18 @@
"officialAgent1Desc": "伺服器管理、SSH 執行、日誌分析", "officialAgent1Desc": "伺服器管理、SSH 執行、日誌分析",
"myAgentsSection": "我的智能體", "myAgentsSection": "我的智能體",
"noOwnAgentsTitle": "還沒有自己的智能體", "noOwnAgentsTitle": "還沒有自己的智能體",
"noOwnAgentsDesc": "點擊下方機器人按鈕,告訴 我智能體\n\"幫我招募一個 OpenClaw 智能體\"", "noOwnAgentsDesc": "點擊下方機器人按鈕,告訴 我智能體\n\"幫我招募一個 小龍蝦 智能體\"",
"quickTipsHeader": "你可以這樣說...", "quickTipsHeader": "你可以這樣說...",
"quickTip1": "💬 \"幫我招募一個監控 GitHub Actions 的智能體\"", "quickTip1": "💬 \"幫我招募一個監控 GitHub Actions 的智能體\"",
"quickTip2": "🔧 \"把我的 OpenClaw 配置匯出為 JSON\"", "quickTip2": "🔧 \"把我的 小龍蝦 配置匯出為 JSON\"",
"quickTip3": "📊 \"分析我的伺服器最近7天的負載情況\"", "quickTip3": "📊 \"分析我的伺服器最近7天的負載情況\"",
"quickTip4": "🛡️ \"幫我設置每天凌晨2點自動備份資料庫\"", "quickTip4": "🛡️ \"幫我設置每天凌晨2點自動備份資料庫\"",
"myAgentsTitle": "我的智能體", "myAgentsTitle": "我的智能體",
"myAgentsEmptyTitle": "招募你的專屬智能體", "myAgentsEmptyTitle": "招募你的專屬智能體",
"myAgentsEmptyDesc": "透過與 我智能體 對話,你可以招募各種智能體:\nOpenClaw 程式助手、運維機器人、資料分析師...", "myAgentsEmptyDesc": "透過與 我智能體 對話,你可以招募各種智能體:\n小龍蝦 程式助手、運維機器人、資料分析師...",
"myAgentsStep1Desc": "打開與 我智能體 的對話視窗", "myAgentsStep1Desc": "打開與 我智能體 的對話視窗",
"myAgentsStep2Desc": "例如:\"幫我招募一個 OpenClaw 程式助手\"", "myAgentsStep2Desc": "例如:\"幫我招募一個 小龍蝦 程式助手\"",
"myAgentsStep3Title": "我智能體 自動部署", "myAgentsStep3Title": "我智能體 自動部署",
"myAgentsStep3Desc": "部署完成後出現在這裡,透過 Telegram/WhatsApp 等渠道與它對話", "myAgentsStep3Desc": "部署完成後出現在這裡,透過 Telegram/WhatsApp 等渠道與它對話",
"myAgentsTemplatesHeader": "熱門模板(告訴 我智能體 你想要哪種)", "myAgentsTemplatesHeader": "熱門模板(告訴 我智能體 你想要哪種)",