Conversation
|
我开错位置了 |
There was a problem hiding this comment.
Hey - 我发现了 4 个问题,并给出了一些整体层面的反馈:
- 前端调用的是
axios.post('/api/setLang', { lang }),但LangRoute目前注册的是'/setLang'的GET方法并读取 JSON body;二者在路径和 HTTP 方法上都需要对齐,以避免运行时出现 404 / 方法不匹配以及请求体相关的问题。 main.py中新增的t(...)调用使用了位置参数(例如t('main-use-specified-webui', webui_dir)),但Lang.__call__期望的是关键字参数,并且 FTL 中的变量(如$webui_dir,$v,$version,$error)必须和这些关键字参数名保持一致;请将调用改为使用命名参数,并确保 .ftl 文件中的变量名和代码中的参数名一致。- zh-CN 的 FTL 条目使用了
{webui_dir},{v},{VERSION},{e}这样的占位符,没有$前缀,而且名称也与英文版本不同;为避免格式化错误,请统一改为 Fluent 语法(例如{ $webui_dir }),并将变量名与 Python 代码中传入的参数保持一致。
给 AI Agent 的提示词
Please address the comments from this code review:
## Overall Comments
- The frontend calls `axios.post('/api/setLang', { lang })`, but `LangRoute` currently registers `'/setLang'` with the `GET` method and reads a JSON body; this should be aligned (path and HTTP verb) to avoid runtime 404/method and request-body issues.
- The new `t(...)` usages in `main.py` pass positional arguments (e.g. `t('main-use-specified-webui', webui_dir)`), but `Lang.__call__` expects keyword arguments and the FTL variables (e.g. `$webui_dir`, `$v`, `$version`, `$error`) must match those keyword names; update calls to use named arguments and ensure the variable names in the .ftl files and code are consistent.
- The zh-CN FTL entries use placeholders like `{webui_dir}`, `{v}`, `{VERSION}`, `{e}` without the `$` prefix and with names that differ from the English version; to prevent formatting errors, standardize them to Fluent syntax (e.g. `{ $webui_dir }`) and align variable names with the arguments you pass from Python.
## Individual Comments
### Comment 1
<location> `main.py:71` </location>
<code_context>
if webui_dir:
if os.path.exists(webui_dir):
- logger.info(f"使用指定的 WebUI 目录: {webui_dir}")
+ logger.info(t("main-use-specified-webui", webui_dir))
return webui_dir
- logger.warning(f"指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。")
</code_context>
<issue_to_address>
**issue (bug_risk):** Fluent translation calls use positional args, which will raise TypeError and also don't match the variable names in the FTL files.
`Lang.__call__` is defined as `def __call__(self, key: str, **kwargs)`, so `t("main-use-specified-webui", webui_dir)` will raise `TypeError` due to the extra positional argument. The FTL entries also expect named variables (`$webui_dir`, `$v`, `$version`, `$error`), so these should be passed as keyword args, e.g.:
```python
logger.info(t("main-use-specified-webui", webui_dir=webui_dir))
logger.warning(t("main-webui-not-found", webui_dir=webui_dir))
logger.warning(t("main-webui-version-mismatch", v=v, version=VERSION))
logger.critical(t("main-download-dashboard-failed", error=e))
```
This avoids the runtime error and matches Fluent's variable naming.
</issue_to_address>
### Comment 2
<location> `locales/zh-cn/main.ftl:2-7` </location>
<code_context>
+main-python-version-error = 请使用 Python3.10+ 运行本项目。
+main-use-specified-webui = 使用指定的 WebUI 目录: {webui_dir}
+main-webui-not-found = 指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。
+main-webui-latest = WebUI 版本已是最新
+main-webui-version-mismatch = 检测到 WebUI 版本 ({v}) 与当前 AstrBot 版本 (v{VERSION}) 不符。
+main-downloading-dashboard = 开始下载管理面板文件...高峰期(晚上)可能导致较慢的速度。如多次下载失败,请前往 https://github.com/AstrBotDevs/AstrBot/releases/latest 下载 dist.zip,并将其中的 dist 文件夹解压至 data 目录下。
+main-download-dashboard-failed = 下载管理面板文件失败: {e}。
+main-download-dashboard-success = 管理面板下载完成。
+main-argparse-webui-dir-help = 指定 WebUI 静态文件目录路径
</code_context>
<issue_to_address>
**issue (bug_risk):** The zh-CN FTL file uses non-Fluent placeholder syntax that won’t be substituted correctly.
In Fluent, external arguments must be referenced with a leading `$`, e.g. `{ $webui_dir }`, `{ $v }`, `{ $version }`, `{ $error }`. The current zh-CN entries omit the `$` and use `VERSION`/`e`, which don’t match the variables you’ll pass from Python. Please align them with the en file and your Python kwargs, for example:
```ftl
main-use-specified-webui = 使用指定的 WebUI 目录: { $webui_dir }
main-webui-not-found = 指定的 WebUI 目录 { $webui_dir } 不存在,将使用默认逻辑。
main-webui-version-mismatch = 检测到 WebUI 版本 ({ $v }) 与当前 AstrBot 版本 (v{ $version }) 不符。
main-download-dashboard-failed = 下载管理面板文件失败: { $error }。
```
This way the Fluent runtime can correctly interpolate the values.
</issue_to_address>
### Comment 3
<location> `astrbot/dashboard/routes/lang_route.py:8-9` </location>
<code_context>
+class LangRoute(Route):
+ def __init__(self, context: RouteContext) -> None:
+ super().__init__(context)
+ self.routes = {
+ "/setLang": ("GET", self.set_Lang),
+ }
+ self.register_routes()
</code_context>
<issue_to_address>
**issue (bug_risk):** Route is registered as GET but the frontend uses POST with a JSON body, leading to a method mismatch.
The frontend calls `axios.post("/api/setLang", { lang: ... })`, but this route is registered as `"GET"`. Because `set_Lang` uses `await request.get_json()`, this should be exposed as a POST endpoint instead:
```python
self.routes = {
"/setLang": ("POST", self.set_Lang),
}
```
</issue_to_address>
### Comment 4
<location> `dashboard/src/i18n/composables.ts:101-110` </location>
<code_context>
detail: { locale: newLocale }
}));
+
+ axios.post("/api/setLang", { lang: newLocale })
+ .then(response => {
+ if (response.data.code !== 200) {
</code_context>
<issue_to_address>
**suggestion:** The language-setting call is duplicated in both `setLocale` and `setupI18n`, which could drift or complicate behavior changes.
The `axios.post("/api/setLang", ...)` call is implemented both on init and on locale change. To avoid duplication and potential drift, extract this into a helper like `syncLangWithServer(locale)` that both `setLocale` and `setupI18n` use, so future changes (e.g., error handling, retries) stay consistent in one place.
Suggested implementation:
```typescript
import { translations as staticTranslations } from './translations';
import type { Locale } from './types';
import axios from 'axios';
const syncLangWithServer = (locale: Locale) => {
return axios.post('/api/setLang', { lang: locale })
.then(response => {
if (response.data.code !== 200) {
console.error('Failed to set language on server:', response.data.message);
}
})
.catch(error => {
console.error('Error setting language on server:', error);
});
};
// 全局状态
const currentLocale = ref<Locale>('zh-CN');
```
```typescript
window.dispatchEvent(new CustomEvent('astrbot-locale-changed', {
detail: { locale: newLocale }
}));
syncLangWithServer(newLocale);
```
There is a second `axios.post("/api/setLang", ...)` call in the initialization logic of `setupI18n` (used on first load / init) that is not shown in the snippet. That block should also be replaced with `syncLangWithServer(initialLocale)` (or the appropriate variable used for the initial locale) so both init and runtime changes share the same implementation and error handling.帮我变得更有用!请在每条评论上点 👍 或 👎,我会根据你的反馈改进 Review 质量。
Original comment in English
Hey - I've found 4 issues, and left some high level feedback:
- The frontend calls
axios.post('/api/setLang', { lang }), butLangRoutecurrently registers'/setLang'with theGETmethod and reads a JSON body; this should be aligned (path and HTTP verb) to avoid runtime 404/method and request-body issues. - The new
t(...)usages inmain.pypass positional arguments (e.g.t('main-use-specified-webui', webui_dir)), butLang.__call__expects keyword arguments and the FTL variables (e.g.$webui_dir,$v,$version,$error) must match those keyword names; update calls to use named arguments and ensure the variable names in the .ftl files and code are consistent. - The zh-CN FTL entries use placeholders like
{webui_dir},{v},{VERSION},{e}without the$prefix and with names that differ from the English version; to prevent formatting errors, standardize them to Fluent syntax (e.g.{ $webui_dir }) and align variable names with the arguments you pass from Python.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The frontend calls `axios.post('/api/setLang', { lang })`, but `LangRoute` currently registers `'/setLang'` with the `GET` method and reads a JSON body; this should be aligned (path and HTTP verb) to avoid runtime 404/method and request-body issues.
- The new `t(...)` usages in `main.py` pass positional arguments (e.g. `t('main-use-specified-webui', webui_dir)`), but `Lang.__call__` expects keyword arguments and the FTL variables (e.g. `$webui_dir`, `$v`, `$version`, `$error`) must match those keyword names; update calls to use named arguments and ensure the variable names in the .ftl files and code are consistent.
- The zh-CN FTL entries use placeholders like `{webui_dir}`, `{v}`, `{VERSION}`, `{e}` without the `$` prefix and with names that differ from the English version; to prevent formatting errors, standardize them to Fluent syntax (e.g. `{ $webui_dir }`) and align variable names with the arguments you pass from Python.
## Individual Comments
### Comment 1
<location> `main.py:71` </location>
<code_context>
if webui_dir:
if os.path.exists(webui_dir):
- logger.info(f"使用指定的 WebUI 目录: {webui_dir}")
+ logger.info(t("main-use-specified-webui", webui_dir))
return webui_dir
- logger.warning(f"指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。")
</code_context>
<issue_to_address>
**issue (bug_risk):** Fluent translation calls use positional args, which will raise TypeError and also don't match the variable names in the FTL files.
`Lang.__call__` is defined as `def __call__(self, key: str, **kwargs)`, so `t("main-use-specified-webui", webui_dir)` will raise `TypeError` due to the extra positional argument. The FTL entries also expect named variables (`$webui_dir`, `$v`, `$version`, `$error`), so these should be passed as keyword args, e.g.:
```python
logger.info(t("main-use-specified-webui", webui_dir=webui_dir))
logger.warning(t("main-webui-not-found", webui_dir=webui_dir))
logger.warning(t("main-webui-version-mismatch", v=v, version=VERSION))
logger.critical(t("main-download-dashboard-failed", error=e))
```
This avoids the runtime error and matches Fluent's variable naming.
</issue_to_address>
### Comment 2
<location> `locales/zh-cn/main.ftl:2-7` </location>
<code_context>
+main-python-version-error = 请使用 Python3.10+ 运行本项目。
+main-use-specified-webui = 使用指定的 WebUI 目录: {webui_dir}
+main-webui-not-found = 指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。
+main-webui-latest = WebUI 版本已是最新
+main-webui-version-mismatch = 检测到 WebUI 版本 ({v}) 与当前 AstrBot 版本 (v{VERSION}) 不符。
+main-downloading-dashboard = 开始下载管理面板文件...高峰期(晚上)可能导致较慢的速度。如多次下载失败,请前往 https://github.com/AstrBotDevs/AstrBot/releases/latest 下载 dist.zip,并将其中的 dist 文件夹解压至 data 目录下。
+main-download-dashboard-failed = 下载管理面板文件失败: {e}。
+main-download-dashboard-success = 管理面板下载完成。
+main-argparse-webui-dir-help = 指定 WebUI 静态文件目录路径
</code_context>
<issue_to_address>
**issue (bug_risk):** The zh-CN FTL file uses non-Fluent placeholder syntax that won’t be substituted correctly.
In Fluent, external arguments must be referenced with a leading `$`, e.g. `{ $webui_dir }`, `{ $v }`, `{ $version }`, `{ $error }`. The current zh-CN entries omit the `$` and use `VERSION`/`e`, which don’t match the variables you’ll pass from Python. Please align them with the en file and your Python kwargs, for example:
```ftl
main-use-specified-webui = 使用指定的 WebUI 目录: { $webui_dir }
main-webui-not-found = 指定的 WebUI 目录 { $webui_dir } 不存在,将使用默认逻辑。
main-webui-version-mismatch = 检测到 WebUI 版本 ({ $v }) 与当前 AstrBot 版本 (v{ $version }) 不符。
main-download-dashboard-failed = 下载管理面板文件失败: { $error }。
```
This way the Fluent runtime can correctly interpolate the values.
</issue_to_address>
### Comment 3
<location> `astrbot/dashboard/routes/lang_route.py:8-9` </location>
<code_context>
+class LangRoute(Route):
+ def __init__(self, context: RouteContext) -> None:
+ super().__init__(context)
+ self.routes = {
+ "/setLang": ("GET", self.set_Lang),
+ }
+ self.register_routes()
</code_context>
<issue_to_address>
**issue (bug_risk):** Route is registered as GET but the frontend uses POST with a JSON body, leading to a method mismatch.
The frontend calls `axios.post("/api/setLang", { lang: ... })`, but this route is registered as `"GET"`. Because `set_Lang` uses `await request.get_json()`, this should be exposed as a POST endpoint instead:
```python
self.routes = {
"/setLang": ("POST", self.set_Lang),
}
```
</issue_to_address>
### Comment 4
<location> `dashboard/src/i18n/composables.ts:101-110` </location>
<code_context>
detail: { locale: newLocale }
}));
+
+ axios.post("/api/setLang", { lang: newLocale })
+ .then(response => {
+ if (response.data.code !== 200) {
</code_context>
<issue_to_address>
**suggestion:** The language-setting call is duplicated in both `setLocale` and `setupI18n`, which could drift or complicate behavior changes.
The `axios.post("/api/setLang", ...)` call is implemented both on init and on locale change. To avoid duplication and potential drift, extract this into a helper like `syncLangWithServer(locale)` that both `setLocale` and `setupI18n` use, so future changes (e.g., error handling, retries) stay consistent in one place.
Suggested implementation:
```typescript
import { translations as staticTranslations } from './translations';
import type { Locale } from './types';
import axios from 'axios';
const syncLangWithServer = (locale: Locale) => {
return axios.post('/api/setLang', { lang: locale })
.then(response => {
if (response.data.code !== 200) {
console.error('Failed to set language on server:', response.data.message);
}
})
.catch(error => {
console.error('Error setting language on server:', error);
});
};
// 全局状态
const currentLocale = ref<Locale>('zh-CN');
```
```typescript
window.dispatchEvent(new CustomEvent('astrbot-locale-changed', {
detail: { locale: newLocale }
}));
syncLangWithServer(newLocale);
```
There is a second `axios.post("/api/setLang", ...)` call in the initialization logic of `setupI18n` (used on first load / init) that is not shown in the snippet. That block should also be replaced with `syncLangWithServer(initialLocale)` (or the appropriate variable used for the initial locale) so both init and runtime changes share the same implementation and error handling.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| if webui_dir: | ||
| if os.path.exists(webui_dir): | ||
| logger.info(f"使用指定的 WebUI 目录: {webui_dir}") | ||
| logger.info(t("main-use-specified-webui", webui_dir)) |
There was a problem hiding this comment.
issue (bug_risk): Fluent 的翻译调用使用了位置参数,这会触发 TypeError,并且也与 FTL 文件中的变量名不匹配。
Lang.__call__ 的定义是 def __call__(self, key: str, **kwargs),因此 t("main-use-specified-webui", webui_dir) 会因为多出的那个位置参数触发 TypeError。FTL 条目也期望使用具名变量($webui_dir, $v, $version, $error),因此应该通过关键字参数传入,例如:
logger.info(t("main-use-specified-webui", webui_dir=webui_dir))
logger.warning(t("main-webui-not-found", webui_dir=webui_dir))
logger.warning(t("main-webui-version-mismatch", v=v, version=VERSION))
logger.critical(t("main-download-dashboard-failed", error=e))这样可以避免运行时错误,并与 Fluent 的变量命名保持一致。
Original comment in English
issue (bug_risk): Fluent translation calls use positional args, which will raise TypeError and also don't match the variable names in the FTL files.
Lang.__call__ is defined as def __call__(self, key: str, **kwargs), so t("main-use-specified-webui", webui_dir) will raise TypeError due to the extra positional argument. The FTL entries also expect named variables ($webui_dir, $v, $version, $error), so these should be passed as keyword args, e.g.:
logger.info(t("main-use-specified-webui", webui_dir=webui_dir))
logger.warning(t("main-webui-not-found", webui_dir=webui_dir))
logger.warning(t("main-webui-version-mismatch", v=v, version=VERSION))
logger.critical(t("main-download-dashboard-failed", error=e))This avoids the runtime error and matches Fluent's variable naming.
| main-use-specified-webui = 使用指定的 WebUI 目录: {webui_dir} | ||
| main-webui-not-found = 指定的 WebUI 目录 {webui_dir} 不存在,将使用默认逻辑。 | ||
| main-webui-latest = WebUI 版本已是最新 | ||
| main-webui-version-mismatch = 检测到 WebUI 版本 ({v}) 与当前 AstrBot 版本 (v{VERSION}) 不符。 | ||
| main-downloading-dashboard = 开始下载管理面板文件...高峰期(晚上)可能导致较慢的速度。如多次下载失败,请前往 https://github.com/AstrBotDevs/AstrBot/releases/latest 下载 dist.zip,并将其中的 dist 文件夹解压至 data 目录下。 | ||
| main-download-dashboard-failed = 下载管理面板文件失败: {e}。 |
There was a problem hiding this comment.
issue (bug_risk): zh-CN 的 FTL 文件使用了非 Fluent 的占位符语法,无法被正确替换。
在 Fluent 中,外部参数必须使用带有 $ 前缀的形式引用,例如 { $webui_dir }, { $v }, { $version }, { $error }。当前 zh-CN 条目省略了 $,并使用 VERSION / e,这和你在 Python 中传入的变量名并不匹配。请将它们与英文文件以及 Python 里的关键字参数对齐,例如:
main-use-specified-webui = 使用指定的 WebUI 目录: { $webui_dir }
main-webui-not-found = 指定的 WebUI 目录 { $webui_dir } 不存在,将使用默认逻辑。
main-webui-version-mismatch = 检测到 WebUI 版本 ({ $v }) 与当前 AstrBot 版本 (v{ $version }) 不符。
main-download-dashboard-failed = 下载管理面板文件失败: { $error }。这样 Fluent 运行时时才能正确插入这些变量值。
Original comment in English
issue (bug_risk): The zh-CN FTL file uses non-Fluent placeholder syntax that won’t be substituted correctly.
In Fluent, external arguments must be referenced with a leading $, e.g. { $webui_dir }, { $v }, { $version }, { $error }. The current zh-CN entries omit the $ and use VERSION/e, which don’t match the variables you’ll pass from Python. Please align them with the en file and your Python kwargs, for example:
main-use-specified-webui = 使用指定的 WebUI 目录: { $webui_dir }
main-webui-not-found = 指定的 WebUI 目录 { $webui_dir } 不存在,将使用默认逻辑。
main-webui-version-mismatch = 检测到 WebUI 版本 ({ $v }) 与当前 AstrBot 版本 (v{ $version }) 不符。
main-download-dashboard-failed = 下载管理面板文件失败: { $error }。This way the Fluent runtime can correctly interpolate the values.
| self.routes = { | ||
| "/setLang": ("GET", self.set_Lang), |
There was a problem hiding this comment.
issue (bug_risk): 路由注册为 GET,但前端使用的是带 JSON body 的 POST 请求,导致方法不匹配。
前端调用的是 axios.post("/api/setLang", { lang: ... }),但当前路由注册的是 "GET"。由于 set_Lang 使用了 await request.get_json(),因此应将其暴露为 POST 接口,例如:
self.routes = {
"/setLang": ("POST", self.set_Lang),
}Original comment in English
issue (bug_risk): Route is registered as GET but the frontend uses POST with a JSON body, leading to a method mismatch.
The frontend calls axios.post("/api/setLang", { lang: ... }), but this route is registered as "GET". Because set_Lang uses await request.get_json(), this should be exposed as a POST endpoint instead:
self.routes = {
"/setLang": ("POST", self.set_Lang),
}| axios.post("/api/setLang", { lang: newLocale }) | ||
| .then(response => { | ||
| if (response.data.code !== 200) { | ||
| console.error('Failed to set language on server:', response.data.message); | ||
| } | ||
| }) | ||
| .catch(error => { | ||
| console.error('Error setting language on server:', error); | ||
| }); | ||
| } |
There was a problem hiding this comment.
suggestion: 语言设置的调用在 setLocale 和 setupI18n 中都各写了一遍,这可能导致逻辑漂移,也会让之后修改行为变得更复杂。
axios.post("/api/setLang", ...) 在初始化阶段和语言切换时都实现了一遍。为了避免重复和潜在的不一致,可以抽取一个类似 syncLangWithServer(locale) 的帮助函数,让 setLocale 和 setupI18n 共同使用,这样未来的改动(比如错误处理、重试机制)只需要维护一个地方。
建议实现:
import { translations as staticTranslations } from './translations';
import type { Locale } from './types';
import axios from 'axios';
const syncLangWithServer = (locale: Locale) => {
return axios.post('/api/setLang', { lang: locale })
.then(response => {
if (response.data.code !== 200) {
console.error('Failed to set language on server:', response.data.message);
}
})
.catch(error => {
console.error('Error setting language on server:', error);
});
};
// 全局状态
const currentLocale = ref<Locale>('zh-CN'); window.dispatchEvent(new CustomEvent('astrbot-locale-changed', {
detail: { locale: newLocale }
}));
syncLangWithServer(newLocale);在 setupI18n 的初始化逻辑中还有第二个 axios.post("/api/setLang", ...) 调用(用于首次加载 / 初始化),该代码片段没有出现在当前截取的内容里。那一块也应该替换为 syncLangWithServer(initialLocale)(或使用对应的初始语言变量),这样初始化和运行时的语言同步逻辑及错误处理就能共用同一套实现。
Original comment in English
suggestion: The language-setting call is duplicated in both setLocale and setupI18n, which could drift or complicate behavior changes.
The axios.post("/api/setLang", ...) call is implemented both on init and on locale change. To avoid duplication and potential drift, extract this into a helper like syncLangWithServer(locale) that both setLocale and setupI18n use, so future changes (e.g., error handling, retries) stay consistent in one place.
Suggested implementation:
import { translations as staticTranslations } from './translations';
import type { Locale } from './types';
import axios from 'axios';
const syncLangWithServer = (locale: Locale) => {
return axios.post('/api/setLang', { lang: locale })
.then(response => {
if (response.data.code !== 200) {
console.error('Failed to set language on server:', response.data.message);
}
})
.catch(error => {
console.error('Error setting language on server:', error);
});
};
// 全局状态
const currentLocale = ref<Locale>('zh-CN'); window.dispatchEvent(new CustomEvent('astrbot-locale-changed', {
detail: { locale: newLocale }
}));
syncLangWithServer(newLocale);There is a second axios.post("/api/setLang", ...) call in the initialization logic of setupI18n (used on first load / init) that is not shown in the snippet. That block should also be replaced with syncLangWithServer(initialLocale) (or the appropriate variable used for the initial locale) so both init and runtime changes share the same implementation and error handling.
Modifications / 改动点
astrbot/dashboard/routes/lang_route.py
给这个地方添加了个文件用于注册lang相关的路由
astrbot/dashboard/server.py
在这个代码的AstrBotDashboard添加了LangRoute的实例化
astrbot/core/lang.py
给Lang添加了load_locale方法,方便外部进行t的语言更新
dashboard/src/i18n/composables.ts
在切换和初始化部分添加了向后端的请求,用于切换i18n
实现的功能是能够让webui在操作i18n时能够实时反映到后端的日志上面去
Screenshots or Test Results / 运行截图或测试结果
没有,先这样改吧,后续讨论!
Checklist / 检查清单
没有测试喵
requirements.txt和pyproject.toml文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations inrequirements.txtandpyproject.toml.Summary by Sourcery
添加一个共享的 i18n 系统,使得 WebUI 语言环境更改时可以更新后端语言并本地化核心消息。
新功能:
/api/setLang仪表盘路由,以便从 WebUI 在运行时更新后端语言。改进:
main.py中使用本地化消息键对关键启动日志和 CLI 帮助文本进行国际化。Original summary in English
Summary by Sourcery
Add a shared i18n system so WebUI locale changes update backend language and localize core messages.
New Features:
Enhancements: