i18n: add English support for landing page editor modal

This commit is contained in:
haorwen
2026-06-26 22:28:04 +08:00
parent 0f1bbf852c
commit bda648682b
10 changed files with 185 additions and 13 deletions
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Zum Senden anmelden", "sign_in_tip": "Zum Senden anmelden",
"vocespace": " VoceSpace Videoanruf", "vocespace": " VoceSpace Videoanruf",
"license": "VoceChat Upgrade-Lizenz", "license": "VoceChat Upgrade-Lizenz",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "VoceChat-Einrichtung", "title": "VoceChat-Einrichtung",
"welcome": "Willkommen bei VoceChat!", "welcome": "Willkommen bei VoceChat!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Please sign in to send message", "sign_in_tip": "Please sign in to send message",
"vocespace": "VoceSpace Video Call", "vocespace": "VoceSpace Video Call",
"license": "VoceChat Upgrade License", "license": "VoceChat Upgrade License",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "VoceChat Setup", "title": "VoceChat Setup",
"welcome": "Welcome to your VoceChat!", "welcome": "Welcome to your VoceChat!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Por favor, inicia sesión para enviar mensajes", "sign_in_tip": "Por favor, inicia sesión para enviar mensajes",
"vocespace": "Llamada de video VoceSpace", "vocespace": "Llamada de video VoceSpace",
"license": "VoceChat Licencia de Actualización", "license": "VoceChat Licencia de Actualización",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "Configuración de VoceChat", "title": "Configuración de VoceChat",
"welcome": "¡Bienvenido a tu VoceChat!", "welcome": "¡Bienvenido a tu VoceChat!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Veuillez vous connecter pour envoyer un message", "sign_in_tip": "Veuillez vous connecter pour envoyer un message",
"vocespace": "Appel Vidéo VoceSpace", "vocespace": "Appel Vidéo VoceSpace",
"license": "VoceChat Licence de Mise à Niveau", "license": "VoceChat Licence de Mise à Niveau",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "Configuration de VoceChat", "title": "Configuration de VoceChat",
"welcome": "Bienvenue dans votre VoceChat !", "welcome": "Bienvenue dans votre VoceChat !",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Please sign in to send message", "sign_in_tip": "Please sign in to send message",
"vocespace": " VoceSpace ビデオ通話", "vocespace": " VoceSpace ビデオ通話",
"license": "VoceChat アップグレードライセンス", "license": "VoceChat アップグレードライセンス",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "VoceChat初期化", "title": "VoceChat初期化",
"welcome": "あなたのVoceChatへようこそ!", "welcome": "あなたのVoceChatへようこそ!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Faça login para enviar mensagem", "sign_in_tip": "Faça login para enviar mensagem",
"vocespace": "Chamada de vídeo VoceSpace", "vocespace": "Chamada de vídeo VoceSpace",
"license": "VoceChat Licença de Atualização", "license": "VoceChat Licença de Atualização",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "Configuração do VoceChat", "title": "Configuração do VoceChat",
"welcome": "Bem-vindo ao seu VoceChat!", "welcome": "Bem-vindo ao seu VoceChat!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "Пожалуйста, войдите, чтобы отправить сообщение", "sign_in_tip": "Пожалуйста, войдите, чтобы отправить сообщение",
"vocespace": "Видеозвонок VoceSpace", "vocespace": "Видеозвонок VoceSpace",
"license": "VoceChat Лицензия на обновление", "license": "VoceChat Лицензия на обновление",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "Настройка VoceChat", "title": "Настройка VoceChat",
"welcome": "Добро пожаловать в ваш VoceChat!", "welcome": "Добро пожаловать в ваш VoceChat!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "İleti göndermek için lütfen oturum açın", "sign_in_tip": "İleti göndermek için lütfen oturum açın",
"vocespace": " VoceSpace Video Görüşmesi", "vocespace": " VoceSpace Video Görüşmesi",
"license": "VoceChat Yükseltme Lisansı", "license": "VoceChat Yükseltme Lisansı",
"page_editor": {
"title": "Page Management",
"status_select": "Select State",
"signed_in": "Signed In",
"not_signed_in": "Visitors",
"signed_in_users": "Signed-in Users",
"not_signed_in_users": "Visitors",
"current_state": "Current State:",
"download_html": "Download Page HTML",
"upload_html": "Upload Custom HTML Page",
"uploading": "Uploading…",
"reset": "Reset to Default",
"resetting": "Resetting…",
"ai_tip": "Want to use an AI agent to automatically write your homepage?",
"copy_prompt": "Copy Prompt",
"copied": "Copied!",
"html_preview": "Current Active HTML Preview",
"loading": "Loading…"
},
"onboarding": { "onboarding": {
"title": "VoceChat Kurulumu", "title": "VoceChat Kurulumu",
"welcome": "VoceChat'e Hoşgeldiniz!", "welcome": "VoceChat'e Hoşgeldiniz!",
+19
View File
@@ -9,6 +9,25 @@
"sign_in_tip": "请登录后发消息", "sign_in_tip": "请登录后发消息",
"vocespace": " VoceSpace 视频通话", "vocespace": " VoceSpace 视频通话",
"license": "VoceChat 升级证书", "license": "VoceChat 升级证书",
"page_editor": {
"title": "页面管理",
"status_select": "状态选择",
"signed_in": "已登录",
"not_signed_in": "未登录",
"signed_in_users": "已登录用户",
"not_signed_in_users": "未登录用户",
"current_state": "当前管理状态:",
"download_html": "下载当前页面HTML",
"upload_html": "上传自定义 HTML 页面",
"uploading": "上传中…",
"reset": "恢复默认",
"resetting": "恢复中…",
"ai_tip": "想要使用 agent tool 自动完成首页编写?",
"copy_prompt": "一键复制提示词",
"copied": "已复制!",
"html_preview": "当前生效 HTML 代码预览",
"loading": "加载中…"
},
"onboarding": { "onboarding": {
"title": "VoceChat初始化", "title": "VoceChat初始化",
"welcome": "欢迎来到你的VoceChat", "welcome": "欢迎来到你的VoceChat",
+14 -13
View File
@@ -40,6 +40,7 @@ const legacyClasses = {
const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => { const BlankPlaceholder: FC<Props> = ({ type = "chat" }) => {
const { t } = useTranslation("welcome"); const { t } = useTranslation("welcome");
const { t: te } = useTranslation("welcome", { keyPrefix: "page_editor" });
const iframeRef = useRef<HTMLIFrameElement>(null); const iframeRef = useRef<HTMLIFrameElement>(null);
const { getExtSetting } = useServerExtSetting(); const { getExtSetting } = useServerExtSetting();
const onlyAdminCanInvite = getExtSetting(KEY_ADMIN_ONLY_INVITE); const onlyAdminCanInvite = getExtSetting(KEY_ADMIN_ONLY_INVITE);
@@ -217,7 +218,7 @@ Please start asking me questions now and wait for my detailed response.
const iframeSrc = `${BASE_ORIGIN}/api/page/${previewPage}${cacheBust ? `?t=${cacheBust}` : ""}`; const iframeSrc = `${BASE_ORIGIN}/api/page/${previewPage}${cacheBust ? `?t=${cacheBust}` : ""}`;
const htmlLines = (htmlPreview ?? "").split("\n"); const htmlLines = (htmlPreview ?? "").split("\n");
const pageLabel = previewPage === "after_signin" ? "已登录用户" : "未登录用户"; const pageLabel = previewPage === "after_signin" ? te("signed_in_users") : te("not_signed_in_users");
if (!useIframe) { if (!useIframe) {
const chatTip = type === "chat" ? t("start_by_channel") : t("start_by_dm"); const chatTip = type === "chat" ? t("start_by_channel") : t("start_by_dm");
@@ -337,7 +338,7 @@ Please start asking me questions now and wait for my detailed response.
> >
{/* Header */} {/* Header */}
<div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 shrink-0"> <div className="flex items-center justify-between p-4 border-b border-gray-200 dark:border-gray-700 shrink-0">
<h2 className="text-lg font-semibold text-gray-700 dark:text-gray-50"></h2> <h2 className="text-lg font-semibold text-gray-700 dark:text-gray-50">{te("title")}</h2>
<CloseIcon <CloseIcon
className="cursor-pointer dark:fill-white" className="cursor-pointer dark:fill-white"
onClick={() => setEditorModalVisible(false)} onClick={() => setEditorModalVisible(false)}
@@ -348,7 +349,7 @@ Please start asking me questions now and wait for my detailed response.
<div className="flex flex-1 overflow-hidden"> <div className="flex flex-1 overflow-hidden">
{/* Left sidebar */} {/* Left sidebar */}
<div className="w-28 shrink-0 border-r border-gray-200 dark:border-gray-700 p-3 flex flex-col gap-1"> <div className="w-28 shrink-0 border-r border-gray-200 dark:border-gray-700 p-3 flex flex-col gap-1">
<p className="text-xs text-gray-400 dark:text-gray-500 mb-2 px-1"></p> <p className="text-xs text-gray-400 dark:text-gray-500 mb-2 px-1">{te("status_select")}</p>
<button <button
className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${ className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${
previewPage === "after_signin" previewPage === "after_signin"
@@ -357,7 +358,7 @@ Please start asking me questions now and wait for my detailed response.
}`} }`}
onClick={() => setPreviewPage("after_signin")} onClick={() => setPreviewPage("after_signin")}
> >
{te("signed_in")}
</button> </button>
<button <button
className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${ className={`w-full text-left px-3 py-2 rounded-md text-sm transition-colors ${
@@ -367,7 +368,7 @@ Please start asking me questions now and wait for my detailed response.
}`} }`}
onClick={() => setPreviewPage("landing")} onClick={() => setPreviewPage("landing")}
> >
{te("not_signed_in")}
</button> </button>
</div> </div>
@@ -375,7 +376,7 @@ Please start asking me questions now and wait for my detailed response.
<div className="flex-1 flex flex-col overflow-hidden p-4 gap-4"> <div className="flex-1 flex flex-col overflow-hidden p-4 gap-4">
{/* Status label */} {/* Status label */}
<p className="text-sm text-gray-500 dark:text-gray-400 shrink-0"> <p className="text-sm text-gray-500 dark:text-gray-400 shrink-0">
{te("current_state")}
<span className="font-semibold text-gray-900 dark:text-white"> <span className="font-semibold text-gray-900 dark:text-white">
{pageLabel} {pageLabel}
</span> </span>
@@ -390,7 +391,7 @@ Please start asking me questions now and wait for my detailed response.
className="flex items-center gap-2 px-3.5 py-2 rounded-lg bg-primary-400 text-white text-sm hover:bg-primary-500 active:bg-primary-500 transition-colors whitespace-nowrap" className="flex items-center gap-2 px-3.5 py-2 rounded-lg bg-primary-400 text-white text-sm hover:bg-primary-500 active:bg-primary-500 transition-colors whitespace-nowrap"
> >
<DownloadIcon className="w-4 h-4 shrink-0 fill-white" /> <DownloadIcon className="w-4 h-4 shrink-0 fill-white" />
HTML {te("download_html")}
</button> </button>
<button <button
onClick={handleUpload} onClick={handleUpload}
@@ -403,7 +404,7 @@ Please start asking me questions now and wait for my detailed response.
<path d="M16.5303 11.7204L16.4462 11.6478C16.1526 11.4299 15.7359 11.4541 15.4697 11.7204L12.7503 14.4397L12.75 7.75003L12.7432 7.64826C12.6935 7.28218 12.3797 7.00003 12 7.00003L11.8982 7.00688C11.5322 7.05654 11.25 7.37033 11.25 7.75003L11.2503 14.4417L8.52961 11.7198L8.4455 11.6472C8.15193 11.4293 7.73527 11.4534 7.46895 11.7196C7.176 12.0124 7.17591 12.4873 7.46875 12.7803L11.4687 16.7818L11.5529 16.8544C11.8465 17.0724 12.2632 17.0482 12.5295 16.7819L16.5303 12.7811L16.6029 12.6969C16.8208 12.4033 16.7966 11.9867 16.5303 11.7204Z" /> <path d="M16.5303 11.7204L16.4462 11.6478C16.1526 11.4299 15.7359 11.4541 15.4697 11.7204L12.7503 14.4397L12.75 7.75003L12.7432 7.64826C12.6935 7.28218 12.3797 7.00003 12 7.00003L11.8982 7.00688C11.5322 7.05654 11.25 7.37033 11.25 7.75003L11.2503 14.4417L8.52961 11.7198L8.4455 11.6472C8.15193 11.4293 7.73527 11.4534 7.46895 11.7196C7.176 12.0124 7.17591 12.4873 7.46875 12.7803L11.4687 16.7818L11.5529 16.8544C11.8465 17.0724 12.2632 17.0482 12.5295 16.7819L16.5303 12.7811L16.6029 12.6969C16.8208 12.4033 16.7966 11.9867 16.5303 11.7204Z" />
</g> </g>
</svg> </svg>
{uploading ? "上传中…" : "上传自定义 HTML 页面"} {uploading ? te("uploading") : te("upload_html")}
</button> </button>
<button <button
onClick={handleReset} onClick={handleReset}
@@ -414,14 +415,14 @@ Please start asking me questions now and wait for my detailed response.
<path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" /> <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8" />
<path d="M3 3v5h5" /> <path d="M3 3v5h5" />
</svg> </svg>
{resetting ? "恢复中…" : "恢复默认"} {resetting ? te("resetting") : te("reset")}
</button> </button>
</div> </div>
{/* AI tip */} {/* AI tip */}
<div className="flex-1 border border-dashed border-gray-300 dark:border-gray-400 rounded-lg p-3 flex flex-col justify-between gap-2"> <div className="flex-1 border border-dashed border-gray-300 dark:border-gray-400 rounded-lg p-3 flex flex-col justify-between gap-2">
<p className="text-xs text-gray-500 dark:text-gray-400"> <p className="text-xs text-gray-500 dark:text-gray-400">
使 agent tool {te("ai_tip")}
</p> </p>
<button <button
onClick={handleCopyPrompt} onClick={handleCopyPrompt}
@@ -431,7 +432,7 @@ Please start asking me questions now and wait for my detailed response.
? <CheckIcon className="w-3.5 h-3.5 shrink-0 fill-white" /> ? <CheckIcon className="w-3.5 h-3.5 shrink-0 fill-white" />
: <CopyIcon className="w-3.5 h-3.5 shrink-0 fill-white" /> : <CopyIcon className="w-3.5 h-3.5 shrink-0 fill-white" />
} }
{copied ? "已复制!" : "一键复制提示词"} {copied ? te("copied") : te("copy_prompt")}
</button> </button>
</div> </div>
</div> </div>
@@ -439,11 +440,11 @@ Please start asking me questions now and wait for my detailed response.
{/* HTML preview */} {/* HTML preview */}
<div className="flex flex-col gap-1.5 overflow-hidden flex-1 min-h-0"> <div className="flex flex-col gap-1.5 overflow-hidden flex-1 min-h-0">
<p className="text-sm font-semibold text-gray-700 dark:text-gray-50 shrink-0"> <p className="text-sm font-semibold text-gray-700 dark:text-gray-50 shrink-0">
HTML {te("html_preview")}
</p> </p>
<div className="flex-1 overflow-auto bg-gray-100 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700"> <div className="flex-1 overflow-auto bg-gray-100 dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700">
{htmlPreview === null ? ( {htmlPreview === null ? (
<div className="p-4 text-xs text-gray-400"></div> <div className="p-4 text-xs text-gray-400">{te("loading")}</div>
) : htmlLines.map((line, i) => ( ) : htmlLines.map((line, i) => (
<div key={i} className="flex hover:bg-gray-200 dark:hover:bg-gray-700"> <div key={i} className="flex hover:bg-gray-200 dark:hover:bg-gray-700">
<span className="w-9 shrink-0 text-right pr-2.5 py-0.5 text-gray-400 dark:text-gray-500 select-none border-r border-gray-200 dark:border-gray-700 text-xs font-mono leading-5"> <span className="w-9 shrink-0 text-right pr-2.5 py-0.5 text-gray-400 dark:text-gray-500 select-none border-r border-gray-200 dark:border-gray-700 text-xs font-mono leading-5">