Archived
1
0
Fork 0

add full i18n for chemical code

This commit is contained in:
yzhh 2023-03-01 17:10:45 +08:00
parent 2d6578ca6c
commit a31c2520ba
9 changed files with 95 additions and 40 deletions

View file

@ -127,7 +127,7 @@ def parse_template(argv: List[str]) -> List[Template]:
for a in argv_:
template = Template([])
patterns = filter(None, re.split(r'(\[.*?])|(<.*?>)|(\{.*?})| ', a))
patterns = filter(None, re.split(r'(\[.*?])|(<.*?>)|(\{.*})| ', a))
for p in patterns:
strip_pattern = p.strip()
if strip_pattern == '':

View file

@ -6,6 +6,7 @@ from typing import Union, Dict
from core.exceptions import InvalidCommandFormatError
from core.types import Command, MessageSession
from core.utils.i18n import get_target_locale, Locale
from .args import parse_argv, Template, templates_to_str, DescPattern
from ..logger import Logger
@ -33,16 +34,20 @@ class CommandParser:
self.args: Dict[Union[Template, ''], dict] = help_docs
def return_formatted_help_doc(self) -> str:
lang = get_target_locale(self.msg) if self.msg is not None else Locale('zh_cn')
if not self.args:
return '(此模块没有帮助信息)'
return lang.t('core.help.none')
lst = []
format_args = templates_to_str([args for args in self.args if args != ''], with_desc=True)
for x in format_args:
if locale_str := re.findall(r'\{(.*)}', x):
for l in locale_str:
x = x.replace(f'{{{l}}}', lang.t(l))
x = f'{self.command_prefixes[0]}{self.bind_prefix} {x}'
lst.append(x)
args = '\n'.join(y for y in lst)
if self.options_desc:
args += '\n参数:\n' + '\n'.join(self.options_desc)
args += f'\n{lang.t("core.help.options")}\n' + '\n'.join(self.options_desc)
return args
def parse(self, command):

View file

@ -30,10 +30,22 @@ def flatten(d, parent_key='', sep='.'):
def load_locale_file():
locales = os.listdir('./locales')
locales_path = os.path.abspath('./locales')
locales = os.listdir(locales_path)
for l in locales:
with open(f'./locales/{l}', 'r', encoding='utf-8') as f:
with open(f'{locales_path}/{l}', 'r', encoding='utf-8') as f:
locale_cache[remove_suffix(l, '.json')] = flatten(json.load(f))
modules_path = os.path.abspath('./modules')
for m in os.listdir(modules_path):
if os.path.isdir(f'{modules_path}/{m}'):
if os.path.exists(f'{modules_path}/{m}/locales'):
locales_m = os.listdir(f'{modules_path}/{m}/locales')
for lm in locales_m:
with open(f'{modules_path}/{m}/locales/{lm}', 'r', encoding='utf-8') as f:
if remove_suffix(lm, '.json') in locale_cache:
locale_cache[remove_suffix(lm, '.json')].update(flatten(json.load(f)))
else:
locale_cache[remove_suffix(lm, '.json')] = flatten(json.load(f))
load_locale_file()

View file

@ -1,5 +1,8 @@
{
"example": "Hello world!",
"fallback": "Fallback!!!",
"success": "Success."
"success": "Success.",
"core.help.none": "(This module has no help information)",
"core.help.options": "Options: ",
"core.help.alias": "Alias: "
}

View file

