Skip to content

feat: add i18n supports for custom platform adapters#5045

Merged
Soulter merged 2 commits intoAstrBotDevs:masterfrom
stevessr:metadata-patch
Feb 12, 2026
Merged

feat: add i18n supports for custom platform adapters#5045
Soulter merged 2 commits intoAstrBotDevs:masterfrom
stevessr:metadata-patch

Conversation

@stevessr
Copy link
Contributor

@stevessr stevessr commented Feb 11, 2026

目前,由插件提供的适配器通过 monkey patch 的方法注入 metadata ,然而,此举在最近版本的 UI 中遭到了损坏,此修改旨在为其提供可用的修饰器参数

Modifications / 改动点

astrbot/core/platform/platform_metadata.py
添加了可选的metadata和i18n传入

    i18n_resources: dict[str, dict] | None = None
    """国际化资源数据,如 {"zh-CN": {...}, "en-US": {...}}"""

    config_metadata: dict | None = None
    """配置项元数据,用于 WebUI 生成表单。对应 config_metadata.json 的内容"""

astrbot/dashboard/routes/config.py
为外部平台添加了专门的 platform_i18n_translations 键值

dashboard/src/components/platform/AddNewPlatform.vue
添加了平台图标回落(对于外部注入的部分)

dashboard/src/i18n/composables.ts
dashboard/src/main.ts
dashboard/src/views/ConfigPage.vue
dashboard/src/views/ExtensionPage.vue
dashboard/src/views/PlatformPage.vue
添加动态多语言

  • This is NOT a breaking change. / 这不是一个破坏性变更。

Screenshots or Test Results / 运行截图或测试结果

image image 修改后 image image

Checklist / 检查清单

  • 😊 如果 PR 中有新加入的功能,已经通过 Issue / 邮件等方式和作者讨论过。/ If there are new features added in the PR, I have discussed it with the authors through issues/emails, etc.
  • 👀 我的更改经过了良好的测试,并已在上方提供了“验证步骤”和“运行截图”。/ My changes have been well-tested, and "Verification Steps" and "Screenshots" have been provided above.
  • 🤓 我确保没有引入新依赖库,或者引入了新依赖库的同时将其添加到了 requirements.txtpyproject.toml 文件相应位置。/ I have ensured that no new dependencies are introduced, OR if new dependencies are introduced, they have been added to the appropriate locations in requirements.txt and pyproject.toml.
  • 😮 我的更改没有引入恶意代码。/ My changes do not introduce malicious code.

由 Sourcery 提供的总结

为插件提供的平台适配器新增一等公民的元数据和国际化(i18n)支持,使其配置界面和文本可以按不同语言环境(locale)动态渲染。

新功能:

  • 允许平台适配器通过注册装饰器提供配置元数据和 i18n 资源,用于驱动 WebUI 表单生成和文案翻译。
  • 通过后端配置 API 暴露平台适配器的 i18n 翻译数据,供仪表盘(dashboard)使用。
  • 在仪表盘中添加新平台时支持插件提供的平台 Logo。

缺陷修复:

  • 用结构化的数据路径替换脆弱的适配器元数据 monkey-patching,避免在新版 UI 中出现兼容性问题。

改进增强:

  • 通过 axios 和 fetch 请求中的 Accept-Language 头传递并遵循当前选择的语言环境,当语言环境改变时重新加载相关页面。
  • 将动态加载的平台配置翻译数据合并到前端 i18n 存储中,从而在无需刷新页面的情况下实现运行时更新。
  • 确保平台和插件配置视图在语言环境变化事件发生时,通过在新的语言上下文中重新获取配置数据来做出响应。
Original summary in English

Summary by Sourcery

Add first-class metadata and i18n support for plugin-provided platform adapters so their configuration UIs and texts can be dynamically rendered per locale.

New Features:

  • Allow platform adapters to provide config metadata and i18n resources via the registration decorator to drive WebUI form generation and translations.
  • Expose platform adapter i18n translations from the backend config API for consumption by the dashboard.
  • Support plugin-provided platform logos when adding new platforms in the dashboard.

Bug Fixes:

  • Replace fragile monkey-patching of adapter metadata with a structured data path, preventing breakage in newer UI versions.

