Spaces:
Sleeping
Sleeping
fix: switch all frontend default language to English
Browse files- Change all fallback language from 'zh' to 'en'
- Translate hardcoded Chinese strings: guest bubble thoughts, error messages, loading text, panel titles
- Demo visitor names/bubbles now in English
- Force Docker rebuild (v3.2)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Dockerfile +1 -1
- frontend/electron-standalone.html +31 -31
Dockerfile
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# OpenClaw on Hugging Face Spaces — Pre-built image (v3.
|
| 2 |
# Uses official pre-built image to avoid 30+ minute builds on cpu-basic
|
| 3 |
|
| 4 |
# ── Stage 1: Pull pre-built OpenClaw ─────────────────────────────────────────
|
|
|
|
| 1 |
+
# OpenClaw on Hugging Face Spaces — Pre-built image (v3.2)
|
| 2 |
# Uses official pre-built image to avoid 30+ minute builds on cpu-basic
|
| 3 |
|
| 4 |
# ── Stage 1: Pull pre-built OpenClaw ─────────────────────────────────────────
|
frontend/electron-standalone.html
CHANGED
|
@@ -1678,18 +1678,18 @@
|
|
| 1678 |
|
| 1679 |
<!-- Guest Agent 名单面板(右下角) -->
|
| 1680 |
<div id="guest-agent-panel">
|
| 1681 |
-
<div id="guest-agent-panel-title">
|
| 1682 |
<div id="guest-agent-list">
|
| 1683 |
-
<div style="color:#9ca3af;font-size:12px;text-align:center;padding:20px 0;">
|
| 1684 |
</div>
|
| 1685 |
</div>
|
| 1686 |
</div>
|
| 1687 |
|
| 1688 |
<!-- Chat Log 面板 -->
|
| 1689 |
<div id="chatlog-panel">
|
| 1690 |
-
<div id="chatlog-title">🦞 Adam ↔ Eve
|
| 1691 |
<div id="chatlog-content">
|
| 1692 |
-
<div style="color:#9ca3af;font-size:12px;text-align:center;padding:20px 0;">
|
| 1693 |
</div>
|
| 1694 |
</div>
|
| 1695 |
</div>
|
|
@@ -1698,7 +1698,7 @@
|
|
| 1698 |
<div id="room-loading-overlay" aria-live="polite" aria-busy="true">
|
| 1699 |
<div class="room-loading-inner">
|
| 1700 |
<div id="room-loading-emoji">🦞</div>
|
| 1701 |
-
<div id="room-loading-text">
|
| 1702 |
</div>
|
| 1703 |
</div>
|
| 1704 |
|
|
@@ -2650,7 +2650,7 @@
|
|
| 2650 |
|
| 2651 |
function getAssetDisplayName(path) {
|
| 2652 |
const stem = toAssetStem(path);
|
| 2653 |
-
const lang = (uiLang || '
|
| 2654 |
const nameMap = {
|
| 2655 |
zh: {
|
| 2656 |
'star-idle-v5': '主角·待命状态',
|
|
@@ -2833,8 +2833,8 @@
|
|
| 2833 |
|
| 2834 |
function getAssetHelpText(path) {
|
| 2835 |
const stem = toAssetStem(path);
|
| 2836 |
-
const lang = (uiLang || '
|
| 2837 |
-
const map = ASSET_HELP_TEXT_MAP[lang] || ASSET_HELP_TEXT_MAP.
|
| 2838 |
return map[stem] || t('assetHintDefault');
|
| 2839 |
}
|
| 2840 |
|
|
@@ -3579,7 +3579,7 @@
|
|
| 3579 |
fd.append('pixel_art', '1');
|
| 3580 |
}
|
| 3581 |
|
| 3582 |
-
out.textContent = '⏳
|
| 3583 |
const res = await fetch('/assets/upload', { method: 'POST', body: fd });
|
| 3584 |
const data = await res.json();
|
| 3585 |
if (!data.ok) {
|
|
@@ -3732,7 +3732,7 @@ function toggleBrokerPanel() {
|
|
| 3732 |
'旅が次の番地を届けるのを待っています……'
|
| 3733 |
]
|
| 3734 |
};
|
| 3735 |
-
const steps = loadingTexts[uiLang] || loadingTexts.
|
| 3736 |
const emojis = ['🦞','🦀','🦐','🦑','🐙','🐟','🐠','🐡','🦪','🍣','🍤','🍱','🍲','🍜','🍝','🌊','🐚','🪸'];
|
| 3737 |
|
| 3738 |
roomLoadingIndex = 0;
|
|
@@ -3915,7 +3915,7 @@ function toggleBrokerPanel() {
|
|
| 3915 |
const out = document.getElementById('asset-move-result') || document.getElementById('asset-upload-result');
|
| 3916 |
// 点击即刻显示遮罩,先于任何网络调用
|
| 3917 |
showRoomLoadingOverlay();
|
| 3918 |
-
out.textContent = '🧳
|
| 3919 |
try {
|
| 3920 |
const res = await fetch('/assets/generate-rpg-background', {
|
| 3921 |
method: 'POST',
|
|
@@ -3939,7 +3939,7 @@ function toggleBrokerPanel() {
|
|
| 3939 |
}
|
| 3940 |
return;
|
| 3941 |
}
|
| 3942 |
-
out.textContent = '✅
|
| 3943 |
const ok = await refreshOfficeBackgroundOnly();
|
| 3944 |
await notifyMainWindowAssetRefresh('office_bg', 'office_bg_small.webp');
|
| 3945 |
if (ok) {
|
|
@@ -3968,7 +3968,7 @@ function toggleBrokerPanel() {
|
|
| 3968 |
setWorkingStatus(t('statusRestoreHome'));
|
| 3969 |
// 点击即刻显示遮罩,先于任何网络调用
|
| 3970 |
showRoomLoadingOverlay();
|
| 3971 |
-
out.textContent = '🏡
|
| 3972 |
try {
|
| 3973 |
const res = await fetch('/assets/restore-reference-background', { method: 'POST' });
|
| 3974 |
const data = await res.json();
|
|
@@ -4004,7 +4004,7 @@ function toggleBrokerPanel() {
|
|
| 4004 |
|
| 4005 |
setWorkingStatus(t('statusRestoreLastBg'));
|
| 4006 |
showRoomLoadingOverlay();
|
| 4007 |
-
out.textContent = '↩️
|
| 4008 |
try {
|
| 4009 |
const res = await fetch('/assets/restore-last-generated-background', { method: 'POST' });
|
| 4010 |
const data = await res.json();
|
|
@@ -4315,7 +4315,7 @@ function toggleBrokerPanel() {
|
|
| 4315 |
alert('离开失败:' + (data.msg || '未知错误'));
|
| 4316 |
}
|
| 4317 |
}).catch(error => {
|
| 4318 |
-
alert('
|
| 4319 |
});
|
| 4320 |
}
|
| 4321 |
|
|
@@ -4332,7 +4332,7 @@ function toggleBrokerPanel() {
|
|
| 4332 |
alert('批准失败:' + (data.msg || '未知错误'));
|
| 4333 |
}
|
| 4334 |
}).catch(error => {
|
| 4335 |
-
alert('
|
| 4336 |
});
|
| 4337 |
}
|
| 4338 |
|
|
@@ -4349,7 +4349,7 @@ function toggleBrokerPanel() {
|
|
| 4349 |
alert('拒绝失败:' + (data.msg || '未知错误'));
|
| 4350 |
}
|
| 4351 |
}).catch(error => {
|
| 4352 |
-
alert('
|
| 4353 |
});
|
| 4354 |
}
|
| 4355 |
|
|
@@ -4357,8 +4357,8 @@ function toggleBrokerPanel() {
|
|
| 4357 |
if (!DEMO_MODE) return;
|
| 4358 |
if (!Array.isArray(window.__demoVisitors) || window.__demoVisitors.length === 0) {
|
| 4359 |
window.__demoVisitors = [
|
| 4360 |
-
{ agentId: 'demo_nika', name: '
|
| 4361 |
-
{ agentId: 'demo_mercury', name: '
|
| 4362 |
];
|
| 4363 |
}
|
| 4364 |
}
|
|
@@ -4630,12 +4630,12 @@ function toggleBrokerPanel() {
|
|
| 4630 |
: null;
|
| 4631 |
|
| 4632 |
const statusThoughtsMap = {
|
| 4633 |
-
idle: ['
|
| 4634 |
-
writing: ['
|
| 4635 |
-
researching: ['
|
| 4636 |
-
executing: ['
|
| 4637 |
-
syncing: ['
|
| 4638 |
-
error: ['
|
| 4639 |
};
|
| 4640 |
const agentData = guestAgents.find(a => a.agentId === id) || {};
|
| 4641 |
const agentState = agentData.state || 'idle';
|
|
@@ -4824,7 +4824,7 @@ function toggleBrokerPanel() {
|
|
| 4824 |
en: [`Welcome ${newAgent.name} to the office!`,`Hi ${newAgent.name}, let’s build something.`,`${newAgent.name} just joined — welcome!`],
|
| 4825 |
ja: [`${newAgent.name} さん、オフィスへようこそ!`,`Hi ${newAgent.name}、一緒に進めよう。`,`${newAgent.name} さんが参加しました、歓迎!`]
|
| 4826 |
};
|
| 4827 |
-
const langPack = BUBBLE_TEXTS[lang] || BUBBLE_TEXTS.
|
| 4828 |
const oldTexts = Array.isArray(langPack.writing) ? [...langPack.writing] : [];
|
| 4829 |
langPack.writing = welcomeTexts[lang] || welcomeTexts.zh;
|
| 4830 |
showBubble();
|
|
@@ -5663,7 +5663,7 @@ function toggleBrokerPanel() {
|
|
| 5663 |
}
|
| 5664 |
} catch (err) {
|
| 5665 |
console.error('fetchStatus apply error', err);
|
| 5666 |
-
typewriterTarget = '
|
| 5667 |
typewriterText = '';
|
| 5668 |
typewriterIndex = 0;
|
| 5669 |
}
|
|
@@ -5673,8 +5673,8 @@ function toggleBrokerPanel() {
|
|
| 5673 |
// Temporarily switch state to allow bubble display
|
| 5674 |
const savedState = currentState;
|
| 5675 |
currentState = 'writing';
|
| 5676 |
-
const lang = uiLang || '
|
| 5677 |
-
const langPack = BUBBLE_TEXTS[lang] || BUBBLE_TEXTS.
|
| 5678 |
const oldTexts = Array.isArray(langPack.writing) ? [...langPack.writing] : [];
|
| 5679 |
const bubbleMsg = data.bubbleText.length > 30 ? data.bubbleText.slice(0, 30) + '…' : data.bubbleText;
|
| 5680 |
langPack.writing = [bubbleMsg];
|
|
@@ -5684,7 +5684,7 @@ function toggleBrokerPanel() {
|
|
| 5684 |
}
|
| 5685 |
})
|
| 5686 |
.catch(error => {
|
| 5687 |
-
typewriterTarget = '
|
| 5688 |
typewriterText = '';
|
| 5689 |
typewriterIndex = 0;
|
| 5690 |
});
|
|
@@ -5803,7 +5803,7 @@ function toggleBrokerPanel() {
|
|
| 5803 |
}
|
| 5804 |
|
| 5805 |
function getBubbleTextsByState(stateKey) {
|
| 5806 |
-
const langPack = BUBBLE_TEXTS[uiLang] || BUBBLE_TEXTS.
|
| 5807 |
return langPack[stateKey] || langPack.idle || [];
|
| 5808 |
}
|
| 5809 |
|
|
|
|
| 1678 |
|
| 1679 |
<!-- Guest Agent 名单面板(右下角) -->
|
| 1680 |
<div id="guest-agent-panel">
|
| 1681 |
+
<div id="guest-agent-panel-title">GUESTS</div>
|
| 1682 |
<div id="guest-agent-list">
|
| 1683 |
+
<div style="color:#9ca3af;font-size:12px;text-align:center;padding:20px 0;">Loading guests...</div>
|
| 1684 |
</div>
|
| 1685 |
</div>
|
| 1686 |
</div>
|
| 1687 |
|
| 1688 |
<!-- Chat Log 面板 -->
|
| 1689 |
<div id="chatlog-panel">
|
| 1690 |
+
<div id="chatlog-title">🦞 Adam ↔ Eve Conversation</div>
|
| 1691 |
<div id="chatlog-content">
|
| 1692 |
+
<div style="color:#9ca3af;font-size:12px;text-align:center;padding:20px 0;">Waiting for conversation to start...</div>
|
| 1693 |
</div>
|
| 1694 |
</div>
|
| 1695 |
</div>
|
|
|
|
| 1698 |
<div id="room-loading-overlay" aria-live="polite" aria-busy="true">
|
| 1699 |
<div class="room-loading-inner">
|
| 1700 |
<div id="room-loading-emoji">🦞</div>
|
| 1701 |
+
<div id="room-loading-text">Loading the office...</div>
|
| 1702 |
</div>
|
| 1703 |
</div>
|
| 1704 |
|
|
|
|
| 2650 |
|
| 2651 |
function getAssetDisplayName(path) {
|
| 2652 |
const stem = toAssetStem(path);
|
| 2653 |
+
const lang = (uiLang || 'en');
|
| 2654 |
const nameMap = {
|
| 2655 |
zh: {
|
| 2656 |
'star-idle-v5': '主角·待命状态',
|
|
|
|
| 2833 |
|
| 2834 |
function getAssetHelpText(path) {
|
| 2835 |
const stem = toAssetStem(path);
|
| 2836 |
+
const lang = (uiLang || 'en');
|
| 2837 |
+
const map = ASSET_HELP_TEXT_MAP[lang] || ASSET_HELP_TEXT_MAP.en;
|
| 2838 |
return map[stem] || t('assetHintDefault');
|
| 2839 |
}
|
| 2840 |
|
|
|
|
| 3579 |
fd.append('pixel_art', '1');
|
| 3580 |
}
|
| 3581 |
|
| 3582 |
+
out.textContent = '⏳ Uploading and replacing, please wait...';
|
| 3583 |
const res = await fetch('/assets/upload', { method: 'POST', body: fd });
|
| 3584 |
const data = await res.json();
|
| 3585 |
if (!data.ok) {
|
|
|
|
| 3732 |
'旅が次の番地を届けるのを待っています……'
|
| 3733 |
]
|
| 3734 |
};
|
| 3735 |
+
const steps = loadingTexts[uiLang] || loadingTexts.en;
|
| 3736 |
const emojis = ['🦞','🦀','🦐','🦑','🐙','🐟','🐠','🐡','🦪','🍣','🍤','🍱','🍲','🍜','🍝','🌊','🐚','🪸'];
|
| 3737 |
|
| 3738 |
roomLoadingIndex = 0;
|
|
|
|
| 3915 |
const out = document.getElementById('asset-move-result') || document.getElementById('asset-upload-result');
|
| 3916 |
// 点击即刻显示遮罩,先于任何网络调用
|
| 3917 |
showRoomLoadingOverlay();
|
| 3918 |
+
out.textContent = '🧳 Packing up, please wait (~30-60s)...';
|
| 3919 |
try {
|
| 3920 |
const res = await fetch('/assets/generate-rpg-background', {
|
| 3921 |
method: 'POST',
|
|
|
|
| 3939 |
}
|
| 3940 |
return;
|
| 3941 |
}
|
| 3942 |
+
out.textContent = '✅ Generated and replaced background, refreshing room...';
|
| 3943 |
const ok = await refreshOfficeBackgroundOnly();
|
| 3944 |
await notifyMainWindowAssetRefresh('office_bg', 'office_bg_small.webp');
|
| 3945 |
if (ok) {
|
|
|
|
| 3968 |
setWorkingStatus(t('statusRestoreHome'));
|
| 3969 |
// 点击即刻显示遮罩,先于任何网络调用
|
| 3970 |
showRoomLoadingOverlay();
|
| 3971 |
+
out.textContent = '🏡 Restoring original background...';
|
| 3972 |
try {
|
| 3973 |
const res = await fetch('/assets/restore-reference-background', { method: 'POST' });
|
| 3974 |
const data = await res.json();
|
|
|
|
| 4004 |
|
| 4005 |
setWorkingStatus(t('statusRestoreLastBg'));
|
| 4006 |
showRoomLoadingOverlay();
|
| 4007 |
+
out.textContent = '↩️ Reverting to last generated background...';
|
| 4008 |
try {
|
| 4009 |
const res = await fetch('/assets/restore-last-generated-background', { method: 'POST' });
|
| 4010 |
const data = await res.json();
|
|
|
|
| 4315 |
alert('离开失败:' + (data.msg || '未知错误'));
|
| 4316 |
}
|
| 4317 |
}).catch(error => {
|
| 4318 |
+
alert('Request failed: ' + error);
|
| 4319 |
});
|
| 4320 |
}
|
| 4321 |
|
|
|
|
| 4332 |
alert('批准失败:' + (data.msg || '未知错误'));
|
| 4333 |
}
|
| 4334 |
}).catch(error => {
|
| 4335 |
+
alert('Request failed: ' + error);
|
| 4336 |
});
|
| 4337 |
}
|
| 4338 |
|
|
|
|
| 4349 |
alert('拒绝失败:' + (data.msg || '未知错误'));
|
| 4350 |
}
|
| 4351 |
}).catch(error => {
|
| 4352 |
+
alert('Request failed: ' + error);
|
| 4353 |
});
|
| 4354 |
}
|
| 4355 |
|
|
|
|
| 4357 |
if (!DEMO_MODE) return;
|
| 4358 |
if (!Array.isArray(window.__demoVisitors) || window.__demoVisitors.length === 0) {
|
| 4359 |
window.__demoVisitors = [
|
| 4360 |
+
{ agentId: 'demo_nika', name: 'Nika', authStatus: 'approved', state: 'writing', bubbleText: 'Working on it', isDemo: true, updated_at: new Date().toISOString() },
|
| 4361 |
+
{ agentId: 'demo_mercury', name: 'Mercury', authStatus: 'approved', state: 'idle', bubbleText: 'Taking a break', isDemo: true, updated_at: new Date().toISOString() }
|
| 4362 |
];
|
| 4363 |
}
|
| 4364 |
}
|
|
|
|
| 4630 |
: null;
|
| 4631 |
|
| 4632 |
const statusThoughtsMap = {
|
| 4633 |
+
idle: ['Standing by in the break room', 'Taking a breather before next task', 'Recharging in the rest area'],
|
| 4634 |
+
writing: ['Working on tasks in the office', 'Organizing docs and executing', 'Focused in the work zone'],
|
| 4635 |
+
researching: ['In research mode, gathering info', 'Looking up references and verifying', 'Researching, will share findings soon'],
|
| 4636 |
+
executing: ['Executing, running the pipeline', 'Pushing tasks forward at the desk', 'Turning plans into action'],
|
| 4637 |
+
syncing: ['Syncing, updating status soon', 'Syncing progress to system', 'Data sync in progress, hold on'],
|
| 4638 |
+
error: ['In the bug zone, investigating', 'Anomaly detected, fixing now', 'Alert mode, locating the issue']
|
| 4639 |
};
|
| 4640 |
const agentData = guestAgents.find(a => a.agentId === id) || {};
|
| 4641 |
const agentState = agentData.state || 'idle';
|
|
|
|
| 4824 |
en: [`Welcome ${newAgent.name} to the office!`,`Hi ${newAgent.name}, let’s build something.`,`${newAgent.name} just joined — welcome!`],
|
| 4825 |
ja: [`${newAgent.name} さん、オフィスへようこそ!`,`Hi ${newAgent.name}、一緒に進めよう。`,`${newAgent.name} さんが参加しました、歓迎!`]
|
| 4826 |
};
|
| 4827 |
+
const langPack = BUBBLE_TEXTS[lang] || BUBBLE_TEXTS.en;
|
| 4828 |
const oldTexts = Array.isArray(langPack.writing) ? [...langPack.writing] : [];
|
| 4829 |
langPack.writing = welcomeTexts[lang] || welcomeTexts.zh;
|
| 4830 |
showBubble();
|
|
|
|
| 5663 |
}
|
| 5664 |
} catch (err) {
|
| 5665 |
console.error('fetchStatus apply error', err);
|
| 5666 |
+
typewriterTarget = 'Status update error, recovering...';
|
| 5667 |
typewriterText = '';
|
| 5668 |
typewriterIndex = 0;
|
| 5669 |
}
|
|
|
|
| 5673 |
// Temporarily switch state to allow bubble display
|
| 5674 |
const savedState = currentState;
|
| 5675 |
currentState = 'writing';
|
| 5676 |
+
const lang = uiLang || 'en';
|
| 5677 |
+
const langPack = BUBBLE_TEXTS[lang] || BUBBLE_TEXTS.en;
|
| 5678 |
const oldTexts = Array.isArray(langPack.writing) ? [...langPack.writing] : [];
|
| 5679 |
const bubbleMsg = data.bubbleText.length > 30 ? data.bubbleText.slice(0, 30) + '…' : data.bubbleText;
|
| 5680 |
langPack.writing = [bubbleMsg];
|
|
|
|
| 5684 |
}
|
| 5685 |
})
|
| 5686 |
.catch(error => {
|
| 5687 |
+
typewriterTarget = 'Connection failed, retrying...';
|
| 5688 |
typewriterText = '';
|
| 5689 |
typewriterIndex = 0;
|
| 5690 |
});
|
|
|
|
| 5803 |
}
|
| 5804 |
|
| 5805 |
function getBubbleTextsByState(stateKey) {
|
| 5806 |
+
const langPack = BUBBLE_TEXTS[uiLang] || BUBBLE_TEXTS.en;
|
| 5807 |
return langPack[stateKey] || langPack.idle || [];
|
| 5808 |
}
|
| 5809 |
|