@ -1,20 +1,9 @@
{
"example": "你好世界!",
"success": "成功。",
"chemical_code.help": "化学式回答小游戏",
"chemical_code.normal.help": "普通样式(时间限制,多人)",
"chemical_code.captcha.help": "验证码样式不支持指定ID只限一次单人",
"chemical_code.stop.help": "停止当前的游戏。",
"chemical_code.csid.help": "根据 ChemSpider ID 出题",
"chemical_code.csid.invalid": "发生错误:请输入纯数字 ID",
"chemical_code.running": "当前有一局游戏正在进行中。",
"chemical_code.error": "发生错误:拉取题目失败,可能是因为请求超时或 ID 无效,请重新发起游戏。",
"chemical_code.timeup": "已超时,正确答案是",
"chemical_code.normal.text2": "请在",
"chemical_code.normal.text1": "分钟内发送这个化合物的分子式。(除 C、H 外使用字母表顺序CHBrClF",
"chemical_code.captcha.text": "请发送这个化合物的分子式。(除 C、H 外使用字母表顺序CHBrClF",
"chemical_code.correct": "回答正确。",
"chemical_code.incorrect": "回答错误,正确答案是",
"core.help.none": "(此模块没有帮助信息)",
"core.help.options": "参数:",
"core.help.alias": "命令别名:",
"color.help": "提供颜色信息。",
"color.color.help": "提供颜色信息。支持十六进制、RGB、HSL 颜色代码或 CSS3 和 Material Design 1 中的颜色名称。留空则为随机颜色。",
"color.color.invalid": "发生错误:无法识别的颜色格式。",

View file

@ -15,6 +15,7 @@ from core.component import on_command
from core.logger import Logger
from core.utils.cache import random_cache_path
from core.utils.http import get_url, download_to_cache
from core.utils.i18n import get_target_locale
csr_link = 'https://www.chemspider.com' # ChemSpider 的链接
special_id = ["22398", "140526", "4509317", "4509318", "4510681", "4510778", "4512975", "4514248", "4514266", "4514293",
@ -53,54 +54,57 @@ async def search_csr(id=None): # 根据 ChemSpider 的 ID 查询 ChemSpider 的
cc = on_command('chemical_code', alias={'cc': 'chemical_code',
'chemicalcode': 'chemical_code',
'captcha': 'chemical_code captcha'},
desc='化学式回答小游戏', developers=['OasisAkari'])
desc='{chemical_code.desc}', developers=['OasisAkari'])
play_state = {} # 创建一个空字典用于存放游戏状态
@cc.handle('{普通样式(时间限制,多人)}') # 直接使用 cc 命令将触发此装饰器
@cc.handle('{{chemical_code.normal.help}}') # 直接使用 cc 命令将触发此装饰器
async def chemical_code_by_random(msg: Bot.MessageSession):
await chemical_code(msg) # 将消息会话传入 chemical_code 函数
@cc.handle('captcha {验证码样式不支持指定ID只限一次单人}')
@cc.handle('captcha {{chemical_code.captcha.help}}')
async def _(msg: Bot.MessageSession):
await chemical_code(msg, captcha_mode=True)
@cc.handle('stop {停止当前的游戏。}')
@cc.handle('stop {{chemical_code.stop.help}}')
async def s(msg: Bot.MessageSession):
state = play_state.get(msg.target.targetId, False) # 尝试获取 play_state 中是否有此对象的游戏状态
lang = get_target_locale(msg)
if state: # 若有
if state['active']: # 检查是否为活跃状态
play_state[msg.target.targetId]['active'] = False # 标记为非活跃状态
await msg.sendMessage(f'已停止,正确答案是 {state["answer"]}', quote=False) # 发送存储于 play_state 中的答案
await msg.sendMessage(lang.t('chemical_code.stop.stopped', state["answer"]), quote=False) # 发送存储于 play_state 中的答案
else:
await msg.sendMessage('当前无活跃状态的游戏。')
await msg.sendMessage(lang.t('chemical_code.stop.nothing'))
else:
await msg.sendMessage('当前无活跃状态的游戏。')
await msg.sendMessage(lang.t('chemical_code.stop.nothing'))
@cc.handle('<csid> {根据 ChemSpider ID 出题}')
@cc.handle('<csid> {{chemical_code.csid.help}}')
async def chemical_code_by_id(msg: Bot.MessageSession):
lang = get_target_locale(msg)
id = msg.parsed_msg['<csid>'] # 从已解析的消息中获取 ChemSpider ID
if (id.isdigit() and int(id) > 0): # 如果 ID 为纯数字
await chemical_code(msg, id) # 将消息会话和 ID 一并传入 chemical_code 函数
else:
await msg.finish('发生错误:请输入正确的 ID')
await msg.finish(lang.t('chemical_code.csid.invalid'))
async def chemical_code(msg: Bot.MessageSession, id=None, captcha_mode=False):
lang = get_target_locale(msg)
# 要求传入消息会话和 ChemSpider IDID 留空将会使用缺省值 None
if msg.target.targetId in play_state and play_state[msg.target.targetId][
'active']: # 检查对象(群组或私聊)是否在 play_state 中有记录及是否为活跃状态
await msg.finish('当前有一局游戏正在进行中。')
await msg.finish(lang.t('chemical_code.running'))
play_state.update({msg.target.targetId: {'active': True}}) # 若无,则创建一个新的记录并标记为活跃状态
try:
csr = await search_csr(id) # 尝试获取 ChemSpider ID 对应的化学式列表
except Exception as e: # 意外情况
traceback.print_exc() # 打印错误信息
play_state[msg.target.targetId]['active'] = False # 将对象标记为非活跃状态
return await msg.finish('发生错误:拉取题目失败,可能是因为请求超时或 ID 无效,请重新发起游戏。')
return await msg.finish(lang.t('chemical_code.error'))
# print(csr)
play_state[msg.target.targetId]['answer'] = csr['name'] # 将正确答案标记于 play_state 中存储的对象中
Logger.info(f'Answer: {csr["name"]}') # 在日志中输出正确答案
@ -133,13 +137,13 @@ async def chemical_code(msg: Bot.MessageSession, id=None, captcha_mode=False):
Logger.info(f'{wait.asDisplay()} != {answer}') # 输出日志
return await ans(wait, answer) # 进行下一轮检查
else:
await wait.sendMessage('回答正确。')
await wait.sendMessage(lang.t('chemical_code.correct'))
play_state[msg.target.targetId]['active'] = False # 将对象标记为非活跃状态
async def timer(start): # 计时器函数
if play_state[msg.target.targetId]['active']: # 检查对象是否为活跃状态
if datetime.now().timestamp() - start > 60 * set_timeout: # 如果超过2分钟
await msg.sendMessage(f'已超时,正确答案是 {play_state[msg.target.targetId]["answer"]}', quote=False)
await msg.sendMessage(lang.t('chemical_code.timeup', answer=play_state[msg.target.targetId]["answer"]))
play_state[msg.target.targetId]['active'] = False
else: # 如果未超时
await asyncio.sleep(1) # 等待1秒
@ -147,17 +151,16 @@ async def chemical_code(msg: Bot.MessageSession, id=None, captcha_mode=False):
if not captcha_mode:
await msg.sendMessage([Image(newpath),
Plain(
f'请在 {set_timeout} 分钟内发送这个化合物的分子式。(除 C、H 外使用字母表顺序CHBrClF')])
Plain(lang.t('chemical_code.normal.text', times=set_timeout))])
time_start = datetime.now().timestamp() # 记录开始时间
await asyncio.gather(ans(msg, csr['name']), timer(time_start)) # 同时启动回答函数和计时器函数
else:
result = await msg.waitNextMessage(
[Image(newpath), Plain('请发送这个化合物的分子式。(除 C、H 外使用字母表顺序CHBrClF')])
[Image(newpath), Plain(lang.t('chemical_code.captcha.text', times=set_timeout))])
if play_state[msg.target.targetId]['active']: # 检查对象是否为活跃状态
if result.asDisplay() == csr['name']:
await result.sendMessage('回答正确。')
await result.sendMessage(lang.t('chemical_code.correct'))
else:
await result.sendMessage('回答错误,正确答案是 ' + csr['name'])
await result.sendMessage(lang.t('chemical_code.incorrect', csr['name']))
play_state[msg.target.targetId]['active'] = False

View file

@ -0,0 +1,18 @@
{
"chemical_code.desc": "A game about chemical formulas",
"chemical_code.normal.help": "Default mode (Time limits, multiplayer)",
"chemical_code.captcha.help": "Captcha mode(Only one chance, solo)",
"chemical_code.stop.help": "Stop the current game.",
"chemical_code.stop.stopped": "Stopped. The correct answer is $answer",
"chemical_code.stop.nothing": "There is no game in progress.",
"chemical_code.csid.help": "Start a game by ChemSpider ID",
"chemical_code.csid.invalid": "Failed: Invalid ID!",
"chemical_code.csid.invalid.num": "Failed: ID must be purely numeric!",
"chemical_code.running": "There is currently a game in progress.",
"chemical_code.error": "An error occurred: Failed to start, maybe caused by request database timed out or the ID is invalid? Please restart the game.",
"chemical_code.timeup": "Timeout. The correct answer is $answer",
"chemical_code.normal.text": "Please answer the chemical formula of this compound within $times minutes. (Alphabetical order except C, H. eg: CHBrClF)",
"chemical_code.captcha.text": "Please answer the chemical formula of this compound. (Alphabetical order except C, H. eg: CHBrClF)",
"chemical_code.correct": "Correct.",
"chemical_code.incorrect": "Sorry, incorrect. The correct answer is $answer"
}

View file

@ -0,0 +1,18 @@
{
"chemical_code.desc": "化学式回答小游戏",
"chemical_code.normal.help": "普通样式(时间限制,多人)",
"chemical_code.captcha.help": "验证码样式不支持指定ID只限一次单人",
"chemical_code.stop.help": "停止当前的游戏。",
"chemical_code.stop.stopped": "已停止,正确答案是 $answer",
"chemical_code.stop.nothing": "当前没有游戏在进行中。",
"chemical_code.csid.help": "根据 ChemSpider ID 出题",
"chemical_code.csid.invalid": "发生错误:请输入正确的 ID",
"chemical_code.csid.invalid.num": "发生错误:请输入纯数字 ID",
"chemical_code.running": "当前有一局游戏正在进行中。",
"chemical_code.error": "发生错误:拉取题目失败,可能是因为请求超时或 ID 无效,请重新发起游戏。",
"chemical_code.timeup": "已超时,正确答案是 $answer",
"chemical_code.normal.text": "请在 $times 分钟内发送这个化合物的分子式。(除 C、H 外使用字母表顺序CHBrClF",
"chemical_code.captcha.text": "请发送这个化合物的分子式。(除 C、H 外使用字母表顺序CHBrClF",
"chemical_code.correct": "回答正确。",
"chemical_code.incorrect": "回答错误,正确答案是 $answer"
}

View file

@ -1,3 +1,4 @@
import re
import traceback
from core.builtins import Image, Plain, Bot
@ -6,6 +7,7 @@ from core.exceptions import InvalidHelpDocTypeError
from core.loader import ModulesManager
from core.parser.command import CommandParser
from core.types import Command
from core.utils.i18n import get_target_locale
from core.utils.image_table import ImageTable, image_table_render
from database import BotDBUtil
@ -203,6 +205,7 @@ async def bot_help(msg: Bot.MessageSession):
targetFrom=msg.target.targetFrom)
developers = ModulesManager.return_modules_developers_map()
alias = ModulesManager.return_modules_alias_map()
lang = get_target_locale(msg)
if msg.parsed_msg is not None:
msgs = []
help_name = msg.parsed_msg['<module>']
@ -211,7 +214,11 @@ async def bot_help(msg: Bot.MessageSession):
if help_name in module_list:
module_ = module_list[help_name]
if module_.desc is not None:
msgs.append(module_.desc)
desc = module_.desc
if locale_str := re.match(r'\{(.*)}', desc):
if locale_str:
desc = lang.t(locale_str.group(1))
msgs.append(desc)
if isinstance(module_, Command):
help_ = CommandParser(module_list[help_name], msg=msg, bind_prefix=module_list[help_name].bind_prefix,
command_prefixes=msg.prefixes)
@ -224,7 +231,7 @@ async def bot_help(msg: Bot.MessageSession):
for a in module_alias:
malias.append(f'{a} -> {module_alias[a]}')
if malias:
doc += '\n命令别名:\n' + '\n'.join(malias)
doc += f'\n{lang.t("core.help.alias")}\n' + '\n'.join(malias)
if help_name in developers:
dev_list = developers[help_name]
if isinstance(dev_list, (list, tuple)):