Enhancements:

  • Propagate and respect the selected locale via Accept-Language headers in axios and fetch requests, and reload relevant pages when the locale changes.
  • Merge dynamically loaded translation data for platform configuration into the frontend i18n store, enabling runtime updates without reloads.
  • Ensure platform and plugin configuration views react to locale change events by refetching config data with the new language context.

Copilot AI review requested due to automatic review settings February 11, 2026 14:47
@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Feb 11, 2026
@dosubot
Copy link

dosubot bot commented Feb 11, 2026

Related Documentation

Checked 1 published document(s) in 1 knowledge base(s). No updates required.

How did I do? Any feedback?  Join Discord

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了 1 个问题,并给出了一些整体性的反馈:

  • 新增的 config.py 中的 _resolve_accept_language 辅助函数目前没有被使用;请要么将其接入相关的请求/响应流程(例如在构造 i18n 负载时使用),要么移除它以避免产生死代码。
  • register_platform_adapter 中的 i18n_resources 参数被标注为 dict[str, str],但 PlatformMetadata.i18n_resources 的类型是 dict[str, dict];请对齐这两处的类型,并明确预期的数据结构(例如 { 'zh-CN': { ... } }),以免让适配器作者产生困惑。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The newly added `_resolve_accept_language` helper in `config.py` is currently unused; either wire it into the relevant request/response flow (e.g., when shaping i18n payloads) or remove it to avoid dead code.
- The `i18n_resources` parameter in `register_platform_adapter` is typed as `dict[str, str]`, but `PlatformMetadata.i18n_resources` is `dict[str, dict]`; aligning these types and clarifying the expected structure (e.g., `{ 'zh-CN': { ... } }`) will prevent confusion for adapter authors.

## Individual Comments

### Comment 1
<location> `astrbot/core/platform/register.py:18-19` </location>
<code_context>
     adapter_display_name: str | None = None,
     logo_path: str | None = None,
     support_streaming_message: bool = True,
+    i18n_resources: dict[str, str] | None = None,
+    config_metadata: dict | None = None,
 ):
     """用于注册平台适配器的带参装饰器。
</code_context>

<issue_to_address>
**issue:** Align `i18n_resources` type annotation with `PlatformMetadata` to avoid confusion and misuse.

Here `i18n_resources` is annotated as `dict[str, str] | None`, while `PlatformMetadata.i18n_resources` is `dict[str, dict] | None`. This inconsistency suggests a different structure and can confuse users and type checkers. Please update the decorator parameter to match `PlatformMetadata` (likely `dict[str, dict] | None`).
</issue_to_address>

Sourcery 对开源项目免费使用——如果你觉得我们的代码审查有帮助,欢迎帮忙分享 ✨
帮我变得更有用!请对每条评论点 👍 或 👎,我会根据你的反馈改进后续的审查建议。
Original comment in English

Hey - I've found 1 issue, and left some high level feedback:

  • The newly added _resolve_accept_language helper in config.py is currently unused; either wire it into the relevant request/response flow (e.g., when shaping i18n payloads) or remove it to avoid dead code.
  • The i18n_resources parameter in register_platform_adapter is typed as dict[str, str], but PlatformMetadata.i18n_resources is dict[str, dict]; aligning these types and clarifying the expected structure (e.g., { 'zh-CN': { ... } }) will prevent confusion for adapter authors.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The newly added `_resolve_accept_language` helper in `config.py` is currently unused; either wire it into the relevant request/response flow (e.g., when shaping i18n payloads) or remove it to avoid dead code.
- The `i18n_resources` parameter in `register_platform_adapter` is typed as `dict[str, str]`, but `PlatformMetadata.i18n_resources` is `dict[str, dict]`; aligning these types and clarifying the expected structure (e.g., `{ 'zh-CN': { ... } }`) will prevent confusion for adapter authors.

## Individual Comments

### Comment 1
<location> `astrbot/core/platform/register.py:18-19` </location>
<code_context>
     adapter_display_name: str | None = None,
     logo_path: str | None = None,
     support_streaming_message: bool = True,
+    i18n_resources: dict[str, str] | None = None,
+    config_metadata: dict | None = None,
 ):
     """用于注册平台适配器的带参装饰器。
</code_context>

<issue_to_address>
**issue:** Align `i18n_resources` type annotation with `PlatformMetadata` to avoid confusion and misuse.

Here `i18n_resources` is annotated as `dict[str, str] | None`, while `PlatformMetadata.i18n_resources` is `dict[str, dict] | None`. This inconsistency suggests a different structure and can confuse users and type checkers. Please update the decorator parameter to match `PlatformMetadata` (likely `dict[str, dict] | None`).
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@dosubot dosubot bot added area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. area:webui The bug / feature is about webui(dashboard) of astrbot. labels Feb 11, 2026
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

@Soulter
Copy link
Member

Soulter commented Feb 12, 2026

你好,请问可以给一个修改之后的

    i18n_resources: dict[str, dict] | None = None
    """国际化资源数据,如 {"zh-CN": {...}, "en-US": {...}}"""

    config_metadata: dict | None = None
    """配置项元数据,用于 WebUI 生成表单。对应 config_metadata.json 的内容"""

的例子嘛

@stevessr
Copy link
Contributor Author

你好,请问可以给一个修改之后的

    i18n_resources: dict[str, dict] | None = None
    """国际化资源数据,如 {"zh-CN": {...}, "en-US": {...}}"""

    config_metadata: dict | None = None
    """配置项元数据,用于 WebUI 生成表单。对应 config_metadata.json 的内容"""

的例子嘛

https://github.com/stevessr/astrbot_plugin_astrbook/blob/32db37862669e1e33d0836415462266f6cfa07d2/adapter/astrbook_adapter.py

diff --git a/adapter/astrbook_adapter.py b/adapter/astrbook_adapter.py
index abdf0b8..e8fc72d 100644
--- a/adapter/astrbook_adapter.py
+++ b/adapter/astrbook_adapter.py
@@ -44,6 +44,118 @@ from .forum_memory import ForumMemory
         "reply_probability": 0.3,  # Probability to trigger LLM reply (0.0-1.0)
         "custom_prompt": "",  # Custom browse prompt, leave empty to use default
     },
+    i18n_resources={
+        "zh-CN": {
+            "api_base": {
+                "description": "基础 api",
+                "hint": "astbook API 的基础地址",
+            },
+            "token": {
+                "description": "astbook 平台 token",
+                "hint": "astbook 平台 token",
+            },
+            "auto_browse": {
+                "description": "自动浏览",
+                "hint": "是否启动 astbook 自动浏览",
+            },
+            "browse_interval": {
+                "description": "自动浏览时间间隔 (s)",
+                "hint": "astbook 自动浏览时间间隔 (s)",
+            },
+            "auto_reply_mentions": {
+                "description": "自动回复",
+                "hint": "是否启动 astbook 自动回复",
+            },
+            "max_memory_items": {
+                "description": "最大记忆量",
+                "hint": "astbook 的记忆存储的最大记忆量",
+            },
+            "reply_probability": {
+                "description": "回复概率",
+                "hint": "astbook 自动回复概率",
+            },
+            "custom_prompt": {
+                "description": "自定义逛帖提示词",
+                "hint": "自定义浏览论坛时的提示词,留空使用默认",
+            },
+        },
+        "en-US": {
+            "api_base": {
+                "description": "base api",
+                "hint": "base address of the astbook API",
+            },
+            "token": {
+                "description": "astbook platform token",
+                "hint": "astbook platform token",
+            },
+            "auto_browse": {
+                "description": "auto browse",
+                "hint": "whether to enable astbook auto browse",
+            },
+            "browse_interval": {
+                "description": "auto browse interval (s)",
+                "hint": "astbook auto browse interval (s)",
+            },
+            "auto_reply_mentions": {
+                "description": "auto reply",
+                "hint": "whether to enable astbook auto reply",
+            },
+            "max_memory_items": {
+                "description": "maximum memory items",
+                "hint": "maximum memory items stored by astbook",
+            },
+            "reply_probability": {
+                "description": "reply probability",
+                "hint": "astbook auto reply probability",
+            },
+            "custom_prompt": {
+                "description": "custom browse prompt",
+                "hint": "custom browse prompt for the forum, leave empty to use default",
+            },
+        },
+    },
+    config_metadata={
+        "api_base": {
+            "description": "基础 api",
+            "type": "string",
+            "hint": "astbook API 的基础地址",
+        },
+        "token": {
+            "description": "astbook 平台 token",
+            "type": "string",
+            "hint": "astbook 平台 token",
+        },
+        "auto_browse": {
+            "description": "自动浏览",
+            "type": "bool",
+            "hint": "是否启动 astbook 自动浏览",
+        },
+        "browse_interval": {
+            "description": "自动浏览时间间隔 (s)",
+            "type": "int",
+            "hint": "astbook 自动浏览时间间隔 (s)",
+        },
+        "auto_reply_mentions": {
+            "description": "自动回复",
+            "type": "bool",
+            "hint": "是否启动 astbook 自动回复",
+        },
+        "max_memory_items": {
+            "description": "最大记忆量",
+            "type": "int",
+            "hint": "astbook 的记忆存储的最大记忆量",
+        },
+        "reply_probability": {
+            "description": "回复概率",
+            "type": "float",
+            "hint": "astbook 自动回复概率",
+        },
+        "custom_prompt": {
+            "description": "自定义逛帖提示词",
+            "type": "string",
+            "hint": "自定义浏览论坛时的提示词,留空使用默认",
+        },
+    },
 )
 class AstrBookAdapter(Platform):
     """AstrBook platform adapter implementation."""
