Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions emrg/gui/renderer/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</div>
<!-- 成长状态卡(WorkBuddy P3:自进化可见化;#501) -->
<div class="growth-card" id="growth-card" title="EMRG 每次自我改进都会自动汇报">
<div class="growth-line">🌱 已自我进化 <b id="growth-count">0</b> </div>
<div class="growth-line">🌱 <span data-i18n="copy.growthCountPrefix">已自我进化</span> <b id="growth-count">0</b> <span data-i18n="copy.times">次</span></div>
<div class="growth-note" id="growth-note">边工作边学习,越用越懂你</div>
</div>
<button id="new-chat-btn" class="new-chat-btn" title="新对话 (⌘N)" data-i18n="sidebar.newChat" data-i18n-title="sidebar.newChatTitle">+ 新对话</button>
Expand Down Expand Up @@ -146,7 +146,7 @@ <h2 data-i18n="settings.title">设置</h2>
<div class="settings-group">
<div class="settings-group-title">关于</div>
<div class="about-box">
<div class="about-line">EMRG <span id="about-version">v0.2.8</span> · <span id="about-evolutions">🌱 已自我进化 0 </span></div>
<div class="about-line">EMRG <span id="about-version">v0.2.8</span> · <span id="about-evolutions">🌱 <span data-i18n="copy.growthCountPrefix">已自我进化</span> 0 <span data-i18n="copy.times">次</span></span></div>
<div class="hint" style="margin-top:6px;">EMRG 是一个会自我进化的 AI 智能体——每次改进都会自动汇报,你可以随时在这里看到它的成长。</div>
</div>
</div>
Expand Down
122 changes: 61 additions & 61 deletions emrg/gui/renderer/js/app.js

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions emrg/gui/renderer/js/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@ const Chat = (() => {
if (!pre) return;
const code = pre.textContent || "";
const done = () => {
btn.textContent = "已复制 ✓";
setTimeout(() => { btn.textContent = "复制"; }, 1500);
btn.textContent = EMRG_Copy._t("chat.copied");
setTimeout(() => { btn.textContent = EMRG_Copy._t("chat.copyCode"); }, 1500);
};
const fail = () => {
btn.textContent = "复制失败";
setTimeout(() => { btn.textContent = "复制"; }, 1500);
btn.textContent = EMRG_Copy._t("chat.copyFailed");
setTimeout(() => { btn.textContent = EMRG_Copy._t("chat.copyCode"); }, 1500);
};
if (navigator.clipboard?.writeText) {
navigator.clipboard.writeText(code).then(done, fail);
Expand Down Expand Up @@ -77,7 +77,7 @@ const Chat = (() => {
function createAssistantNode(isOwn) {
const node = el("div", { class: "msg assistant" });
if (!isOwn) {
node.appendChild(el("div", { class: "remote-label" }, "(来自其他客户端)"));
node.appendChild(el("div", { class: "remote-label" }, EMRG_Copy._t("chat.fromOtherClient")));
}
const mark = el("span", { class: "msg-assistant-mark" }, "✦ ");
const body = el("div", { class: "msg-body typing" });
Expand Down Expand Up @@ -132,7 +132,7 @@ const Chat = (() => {
groupNodes.delete(rid);
}
if (data.timeout) {
addSystemMessage("⚠️ 响应超时了,我还没说完——可以再试一次。");
addSystemMessage(EMRG_Copy._t("chat.timeoutWarn"));
}
}

Expand Down Expand Up @@ -181,7 +181,7 @@ const Chat = (() => {
}
const elapsed = data.elapsed !== undefined ? `${data.elapsed.toFixed(1)}s` : "";
if (elapsed && ok) {
row.title = `耗时 ${elapsed}`;
row.title = EMRG_Copy._t("chat.elapsed", { s: elapsed });
}
// G91/G131:content 截断 2000 字符 + 展开全文
const content = data.content || "";
Expand All @@ -190,7 +190,7 @@ const Chat = (() => {
const out = el("div", { class: "tool-output hidden" }, truncated);
row.appendChild(out);
if (content.length > 2000) {
const btn = el("button", { class: "tool-expand-btn" }, "展开全文");
const btn = el("button", { class: "tool-expand-btn" }, EMRG_Copy._t("chat.expand"));
btn.addEventListener("click", () => {
out.textContent = content;
btn.remove();
Expand Down
1 change: 1 addition & 0 deletions emrg/gui/renderer/js/copywriting.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ const EMRG_Copy = (() => {
toolPhrases,
COPY,
refresh,
_t, // rant 21:19 Stage 2:chat.js 等模块取词统一走这里(i18n 就绪时)
get TOOL_FAIL_TEXT() { return failText; },
};
})();
Expand Down
52 changes: 26 additions & 26 deletions emrg/gui/renderer/js/dialogs.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ const Dialogs = (() => {
const def = extraModels.find((m) => m.name === defaultName);
list.appendChild(
renderModelItem(
defaultName || "未配置",
defaultName || _t("dlg.notConfigured"),
true,
Boolean(def?.vision),
def?.model && def.model !== def.name ? def.model : ""
Expand All @@ -85,15 +85,15 @@ const Dialogs = (() => {
);
}
if (extraModels.filter((m) => m.name !== defaultName).length === 0) {
const hint = el("div", { class: "model-list-empty" }, "暂无其他模型,点下方按钮添加");
const hint = el("div", { class: "model-list-empty" }, _t("dlg.noOtherModels"));
list.appendChild(hint);
}
}

function renderModelItem(name, isDefault, vision, modelId) {
const row = el("div", { class: "model-item" + (isDefault ? " default" : "") });
// 单选圆点 → 设为默认
const radio = el("button", { class: "model-radio" + (isDefault ? " checked" : ""), title: isDefault ? "当前默认模型" : "设为默认" });
const radio = el("button", { class: "model-radio" + (isDefault ? " checked" : ""), title: isDefault ? _t("dlg.currentDefault") : _t("dlg.setDefault") });
if (isDefault) {
radio.textContent = "●";
} else {
Expand All @@ -105,20 +105,20 @@ const Dialogs = (() => {
}
row.appendChild(radio);
const title = el("span", { class: "model-name" }, name);
if (isDefault) title.appendChild(el("span", { class: "model-badge" }, "默认"));
if (isDefault) title.appendChild(el("span", { class: "model-badge" }, _t("dlg.defaultBadge")));
row.appendChild(title);
if (modelId) row.appendChild(el("span", { class: "model-id" }, modelId));
if (vision) row.appendChild(el("span", { class: "model-vision" }, "🖼 支持图片"));
if (vision) row.appendChild(el("span", { class: "model-vision" }, _t("dlg.supportsImages")));
// 操作:编辑(非默认行 → 打开表单填本条);删除(默认不可删)
const actions = el("span", { class: "model-actions" });
const editBtn = el("button", { class: "model-action-btn", title: "编辑" }, "编辑");
const editBtn = el("button", { class: "model-action-btn", title: _t("dlg.edit") }, _t("dlg.edit"));
editBtn.addEventListener("click", () => openModelForm(name, isDefault));
actions.appendChild(editBtn);
if (!isDefault) {
const delBtn = el("button", { class: "model-action-btn danger", title: "删除" }, "删除");
const delBtn = el("button", { class: "model-action-btn danger", title: _t("dlg.delete") }, _t("dlg.delete"));
delBtn.addEventListener("click", () => {
showConfirm("删除这个模型?", `「${name}」将从可用模型里移除。`, {
okText: "删除",
showConfirm(_t("dlg.deleteModelTitle"), _t("dlg.deleteModelBody", { name }), {
okText: _t("dlg.delete"),
danger: true,
onOk: () => {
extraModels = extraModels.filter((m) => m.name !== name);
Expand Down Expand Up @@ -156,7 +156,7 @@ const Dialogs = (() => {
function saveModelForm() {
const name = $("model-form-name").value.trim();
if (!name) {
showConfirm("还差一步", "模型名称是必填的哦。", { okText: "知道了", danger: false });
showConfirm(_t("dlg.stepTitle"), _t("dlg.nameRequiredBody"), { okText: _t("dlg.gotIt"), danger: false });
return;
}
const modelId = $("model-form-id").value.trim() || name;
Expand All @@ -165,7 +165,7 @@ const Dialogs = (() => {
if (editingName === null) {
// 添加新模型
if (name === defaultName || extraModels.some((m) => m.name === name)) {
showConfirm("重名了", "这个名称已经有模型了,换个名字吧。", { okText: "知道了", danger: false });
showConfirm(_t("dlg.duplicateTitle"), _t("dlg.duplicateBody"), { okText: _t("dlg.gotIt"), danger: false });
return;
}
extraModels.push({ name, model: modelId, vision });
Expand All @@ -178,11 +178,11 @@ const Dialogs = (() => {
} else {
// 编辑非默认模型
if (name === defaultName) {
showConfirm("重名了", "这个名称是默认模型,请在默认行编辑。", { okText: "知道了", danger: false });
showConfirm(_t("dlg.duplicateTitle"), _t("dlg.duplicateDefaultBody"), { okText: _t("dlg.gotIt"), danger: false });
return;
}
if (name !== editingName && extraModels.some((m) => m.name === name)) {
showConfirm("重名了", "这个名称已经有模型了,换个名字吧。", { okText: "知道了", danger: false });
showConfirm(_t("dlg.duplicateTitle"), _t("dlg.duplicateBody"), { okText: _t("dlg.gotIt"), danger: false });
return;
}
extraModels = extraModels.map((m) => (m.name === editingName ? { name, model: modelId, vision } : m));
Expand Down Expand Up @@ -228,10 +228,10 @@ const Dialogs = (() => {
const ver = $("about-version");
if (ver) ver.textContent = `v${App.state.version || "0.2.8"}`;
const evo = $("about-evolutions");
if (evo) evo.textContent = EMRG_Copy.COPY.growthCount(App.state.evolutionCount ?? 0);
if (evo) evo.textContent = `🌱 ${_t("copy.growthCountPrefix")} ${App.state.evolutionCount ?? 0} ${_t("copy.times")}`;
} catch { /* 元素缺失(测试桩)时忽略 */ }
} catch (e) {
Chat.addSystemMessage(`读取设置失败了:${e.message}`);
Chat.addSystemMessage(_t("settings.readFailed", { msg: e.message }));
}
$("settings-dialog").showModal();
}
Expand All @@ -246,23 +246,23 @@ const Dialogs = (() => {
models: extraModels,
};
if (!config.apiKey) {
showConfirm("还差一步", "API Key 是连接模型服务必需的,填上才能继续哦。", {
okText: "知道了",
showConfirm(_t("dlg.stepTitle"), _t("app.authKeyRequired"), {
okText: _t("dlg.gotIt"),
danger: false,
});
return;
}
try {
await window.emrg.saveSettings(config);
if ($("settings-dialog").open) $("settings-dialog").close();
Chat.addSystemMessage("设置已保存。");
Chat.addSystemMessage(_t("dlg.saved"));
App.state.apiKeyConfigured = true;
App.state.projectDir = config.projectDir || App.state.projectDir;
App.state.model = defaultName;
App.updateModelSwitcher();
await App.boot();
} catch (e) {
Chat.addSystemMessage(`保存失败了:${e.message}`);
Chat.addSystemMessage(_t("settings.saveFailed", { msg: e.message }));
}
}

Expand All @@ -271,7 +271,7 @@ const Dialogs = (() => {
$("welcome-project-dir").value = "";
$("welcome-api-key").value = "";
$("welcome-base-url").value = "";
$("welcome-model").innerHTML = "<option value=''>加载中…</option>";
$("welcome-model").innerHTML = `<option value="">${_t("dlg.loading")}</option>`;
$("welcome-dialog").showModal();
window.emrg.getSettings().then((s) => {
const sel = $("welcome-model");
Expand All @@ -293,8 +293,8 @@ const Dialogs = (() => {
async function saveWelcome() {
const key = $("welcome-api-key").value.trim();
if (!key) {
showConfirm("还差一步", "API Key 是连接模型服务必需的,填上才能继续哦。", {
okText: "知道了",
showConfirm(_t("dlg.stepTitle"), _t("app.authKeyRequired"), {
okText: _t("dlg.gotIt"),
danger: false,
});
return;
Expand All @@ -308,12 +308,12 @@ const Dialogs = (() => {
try {
await window.emrg.saveSettings(config);
if ($("welcome-dialog").open) $("welcome-dialog").close();
Chat.addSystemMessage("设置完成,正在启动…");
Chat.addSystemMessage(_t("dlg.starting"));
App.state.apiKeyConfigured = true;
App.state.projectDir = config.projectDir || App.state.projectDir;
await App.boot();
} catch (e) {
Chat.addSystemMessage(`初始化失败了:${e.message}`);
Chat.addSystemMessage(_t("dlg.initFailed", { msg: e.message }));
}
}

Expand All @@ -339,7 +339,7 @@ const Dialogs = (() => {
$("rename-dialog").close();
await App.refreshSessions();
} catch (e) {
Chat.addSystemMessage(`重命名失败了:${e.message}`);
Chat.addSystemMessage(_t("dlg.renameFailed", { msg: e.message }));
}
}

Expand All @@ -363,7 +363,7 @@ const Dialogs = (() => {
$("confirm-title").textContent = title;
$("confirm-message").textContent = message;
const ok = $("confirm-ok");
ok.textContent = opts.okText || "删除";
ok.textContent = opts.okText || _t("dlg.delete");
ok.className = opts.danger === false ? "btn btn-primary" : "btn btn-danger";
confirmCb = opts.onOk || null;
$("confirm-dialog").showModal();
Expand Down
Loading
Loading