mirror of
https://github.com/TriM-Organization/LiteyukiBot-TriM.git
synced 2024-11-25 00:25:04 +08:00
feat: 添加了语言设置界面
This commit is contained in:
parent
1aacceecf0
commit
bcc5cb77ad
@ -66,7 +66,7 @@ async def _(event: T_MessageEvent, bot: T_Bot):
|
|||||||
md.button(lang.get('npm.uninstall'), f'npm remove {plugin.module_name}')) if plugin_in_database else lang.get(
|
md.button(lang.get('npm.uninstall'), f'npm remove {plugin.module_name}')) if plugin_in_database else lang.get(
|
||||||
'npm.uninstall')
|
'npm.uninstall')
|
||||||
btn_toggle_global = lang.get('npm.disable') if plugin.metadata and not plugin.metadata.extra.get('toggleable') \
|
btn_toggle_global = lang.get('npm.disable') if plugin.metadata and not plugin.metadata.extra.get('toggleable') \
|
||||||
else md.button(lang.get('npm.disable_global'), f'disable-plugin {plugin.module_name} global')
|
else md.button(lang.get('npm.disable_global'), f'disable-plugin {plugin.module_name} true')
|
||||||
reply += f" {btn_remove} {btn_toggle_global}"
|
reply += f" {btn_remove} {btn_toggle_global}"
|
||||||
|
|
||||||
reply += "\n\n***\n"
|
reply += "\n\n***\n"
|
||||||
|
8
src/plugins/liteyuki_plugin_npm/permission.py
Normal file
8
src/plugins/liteyuki_plugin_npm/permission.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 插件权限管理器,对api调用进行hook限制,防止插件滥用api
|
||||||
|
from src.utils.data import LiteModel
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionAllow(LiteModel):
|
||||||
|
plugin_name: str
|
||||||
|
api_name: str
|
||||||
|
allow: bool
|
2
src/plugins/liteyuki_plugin_user/input_handle.py
Normal file
2
src/plugins/liteyuki_plugin_user/input_handle.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
def detect_lang(input_str: str) -> str:
|
||||||
|
return "zh-CN" if input_str == "zh" else "en"
|
@ -8,7 +8,7 @@ from nonebot_plugin_alconna import on_alconna, Alconna, Args, Arparma, Option, S
|
|||||||
from src.utils.data import LiteModel
|
from src.utils.data import LiteModel
|
||||||
from src.utils.typing import T_Bot, T_Message, T_MessageEvent
|
from src.utils.typing import T_Bot, T_Message, T_MessageEvent
|
||||||
from src.utils.data_manager import User, user_db
|
from src.utils.data_manager import User, user_db
|
||||||
from src.utils.language import get_user_lang
|
from src.utils.language import Language, get_all_lang, get_user_lang
|
||||||
from src.utils.message import Markdown as md, send_markdown
|
from src.utils.message import Markdown as md, send_markdown
|
||||||
|
|
||||||
profile_alc = on_alconna(
|
profile_alc = on_alconna(
|
||||||
@ -16,7 +16,7 @@ profile_alc = on_alconna(
|
|||||||
["profile", "个人信息"],
|
["profile", "个人信息"],
|
||||||
Subcommand(
|
Subcommand(
|
||||||
"set",
|
"set",
|
||||||
Args["key", str]["value", str, Optional],
|
Args["key", str]["value", str, None],
|
||||||
alias=["s", "设置"],
|
alias=["s", "设置"],
|
||||||
),
|
),
|
||||||
Subcommand(
|
Subcommand(
|
||||||
@ -42,13 +42,27 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot):
|
|||||||
ulang = get_user_lang(str(event.user_id))
|
ulang = get_user_lang(str(event.user_id))
|
||||||
if result.subcommands.get("set"):
|
if result.subcommands.get("set"):
|
||||||
if result.subcommands["set"].args.get("value"):
|
if result.subcommands["set"].args.get("value"):
|
||||||
# TODO
|
# 对合法性进行校验后设置
|
||||||
pass
|
r = set_profile(result.args["key"], result.args["value"])
|
||||||
|
if r:
|
||||||
|
user.profile[result.args["key"]] = result.args["value"]
|
||||||
|
user_db.save(user) # 数据库保存
|
||||||
|
await profile_alc.finish(
|
||||||
|
ulang.get(
|
||||||
|
"user.profile.set_success",
|
||||||
|
ATTR=ulang.get(f"user.profile.{result.args['key']}"),
|
||||||
|
VALUE=result.args["value"]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await profile_alc.finish(ulang.get("user.profile.set_failed", ATTR=ulang.get(f"user.profile.{result.args['key']}")))
|
||||||
else:
|
else:
|
||||||
# 没有值尝试呼出菜单,若菜单为none则提示用户输入值再次尝试
|
# 未输入值,尝试呼出菜单
|
||||||
# TODO
|
menu = get_profile_menu(result.args["key"], ulang)
|
||||||
pass
|
if menu:
|
||||||
|
await send_markdown(menu, bot, event=event)
|
||||||
|
else:
|
||||||
|
await profile_alc.finish(ulang.get("user.profile.input_value", ATTR=ulang.get(f"user.profile.{result.args['key']}")))
|
||||||
|
|
||||||
user.profile[result.args["key"]] = result.args["value"]
|
user.profile[result.args["key"]] = result.args["value"]
|
||||||
|
|
||||||
@ -60,10 +74,10 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot):
|
|||||||
else:
|
else:
|
||||||
profile = Profile(**user.profile)
|
profile = Profile(**user.profile)
|
||||||
|
|
||||||
for k, v in user.profile:
|
for k, v in user.profile.items():
|
||||||
profile.__setattr__(k, v)
|
profile.__setattr__(k, v)
|
||||||
|
|
||||||
reply = f"# {ulang.get("user.profile.settings")}\n***\n"
|
reply = f"# {ulang.get('user.profile.info')}\n***\n"
|
||||||
|
|
||||||
hidden_attr = ["id"]
|
hidden_attr = ["id"]
|
||||||
enter_attr = ["lang", "timezone"]
|
enter_attr = ["lang", "timezone"]
|
||||||
@ -80,14 +94,29 @@ async def _(result: Arparma, event: T_MessageEvent, bot: T_Bot):
|
|||||||
await send_markdown(reply, bot, event=event)
|
await send_markdown(reply, bot, event=event)
|
||||||
|
|
||||||
|
|
||||||
def get_profile_menu(key: str) -> str:
|
def get_profile_menu(key: str, ulang: Language) -> Optional[str]:
|
||||||
"""获取属性的markdown菜单
|
"""获取属性的markdown菜单
|
||||||
Args:
|
Args:
|
||||||
key:
|
ulang: 用户语言
|
||||||
|
key: 属性键
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
setting_name = ulang.get(f"user.profile.{key}")
|
||||||
|
|
||||||
|
no_menu = ["id", "nickname", "location"]
|
||||||
|
|
||||||
|
if key in no_menu:
|
||||||
|
return None
|
||||||
|
|
||||||
|
reply = f"{setting_name} {ulang.get('user.profile.settings')}\n***\n"
|
||||||
|
if key == "lang":
|
||||||
|
for lang_code, lang_name in get_all_lang().items():
|
||||||
|
btn_set = md.button(ulang.get('user.profile.set'), f"profile set {key} {lang_code}")
|
||||||
|
reply += (f"\n**{lang_name}** **{lang_code}**\n"
|
||||||
|
f"\n> {btn_set}\n\n***")
|
||||||
|
return reply
|
||||||
|
|
||||||
|
|
||||||
def set_profile(key: str, value: str) -> bool:
|
def set_profile(key: str, value: str) -> bool:
|
||||||
@ -100,3 +129,10 @@ def set_profile(key: str, value: str) -> bool:
|
|||||||
是否成功设置,输入合法性不通过返回False
|
是否成功设置,输入合法性不通过返回False
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
if key == 'lang':
|
||||||
|
if value in get_all_lang():
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
elif key == 'timezone':
|
||||||
|
# TODO
|
||||||
|
pass
|
||||||
|
@ -43,15 +43,27 @@ npm.homepage=Homepage
|
|||||||
npm.pypi=PyPI
|
npm.pypi=PyPI
|
||||||
npm.next_page=Next
|
npm.next_page=Next
|
||||||
npm.prev_page=Prev
|
npm.prev_page=Prev
|
||||||
npm.plugin_cannot_be_toggled=This plugin {NAME} cannot be toggled
|
npm.plugin_cannot_be_toggled=Plugin {NAME} cannot be toggled
|
||||||
npm.toggle_failed=Failed to {STATUS} {NAME}: {ERROR}
|
npm.plugin_already=Plugin {NAME} is already in {STATUS} state, no need for repeated operation
|
||||||
|
npm.toggle_failed=Failed to {STATUS} plugin {NAME}: {ERROR}
|
||||||
|
|
||||||
user.profile.edit=Edit
|
user.profile.edit=Edit
|
||||||
|
user.profile.set=Set
|
||||||
user.profile_manager.query=Your {ATTR} is {VALUE}
|
user.profile_manager.query=Your {ATTR} is {VALUE}
|
||||||
user.profile_manager.set=Yours {ATTR} has been set to {VALUE}
|
user.profile_manager.set=Yours {ATTR} has been set to {VALUE}
|
||||||
user.profile.settings=Personal settings
|
user.profile.settings=settings
|
||||||
|
user.profile.info=Personal information
|
||||||
user.profile.lang=Language
|
user.profile.lang=Language
|
||||||
|
user.profile.lang.desc=Set user language
|
||||||
user.profile.timezone=Timezone
|
user.profile.timezone=Timezone
|
||||||
|
user.profile.timezone.desc=Set user's current timezone
|
||||||
user.profile.theme=Theme
|
user.profile.theme=Theme
|
||||||
|
user.profile.theme.desc=Set user interface theme
|
||||||
user.profile.location=Location
|
user.profile.location=Location
|
||||||
|
user.profile.location.desc=Set user location information
|
||||||
user.profile.nickname=Nickname
|
user.profile.nickname=Nickname
|
||||||
|
user.profile.nickname.desc=Set Bot's nickname for the user
|
||||||
|
|
||||||
|
user.profile.input_value=Please enter a value of {ATTR}
|
||||||
|
user.profile.set_success=Succeeded in setting {ATTR} as {VALUE}
|
||||||
|
user.profile.set_failed=Setting {ATTR} failed, please check the input value
|
@ -43,15 +43,27 @@ npm.homepage = ホームページ
|
|||||||
npm.pypi = PyPI
|
npm.pypi = PyPI
|
||||||
npm.next_page = 次のページ
|
npm.next_page = 次のページ
|
||||||
npm.prev_page = 前のページ
|
npm.prev_page = 前のページ
|
||||||
npm.plugin_cannot_be_toggled = このプラグイン { NAME } は無効にできません
|
npm.plugin_cannot_be_toggled=プラグイン {NAME} は有効または無効にできません
|
||||||
npm.toggle_failed = プラグイン { NAME } の{ STATUS}切り替えに失敗しました:{ ERROR }
|
npm.plugin_already=プラグイン {NAME} はすでに {STATUS} 状態です。繰り返し操作する必要はありません
|
||||||
|
npm.toggle_failed=プラグイン {NAME} を {STATUS} にするのに失敗しました: {ERROR}
|
||||||
|
|
||||||
user.profile.edit=編集
|
user.profile.edit=編集
|
||||||
|
user.profile.set=設定
|
||||||
user.profile_manager.query=あなたの個人情報 {ATTR} は {VALUE} です
|
user.profile_manager.query=あなたの個人情報 {ATTR} は {VALUE} です
|
||||||
user.profile_manager.set=あなたの個人情報 {ATTR} は {VALUE} に設定されました
|
user.profile_manager.set=あなたの個人情報 {ATTR} は {VALUE} に設定されました
|
||||||
user.profile.settings=個人設定
|
user.profile.settings=設定
|
||||||
|
user.profile.info=個人情報
|
||||||
user.profile.lang=言語
|
user.profile.lang=言語
|
||||||
|
user.profile.lang.desc=ユーザーの言語を設定します
|
||||||
user.profile.timezone=タイムゾーン
|
user.profile.timezone=タイムゾーン
|
||||||
|
user.profile.timezone.desc=ユーザーの現在のタイムゾーンを設定します
|
||||||
user.profile.theme=テーマ
|
user.profile.theme=テーマ
|
||||||
user.profile.location=位置
|
user.profile.theme.desc=ユーザーインターフェースのテーマを設定します
|
||||||
|
user.profile.location=場所
|
||||||
|
user.profile.location.desc=ユーザーの位置情報を設定します
|
||||||
user.profile.nickname=ニックネーム
|
user.profile.nickname=ニックネーム
|
||||||
|
user.profile.nickname.desc=ユーザーのニックネームを設定します
|
||||||
|
|
||||||
|
user.profile.input_value=新しい{ATTR}を入力してください
|
||||||
|
user.profile.set_success=設定{ATTR}成功{VALUE}
|
||||||
|
user.profile.set_failed=設定{ATTR}失敗,詳細はInputを参照してください
|
@ -48,11 +48,22 @@ npm.plugin_already=插件 {NAME} 已经是 {STATUS} 状态,无需重复操作
|
|||||||
npm.toggle_failed=插件 {NAME} {STATUS} 失败: {ERROR}
|
npm.toggle_failed=插件 {NAME} {STATUS} 失败: {ERROR}
|
||||||
|
|
||||||
user.profile.edit=修改
|
user.profile.edit=修改
|
||||||
|
user.profile.set=设置
|
||||||
user.profile_manager.query=你的个人信息 {ATTR} 为 {VALUE}
|
user.profile_manager.query=你的个人信息 {ATTR} 为 {VALUE}
|
||||||
user.profile_manager.set=你的个人信息 {ATTR} 已设置为 {VALUE}
|
user.profile_manager.set=你的个人信息 {ATTR} 已设置为 {VALUE}
|
||||||
user.profile.settings=个人设置
|
user.profile.settings=设置
|
||||||
|
user.profile.info=个人信息
|
||||||
user.profile.lang=语言
|
user.profile.lang=语言
|
||||||
|
user.profile.lang.desc=设置用户语言
|
||||||
user.profile.timezone=时区
|
user.profile.timezone=时区
|
||||||
|
user.profile.timezone.desc=设置用户当前时区
|
||||||
user.profile.theme=主题
|
user.profile.theme=主题
|
||||||
|
user.profile.theme.desc=设置用户界面主题
|
||||||
user.profile.location=位置
|
user.profile.location=位置
|
||||||
|
user.profile.location.desc=设置用户位置信息
|
||||||
user.profile.nickname=称呼
|
user.profile.nickname=称呼
|
||||||
|
user.profile.nickname.desc=设置Bot对用户的称呼
|
||||||
|
|
||||||
|
user.profile.input_value=请输入 {ATTR} 的值
|
||||||
|
user.profile.set_success=成功将 {ATTR} 设置为 {VALUE}
|
||||||
|
user.profile.set_failed=设置 {ATTR} 失败,请检查输入是否合法
|
@ -141,10 +141,10 @@ class Database(BaseORMAdapter):
|
|||||||
if isinstance(r_type, type(LiteModel)):
|
if isinstance(r_type, type(LiteModel)):
|
||||||
model_fields.append(f'{self.FOREIGNID}{field}')
|
model_fields.append(f'{self.FOREIGNID}{field}')
|
||||||
model_types.append('TEXT')
|
model_types.append('TEXT')
|
||||||
elif isinstance(r_type, list):
|
elif r_type in [list[str], list[int], list[float], list[bool], list]:
|
||||||
model_fields.append(f'{self.LIST}{field}')
|
model_fields.append(f'{self.LIST}{field}')
|
||||||
model_types.append('TEXT')
|
model_types.append('TEXT')
|
||||||
elif isinstance(r_type, dict):
|
elif r_type in [dict[str, str], dict[str, int], dict[str, float], dict[str, bool], dict]:
|
||||||
model_fields.append(f'{self.DICT}{field}')
|
model_fields.append(f'{self.DICT}{field}')
|
||||||
model_types.append('TEXT')
|
model_types.append('TEXT')
|
||||||
elif isinstance(r_type, types.GenericAlias):
|
elif isinstance(r_type, types.GenericAlias):
|
||||||
@ -155,12 +155,12 @@ class Database(BaseORMAdapter):
|
|||||||
model_types.append(self.type_map.get(r_type, 'TEXT'))
|
model_types.append(self.type_map.get(r_type, 'TEXT'))
|
||||||
|
|
||||||
# 检测新字段或字段类型是否有变化,有则增删字段,已经加了前缀类型
|
# 检测新字段或字段类型是否有变化,有则增删字段,已经加了前缀类型
|
||||||
for field, type_, r_type in zip(model_fields, model_types, raw_types):
|
for field_changed, type_, r_type in zip(model_fields, model_types, raw_types):
|
||||||
if field not in table_fields:
|
if field_changed not in table_fields:
|
||||||
nonebot.logger.debug(f'ALTER TABLE {table_name} ADD COLUMN {field} {type_}')
|
nonebot.logger.debug(f'ALTER TABLE {table_name} ADD COLUMN {field_changed} {type_}')
|
||||||
self.cursor.execute(f'ALTER TABLE {table_name} ADD COLUMN {field} {type_}')
|
self.cursor.execute(f'ALTER TABLE {table_name} ADD COLUMN {field_changed} {type_}')
|
||||||
# 在原有的行中添加新字段对应类型的默认值,从DEFAULT_TYPE中获取
|
# 在原有的行中添加新字段对应类型的默认值,从DEFAULT_TYPE中获取
|
||||||
self.cursor.execute(f'UPDATE {table_name} SET {field} = ? WHERE {field} IS NULL', (self.DEFAULT_VALUE.get(type_, ""),))
|
self.cursor.execute(f'UPDATE {table_name} SET {field_changed} = ? WHERE {field_changed} IS NULL', (self.DEFAULT_VALUE.get(type_, ""),))
|
||||||
|
|
||||||
# 检测多余字段,除了id字段
|
# 检测多余字段,除了id字段
|
||||||
for field in table_fields:
|
for field in table_fields:
|
||||||
@ -193,6 +193,12 @@ class Database(BaseORMAdapter):
|
|||||||
if isinstance(value, LiteModel):
|
if isinstance(value, LiteModel):
|
||||||
key_list.append(f'{self.FOREIGNID}{field}')
|
key_list.append(f'{self.FOREIGNID}{field}')
|
||||||
value_list.append(f'{self.ID}:{value.__class__.__name__}:{self.save(value)}')
|
value_list.append(f'{self.ID}:{value.__class__.__name__}:{self.save(value)}')
|
||||||
|
elif isinstance(value, list):
|
||||||
|
key_list.append(f'{self.LIST}{field}')
|
||||||
|
value_list.append(self._flat(value))
|
||||||
|
elif isinstance(value, dict):
|
||||||
|
key_list.append(f'{self.DICT}{field}')
|
||||||
|
value_list.append(self._flat(value))
|
||||||
elif isinstance(value, BaseIterable):
|
elif isinstance(value, BaseIterable):
|
||||||
key_list.append(f'{self.JSON}{field}')
|
key_list.append(f'{self.JSON}{field}')
|
||||||
value_list.append(self._flat(value))
|
value_list.append(self._flat(value))
|
||||||
@ -220,6 +226,10 @@ class Database(BaseORMAdapter):
|
|||||||
for k, v in data.items():
|
for k, v in data.items():
|
||||||
if isinstance(v, LiteModel):
|
if isinstance(v, LiteModel):
|
||||||
return_data[f'{self.FOREIGNID}{k}'] = f'{self.ID}:{v.__class__.__name__}:{self.save(v)}'
|
return_data[f'{self.FOREIGNID}{k}'] = f'{self.ID}:{v.__class__.__name__}:{self.save(v)}'
|
||||||
|
elif isinstance(v, list):
|
||||||
|
return_data[f'{self.LIST}{k}'] = self._flat(v)
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
return_data[f'{self.DICT}{k}'] = self._flat(v)
|
||||||
elif isinstance(v, BaseIterable):
|
elif isinstance(v, BaseIterable):
|
||||||
return_data[f'{self.JSON}{k}'] = self._flat(v)
|
return_data[f'{self.JSON}{k}'] = self._flat(v)
|
||||||
else:
|
else:
|
||||||
@ -230,6 +240,10 @@ class Database(BaseORMAdapter):
|
|||||||
for v in data:
|
for v in data:
|
||||||
if isinstance(v, LiteModel):
|
if isinstance(v, LiteModel):
|
||||||
return_data.append(f'{self.ID}:{v.__class__.__name__}:{self.save(v)}')
|
return_data.append(f'{self.ID}:{v.__class__.__name__}:{self.save(v)}')
|
||||||
|
elif isinstance(v, list):
|
||||||
|
return_data.append(self._flat(v))
|
||||||
|
elif isinstance(v, dict):
|
||||||
|
return_data.append(self._flat(v))
|
||||||
elif isinstance(v, BaseIterable):
|
elif isinstance(v, BaseIterable):
|
||||||
return_data.append(self._flat(v))
|
return_data.append(self._flat(v))
|
||||||
else:
|
else:
|
||||||
@ -333,15 +347,16 @@ class Database(BaseORMAdapter):
|
|||||||
if k.startswith(self.FOREIGNID):
|
if k.startswith(self.FOREIGNID):
|
||||||
new_d[k.replace(self.FOREIGNID, '')] = load(
|
new_d[k.replace(self.FOREIGNID, '')] = load(
|
||||||
dict(self.cursor.execute(f'SELECT * FROM {v.split(":", 2)[1]} WHERE id = ?', (v.split(":", 2)[2],)).fetchone()))
|
dict(self.cursor.execute(f'SELECT * FROM {v.split(":", 2)[1]} WHERE id = ?', (v.split(":", 2)[2],)).fetchone()))
|
||||||
elif k.startswith(self.JSON):
|
|
||||||
if v == '': v = '[]'
|
|
||||||
new_d[k.replace(self.JSON, '')] = load(json.loads(v))
|
|
||||||
elif k.startswith(self.LIST):
|
elif k.startswith(self.LIST):
|
||||||
if v == '': v = '[]'
|
if v == '': v = '[]'
|
||||||
new_d[k.replace(self.LIST, '')] = load(json.loads(v))
|
new_d[k.replace(self.LIST, '')] = load(json.loads(v))
|
||||||
elif k.startswith(self.DICT):
|
elif k.startswith(self.DICT):
|
||||||
if v == '': v = '{}'
|
if v == '': v = '{}'
|
||||||
new_d[k.replace(self.DICT, '')] = load(json.loads(v))
|
new_d[k.replace(self.DICT, '')] = load(json.loads(v))
|
||||||
|
elif k.startswith(self.JSON):
|
||||||
|
if v == '': v = '[]'
|
||||||
|
new_d[k.replace(self.JSON, '')] = load(json.loads(v))
|
||||||
else:
|
else:
|
||||||
new_d[k] = v
|
new_d[k] = v
|
||||||
elif isinstance(d, list | tuple | set):
|
elif isinstance(d, list | tuple | set):
|
||||||
|
@ -12,7 +12,7 @@ plugin_db = DB(os.path.join(DATA_PATH, 'plugins.ldb'))
|
|||||||
class User(LiteModel):
|
class User(LiteModel):
|
||||||
user_id: str
|
user_id: str
|
||||||
username: str = ""
|
username: str = ""
|
||||||
profile: dict = {}
|
profile: dict[str, str] = {}
|
||||||
enabled_plugins: list[str] = []
|
enabled_plugins: list[str] = []
|
||||||
disabled_plugins: list[str] = []
|
disabled_plugins: list[str] = []
|
||||||
|
|
||||||
|
@ -154,3 +154,15 @@ def get_system_lang() -> Language:
|
|||||||
获取系统语言
|
获取系统语言
|
||||||
"""
|
"""
|
||||||
return Language(get_system_lang_code())
|
return Language(get_system_lang_code())
|
||||||
|
|
||||||
|
|
||||||
|
def get_all_lang() -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
获取所有语言
|
||||||
|
Returns
|
||||||
|
{'en': 'English'}
|
||||||
|
"""
|
||||||
|
d = {}
|
||||||
|
for key in _language_data:
|
||||||
|
d[key] = _language_data[key].get("language.name", key)
|
||||||
|
return d
|
||||||
|
@ -115,7 +115,7 @@ class Markdown:
|
|||||||
转义后的文本
|
转义后的文本
|
||||||
|
|
||||||
"""
|
"""
|
||||||
chars = "*[]()~_-`>#+-=|{}.!"
|
chars = "*[]()~_`>#+=|{}.!"
|
||||||
for char in chars:
|
for char in chars:
|
||||||
text = text.replace(char, f"\\\\{char}")
|
text = text.replace(char, f"\\\\{char}")
|
||||||
return text
|
return text
|
||||||
|
Loading…
Reference in New Issue
Block a user