@@ -98,7 +210,7 @@ class AstrBookAdapter(Platform):
         message_chain: MessageChain,
     ):
         """Send message through session.
-        
+
         Note: For AstrBook, LLM uses tools (reply_thread, reply_floor) to send messages.
         This method is kept for compatibility but does nothing special.
         """
@@ -190,11 +302,15 @@ class AstrBookAdapter(Platform):
                 timeout=aiohttp.ClientTimeout(total=None, sock_read=None),
             ) as resp:
                 if resp.status == 401:
-                    logger.error("[AstrBook] SSE authentication failed: invalid or expired token")
+                    logger.error(
+                        "[AstrBook] SSE authentication failed: invalid or expired token"
+                    )
                     return
 
                 if resp.status != 200:
-                    logger.error(f"[AstrBook] SSE connection failed with status {resp.status}")
+                    logger.error(
+                        f"[AstrBook] SSE connection failed with status {resp.status}"
+                    )
                     return
 
                 self._connected = True
@@ -379,11 +495,15 @@ class AstrBookAdapter(Platform):
                 "Content-Type": "application/json",
             }
             async with aiohttp.ClientSession() as session:
-                async with session.post(url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)) as resp:
+                async with session.post(
+                    url, headers=headers, timeout=aiohttp.ClientTimeout(total=10)
+                ) as resp:
                     if resp.status == 200:
                         logger.debug("[AstrBook] Notifications marked as read")
                     else:
-                        logger.warning(f"[AstrBook] Failed to mark notifications as read: {resp.status}")
+                        logger.warning(
+                            f"[AstrBook] Failed to mark notifications as read: {resp.status}"
+                        )
         except Exception as e:
             logger.warning(f"[AstrBook] Error marking notifications as read: {e}")
 
@@ -498,7 +618,7 @@ class AstrBookAdapter(Platform):
 
     def get_unified_msg_origin(self) -> str:
         """Get the unified_msg_origin string for the AstrBook adapter session.
-        
+
         Format: platform_id:FriendMessage:astrbook_browse_system
         """
         return f"{self._metadata.id}:FriendMessage:astrbook_browse_system"

@Li-shi-ling Li-shi-ling mentioned this pull request Feb 12, 2026
1 task
@dosubot dosubot bot added the lgtm This PR has been approved by a maintainer label Feb 12, 2026
Added references to pull request 5045 in docstrings.
@Soulter Soulter merged commit 473e01a into AstrBotDevs:master Feb 12, 2026
5 checks passed
@Soulter Soulter changed the title [Feat]: 为插件提供的适配器的元数据提供数据通路 feat: add i18n supports for custom platform adapters Feb 12, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:platform The bug / feature is about IM platform adapter, such as QQ, Lark, Telegram, WebChat and so on. area:webui The bug / feature is about webui(dashboard) of astrbot. lgtm This PR has been approved by a maintainer size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants