mirror of
https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
synced 2026-03-05 05:36:54 +08:00
🌐 支持i18n (#501)
* ✨ 支持 i18n #410 * 🚨 更改noqa方式 * 📝 添加 CONTRIBUTING.md 文件 * 🌐 将 i18n 默认语言设置为 en-US * 📝 添加英文版 CONTRIBUTING.md
This commit is contained in:
67
CONTRIBUTING.en-US.md
Normal file
67
CONTRIBUTING.en-US.md
Normal file
@@ -0,0 +1,67 @@
|
||||
# How to Contribute?
|
||||
|
||||
## Setting Up the Environment
|
||||
|
||||
### For Developers with Basic Python Knowledge
|
||||
|
||||
First, you need [Python **3.10**](https://www.python.org/) and [Poetry](https://python-poetry.org/).
|
||||
Then, you need to clone this repository to your local machine using the `git clone` command, and install dependencies using `poetry install --sync`.
|
||||
|
||||
### For Developers with Limited Python Knowledge
|
||||
|
||||
Here are **my recommended** best practices:
|
||||
|
||||
```bash
|
||||
# Install uv
|
||||
# Please refer to https://docs.astral.sh/uv/getting-started/installation/
|
||||
|
||||
# Set up the basic Python environment
|
||||
uv python install 3.10
|
||||
uv tool install poetry
|
||||
|
||||
# Clone the repository
|
||||
git clone https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
|
||||
cd nonebot-plugin-tetris-stats
|
||||
|
||||
# Install dependencies
|
||||
uv run --no-project --python 3.10 poetry env use python
|
||||
poetry install --sync
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
### Code Development
|
||||
|
||||
1. For static code analysis, use [ruff](https://docs.astral.sh/ruff/). You can install the corresponding plugin for your IDE or use the command line with `ruff check ./nonebot_plugin_tetris_stats/` to check the code.
|
||||
2. For code formatting, use [ruff](https://docs.astral.sh/ruff/). You can install the corresponding plugin for your IDE or use the command line with `ruff format ./nonebot_plugin_tetris_stats/` to format the code.
|
||||
3. For type checking, use both [basedpyright](https://docs.basedpyright.com/latest/) and [mypy](https://www.mypy-lang.org/). You can install the corresponding plugins for your IDE or use the following commands in the terminal to check the code:
|
||||
|
||||
```bash
|
||||
# basedpyright
|
||||
basedpyright ./nonebot_plugin_tetris_stats/
|
||||
|
||||
# mypy
|
||||
mypy ./nonebot_plugin_tetris_stats/
|
||||
```
|
||||
|
||||
### Internationalization
|
||||
|
||||
This project uses [Tarina](https://github.com/ArcletProject/Tarina) for internationalization support.
|
||||
|
||||
#### Adding a New Language
|
||||
|
||||
1. Navigate to the `./nonebot_plugin_tetris_stats/i18n/` directory.
|
||||
2. Run `tarina-lang create {language_code}` * Please note that the language code should preferably follow the [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag) standard.
|
||||
3. Edit the generated `./nonebot_plugin_tetris_stats/i18n/{language_code}.json` file.
|
||||
|
||||
#### Updating an Existing Language
|
||||
|
||||
1. Navigate to the `./nonebot_plugin_tetris_stats/i18n/` directory.
|
||||
2. Edit the corresponding `./nonebot_plugin_tetris_stats/i18n/{language_code}.json` file.
|
||||
|
||||
#### Adding New Entries
|
||||
|
||||
1. Navigate to the `./nonebot_plugin_tetris_stats/i18n/` directory.
|
||||
2. Edit the `.template.json` file.
|
||||
3. Run `tarina-lang schema && tarina-lang model`.
|
||||
4. Modify the language files, adding new entries at least to `en-US.json`.
|
||||
68
CONTRIBUTING.md
Normal file
68
CONTRIBUTING.md
Normal file
@@ -0,0 +1,68 @@
|
||||
# 我该如何参与开发?
|
||||
|
||||
## 配置环境
|
||||
|
||||
### 对于有一定 Python 基础的开发者
|
||||
|
||||
首先你需要 [Python **3.10**](https://www.python.org/) 以及 [Poetry](https://python-poetry.org/)。
|
||||
然后你需要使用`git clone`命令将本仓库克隆到本地,然后使用`poetry install --sync`安装依赖。
|
||||
|
||||
### 对于基础不是很好的开发者
|
||||
|
||||
以下是**我认为的**最佳实践:
|
||||
|
||||
```bash
|
||||
# 安装 uv
|
||||
# 请参考 https://docs.astral.sh/uv/getting-started/installation/
|
||||
|
||||
# 配置基础 Python 环境
|
||||
uv python install 3.10
|
||||
uv tool install poetry
|
||||
|
||||
# 克隆仓库
|
||||
git clone https://github.com/A-Minos/nonebot-plugin-tetris-stats.git
|
||||
cd nonebot-plugin-tetris-stats
|
||||
|
||||
# 安装依赖
|
||||
uv run --no-project --python 3.10 poetry env use python
|
||||
poetry install --sync
|
||||
```
|
||||
|
||||
## 开发
|
||||
|
||||
### 代码开发
|
||||
|
||||
1. 代码静态检查使用 [ruff](https://docs.astral.sh/ruff/),你可以为你的ide安装对应插件来使用,也可以在命令行使用`ruff check ./nonebot_plugin_tetris_stats/`来检查代码。
|
||||
2. 代码格式化使用 [ruff](https://docs.astral.sh/ruff/),你可以为你的ide安装对应插件来使用,也可以在命令行使用`ruff format ./nonebot_plugin_tetris_stats/`来格式化代码。
|
||||
3. 类型检查同时使用 [basedpyright](https://docs.basedpyright.com/latest/) 和 [mypy](https://www.mypy-lang.org/),你可以为你的ide安装对应插件来使用。
|
||||
也可以在命令行使用下面的命令来检查代码:
|
||||
|
||||
```bash
|
||||
# basedpyright
|
||||
basedpyright ./nonebot_plugin_tetris_stats/
|
||||
|
||||
# mypy
|
||||
mypy ./nonebot_plugin_tetris_stats/
|
||||
```
|
||||
|
||||
### 国际化
|
||||
|
||||
本项目使用 [Tarina](https://github.com/ArcletProject/Tarina) 提供国际化支持。
|
||||
|
||||
#### 添加新的语言
|
||||
|
||||
1. 进入 `./nonebot_plugin_tetris_stats/i18n/` 目录。
|
||||
2. 运行 `tarina-lang create {语言代码}` * 请注意,语言代码最好符合 [IETF语言标签](https://zh.wikipedia.org/wiki/IETF%E8%AF%AD%E8%A8%80%E6%A0%87%E7%AD%BE) 的规范。
|
||||
3. 编辑生成的 `./nonebot_plugin_tetris_stats/i18n/{语言代码}.json` 文件。
|
||||
|
||||
#### 更新已有语言
|
||||
|
||||
1. 进入 `./nonebot_plugin_tetris_stats/i18n/` 目录。
|
||||
2. 编辑对应的 `./nonebot_plugin_tetris_stats/i18n/{语言代码}.json` 文件。
|
||||
|
||||
#### 添加新的条目
|
||||
|
||||
1. 进入 `./nonebot_plugin_tetris_stats/i18n/` 目录。
|
||||
2. 编辑 `.template.json` 文件。
|
||||
3. 运行 `tarina-lang schema && tarina-lang model`。
|
||||
4. 修改语言文件,至少为`en-US.json`添加新的条目。
|
||||
@@ -7,6 +7,7 @@ from nonebot.typing import T_Handler
|
||||
from nonebot_plugin_alconna import AlcMatches, Alconna, At, CommandMeta, on_alconna
|
||||
|
||||
from .. import ns
|
||||
from ..i18n.model import Lang
|
||||
from ..utils.exception import MessageFormatError, NeedCatchError
|
||||
|
||||
command: Alconna = Alconna(
|
||||
@@ -30,7 +31,7 @@ def add_block_handlers(handler: Callable[[T_Handler], T_Handler]) -> None:
|
||||
@handler
|
||||
async def _(bot: Bot, matcher: Matcher, target: At):
|
||||
if isinstance(target, At) and target.target == bot.self_id:
|
||||
await matcher.finish('不能查询bot的信息')
|
||||
await matcher.finish(Lang.interaction.wrong.query_bot())
|
||||
|
||||
|
||||
from . import tetrio, top, tos # noqa: F401, E402
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
CANT_VERIFY_MESSAGE = '* 由于无法验证绑定信息, 不能保证查询到的用户为本人\n'
|
||||
@@ -14,10 +14,10 @@ from nonebot_plugin_user import get_user
|
||||
from sqlalchemy import select
|
||||
|
||||
from ....db import query_bind_info, trigger
|
||||
from ....i18n import Lang
|
||||
from ....utils.exception import FallbackError
|
||||
from ....utils.typing import Me
|
||||
from ... import add_block_handlers, alc
|
||||
from ...constant import CANT_VERIFY_MESSAGE
|
||||
from .. import command, get_player
|
||||
from ..api import Player
|
||||
from ..constant import GAME_TYPE
|
||||
@@ -113,9 +113,10 @@ async def _( # noqa: PLR0913
|
||||
)
|
||||
if bind is None:
|
||||
await matcher.finish('未查询到绑定信息')
|
||||
message = UniMessage(CANT_VERIFY_MESSAGE)
|
||||
player = Player(user_id=bind.game_account, trust=True)
|
||||
await (message + await make_query_result(player, template or 'v1')).finish()
|
||||
await (
|
||||
UniMessage.i18n(Lang.interaction.warning.unverified) + await make_query_result(player, template or 'v1')
|
||||
).finish()
|
||||
|
||||
|
||||
@alc.assign('TETRIO.query')
|
||||
|
||||
@@ -13,6 +13,7 @@ from nonebot_plugin_user import get_user
|
||||
from yarl import URL
|
||||
|
||||
from ....db import query_bind_info, trigger
|
||||
from ....i18n import Lang
|
||||
from ....utils.exception import RecordNotFoundError
|
||||
from ....utils.host import HostPage, get_self_netloc
|
||||
from ....utils.metrics import get_metrics
|
||||
@@ -22,7 +23,6 @@ from ....utils.render.schemas.tetrio.record.base import Finesse, Max, Mini, Tspi
|
||||
from ....utils.render.schemas.tetrio.record.blitz import Record, Statistic
|
||||
from ....utils.screenshot import screenshot
|
||||
from ....utils.typing import Me
|
||||
from ...constant import CANT_VERIFY_MESSAGE
|
||||
from .. import alc
|
||||
from ..api.player import Player
|
||||
from ..constant import GAME_TYPE
|
||||
@@ -60,9 +60,10 @@ async def _(
|
||||
)
|
||||
if bind is None:
|
||||
await matcher.finish('未查询到绑定信息')
|
||||
message = UniMessage(CANT_VERIFY_MESSAGE)
|
||||
player = Player(user_id=bind.game_account, trust=True)
|
||||
await (message + UniMessage.image(raw=await make_blitz_image(player))).finish()
|
||||
await (
|
||||
UniMessage.i18n(Lang.interaction.warning.unverified) + UniMessage.image(raw=await make_blitz_image(player))
|
||||
).finish()
|
||||
|
||||
|
||||
@alc.assign('TETRIO.record.blitz')
|
||||
|
||||
@@ -13,6 +13,7 @@ from nonebot_plugin_user import get_user
|
||||
from yarl import URL
|
||||
|
||||
from ....db import query_bind_info, trigger
|
||||
from ....i18n import Lang
|
||||
from ....utils.exception import RecordNotFoundError
|
||||
from ....utils.host import HostPage, get_self_netloc
|
||||
from ....utils.metrics import get_metrics
|
||||
@@ -22,7 +23,6 @@ from ....utils.render.schemas.tetrio.record.base import Finesse, Max, Mini, Stat
|
||||
from ....utils.render.schemas.tetrio.record.sprint import Record
|
||||
from ....utils.screenshot import screenshot
|
||||
from ....utils.typing import Me
|
||||
from ...constant import CANT_VERIFY_MESSAGE
|
||||
from .. import alc
|
||||
from ..api.player import Player
|
||||
from ..constant import GAME_TYPE
|
||||
@@ -60,9 +60,10 @@ async def _(
|
||||
)
|
||||
if bind is None:
|
||||
await matcher.finish('未查询到绑定信息')
|
||||
message = UniMessage(CANT_VERIFY_MESSAGE)
|
||||
player = Player(user_id=bind.game_account, trust=True)
|
||||
await (message + UniMessage.image(raw=await make_sprint_image(player))).finish()
|
||||
await (
|
||||
UniMessage.i18n(Lang.interaction.warning.unverified) + UniMessage.image(raw=await make_sprint_image(player))
|
||||
).finish()
|
||||
|
||||
|
||||
@alc.assign('TETRIO.record.sprint')
|
||||
|
||||
@@ -8,6 +8,7 @@ from nonebot_plugin_session_orm import get_session_persist_id # type: ignore[im
|
||||
from nonebot_plugin_user import get_user
|
||||
|
||||
from ...db import query_bind_info, trigger
|
||||
from ...i18n import Lang
|
||||
from ...utils.exception import FallbackError
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.metrics import TetrisMetricsBasicWithLPM, get_metrics
|
||||
@@ -18,7 +19,6 @@ from ...utils.render.schemas.top_info import Data as InfoData
|
||||
from ...utils.render.schemas.top_info import Info
|
||||
from ...utils.screenshot import screenshot
|
||||
from ...utils.typing import Me
|
||||
from ..constant import CANT_VERIFY_MESSAGE
|
||||
from . import alc
|
||||
from .api import Player
|
||||
from .api.schemas.user_profile import Data, UserProfile
|
||||
@@ -44,7 +44,7 @@ async def _(event: Event, matcher: Matcher, target: At | Me, event_session: Even
|
||||
if bind is None:
|
||||
await matcher.finish('未查询到绑定信息')
|
||||
await (
|
||||
UniMessage(CANT_VERIFY_MESSAGE)
|
||||
UniMessage.i18n(Lang.interaction.warning.unverified)
|
||||
+ await make_query_result(await Player(user_name=bind.game_account, trust=True).get_profile())
|
||||
).finish()
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ from nonebot_plugin_user import get_user
|
||||
from nonebot_plugin_userinfo import EventUserInfo, UserInfo
|
||||
|
||||
from ...db import query_bind_info, trigger
|
||||
from ...i18n import Lang
|
||||
from ...utils.exception import RequestError
|
||||
from ...utils.host import HostPage, get_self_netloc
|
||||
from ...utils.image import get_avatar
|
||||
@@ -24,7 +25,6 @@ from ...utils.render.schemas.base import People, Ranking
|
||||
from ...utils.render.schemas.tos_info import Info, Multiplayer, Radar
|
||||
from ...utils.screenshot import screenshot
|
||||
from ...utils.typing import Me, Number
|
||||
from ..constant import CANT_VERIFY_MESSAGE
|
||||
from . import alc
|
||||
from .api import Player
|
||||
from .api.schemas.user_info import UserInfoSuccess
|
||||
@@ -124,7 +124,7 @@ async def _(
|
||||
)
|
||||
if bind is None:
|
||||
await matcher.finish('未查询到绑定信息')
|
||||
message = CANT_VERIFY_MESSAGE
|
||||
message = UniMessage.i18n(Lang.interaction.warning.unverified)
|
||||
player = Player(teaid=bind.game_account, trust=True)
|
||||
user_info, game_data = await gather(player.get_info(), get_game_data(player))
|
||||
if game_data is not None:
|
||||
|
||||
5
nonebot_plugin_tetris_stats/i18n/.config.json
Normal file
5
nonebot_plugin_tetris_stats/i18n/.config.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"default": "en-US",
|
||||
"frozen": [],
|
||||
"require": []
|
||||
}
|
||||
72
nonebot_plugin_tetris_stats/i18n/.lang.schema.json
Normal file
72
nonebot_plugin_tetris_stats/i18n/.lang.schema.json
Normal file
@@ -0,0 +1,72 @@
|
||||
{
|
||||
"title": "Lang Schema",
|
||||
"description": "Schema for lang file",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"interaction": {
|
||||
"title": "Interaction",
|
||||
"description": "Scope 'interaction' of lang item",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"wrong": {
|
||||
"title": "Wrong",
|
||||
"description": "Scope 'wrong' of lang item",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"query_bot": {
|
||||
"title": "query_bot",
|
||||
"description": "value of lang item type 'query_bot'",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"warning": {
|
||||
"title": "Warning",
|
||||
"description": "Scope 'warning' of lang item",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"unverified": {
|
||||
"title": "unverified",
|
||||
"description": "value of lang item type 'unverified'",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"title": "Error",
|
||||
"description": "Scope 'error' of lang item",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"MessageFormatError": {
|
||||
"title": "Messageformaterror",
|
||||
"description": "Scope 'MessageFormatError' of lang item",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"TETR.IO": {
|
||||
"title": "TETR.IO",
|
||||
"description": "value of lang item type 'TETR.IO'",
|
||||
"type": "string"
|
||||
},
|
||||
"TOS": {
|
||||
"title": "TOS",
|
||||
"description": "value of lang item type 'TOS'",
|
||||
"type": "string"
|
||||
},
|
||||
"TOP": {
|
||||
"title": "TOP",
|
||||
"description": "value of lang item type 'TOP'",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
16
nonebot_plugin_tetris_stats/i18n/.template.json
Normal file
16
nonebot_plugin_tetris_stats/i18n/.template.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": ".template.schema.json",
|
||||
"scopes": [
|
||||
{
|
||||
"scope": "interaction",
|
||||
"types": [
|
||||
{ "subtype": "wrong", "types": ["query_bot"] },
|
||||
{ "subtype": "warning", "types": ["unverified"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
"scope": "error",
|
||||
"types": [{ "subtype": "MessageFormatError", "types": ["TETR.IO", "TOS", "TOP"] }]
|
||||
}
|
||||
]
|
||||
}
|
||||
54
nonebot_plugin_tetris_stats/i18n/.template.schema.json
Normal file
54
nonebot_plugin_tetris_stats/i18n/.template.schema.json
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"title": "Template",
|
||||
"description": "Template for lang items to generate schema for lang files",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scopes": {
|
||||
"title": "Scopes",
|
||||
"description": "All scopes of lang items",
|
||||
"type": "array",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"title": "Scope",
|
||||
"description": "First level of all lang items",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"scope": {
|
||||
"type": "string",
|
||||
"description": "Scope name"
|
||||
},
|
||||
"types": {
|
||||
"type": "array",
|
||||
"description": "All types of lang items",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "Value of lang item"
|
||||
},
|
||||
{
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"subtype": {
|
||||
"type": "string",
|
||||
"description": "Subtype name of lang item"
|
||||
},
|
||||
"types": {
|
||||
"type": "array",
|
||||
"description": "All subtypes of lang items",
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"$ref": "#/properties/scopes/items/properties/types/items"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
12
nonebot_plugin_tetris_stats/i18n/__init__.py
Normal file
12
nonebot_plugin_tetris_stats/i18n/__init__.py
Normal file
@@ -0,0 +1,12 @@
|
||||
# This file is @generated by tarina.lang CLI tool
|
||||
# It is not intended for manual editing.
|
||||
|
||||
# ruff: noqa: E402, F401, PLC0414
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from tarina.lang import lang # type: ignore[import-untyped]
|
||||
|
||||
lang.load(Path(__file__).parent)
|
||||
|
||||
from .model import Lang as Lang
|
||||
16
nonebot_plugin_tetris_stats/i18n/en-US.json
Normal file
16
nonebot_plugin_tetris_stats/i18n/en-US.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"$schema": ".lang.schema.json",
|
||||
"interaction": {
|
||||
"wrong": { "query_bot": "Can't query bot's information" },
|
||||
"warning": {
|
||||
"unverified": "* Because I can't verify account linking information, I can't guarantee the info I found is yourself/themself."
|
||||
}
|
||||
},
|
||||
"error": {
|
||||
"MessageFormatError": {
|
||||
"TETR.IO": "Username/ID is invalid",
|
||||
"TOS": "Username/ID is invalid",
|
||||
"TOP": "Username is invalid"
|
||||
}
|
||||
}
|
||||
}
|
||||
32
nonebot_plugin_tetris_stats/i18n/model.py
Normal file
32
nonebot_plugin_tetris_stats/i18n/model.py
Normal file
@@ -0,0 +1,32 @@
|
||||
# This file is @generated by tarina.lang CLI tool
|
||||
# It is not intended for manual editing.
|
||||
|
||||
from tarina.lang.model import LangItem, LangModel # type: ignore[import-untyped]
|
||||
|
||||
|
||||
class InteractionWrong:
|
||||
query_bot: LangItem = LangItem('interaction', 'wrong.query_bot')
|
||||
|
||||
|
||||
class InteractionWarning:
|
||||
unverified: LangItem = LangItem('interaction', 'warning.unverified')
|
||||
|
||||
|
||||
class Interaction:
|
||||
wrong = InteractionWrong
|
||||
warning = InteractionWarning
|
||||
|
||||
|
||||
class ErrorMessageformaterror:
|
||||
TETR_IO: LangItem = LangItem('error', 'MessageFormatError.TETR.IO')
|
||||
TOS: LangItem = LangItem('error', 'MessageFormatError.TOS')
|
||||
TOP: LangItem = LangItem('error', 'MessageFormatError.TOP')
|
||||
|
||||
|
||||
class Error:
|
||||
MessageFormatError = ErrorMessageformaterror
|
||||
|
||||
|
||||
class Lang(LangModel):
|
||||
interaction = Interaction
|
||||
error = Error
|
||||
14
nonebot_plugin_tetris_stats/i18n/zh-CN.json
Normal file
14
nonebot_plugin_tetris_stats/i18n/zh-CN.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"$schema": ".lang.schema.json",
|
||||
"interaction": {
|
||||
"wrong": { "query_bot": "不能查询bot的信息" },
|
||||
"warning": { "unverified": "* 由于无法验证绑定信息, 不能保证查询到的用户为本人" }
|
||||
},
|
||||
"error": {
|
||||
"MessageFormatError": {
|
||||
"TETR.IO": "用户名/ID不合法",
|
||||
"TOS": "用户名/ID不合法",
|
||||
"TOP": "用户名不合法"
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user