diff --git a/.gitignore b/.gitignore index 22ff604d4..c8e14cbdb 100644 --- a/.gitignore +++ b/.gitignore @@ -24,6 +24,8 @@ !ui.png !window.py !window.spec +!i18n.pro +!requirements-i18n.txt src/explore_task_data/__pycache__/normal_task_11.cpython-39.pyc *.pyc *.xml diff --git a/core/picture.py b/core/picture.py index aa79c7497..ed9c56add 100644 --- a/core/picture.py +++ b/core/picture.py @@ -1,6 +1,6 @@ import time from core import color, image - +from module.main_story import change_acc_auto def co_detect(self, rgb_ends=None, rgb_possibles=None, img_ends=None, img_possibles=None, skip_first_screenshot=False, tentitive_click=False, tentitivex=1238, tentitivey=45, max_fail_cnt=10, rgb_pop_ups=None, @@ -118,6 +118,8 @@ def deal_with_pop_ups(self, rgb_pop_ups, img_pop_ups): if color.judgeRGBFeature(self, position): self.logger.info("find : " + position) if position == "fighting_feature": + self.logger.info("Enter fight, wait fight auto end") + change_acc_auto(self) img_possibles = { "normal_task_mission-operating-task-info-notice": (995, 101), "normal_task_end-turn": (890, 162), diff --git a/develop_tools/auto_translate.py b/develop_tools/auto_translate.py new file mode 100644 index 000000000..8882f9fe3 --- /dev/null +++ b/develop_tools/auto_translate.py @@ -0,0 +1,175 @@ +import os +import subprocess +import translators as ts + +from bs4 import BeautifulSoup +from lxml import etree +from gui.util.language import Language + + +class Handler: + def set_next(self, request): + request.handlers.pop(0) + if request.handlers: + request.handlers[0].handle(request) + + def handle(self, request): + pass + + +class Request: + def __init__(self, handlers: list[Handler], + qt_language: Language, + translator: str = 'bing', + from_lang: str = 'auto', + to_lang: str = 'en'): + """ + Parameters + ---------- + handlers: list[Handler] + a list of handlers that represent the files to translate. + + qt_language: Language + the memeber of the enum Language to translate + + translator: str + see https://github.com/uliontse/translators + + from_lang: str + see https://github.com/uliontse/translators + + to_lang: str + see https://github.com/uliontse/translators + """ + self.qt_language = qt_language + self.strLang = qt_language.value.name() + self.handlers = handlers + self.translator = translator + self.from_lang = from_lang + self.to_lang = to_lang + + def translate_text(self, text): + text = ts.translate_text(text, self.translator, self.from_lang, self.to_lang) + print(text) + return text + + def translate_html(self, html_text): + return ts.translate_html(html_text, self.translator, self.from_lang, self.to_lang) + + def process(self): + self.handlers[0].handle(self) + + +class Pylupdate5Handler(Handler): + def handle(self, request): + result = subprocess.run(['pylupdate5', 'i18n.pro'], capture_output=True, text=True) + print(result.stdout) + self.set_next(request) + + +class XmlHandler(Handler): + """Translate ts files""" + def handle(self, request): + # Load the XML from a file + input_file = os.path.join('../gui/i18n/', f'{request.strLang}.ts') + output_file = os.path.join('../gui/i18n/', f'{request.strLang}.ts') + + tree = etree.parse(input_file) + root = tree.getroot() + + # Find all 'source' tags and translate their text + for source in root.iter('source'): + + # Find the 'translation' tag within the parent 'message' tag + translation = source.getparent().find('translation') + + # Check the 'type' attribute of the 'translation' tag + if 'type' in translation.attrib: + if translation.attrib['type'] == 'obsolete': + # Delete the parent 'message' tag if 'type' is 'obsolete' + source.getparent().getparent().remove(source.getparent()) + elif translation.attrib['type'] == 'unfinished' and not translation.text: + # Update the 'translation' tag if 'type' is not 'obsolete' + translation.text = request.translate_text(source.text) + else: + # Don't update the 'translation' tag if 'type' attribute doesn't exist + continue + + # Write the updated XML back to the file + tree.write(output_file, encoding='utf8') + self.set_next(request) + + +class HtmlHandler(Handler): + """Generate descriptions""" + def translate_mission_types(self, request, input_dir, output_dir): + input_path = os.path.join(input_dir, '各区域所需队伍属性.html') + output_path = os.path.join(output_dir, request.translate_text('各区域所需队伍属性') + '.html') + + translations = { + '爆发': 'Explosive', + '贯穿': 'Piercing', + '神秘': 'Mystic', + '振动': 'Sonic' + } + + with open(input_path, 'r') as f: + text = f.read() + + for original, translated in translations.items(): + text = text.replace(original, translated) + + with open(output_path, 'w') as f: + f.write(text) + + def handle(self, request): + input_dir = '../src/descriptions/' + output_dir = f'src/descriptions/{request.strLang}' + # Ensure the output directory exists + if not os.path.exists(output_dir): + os.makedirs(output_dir) + + # Iterate over all files in the input directory + for filename in os.listdir(input_dir): + if request.strLang == 'en_us' and filename == '各区域所需队伍属性.html': + self.translate_mission_types(request, input_dir, output_dir) + continue + + if filename.endswith('.html'): + # Parse the HTML file with BeautifulSoup + with open(os.path.join(input_dir, filename), 'r') as f: + html = f.read() + translated_html = request.translate_html(html) + soup = BeautifulSoup(translated_html, 'lxml') + prettyHTML = soup.prettify() + + # Write the translated HTML to the output directory + name, extension = os.path.splitext(filename) + output_name = f'{request.translate_text(name)}.html' + with open(os.path.join(output_dir, output_name), 'w') as f: + f.write(prettyHTML) + + +class LreleaseHandler(Handler): + def handle(self, request): + directory = os.path.join(os.getcwd(), '../gui', 'i18n') + result = subprocess.run(['lrelease', f'{request.strLang}.ts'], cwd=directory, capture_output=True, text=True) + print(result.stdout) + self.set_next(request) + + +if __name__ == "__main__": + pylupdate = Pylupdate5Handler() + gui = XmlHandler() + descriptions = HtmlHandler() + lrelease = LreleaseHandler() + + # request_en = Request([pylupdate, gui, descriptions, lrelease], Language.ENGLISH, 'bing', 'zh-Hans', 'en') + # request_en.process() + + request_en = Request([pylupdate, gui, lrelease], Language.ENGLISH, 'bing', 'zh-Hans', 'en') + request_en.process() + + request_jp = Request([gui], Language.JAPANESE, 'bing', 'zh-Hans', 'ja') + request_jp.process() + diff --git a/develop_tools/explore_task_data_generator.py b/develop_tools/explore_task_data_generator.py index 09ed2a488..564f4d850 100644 --- a/develop_tools/explore_task_data_generator.py +++ b/develop_tools/explore_task_data_generator.py @@ -1,5 +1,5 @@ # this script is used to generate explore task data which can be used -# in function common_gird_method in module.explore_normal_task, the function is under this line +# in function common_gird_method which is under this line in module.explore_normal_task from module.explore_normal_task import common_gird_method diff --git a/docs/i18n.md b/docs/i18n.md new file mode 100644 index 000000000..a2c04c8b1 --- /dev/null +++ b/docs/i18n.md @@ -0,0 +1,184 @@ +# i18n Guide + +## Requirements + +- [Qt Linguist](https://github.com/thurask/Qt-Linguist/releases) +- [OPTIONAL] +``` +pip install -r requirements-i18n.txt +``` + +## Translation + +### Adding a New Language +To include a new language, add a new member to the Language enum representing the language with its corresponding QLocale object. Then, update the combobox method to return a list of language names based on the enum members order. For example, to add Japanese: +``` +class Language(Enum): + """ Language enumeration """ + + CHINESE_SIMPLIFIED = QLocale(QLocale.Chinese, QLocale.China) + ENGLISH = QLocale(QLocale.English, QLocale.UnitedStates) + JAPANESE = QLocale(QLocale.Japanese, QLocale.Japan) + + def combobox(): + return ['简体中文', 'English', '日本語'] +``` + +Run the Python file; it will print the language acronym: + +``` +ja_JP +``` + +Open `i18n.pro` and modify the `TRANSLATION` variable by appending `gui/i18n/` + acronym: + +```pro +TRANSLATIONS += gui/i18n/en_US.ts \ + gui/i18n/ja_JP.ts \ +``` + +Execute the following command to generate `.ts` files: + +``` +pylupdate5 i18n.pro +``` + +OPTIONAL: `auto_translate.py` + +Utilize `argostranslate` to accelerate translations after installing the necessary packages from `requirements-i18n.txt`. Note that while translations may not be perfect, they can speed up the process. + +Simply create a new `Request` instance at the end of `auto_translate.py` and invoke its `process` method. + +The `Request` constructor is as follows: + +```python +class Request: + from_code = "zh" + + def __init__(self, handlers: list[Handler], language: Language, argos_model: str): + """ + Parameters + ---------- + handlers: list[Handler] + a list of handlers that represent the files to translate. + + language: Language + the memeber of the enum Language to translate + + argos_model: str + The argos model to load for translation + """ +``` + +Then: + +```python +model = ModelHandler() +ts = XmlHandler() +descriptions = HtmlHandler() + +request_jp = Request([model, ts, descriptions], Language.JAPANESE, 'ja') +request_jp.process() +``` + +This means that `.ts` and description files will be generated. You can adjust the list of handlers as needed, but `model` must always be the first element. + +Also, in case no model exists for your language, you could create a new subclass of Request, override its translate method to use another Python library, and omit ModelHandler from the list of handlers. + +Open `Qt Linguist`, load the `.ts` file, and manually translate. This step will require some time. + +Afterward, navigate to `gui/i18n` and execute the following command: + +``` +lrelease ja_JP.ts +``` + +This will produce the `.qm` files. + +## `baasTranslator` + +### Problems +In normal scenarios, the `tr` method of `QObject` is used for translation, inherited by most PyQt5 classes. However, this approach isn't always possible for `baas` due to: + +- Widget text being generated from JSON files +- Need to retain user input (e.g., combobox selections) in Chinese within config files + +### Solution +To address this: + +- `ConfigTranslation`: a `QObject` subclass with a dictionary attribute mapping text enclosed in `self.tr` to itself: + +```python +... +self.entries = { + # display + self.tr("每日特别委托"): "每日特别委托", +... +``` + +- Utilize a specific instance of `QTranslator` named `baasTranslator` from `gui/util/translator.py` as `bt`, employing its methods: + + - `tr(context, sourceText)` + - `undo(text)` + +For instance, `bt.tr('ConfigTranslation', '国际服')` will produce its translation, 'Global', and `bt.undo('Global')` will revert it to '国际服'. This functionality is already implemented in `get` and `set` method of `ConfigSet`. + +In essence, `tr` accesses the `.qm` file to retrieve translations based on the `ConfigTranslation` context, while `undo` retrieves the value from the mapped dictionary where the translation was stored. + +Note that contexts other than `'ConfigTranslation'` are accessible. For example: + +```python +class Layout(TemplateLayout): + def __init__(self, parent=None, config=None): + configItems = [ + { + 'label': '一键反和谐', + 'type': 'button', + 'selection': self.fhx, + 'key': None + }, +... + super().__init__(parent=parent, configItems=configItems, config=config) +``` + +Suppose you want to translate the `label` and `selection` but can't access the `tr` method directly since you must first invoke the parent constructor and wish to avoid extensive modifications. Here's a solution: + +```python +class Layout(TemplateLayout): + def __init__(self, parent=None, config=None): + OtherConfig = QObject() + configItems = [ + { + 'label': OtherConfig.tr('一键反和谐'), + 'type': 'button', + 'selection': self.fhx, + 'key': None + }, +... + super().__init__(parent=parent, configItems=configItems, config=config, context="OtherConfig") +``` + +1. Add a new `context` parameter to the `TemplateLayout` constructor. +2. Create an instance of `QObject` named `OtherConfig`. This establishes a new context when generating the `.ts` files, allowing you to pass `'OtherConfig'` to the `TemplateLayout` constructor. + +Now, accessing translations in `TemplateLayout` becomes straightforward: + +```python +class TemplateLayout(QWidget): + patch_signal = pyqtSignal(str) + + def __init__(self, configItems: Union[list[ConfigItem], list[dict]], parent=None, config=None, context=None): +... + labelComponent = QLabel(bt.tr(context, cfg.label), self) +``` + +## Adding new GUI .py files +Please ensure to include the file path of the new GUI .py files into the `i18n.pro` file's `SOURCES` variable, taking care to use the correct slashes. For instance, if you're adding `table.py` located in `gui/components`, it should be appended like this: + +``` +SOURCES += \ + gui/components/table.py \ +``` + +## Adding new Config value +When adding a new config value that appears on the GUI and needs translation, update the `ConfigTranslation` dictionary by adding a new key-value pair. For comboboxes, make sure to include all options. diff --git a/gui/components/dialog_panel.py b/gui/components/dialog_panel.py index 97e28a6e3..55c8bfd54 100644 --- a/gui/components/dialog_panel.py +++ b/gui/components/dialog_panel.py @@ -7,10 +7,10 @@ class SaveSettingMessageBox(MessageBoxBase): def __init__(self, parent=None): super().__init__(parent) - self.titleLabel = SubtitleLabel('新建配置', self) + self.titleLabel = SubtitleLabel(self.tr('新建配置'), self) self.pathLineEdit = LineEdit(self) - self.pathLineEdit.setPlaceholderText('输入新建的配置名:') + self.pathLineEdit.setPlaceholderText(self.tr('输入新建的配置名:')) self.pathLineEdit.setClearButtonEnabled(True) # add widget to view layout @@ -18,8 +18,8 @@ def __init__(self, parent=None): self.viewLayout.addWidget(self.pathLineEdit) # change the text of button - self.yesButton.setText('确定') - self.cancelButton.setText('取消') + self.yesButton.setText(self.tr('确定')) + self.cancelButton.setText(self.tr('取消')) self.widget.setMinimumWidth(350) self.yesButton.setDisabled(True) diff --git a/gui/components/expand/arenaPriority.py b/gui/components/expand/arenaPriority.py index b7558ec76..77af2b35a 100644 --- a/gui/components/expand/arenaPriority.py +++ b/gui/components/expand/arenaPriority.py @@ -15,12 +15,12 @@ def __init__(self, parent=None, config=None): self.hBoxLayout = QVBoxLayout(self) self.lay_1 = QHBoxLayout(self) self.lay_2 = QHBoxLayout(self) - self.label_1 = QLabel('输入你需要对手比你低几级,高几级则填负数:', self) - self.label_2 = QLabel('输入你最多需要刷新几次:', self) + self.label_1 = QLabel(self.tr('输入你需要对手比你低几级,高几级则填负数:'), self) + self.label_2 = QLabel(self.tr('输入你最多需要刷新几次:'), self) self.input_1 = LineEdit(self) self.input_2 = LineEdit(self) - self.accept_1 = QPushButton('确定', self) - self.accept_2 = QPushButton('确定', self) + self.accept_1 = QPushButton(self.tr('确定'), self) + self.accept_2 = QPushButton(self.tr('确定'), self) self.level_diff = self.config.get('ArenaLevelDiff') validator_1 = QIntValidator(-50, 50) @@ -54,9 +54,9 @@ def __init__(self, parent=None, config=None): def __accept_1(self): self.level_diff = int(self.input_1.text()) self.config.set('ArenaLevelDiff', self.level_diff) - notification.success('设置成功', f'你需要对手比你低{self.level_diff}级', self.config) + notification.success(self.tr('设置成功'), f'{self.tr("你需要对手比你低")}{self.level_diff}{"级"}', self.config) def __accept_2(self, _=None): self.refresh_times = int(self.input_2.text()) self.config.set('maxArenaRefreshTimes', self.refresh_times) - notification.success('设置成功', f'你最大刷新次数设置为:{self.refresh_times}', self.config) + notification.success(self.tr('设置成功'), f'{self.tr("你最大刷新次数设置为:")}{self.refresh_times}', self.config) diff --git a/gui/components/expand/arenaShopPriority.py b/gui/components/expand/arenaShopPriority.py index 00ae9fa87..3b82148cc 100644 --- a/gui/components/expand/arenaShopPriority.py +++ b/gui/components/expand/arenaShopPriority.py @@ -2,6 +2,8 @@ from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QHBoxLayout, QVBoxLayout from qfluentwidgets import FlowLayout, CheckBox, LineEdit +from gui.util.translator import baasTranslator as bt + class Layout(QWidget): def __init__(self, parent=None, config=None): @@ -18,17 +20,17 @@ def __init__(self, parent=None, config=None): self.setFixedHeight(400) self.setStyleSheet('Demo{background: white} QPushButton{padding: 5px 10px; font:15px "Microsoft YaHei"}') - self.label = QLabel('刷新次数', self) + self.label = QLabel(self.tr('刷新次数'), self) self.input = LineEdit(self) self.input.setValidator(QIntValidator(0, 3)) self.input.setText(self.config.get('TacticalChallengeShopRefreshTime')) - self.accept = QPushButton('确定', self) + self.accept = QPushButton(self.tr('确定'), self) self.boxes = [] for i in range(0, goods_count): t_cbx = CheckBox(self) t_cbx.setChecked(self.goods[i] == 1) - ccs = QLabel(self.default_goods[i][0], self) + ccs = QLabel(bt.tr('ConfigTranslation', self.default_goods[i][0]), self) ccs.setFixedWidth(110) price_text = str(self.default_goods[i][1]) price_label = QLabel(price_text, self) diff --git a/gui/components/expand/cafeInvite.py b/gui/components/expand/cafeInvite.py index b0ff46fe5..e8f8cd2bb 100644 --- a/gui/components/expand/cafeInvite.py +++ b/gui/components/expand/cafeInvite.py @@ -2,6 +2,8 @@ from PyQt5.QtWidgets import QWidget, QLabel, QHBoxLayout, QVBoxLayout, QPushButton from qfluentwidgets import ComboBox, LineEdit, CheckBox +from gui.util.translator import baasTranslator as bt + class Layout(QWidget): def __init__(self, parent=None, config=None): @@ -16,35 +18,41 @@ def __init__(self, parent=None, config=None): self.lay3_ = QHBoxLayout(self) # 第二咖啡厅邀请学生名字 self.lay6 = QHBoxLayout(self) # 是否有二号咖啡厅 - self.layCollectReward = self.labeledCheckBoxTemplate('是否领取奖励:', 'cafe_reward_collect_hour_reward') - self.layUseInvitationTicket = self.labeledCheckBoxTemplate('是否使用邀请券:', 'cafe_reward_use_invitation_ticket') - self.layInviteLowestAffection = self.labeledCheckBoxTemplate('优先邀请券好感等级低的学生:', 'cafe_reward_lowest_affection_first') - self.layEnableExchangeStudent = self.labeledCheckBoxTemplate('是否允许学生更换服饰:', 'cafe_reward_allow_exchange_student') - + self.layCollectReward = self.labeledCheckBoxTemplate(self.tr('是否领取奖励:'), 'cafe_reward_collect_hour_reward') + self.layUseInvitationTicket = self.labeledCheckBoxTemplate(self.tr('是否使用邀请券:'), 'cafe_reward_use_invitation_ticket') + self.layInviteLowestAffection = self.labeledCheckBoxTemplate(self.tr('优先邀请券好感等级低的学生:'), 'cafe_reward_lowest_affection_first') + self.layEnableExchangeStudent = self.labeledCheckBoxTemplate(self.tr('是否允许学生更换服饰:'), 'cafe_reward_allow_exchange_student') if self.config.server_mode == 'JP' or self.config.server_mode == 'Global': - - self.label_3 = QLabel('是否有二号咖啡厅:', self) + self.label_3 = QLabel(self.tr('是否有二号咖啡厅:'), self) self.second_switch = CheckBox(self) self.second_switch.setChecked(self.config.get('cafe_reward_has_no2_cafe')) self.lay6.addWidget(self.label_3, 1, Qt.AlignLeft) self.lay6.addWidget(self.second_switch, 0, Qt.AlignRight) - self.layEnableDuplicateInvite = self.labeledCheckBoxTemplate('是否允许重复邀请:', 'cafe_reward_allow_duplicate_invite') + self.layEnableDuplicateInvite = self.labeledCheckBoxTemplate(self.tr('是否允许重复邀请:'), 'cafe_reward_allow_duplicate_invite') - self.pat_styles = ['拖动礼物'] + # self.pat_styles = [self.tr('拖动礼物')] + self.pat_styles = [bt.tr('ConfigTranslation', '拖动礼物')] self.student_name = [] - self.label1 = QLabel('列表选择你要添加邀请的学生,修改后请点击确定:', self) + self.label1 = QLabel(self.tr('列表选择你要添加邀请的学生,修改后请点击确定:'), self) for i in range(0, len(self.config.static_config['student_names'])): if self.config.static_config['student_names'][i][self.config.server_mode + '_implementation']: self.student_name.append( self.config.static_config['student_names'][i][self.config.server_mode + '_name']) + + # Store student name for hard_task_combobox in mainlinePriority + if not bt.isChinese(): + cn_name = self.config.static_config['student_names'][i]['CN_name'] + tranlasted_name = self.student_name[-1] + bt.addStudent(cn_name, tranlasted_name) + self.input1 = ComboBox(self) - self.input1.addItem("添加学生") + self.input1.addItem(self.tr("添加学生")) self.input = LineEdit(self) self.input.setFixedWidth(650) - self.ac_btn = QPushButton('确定', self) + self.ac_btn = QPushButton(self.tr('确定'), self) self.favor_student1 = self.config.get('favorStudent1') self.input1.addItems(self.student_name) @@ -52,10 +60,10 @@ def __init__(self, parent=None, config=None): self.config.set('favorStudent1', self.favor_student1) self.input.setText(','.join(self.favor_student1)) - self.label2 = QLabel('选择摸头方式:', self) + self.label2 = QLabel(self.tr('选择摸头方式:'), self) self.input2 = ComboBox(self) - self.pat_style = self.config.get('patStyle') or '普通' + self.pat_style = self.config.get('patStyle') or bt.tr('ConfigTranslation', '普通') self.input2.addItems(self.pat_styles) self.input2.setText(self.pat_style) self.input2.setCurrentIndex(self.pat_styles.index(self.pat_style)) @@ -88,7 +96,7 @@ def __init__(self, parent=None, config=None): self.__init_Signals_and_Slots() def __add_student_name_in_the_last(self): - if self.input1.currentText() == '添加学生': + if self.input1.currentText() == self.tr('添加学生'): return self.favor_student1.append(self.input1.currentText()) self.favor_student1 = self.check_valid_student_names() @@ -96,7 +104,7 @@ def __add_student_name_in_the_last(self): self.input.setText(','.join(self.favor_student1)) def __add_student_name_in_the_last_second(self): - if self.input4.currentText() == '添加学生': + if self.input4.currentText() == self.tr('添加学生'): return self.favor_student2.append(self.input4.currentText()) self.favor_student2 = self.check_valid_student_names_() @@ -167,12 +175,12 @@ def Slot_for_no_2_cafe_Checkbox(self, state): sub_layout.removeItem(item) def set_buttons_for_no2_cafe(self): - self.label4 = QLabel('选择第二咖啡厅邀请的学生', self) + self.label4 = QLabel(self.tr('选择第二咖啡厅邀请的学生'), self) self.input4 = ComboBox(self) - self.input4.addItem("添加学生") + self.input4.addItem(self.tr("添加学生")) self.input_ = LineEdit(self) self.input_.setFixedWidth(650) - self.ac_btn_ = QPushButton('确定', self) + self.ac_btn_ = QPushButton(self.tr('确定'), self) self.favor_student2 = self.config.get('favorStudent2') self.input4.addItems(self.student_name) self.favor_student2 = self.check_valid_student_names_() diff --git a/gui/components/expand/createPriority.py b/gui/components/expand/createPriority.py index 46604b108..9dd225cd6 100644 --- a/gui/components/expand/createPriority.py +++ b/gui/components/expand/createPriority.py @@ -16,11 +16,11 @@ def __init__(self, parent=None, config=None): self.lay3 = QHBoxLayout(self) self.layout_for_acc_ticket = QHBoxLayout(self) - self.label = QLabel('目前制造物品优先级,排在前面的会优先选择', self) + self.label = QLabel(self.tr('目前制造物品优先级,排在前面的会优先选择'), self) self.input1 = QLabel(self) self.input2 = LineEdit(self) - self.accept = QPushButton('确定', self) - self.label_for_use_acc_ticket_check_box = QLabel('是否使用加速券', self) + self.accept = QPushButton(self.tr('确定'), self) + self.label_for_use_acc_ticket_check_box = QLabel(self.tr('是否使用加速券'), self) self.use_acc_ticket_checkbox = CheckBox(self) self.use_acc_ticket_checkbox.setChecked(self.config.get('use_acceleration_ticket')) self.use_acc_ticket_checkbox.stateChanged.connect(self.Slot_for_use_acc_ticket_check_box) diff --git a/gui/components/expand/emulatorConfig.py b/gui/components/expand/emulatorConfig.py index 07405e4bf..1474afaa4 100644 --- a/gui/components/expand/emulatorConfig.py +++ b/gui/components/expand/emulatorConfig.py @@ -1,43 +1,47 @@ from functools import partial +from PyQt5.QtCore import QObject from PyQt5.QtWidgets import QFileDialog, QLabel, QHBoxLayout from qfluentwidgets import LineEdit, PushButton, ComboBox from .expandTemplate import TemplateLayout +from gui.util import notification +from gui.util.translator import baasTranslator as bt + class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + EmulatorConfig = QObject() configItems = [ { - 'label': '在运行Baas时打开模拟器(启动模拟器的功能开关,关闭后不会启动模拟器)', + 'label': EmulatorConfig.tr('在运行Baas时打开模拟器(启动模拟器的功能开关,关闭后不会启动模拟器)'), 'key': 'open_emulator_stat', 'type': 'switch' }, { - 'label': '是否模拟器多开(打开后无视已经启动的模拟器进程,将再启动一个模拟器))', + 'label': EmulatorConfig.tr('是否模拟器多开(打开后无视已经启动的模拟器进程,将再启动一个模拟器))'), 'key': 'multi_emulator_check', 'type': 'switch' }, { - 'label': '等待模拟器启动时间(模拟器从开始启动到桌面加载完成的时间(秒),一般默认)', + 'label': EmulatorConfig.tr('等待模拟器启动时间(模拟器从开始启动到桌面加载完成的时间(秒),一般默认)'), 'type': 'text', 'key': 'emulator_wait_time' }, { - 'label': '是否启用内建的自动扫描模拟器功能(开启后将自动识别系统内已安装的模拟器)', + 'label': EmulatorConfig.tr('是否启用内建的自动扫描模拟器功能(开启后将自动识别系统内已安装的模拟器)'), 'type': 'switch', 'key': 'emulatorIsMultiInstance' } ] - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context='EmulatorConfig') if not self.config.get('emulatorIsMultiInstance'): self._createNotMultiComponent() else: self._createMultiComponent() self.vBoxLayout.children()[3].itemAt(2).widget().checkedChanged.connect(self._soltForEmulatorIsMultiInstanced) - def _choose_file(self, line_edit): file_dialog = QFileDialog() file_dialog.setFileMode(QFileDialog.ExistingFile) @@ -51,15 +55,15 @@ def _choose_file(self, line_edit): self.config.set('program_address', file_path) def _createNotMultiComponent(self): - labelComponent = QLabel('选择模拟器地址', self) + labelComponent = QLabel(self.tr('选择模拟器地址'), self) addressKey = 'program_address' inputComponent = LineEdit(self) inputComponent.setFixedWidth(500) # 设置文本框的固定宽度 inputComponent.setText(str(self.config.get(addressKey))) - confirmButton = PushButton('确定', self) + confirmButton = PushButton(self.tr('确定'), self) confirmButton.setFixedWidth(80) # 设置确定按钮的固定宽度 confirmButton.clicked.connect(partial(self._commit, addressKey, inputComponent, labelComponent)) - selectButton = PushButton('选择', self) + selectButton = PushButton(self.tr('选择'), self) selectButton.setFixedWidth(80) # 设置选择按钮的固定宽度 selectButton.clicked.connect(partial(self._choose_file, inputComponent)) self.emulatorNotMultiAddressHLayout = QHBoxLayout(self) @@ -75,8 +79,8 @@ def _createMultiComponent(self): 'bluestacks_nxt_cn': '蓝叠模拟器', 'bluestacks_nxt': '蓝叠国际版' } - emulatorLabelComponent = QLabel('选择模拟器类型', self) - multiInstanceNumber = QLabel('多开号', self) + emulatorLabelComponent = QLabel(self.tr('选择模拟器类型'), self) + multiInstanceNumber = QLabel(self.tr('多开号'), self) currentInstanceNumber = self.config.get('emulatorMultiInstanceNumber') multiInstanceNumberInputComponent = LineEdit(self) multiInstanceNumberInputComponent.setText(str(currentInstanceNumber)) @@ -84,7 +88,7 @@ def _createMultiComponent(self): currentMultiEmulatorName = self.config.get('multiEmulatorName') chooseMultiEmulatorCombobox = ComboBox(self) values = self.multiMap.keys() - chooseMultiEmulatorCombobox.addItems([self.multiMap[key] for key in values]) + chooseMultiEmulatorCombobox.addItems([bt.tr('ConfigTranslation', self.multiMap[key]) for key in values]) chooseMultiEmulatorCombobox.setCurrentIndex(list(values).index(currentMultiEmulatorName)) chooseMultiEmulatorCombobox.currentIndexChanged.connect(self._slotForMultiInstanceComboBoxIndexChanged) multiInstanceNumberInputComponent.setFixedWidth(80) diff --git a/gui/components/expand/eventMapConfig.py b/gui/components/expand/eventMapConfig.py index f3ab3759f..e48bb38e9 100644 --- a/gui/components/expand/eventMapConfig.py +++ b/gui/components/expand/eventMapConfig.py @@ -1,27 +1,30 @@ +from PyQt5.QtCore import QObject from .expandTemplate import TemplateLayout class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + # name it EventMapConfig to have context with same name + EventMapConfig = QObject() configItems = [ { - 'label': '推故事', + 'label': EventMapConfig.tr('推故事'), 'type': 'button', 'selection': self.activity_story }, { - 'label': '推任务', + 'label': EventMapConfig.tr('推任务'), 'type': 'button', 'selection': self.activity_mission }, { - 'label': '推挑战', + 'label': EventMapConfig.tr('推挑战'), 'type': 'button', 'selection': self.activity_challenge }, ] self.main_thread = config.get_main_thread() - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context='EventMapConfig') def activity_story(self): import threading diff --git a/gui/components/expand/expandTemplate.py b/gui/components/expand/expandTemplate.py index 7adc836eb..d01f3549e 100644 --- a/gui/components/expand/expandTemplate.py +++ b/gui/components/expand/expandTemplate.py @@ -8,6 +8,7 @@ from core.utils import delay from gui.util import notification from gui.util.config_set import ConfigSet +from gui.util.translator import baasTranslator as bt class ConfigItem: @@ -26,7 +27,7 @@ def __init__(self, **kwargs): class TemplateLayout(QWidget): patch_signal = pyqtSignal(str) - def __init__(self, configItems: Union[list[ConfigItem], list[dict]], parent=None, config=None): + def __init__(self, configItems: Union[list[ConfigItem], list[dict]], parent=None, config=None, context=None): super().__init__(parent=parent) self.config = config if isinstance(configItems[0], dict): @@ -44,7 +45,7 @@ def __init__(self, configItems: Union[list[ConfigItem], list[dict]], parent=None confirmButton = None selectButton = None optionPanel = QHBoxLayout(self) - labelComponent = QLabel(cfg.label, self) + labelComponent = QLabel(bt.tr(context, cfg.label), self) optionPanel.addWidget(labelComponent, 0, Qt.AlignLeft) optionPanel.addStretch(1) if cfg.type == 'switch': @@ -55,23 +56,25 @@ def __init__(self, configItems: Union[list[ConfigItem], list[dict]], parent=None elif cfg.type == 'combo': currentKey = cfg.key inputComponent = ComboBox(self) + cfg.selection = [bt.tr(context, x) for x in cfg.selection] if context else cfg.selection inputComponent.addItems(cfg.selection) inputComponent.setCurrentIndex(cfg.selection.index(self.config.get(currentKey))) inputComponent.currentIndexChanged.connect( partial(self._commit, currentKey, inputComponent, labelComponent)) elif cfg.type == 'button': - inputComponent = PushButton('执行', self) + # impossible to translate without specifying TemplateLayout context + text = bt.tr('TemplateLayout', self.tr('执行')) + inputComponent = PushButton(text, self) inputComponent.clicked.connect(cfg.selection) elif cfg.type == 'text': currentKey = cfg.key inputComponent = LineEdit(self) inputComponent.setText(str(self.config.get(currentKey))) self.patch_signal.connect(inputComponent.setText) - confirmButton = PushButton('确定', self) + confirmButton = PushButton(self.tr('确定'), self) confirmButton.clicked.connect(partial(self._commit, currentKey, inputComponent, labelComponent)) elif cfg.type == 'label': inputComponent = QLabel(cfg.selection, self) - else: raise ValueError(f'Unknown config type: {cfg.type}') optionPanel.addWidget(inputComponent, 0, Qt.AlignRight) @@ -92,7 +95,7 @@ def _commit(self, key, target, labelTarget): value = target.text() assert value is not None self.config.update(key, value) - notification.success('设置成功', f'{labelTarget.text()}已经被设置为:{value}', self.config) + notification.success(self.tr('设置成功'), f'{labelTarget.text()}{self.tr("已经被设置为:")}{value}', self.config) class ConfigItemV2(ConfigItem): diff --git a/gui/components/expand/exploreConfig.py b/gui/components/expand/exploreConfig.py index da36127be..008b6ad71 100644 --- a/gui/components/expand/exploreConfig.py +++ b/gui/components/expand/exploreConfig.py @@ -1,4 +1,4 @@ -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QObject from PyQt5.QtWidgets import QHBoxLayout, QLabel from qfluentwidgets import LineEdit, PushButton @@ -8,55 +8,56 @@ class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + ExploreConfig = QObject() self.config = config configItems = [ { - 'label': '是否手动boss战(进入关卡后暂停等待手操)', + 'label': ExploreConfig.tr('是否手动boss战(进入关卡后暂停等待手操)'), 'key': 'manual_boss', 'type': 'switch' }, { - 'label': '是否不强制打到sss(启用后跳过已通过但未sss的关卡)', + 'label': ExploreConfig.tr('是否不强制打到sss(启用后跳过已通过但未sss的关卡)'), 'key': 'explore_normal_task_force_sss', 'type': 'switch' }, { - 'label': '开启后强制打每一个指定的关卡(不管是否sss)', + 'label': ExploreConfig.tr('开启后强制打每一个指定的关卡(不管是否sss)'), 'key': 'explore_normal_task_force_each_fight', 'type': 'switch' }, { - 'label': '爆发一队', + 'label': ExploreConfig.tr('爆发一队'), 'key': 'burst1', 'selection': ['1', '2', '3', '4'], 'type': 'combo' }, { - 'label': '爆发二队', + 'label': ExploreConfig.tr('爆发二队'), 'key': 'burst2', 'selection': ['1', '2', '3', '4'], 'type': 'combo' }, { - 'label': '贯穿一队', + 'label': ExploreConfig.tr('贯穿一队'), 'key': 'pierce1', 'selection': ['1', '2', '3', '4'], 'type': 'combo' }, { - 'label': '贯穿二队', + 'label': ExploreConfig.tr('贯穿二队'), 'key': 'pierce2', 'selection': ['1', '2', '3', '4'], 'type': 'combo' }, { - 'label': '神秘一队', + 'label': ExploreConfig.tr('神秘一队'), 'key': 'mystic1', 'selection': ['1', '2', '3', '4'], 'type': 'combo' }, { - 'label': '神秘二队', + 'label': ExploreConfig.tr('神秘二队'), 'key': 'mystic2', 'selection': ['1', '2', '3', '4'], 'type': 'combo' @@ -65,27 +66,26 @@ def __init__(self, parent=None, config=None): if self.config.server_mode == 'JP' or self.config.server_mode == 'Global': configItems.extend([ { - 'label': '振动一队', + 'label': ExploreConfig.tr('振动一队'), 'key': 'shock1', 'selection': ['1', '2', '3', '4'], 'type': 'combo' }, { - 'label': '振动二队', + 'label': ExploreConfig.tr('振动二队'), 'key': 'shock2', 'selection': ['1', '2', '3', '4'], 'type': 'combo' } ]) - - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context='ExploreConfig') self.push_card = QHBoxLayout(self) self.push_card_label = QHBoxLayout(self) self.label_tip_push = QLabel( - '推图选项 请在下面填写要推的图,填写方式见-普通图自动推图说明-', self) + '' + self.tr('推图选项') + ' ' + self.tr('请在下面填写要推的图,填写方式见-普通图自动推图说明-'), self) self.input_push = LineEdit(self) - self.accept_push = PushButton('开始推图', self) + self.accept_push = PushButton(self.tr('开始推图'), self) self.input_push.setText( self.config.get('explore_normal_task_regions').__str__().replace('[', '').replace(']', '')) @@ -110,7 +110,7 @@ def __init__(self, parent=None, config=None): def _accept_push(self): self.config.set('explore_normal_task_regions', self.input_push.text()) value = self.input_push.text() - notification.success('普通关推图', f'你的普通关配置已经被设置为:{value},正在推普通关。', self.config) + notification.success(self.tr('普通关推图'), f'{self.tr("你的普通关配置已经被设置为:")}{value},{self.tr("正在推普通关。")}', self.config) sig = self.config.get_signal('update_signal') sig.emit(['普通关推图']) import threading diff --git a/gui/components/expand/featureSwitch.py b/gui/components/expand/featureSwitch.py index 39835777e..b71a5f3c2 100644 --- a/gui/components/expand/featureSwitch.py +++ b/gui/components/expand/featureSwitch.py @@ -10,41 +10,42 @@ SubtitleLabel from gui.components.expand.expandTemplate import TemplateLayoutV2 +from gui.util.translator import baasTranslator as bt class DetailSettingMessageBox(MessageBoxBase): def __init__(self, detail_config: dict, all_label_list: list, parent=None, cs=None): super().__init__(parent) - self.titleLabel = SubtitleLabel('配置详情', self) + self.titleLabel = SubtitleLabel(self.tr('配置详情'), self) configItems = [ { - 'label': '优先级', + 'label': self.tr('优先级'), 'dataType': 'int', 'key': 'priority' }, { - 'label': '执行间隔', + 'label': self.tr('执行间隔'), 'dataType': 'int', 'key': 'interval', }, { - 'label': '每日重置', + 'label': self.tr('每日重置'), 'dataType': 'list', 'key': 'daily_reset', }, { - 'label': '禁用时间段', + 'label': self.tr('禁用时间段'), 'dataType': 'list', 'key': 'disabled_time_range', }, { - 'label': '前置任务', + 'label': self.tr('前置任务'), 'dataType': 'list', 'key': 'pre_task', 'presets': [] }, { - 'label': '后置任务', + 'label': self.tr('后置任务'), 'dataType': 'list', 'key': 'post_task', 'presets': [] @@ -55,8 +56,8 @@ def __init__(self, detail_config: dict, all_label_list: list, parent=None, cs=No self.viewLayout.addWidget(self.titleLabel) self.viewLayout.addWidget(self.configWidget) - self.yesButton.setText('确定') - self.cancelButton.setText('取消') + self.yesButton.setText(self.tr('确定')) + self.cancelButton.setText(self.tr('取消')) self.widget.setMinimumWidth(350) @@ -75,20 +76,20 @@ def __init__(self, parent=None, config=None): self.vBox = QVBoxLayout(self) self.option_layout = QHBoxLayout(self) - self.all_check_box = PushButton('全部(不)启用', self) + self.all_check_box = PushButton(self.tr('全部(不)启用'), self) self.all_check_box.clicked.connect(self.all_check) self.option_layout.addWidget(self.all_check_box) self.option_layout.addStretch(1) - self.op_2 = PushButton('刷新执行时间', self) + self.op_2 = PushButton(self.tr('刷新执行时间'), self) self.option_layout.addWidget(self.op_2) self.op_2.clicked.connect(self._refresh) self.option_layout.addStretch(1) - self.label_3 = CaptionLabel('排序方式:', self) + self.label_3 = CaptionLabel(self.tr('排序方式:'), self) self.op_3 = ComboBox(self) - self.op_3.addItems(['默认排序', '按下次执行时间排序']) + self.op_3.addItems([self.tr('默认排序'), self.tr('按下次执行时间排序')]) self.op_3.currentIndexChanged.connect(self._sort) self.option_layout.addWidget(self.label_3) @@ -99,7 +100,7 @@ def __init__(self, parent=None, config=None): self.tableView.setRowCount(len(self.qLabels)) self.tableView.setColumnCount(4) self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.tableView.setHorizontalHeaderLabels(['事件', '下次刷新时间', '启用', '更多配置']) + self.tableView.setHorizontalHeaderLabels([self.tr('事件'), self.tr('下次刷新时间'), self.tr('启用'), self.tr('更多配置')]) self.tableView.setColumnWidth(0, 175) self.tableView.setColumnWidth(1, 175) self.tableView.setColumnWidth(2, 50) @@ -124,8 +125,7 @@ def _init_components(self, config_list): cbx_layout.addWidget(t_cbx, 1, Qt.AlignCenter) cbx_layout.setContentsMargins(30, 0, 0, 0) cbx_wrapper.setLayout(cbx_layout) - - t_ccs = CaptionLabel(self.labels[i]) + t_ccs = CaptionLabel(bt.tr('ConfigTranslation', self.labels[i])) t_ncs = LineEdit(self) t_ncs.setText(str(datetime.fromtimestamp(self.next_ticks[i])).split('.')[0]) t_ncs.textChanged.connect(self._update_config) @@ -135,7 +135,7 @@ def _init_components(self, config_list): self.boxes.append(cbx_wrapper) self.check_boxes.append(t_cbx) - t_cfbs = PushButton('详细配置', self) + t_cfbs = PushButton(self.tr('详细配置'), self) t_cfbs.clicked.connect(partial(self._update_detail, i)) cfbs_wrapper = QWidget() cfbs_layout = QHBoxLayout() @@ -168,7 +168,7 @@ def _sort(self): self.tableView.setRowCount(len(temp)) self.tableView.setColumnCount(4) self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) - self.tableView.setHorizontalHeaderLabels(['事件', '下次刷新时间', '启用', '更多配置']) + self.tableView.setHorizontalHeaderLabels([self.tr('事件'), self.tr('下次刷新时间'), self.tr('启用'), self.tr('更多配置')]) # mode 0: default, mode 1: by next_tick if self.op_3.currentIndex() == 0: @@ -178,7 +178,7 @@ def _sort(self): self._crt_order_config = temp # Add components to table for ind, unit in enumerate(temp): - t_ccs = CaptionLabel(unit['event_name']) + t_ccs = CaptionLabel(bt.tr('ConfigTranslation', unit['event_name'])) self.tableView.setCellWidget(ind, 0, t_ccs) self.qLabels.append(t_ccs) @@ -199,7 +199,7 @@ def _sort(self): self.tableView.setCellWidget(ind, 2, cbx_wrapper) self.check_boxes.append(t_cbx) - t_cfbs = PushButton('详细配置', self) + t_cfbs = PushButton(self.tr('详细配置'), self) t_cfbs.clicked.connect(partial(self._update_detail, ind)) cfbs_wrapper = QWidget() cfbs_layout = QHBoxLayout() @@ -215,7 +215,7 @@ def _sort(self): def _update_config(self): for i in range(len(self.enable_list)): dic = { - 'event_name': self.qLabels[i].text(), + 'event_name': bt.undo(self.qLabels[i].text()), 'next_tick': self.get_next_tick(self.times[i].text()), 'enabled': self.check_boxes[i].isChecked() } @@ -237,7 +237,7 @@ def _update_detail(self, index): } all_label_list = [ - [x['event_name'], x['func_name']] + [bt.tr('ConfigTranslation', x['event_name']), x['func_name']] for x in self._event_config ] @@ -279,7 +279,7 @@ def _refresh_time(self): for item in changed_map: for i in range(len(self.qLabels)): - if self.qLabels[i].text() == item[0]: + if bt.undo(self.qLabels[i].text()) == item[0]: self.times[i].blockSignals(True) self.times[i].setText(str(datetime.fromtimestamp(item[1]))) self.times[i].blockSignals(False) diff --git a/gui/components/expand/hardTaskConfig.py b/gui/components/expand/hardTaskConfig.py index bfc174652..8df9ba780 100644 --- a/gui/components/expand/hardTaskConfig.py +++ b/gui/components/expand/hardTaskConfig.py @@ -1,40 +1,40 @@ -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QObject from PyQt5.QtWidgets import QHBoxLayout, QLabel from qfluentwidgets import LineEdit, PushButton from .expandTemplate import TemplateLayout from ...util import notification - class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + HardTaskConfig = QObject() configItems = [ { - 'label': '打到SSS', + 'label': HardTaskConfig.tr('打到SSS'), 'key': 'explore_hard_task_need_sss', 'type': 'switch' }, { - 'label': '拿礼物', + 'label': HardTaskConfig.tr('拿礼物'), 'key': 'explore_hard_task_need_present', 'type': 'switch' }, { - 'label': '完成成就任务', + 'label': HardTaskConfig.tr('完成成就任务'), 'key': 'explore_hard_task_need_task', 'type': 'switch' } ] - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context="HardTaskConfig") self.push_card = QHBoxLayout(self) self.push_card_label = QHBoxLayout(self) self.label_tip_push = QLabel( - '困难图队伍属性和普通图相同(见普通图推图设置),请按照帮助中说明选择推困难图关卡并按对应图设置队伍', + self.tr('困难图队伍属性和普通图相同(见普通图推图设置),请按照帮助中说明选择推困难图关卡并按对应图设置队伍'), self) self.input_push = LineEdit(self) - self.accept_push = PushButton('开始推图', self) + self.accept_push = PushButton(self.tr('开始推图'), self) self.input_push.setText(self.config.get('explore_hard_task_list')) self.input_push.setFixedWidth(700) @@ -58,7 +58,7 @@ def __init__(self, parent=None, config=None): def _accept_push(self): value = self.input_push.text() self.config.set('explore_hard_task_list', value) - notification.success('困难关推图', f'你的困难关配置已经被设置为:{value},正在推困难关。', self.config) + notification.success(self.tr('困难关推图'), f'{self.tr("你的困难关配置已经被设置为:")}{value},{self.tr("正在推困难关。")}', self.config) import threading threading.Thread(target=self.action).start() diff --git a/gui/components/expand/mainlinePriority.py b/gui/components/expand/mainlinePriority.py index 8c793db75..643d5ed59 100644 --- a/gui/components/expand/mainlinePriority.py +++ b/gui/components/expand/mainlinePriority.py @@ -3,6 +3,8 @@ from qfluentwidgets import LineEdit, ComboBox from gui.util import notification +from gui.util.translator import baasTranslator as bt + class Layout(QWidget): def __init__(self, parent=None, config=None): @@ -15,24 +17,24 @@ def __init__(self, parent=None, config=None): self.lay1_hard = QHBoxLayout(self) self.lay2_hard = QHBoxLayout(self) - self.label = QLabel('普通关卡与次数(如"1-1-1,1-2-3"表示关卡1-1打一次,然后关卡1-2打三次):', self) + self.label = QLabel(self.tr('普通关卡与次数(如"1-1-1,1-2-3"表示关卡1-1打一次,然后关卡1-2打三次):'), self) self.input = LineEdit(self) - self.accept = QPushButton('确定', self) - self.label_hard = QLabel('困难关卡设置同上,(注意:次数最多为3),逗号均为英文逗号,日服、国际服可填max:', self) + self.accept = QPushButton(self.tr('确定'), self) + self.label_hard = QLabel(self.tr('困难关卡设置同上,注意:次数最多为3),逗号均为英文逗号,日服、国际服可填max:'), self) self.input_hard = LineEdit(self) - self.accept_hard = QPushButton('确定', self) + self.accept_hard = QPushButton(self.tr('确定'), self) self.hard_task_combobox = ComboBox(self) self.each_student_task_number_dict = { - "根据学生添加关卡": [], - "爱丽丝宝贝": [], + self.tr("根据学生添加关卡"): [], + self.tr("爱丽丝宝贝"): [], } for i in range(0, len(self.config.static_config["hard_task_student_material"])): - self.each_student_task_number_dict.setdefault(self.config.static_config["hard_task_student_material"][i][1], - []) + translated_name = bt.getStudent(self.config.static_config["hard_task_student_material"][i][1]) + self.each_student_task_number_dict.setdefault(translated_name, []) temp = self.config.static_config["hard_task_student_material"][i][0] + "-3" - (self.each_student_task_number_dict[self.config.static_config["hard_task_student_material"][i][1]].append( - temp)) + (self.each_student_task_number_dict[translated_name].append(temp)) + for key in self.each_student_task_number_dict.keys(): self.hard_task_combobox.addItem(key) self.hard_task_combobox.currentIndexChanged.connect(self.__hard_task_combobox_change) @@ -90,9 +92,9 @@ def __accept_main(self): for i in range(0, len(input_content)): temp.append(readOneNormalTask(input_content[i])) self.config.set("unfinished_normal_tasks", temp) # refresh the config unfinished_normal_tasks - notification.success('设置成功', f'你的普通关卡已经被设置为:{input_content}', self.config) + notification.success(self.tr('设置成功'), f'{self.tr("你的普通关卡已经被设置为:")}{input_content}', self.config) except Exception as e: - notification.error('设置失败', f'请检查输入格式是否正确,错误信息:{e}', self.config) + notification.error(self.tr('设置失败'), f'{self.tr("请检查输入格式是否正确,错误信息:")}{e}', self.config) def __accept_hard(self): try: @@ -104,12 +106,12 @@ def __accept_hard(self): for i in range(0, len(input_content)): temp.append(readOneHardTask(input_content[i])) self.config.set("unfinished_hard_tasks", temp) # refresh the config unfinished_hard_tasks - notification.success('设置成功', f'你的困难关卡已经被设置为:{input_content}', self.config) + notification.success(self.tr('设置成功'), f'{self.tr("你的困难关卡已经被设置为:")}{input_content}', self.config) except Exception as e: - notification.error('设置失败', f'请检查输入格式是否正确,错误信息:{e}', self.config) + notification.error(self.tr('设置失败'), f'{self.tr("请检查输入格式是否正确,错误信息:")}{e}', self.config) def __hard_task_combobox_change(self): - if self.hard_task_combobox.currentText() == "根据学生添加关卡": + if self.hard_task_combobox.currentText() == self.tr("根据学生添加关卡"): return st = "" if self.input_hard.text() != "": diff --git a/gui/components/expand/otherConfig.py b/gui/components/expand/otherConfig.py index cf0dabd58..35330900b 100644 --- a/gui/components/expand/otherConfig.py +++ b/gui/components/expand/otherConfig.py @@ -1,29 +1,31 @@ +from PyQt5.QtCore import QObject from .expandTemplate import TemplateLayout class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + OtherConfig = QObject() configItems = [ { - 'label': '一键反和谐', + 'label': OtherConfig.tr('一键反和谐'), 'type': 'button', 'selection': self.fhx, 'key': None }, { - 'label': '修复Mumu无法登录日服', + 'label': OtherConfig.tr('修复Mumu无法登录日服'), 'type': 'button', 'selection': self.mumu_JP_login_fixer, 'key': None }, { - 'label': '显示首页头图(下次启动时生效)', + 'label': OtherConfig.tr('显示首页头图(下次启动时生效)'), 'type': 'switch', 'key': 'bannerVisibility' } ] - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context="OtherConfig") def mumu_JP_login_fixer(self): self.config.get_main_thread().start_mumu_JP_login_fixer() diff --git a/gui/components/expand/proceedPlot.py b/gui/components/expand/proceedPlot.py index eb57b1f17..c87a29f4f 100644 --- a/gui/components/expand/proceedPlot.py +++ b/gui/components/expand/proceedPlot.py @@ -1,35 +1,37 @@ from .expandTemplate import TemplateLayout +from PyQt5.QtCore import QObject class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + ProceedPlot = QObject() configItems = [ { - 'label': '主线剧情需要推的章节数', + 'label': ProceedPlot.tr('主线剧情需要推的章节数'), 'type': 'text', 'key': 'main_story_regions' }, { - 'label': '开始推主线剧情', + 'label': ProceedPlot.tr('开始推主线剧情'), 'type': 'button', 'selection': self.proceed_main_plot, 'key': None }, { - 'label': '开始推小组剧情', + 'label': ProceedPlot.tr('开始推小组剧情'), 'type': 'button', 'selection': self.proceed_group_plot, 'key': None }, { - 'label': '开始推支线剧情', + 'label': ProceedPlot.tr('开始推支线剧情'), 'type': 'button', 'selection': self.proceed_branch_plot, 'key': None } ] self.main_thread = config.get_main_thread() - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context="ProceedPlot") def proceed_main_plot(self): import threading diff --git a/gui/components/expand/pushConfig.py b/gui/components/expand/pushConfig.py index d17337449..ad37f5d5f 100644 --- a/gui/components/expand/pushConfig.py +++ b/gui/components/expand/pushConfig.py @@ -1,28 +1,30 @@ from .expandTemplate import TemplateLayout +from PyQt5.QtCore import QObject class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + PushConfig = QObject() configItems = [ { - 'label': '在运行出错时推送', + 'label': PushConfig.tr('在运行出错时推送'), 'key': 'push_after_error', 'type': 'switch' }, { - 'label': '在全部任务完成时推送', + 'label': PushConfig.tr('在全部任务完成时推送'), 'key': 'push_after_completion', 'type': 'switch' }, { - 'label': 'json 推送', + 'label': PushConfig.tr('json 推送'), 'type': 'text', 'key': 'push_json' }, { - 'label': 'ServerChan推送', + 'label': PushConfig.tr('ServerChan推送'), 'type': 'text', 'key': 'push_serverchan' } ] - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context="PushConfig") diff --git a/gui/components/expand/schedulePriority.py b/gui/components/expand/schedulePriority.py index 4b7618c18..1dbafdfd7 100644 --- a/gui/components/expand/schedulePriority.py +++ b/gui/components/expand/schedulePriority.py @@ -1,4 +1,4 @@ -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, QTranslator, QLocale from PyQt5.QtGui import QIntValidator from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QVBoxLayout from qfluentwidgets import LineEdit, CheckBox @@ -18,7 +18,7 @@ def __init__(self, parent=None, config=None): self.needed_levels = self.config.get('lesson_each_region_object_priority') self.check_config_validation() self.vBoxLayout = QVBoxLayout(self) - self.relationship_check_box_description = QLabel('优先做好感等级多的日程', self) + self.relationship_check_box_description = QLabel(self.tr('优先做好感等级多的日程'), self) self.relationship_check_box = CheckBox('', self) self.relationship_check_box.setChecked(self.config.get('lesson_relationship_first')) self.hBoxLayout = QHBoxLayout(self) @@ -71,7 +71,7 @@ def Slot_for_lesson_time_change(self, _): res.append(int(self.lesson_time_input[i].text())) self.priority_list = res self.config.set('lesson_times', self.priority_list) - return notification.success('日程次数', f'日程次数设置成功为:{self.priority_list}', self.config) + return notification.success(self.tr('日程次数'), f'{self.tr("日程次数设置成功为:")}{self.priority_list}', self.config) def __init_Signals_and_Slots(self): self.relationship_check_box.stateChanged.connect(self.Slot_for_relationship_check_box) @@ -95,13 +95,13 @@ def __init_relationship_check_box_layout(self): def __init_region_name_layout(self): temp = QVBoxLayout(self) - temp.addWidget(QLabel("区域名称", self), 0, Qt.AlignLeft) + temp.addWidget(QLabel(self.tr("区域名称"), self), 0, Qt.AlignLeft) for i in range(0, len(self.lesson_names)): temp.addWidget(QLabel(self.lesson_names[i], self), 0, Qt.AlignLeft) self.hBoxLayout.addLayout(temp) def __init_lesson_level_layout(self): - name = ["初级", "普通", "高级", "特级"] + name = [self.tr("初级"), self.tr("普通"), self.tr("高级"), self.tr("特级")] for i in range(0, 4): temp = QVBoxLayout(self) temp.setContentsMargins(0, 5, 0, 5) @@ -113,7 +113,7 @@ def __init_lesson_level_layout(self): def __init_lesson_times_layout(self): temp = QVBoxLayout(self) - temp.addWidget(QLabel("日程次数", self), 0, Qt.AlignLeft) + temp.addWidget(QLabel(self.tr("日程次数"), self), 0, Qt.AlignLeft) for i in range(0, len(self.lesson_names)): temp.addWidget(self.lesson_time_input[i], 0, Qt.AlignLeft) self.hBoxLayout.addLayout(temp) diff --git a/gui/components/expand/scriptConfig.py b/gui/components/expand/scriptConfig.py index 5b01be521..acf23d934 100644 --- a/gui/components/expand/scriptConfig.py +++ b/gui/components/expand/scriptConfig.py @@ -13,7 +13,7 @@ def __init__(self, parent=None, config=None): super().__init__(parent=parent) self.config = config self.info_widget = self.parent().parent().parent() - self.serverLabel = QLabel('请填写您的截图间隔:', self) + self.serverLabel = QLabel(self.tr('请填写您的截图间隔:'), self) self.screenshot_box = LineEdit(self) validator = QDoubleValidator(0.0, 65535.0, 2, self) self.screenshot_box.setValidator(validator) @@ -33,4 +33,4 @@ def __init__(self, parent=None, config=None): def _save_port(self, changed_text=None): self.config.set('screenshot_interval', changed_text) - notification.success('截图间隔', f'你的截图间隔已经被设置为:{changed_text}', self.config) + notification.success(self.tr('截图间隔'), f'{self.tr("你的截图间隔已经被设置为:")}{changed_text}', self.config) diff --git a/gui/components/expand/serverConfig.py b/gui/components/expand/serverConfig.py index 08b46ad61..1da6f507e 100644 --- a/gui/components/expand/serverConfig.py +++ b/gui/components/expand/serverConfig.py @@ -1,3 +1,4 @@ +from PyQt5.QtCore import QObject from PyQt5.QtWidgets import QHeaderView, QTableWidgetItem from qfluentwidgets import TableWidget @@ -14,25 +15,26 @@ def get_address_from_str(st): class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + ServerConfig = QObject() configItems = [ { - 'label': '请选择您的服务器,请慎重切换服务器,切换服务器后请重新启动脚本', + 'label': ServerConfig.tr('请选择您的服务器,请慎重切换服务器,切换服务器后请重新启动脚本'), 'type': 'combo', 'key': 'server', - 'selection': ['官服', 'B服', '国际服', '日服'] + 'selection': [ServerConfig.tr('官服'), ServerConfig.tr('B服'), ServerConfig.tr('国际服'), ServerConfig.tr('日服')] }, { - 'label': '请填写您的adb端口号', + 'label': ServerConfig.tr('请填写您的adb端口号'), 'type': 'text', 'key': 'adbPort' }, { - 'label': '检测adb地址(检测目前开启的模拟器adb地址)', + 'label': ServerConfig.tr('检测adb地址(检测目前开启的模拟器adb地址)'), 'type': 'button', 'selection': self.detect_adb_addr, } ] - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context='ServerConfig') self.tableView = TableWidget(self) self.tableView.setFixedHeight(100) @@ -55,7 +57,7 @@ def detect_adb_addr_thread(self): import device_operation results = device_operation.autosearch() if len(results) == 0: - results = ["自动查询模拟器失败!请尝试手动输入端口"] + results = [self.tr("自动查询模拟器失败!请尝试手动输入端口")] self.tableView.setRowCount(len(results)) for i in range(len(results)): self.tableView.setItem(i, 0, QTableWidgetItem(results[i])) @@ -63,7 +65,7 @@ def detect_adb_addr_thread(self): except Exception as e: print(e) self.tableView.setRowCount(1) - self.tableView.setItem(0, 0, QTableWidgetItem("adb地址获取失败")) + self.tableView.setItem(0, 0, QTableWidgetItem(self.tr("adb地址获取失败"))) # import device_operation # results = device_operation.autosearch() diff --git a/gui/components/expand/shopPriority.py b/gui/components/expand/shopPriority.py index 2d42d5f60..14d73fcdf 100644 --- a/gui/components/expand/shopPriority.py +++ b/gui/components/expand/shopPriority.py @@ -2,6 +2,8 @@ from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QHBoxLayout, QVBoxLayout from qfluentwidgets import FlowLayout, CheckBox, LineEdit +from gui.util.translator import baasTranslator as bt + class Layout(QWidget): def __init__(self, parent=None, config=None): @@ -20,24 +22,24 @@ def __init__(self, parent=None, config=None): self.setFixedHeight(700) self.setStyleSheet('Demo{background: white} QPushButton{padding: 5px 10px; font:15px "Microsoft YaHei"}') - self.label = QLabel('刷新次数', self) + self.label = QLabel(self.tr('刷新次数'), self) self.label.setFixedWidth(160) self.input = LineEdit(self) self.input.setValidator(QIntValidator(0, 5)) print(self.config.get('CommonShopRefreshTime')) self.input.setText(str(self.config.get('CommonShopRefreshTime'))) - self.accept = QPushButton('确定', self) + self.accept = QPushButton(self.tr('确定'), self) self.boxes = [] for i in range(len(self.goods)): t_cbx = CheckBox(self) t_cbx.setChecked(self.goods[i] == 1) - ccs = QLabel(self.default_goods[i][0], self) + ccs = QLabel(bt.tr('ConfigTranslation', self.default_goods[i][0]), self) ccs.setFixedWidth(150) price_text = str(self.default_goods[i][1]) if self.default_goods[i][2] == 'creditpoints': - price_text += '信用点' + price_text += self.tr('信用点') else: - price_text += '青辉石' + price_text += self.tr('青辉石') price_label = QLabel(price_text, self) price_label.setFixedWidth(150) wrapper_widget = QWidget() @@ -66,4 +68,3 @@ def __accept(self, input_content=None): def __check_server(self): if len(self.config.get('CommonShopList')) != len(self.default_goods): self.config.set('CommonShopList', len(self.default_goods) * [0]) - diff --git a/gui/components/expand/sweepCountConfig.py b/gui/components/expand/sweepCountConfig.py index 28c4402ab..2e06e5f5b 100644 --- a/gui/components/expand/sweepCountConfig.py +++ b/gui/components/expand/sweepCountConfig.py @@ -1,12 +1,14 @@ +from PyQt5.QtCore import QObject from .expandTemplate import TemplateLayout class Layout(TemplateLayout): def __init__(self, parent=None, config=None): + SweepCountConfig = QObject() sweep_label_description = { - 'CN': '各区域扫荡次数以英文逗号分隔', - 'Global': '各区域扫荡次数以英文逗号分隔,扫荡次数可以为max', - 'JP': '各区域扫荡次数以英文逗号分隔,扫荡次数可以为max', + 'CN': SweepCountConfig.tr('各区域扫荡次数以英文逗号分隔'), + 'Global': SweepCountConfig.tr('各区域扫荡次数以英文逗号分隔,扫荡次数可以为max'), + 'JP': SweepCountConfig.tr('各区域扫荡次数以英文逗号分隔,扫荡次数可以为max'), } configItems = [ { @@ -14,57 +16,57 @@ def __init__(self, parent=None, config=None): 'type': 'label' }, { - 'label': '悬赏委托扫荡', + 'label': SweepCountConfig.tr('悬赏委托扫荡'), 'type': 'text', 'key': 'rewarded_task_times' }, { - 'label': '学园交流会扫荡', + 'label': SweepCountConfig.tr('学园交流会扫荡'), 'type': 'text', 'key': 'scrimmage_times' }, { - 'label': '活动关卡扫荡关卡', + 'label': SweepCountConfig.tr('活动关卡扫荡关卡'), 'type': 'text', 'key': 'activity_sweep_task_number' }, { - 'label': '活动关卡扫荡次数', + 'label': SweepCountConfig.tr('活动关卡扫荡次数'), 'type': 'text', 'key': 'activity_sweep_times' }, { - 'label': '特殊委托扫荡', + 'label': SweepCountConfig.tr('特殊委托扫荡'), 'type': 'text', 'key': 'special_task_times' }, ] additional_items = [ { - 'label': '国服购买邀请券可在商店购买中实现', + 'label': SweepCountConfig.tr('国服购买邀请券可在商店购买中实现'), 'type': 'label' } ] if config.server_mode in ['JP', 'Global']: additional_items = [ { - 'label': '用券数目设置,下拉框选择', + 'label': SweepCountConfig.tr('用券数目设置,下拉框选择'), 'type': 'label' }, { - 'label': '悬赏委托扫荡券购买次数', + 'label': SweepCountConfig.tr('悬赏委托扫荡券购买次数'), 'type': 'combo', 'key': 'purchase_rewarded_task_ticket_times', 'selection': ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'max'] }, { - 'label': '日程券购买次数', + 'label': SweepCountConfig.tr('日程券购买次数'), 'type': 'combo', 'key': 'purchase_lesson_ticket_times', 'selection': ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'max'] }, { - 'label': '学园交流会扫荡券购买次数', + 'label': SweepCountConfig.tr('学园交流会扫荡券购买次数'), 'type': 'combo', 'key': 'purchase_scrimmage_ticket_times', 'selection': ['0', '1', '2', '3', '4', 'max'] @@ -72,4 +74,4 @@ def __init__(self, parent=None, config=None): ] for item in additional_items: configItems.append(item) - super().__init__(parent=parent, configItems=configItems, config=config) + super().__init__(parent=parent, configItems=configItems, config=config, context='SweepCountConfig') diff --git a/gui/components/expand/totalForceFightPriority.py b/gui/components/expand/totalForceFightPriority.py index c954a7b75..776875239 100644 --- a/gui/components/expand/totalForceFightPriority.py +++ b/gui/components/expand/totalForceFightPriority.py @@ -11,8 +11,7 @@ def __init__(self, parent=None, config=None): self.config = config self.info_widget = self.parent() self.hBoxLayout = QHBoxLayout(self) - # self.label = QLabel('输入最高难度', self) - self.label = QLabel('最高难度', self) + self.label = QLabel(self.tr('最高难度'), self) self.input = ComboBox(self) self.difficulties = self.config.static_config['total_assault_difficulties'][self.config.server_mode] self.input.addItems(self.difficulties) @@ -33,4 +32,4 @@ def __init__(self, parent=None, config=None): def __accept(self): self.config.set('totalForceFightDifficulty', self.input.text()) - notification.success('设置成功', f'你的总力战最高难度已经被设置为:{self.input.text()}', self.config) + notification.success(self.tr('设置成功'), f'{self.tr("你的总力战最高难度已经被设置为:")}{self.input.text()}', self.config) diff --git a/gui/components/template_card.py b/gui/components/template_card.py index 35cbdb2d8..d4f3a1785 100644 --- a/gui/components/template_card.py +++ b/gui/components/template_card.py @@ -5,6 +5,8 @@ IndicatorPosition, LineEdit from qfluentwidgets import FluentIcon as FIF +from gui.util.translator import baasTranslator as bt + class TemplateSettingCard(ExpandSettingCard): """ Folder list setting card """ @@ -12,7 +14,9 @@ class TemplateSettingCard(ExpandSettingCard): # statusChanged = pyqtSignal(bool) # timeChanged = pyqtSignal(str) - def __init__(self, title: str = '', content: str = None, parent=None, sub_view=None, config=None): + def __init__(self, title: str = '', content: str = None, parent=None, sub_view=None, config=None, context=None): + if context is not None: + title, content = bt.tr(context, title), bt.tr(context, content) super().__init__(FIF.CHECKBOX, title, content, parent) # Card Top Widgets # self.status_switch = SwitchButton(self.tr('Off'), self, IndicatorPosition.RIGHT) @@ -56,7 +60,9 @@ def setChecked(self, isChecked: bool): class SimpleSettingCard(ExpandSettingCard): """ Folder list setting card """ - def __init__(self, sub_view, title: str = '', content: str = None, parent=None, config=None): + def __init__(self, sub_view, title: str = '', content: str = None, parent=None, config=None, context=None): + if context is not None: + title, content = bt.tr(context, title), bt.tr(context, content) super().__init__(FIF.CHECKBOX, title, content, parent) self.expand_view = sub_view.Layout(self, config) self._adjustViewSize() diff --git a/gui/fragments/history.py b/gui/fragments/history.py index 2f92b997e..8ca8386e2 100644 --- a/gui/fragments/history.py +++ b/gui/fragments/history.py @@ -21,11 +21,11 @@ def __init__(self): # hide index column self.table_view.verticalHeader().setVisible(False) - self.table_view.setHorizontalHeaderLabels(['内容', '贡献者', '提交时间', '提交信息']) + self.table_view.setHorizontalHeaderLabels([self.tr('内容'), self.tr('贡献者'), self.tr('提交时间'), self.tr('提交信息')]) self.table_view.setObjectName('HistoryTable' + random.randint(0, 100000).__str__()) threading.Thread(target=self.fetch_update_info, daemon=True).start() - self.addSubInterface(icon=FIF.CARE_RIGHT_SOLID, interface=self.table_view, text='更新日志') + self.addSubInterface(icon=FIF.CARE_RIGHT_SOLID, interface=self.table_view, text=self.tr('更新日志')) self.show() diff --git a/gui/fragments/home.py b/gui/fragments/home.py index 15042a4a3..7fd150dea 100644 --- a/gui/fragments/home.py +++ b/gui/fragments/home.py @@ -15,8 +15,10 @@ ) from core.notification import notify +from gui.util.translator import baasTranslator as bt from window import Window + MAIN_BANNER = 'gui/assets/banner_home_bg.png' @@ -50,10 +52,10 @@ def __init__(self, parent: Window = None, config=None): self.info_box.setFixedHeight(45) self.infoLayout = QHBoxLayout(self.info_box) - title = f'蔚蓝档案自动脚本 {self.config.get("name")}' + title = self.tr("蔚蓝档案自动脚本") + f' {self.config.get("name")}' self.banner_visible = self.config.get('bannerVisibility') self.label = SubtitleLabel(title, self) - self.info = SubtitleLabel('无任务', self) + self.info = SubtitleLabel(self.tr('无任务'), self) setFont(self.label, 24) setFont(self.info, 24) @@ -74,7 +76,7 @@ def __init__(self, parent: Window = None, config=None): self.tr('启动'), FIF.CARE_RIGHT_SOLID, self.tr('档案,启动'), - '开始你的档案之旅', + self.tr('开始你的档案之旅'), self ) @@ -124,9 +126,9 @@ def call_update(self, data=None, parent=None): if data: if type(data[0]) is dict: - self.info.setText(f'正在运行:{self.event_map[data[0]["func_name"]]}') + self.info.setText(self.tr("正在运行:") + bt.tr('ConfigTranslation', self.event_map[data[0]["func_name"]])) else: - self.info.setText(f'正在运行:{data[0]}') + self.info.setText(self.tr("正在运行:") + bt.tr('ConfigTranslation', data[0])) _main_thread_ = self.config.get_main_thread() _baas_thread_ = _main_thread_.get_baas_thread() if _baas_thread_ is not None: @@ -151,8 +153,9 @@ def call_update(self, data=None, parent=None): print("Empty JSON data") def set_button_state(self, state): + state = bt.tr('MainThread', state) self.startup_card.button.setText(state) - self._main_thread_attach.running = True if state == "停止" else False + self._main_thread_attach.running = True if state == bt.tr("MainThread", "停止") else False def __initLayout(self): self.expandLayout.setSpacing(28) @@ -209,7 +212,7 @@ def __init__(self, config): def run(self): self.running = True - self.display('停止') + self.display(self.tr("停止")) self._init_script() self._main_thread.logger.info("Starting Blue Archive Auto Script...") self._main_thread.send('start') @@ -218,7 +221,7 @@ def stop_play(self): self.running = False if self._main_thread is None: return - self.display('启动') + self.display(self.tr("启动")) self._main_thread.send('stop') self.exit(0) @@ -238,20 +241,20 @@ def display(self, text): def start_hard_task(self): self._init_script() self.update_signal.emit(['困难关推图']) - self.display('停止') + self.display(self.tr("停止")) if self._main_thread.send('solve', 'explore_hard_task'): - notify(title='BAAS', body='困难图推图已完成') - self.update_signal.emit(['无任务']) - self.display('启动') + notify(title='BAAS', body=self.tr('困难图推图已完成')) + self.update_signal.emit([self.tr('无任务')]) + self.display(self.tr("启动")) def start_normal_task(self): self._init_script() - self.update_signal.emit(['普通关推图']) - self.display('停止') + self.update_signal.emit([self.tr('普通关推图')]) + self.display(self.tr('停止')) if self._main_thread.send('solve', 'explore_normal_task'): - notify(title='BAAS', body='普通图推图已完成') - self.update_signal.emit(['无任务']) - self.display('启动') + notify(title='BAAS', body=self.tr('普通图推图已完成')) + self.update_signal.emit([self.tr('无任务')]) + self.display(self.tr('启动')) def start_mumu_JP_login_fixer(self): self._init_script() @@ -263,67 +266,67 @@ def start_mumu_JP_login_fixer(self): def start_fhx(self): self._init_script() if self._main_thread.send('solve', 'de_clothes'): - notify(title='BAAS', body='反和谐成功,请重启BA下载资源') + notify(title='BAAS', body=self.tr('反和谐成功,请重启BA下载资源')) def start_main_story(self): self._init_script() - self.update_signal.emit(['自动主线剧情']) - self.display('停止') + self.update_signal.emit([self.tr('自动主线剧情')]) + self.display(self.tr('停止')) if self._main_thread.send('solve', 'main_story'): if self._main_thread.flag_run: - notify(title='BAAS', body='主线剧情已完成') - self.update_signal.emit(['无任务']) - self.display('启动') + notify(title='BAAS', body=self.tr('主线剧情已完成')) + self.update_signal.emit([self.tr('无任务')]) + self.display(self.tr('启动')) def start_group_story(self): self._init_script() - self.update_signal.emit(['自动小组剧情']) - self.display('停止') + self.update_signal.emit([self.tr('自动小组剧情')]) + self.display(self.tr('停止')) if self._main_thread.send('solve', 'group_story'): if self._main_thread.flag_run: - notify(title='BAAS', body='小组剧情已完成') + notify(title='BAAS', body=self.tr('小组剧情已完成')) self.display('启动') - self.update_signal.emit(['无任务']) + self.update_signal.emit([self.tr('无任务')]) def start_mini_story(self): self._init_script() - self.display('停止') - self.update_signal.emit(['自动支线剧情']) + self.display(self.tr('停止')) + self.update_signal.emit([self.tr('自动支线剧情')]) if self._main_thread.send('solve', 'mini_story'): if self._main_thread.flag_run: - notify(title='BAAS', body='支线剧情已完成') - self.display('启动') - self.update_signal.emit(['无任务']) + notify(title='BAAS', body=self.tr('支线剧情已完成')) + self.display(self.tr('启动')) + self.update_signal.emit([self.tr('无任务')]) def start_explore_activity_story(self): self._init_script() - self.display('停止') - self.update_signal.emit(['自动活动剧情']) + self.display(self.tr('停止')) + self.update_signal.emit([self.tr('自动活动剧情')]) if self._main_thread.send('solve', 'explore_activity_story'): if self._main_thread.flag_run: - notify(title='BAAS', body='活动剧情已完成') - self.display('启动') - self.update_signal.emit(['无任务']) + notify(title='BAAS', body=self.tr('活动剧情已完成')) + self.display(self.tr('启动')) + self.update_signal.emit([self.tr('无任务')]) def start_explore_activity_mission(self): self._init_script() - self.display('停止') - self.update_signal.emit(['自动活动任务']) + self.display(self.tr('停止')) + self.update_signal.emit([self.tr('自动活动任务')]) if self._main_thread.send('solve', 'explore_activity_mission'): if self._main_thread.flag_run: - notify(title='BAAS', body='活动任务已完成') - self.display('启动') - self.update_signal.emit(['无任务']) + notify(title='BAAS', body=self.tr('活动任务已完成')) + self.display(self.tr('启动')) + self.update_signal.emit([self.tr('无任务')]) def start_explore_activity_challenge(self): self._init_script() - self.update_signal.emit(['自动活动挑战']) - self.display('停止') + self.update_signal.emit([self.tr('自动活动挑战')]) + self.display(self.tr('停止')) if self._main_thread.send('solve', 'explore_activity_challenge'): if self._main_thread.flag_run: - notify(title='BAAS', body='活动挑战推图已完成') - self.display('启动') - self.update_signal.emit(['无任务']) + notify(title='BAAS', body=self.tr('活动挑战推图已完成')) + self.display(self.tr('启动')) + self.update_signal.emit([self.tr('无任务')]) def get_baas_thread(self): return self._main_thread diff --git a/gui/fragments/process.py b/gui/fragments/process.py index e4d3da974..bcf8abdd6 100644 --- a/gui/fragments/process.py +++ b/gui/fragments/process.py @@ -8,6 +8,8 @@ from qfluentwidgets import (ScrollArea, TitleLabel, SubtitleLabel, ListWidget, StrongBodyLabel) from gui.components import expand +from gui.util.translator import baasTranslator as bt + lock = threading.Lock() DISPLAY_CONFIG_PATH = './config/display.json' @@ -81,15 +83,17 @@ def refresh_status(self): crt_task = self.baas_thread.scheduler.getCurrentTaskName() task_list = self.baas_thread.scheduler.getWaitingTaskList() print(crt_task, task_list) - crt_task = crt_task if crt_task else "暂无正在执行的任务" - task_list = [task for task in task_list] if task_list else ["暂无队列中的任务"] - self.on_status.setText(crt_task) + + crt_task = crt_task if crt_task else self.tr("暂无正在执行的任务") + task_list = [bt.tr('ConfigTranslation', task) for task in task_list] if task_list else [self.tr("暂无队列中的任务")] + self.on_status.setText(bt.tr('ConfigTranslation', crt_task)) + self.listWidget.clear() self.listWidget.addItems(task_list) else: - self.on_status.setText("暂无正在执行的任务") + self.on_status.setText(self.tr("暂无正在执行的任务")) self.listWidget.clear() - self.listWidget.addItems(["暂无队列中的任务"]) + self.listWidget.addItems([self.tr("暂无队列中的任务")]) main_thread = self.config.get_main_thread() self.baas_thread = main_thread.get_baas_thread() if main_thread else None time.sleep(2) diff --git a/gui/fragments/readme.py b/gui/fragments/readme.py index a6e916a38..167adf672 100644 --- a/gui/fragments/readme.py +++ b/gui/fragments/readme.py @@ -4,6 +4,8 @@ from qfluentwidgets import FluentIcon as FIF, FluentWindow, TextEdit import os +from gui.util.translator import baasTranslator as bt + class ReadMeInterface(QFrame): def __init__(self, content: str): @@ -24,7 +26,7 @@ def __init__(self): super().__init__() docs = [] - path = './src/descriptions/' + path = self.getPath() for file in os.listdir(path): filepath = os.path.join(path, file) filename = file.split('.')[0] @@ -36,6 +38,10 @@ def __init__(self): self.addSubInterface(interface=ReadMeInterface(doc['content']), icon=FIF.TAG, text=doc['title']) self.show() + def getPath(self): + directory = f'./src/descriptions/{bt.stringLang}' + if os.path.isdir(directory): + return directory if __name__ == '__main__': import sys diff --git a/gui/fragments/settings.py b/gui/fragments/settings.py index 1ca8093a0..310d30d8b 100644 --- a/gui/fragments/settings.py +++ b/gui/fragments/settings.py @@ -4,11 +4,14 @@ from PyQt5.QtCore import Qt from PyQt5.QtWidgets import QWidget -from qfluentwidgets import (ExpandLayout, ScrollArea, TitleLabel, SettingCardGroup) +from qfluentwidgets import (ComboBoxSettingCard, ExpandLayout, FluentIcon as FIF, ScrollArea, TitleLabel, SettingCardGroup) +import window from gui.components import expand from gui.components.template_card import SimpleSettingCard - +from gui.util.language import Language +from gui.util import notification +from gui.util.translator import baasTranslator as bt class SettingsFragment(ScrollArea): def __init__(self, parent=None, config=None): @@ -16,31 +19,40 @@ def __init__(self, parent=None, config=None): self.config = config self.scrollWidget = QWidget() self.expandLayout = ExpandLayout(self.scrollWidget) - self.settingLabel = TitleLabel(self.tr(f"普通设置 {self.config['name']}"), self.scrollWidget) + self.settingLabel = TitleLabel(self.tr(f"普通设置") + f' {self.config["name"]}', self.scrollWidget) self.basicGroup = SettingCardGroup( self.tr("基本"), self.scrollWidget) self.basicGroupItems = [ + ComboBoxSettingCard( + bt.cfg.language, + FIF.LANGUAGE, + self.tr('语言'), + self.tr('设置界面的首选语言'), + texts=Language.combobox(), + parent=self.basicGroup + ), + SimpleSettingCard( - title='应用相关设置', - content='选择你的服务器平台,设置你的端口(不知道端口请设置为0)', + title=self.tr('应用相关设置'), + content=self.tr('选择你的服务器平台,设置你的端口(不知道端口请设置为0)'), sub_view=expand.__dict__['serverConfig'], parent=self.basicGroup, config=self.config ), SimpleSettingCard( - title='脚本相关设置', - content='根据你的电脑配置,调整相应的参数。', + title=self.tr('脚本相关设置'), + content=self.tr('根据你的电脑配置,调整相应的参数。'), sub_view=expand.__dict__['scriptConfig'], parent=self.basicGroup, config=self.config ), SimpleSettingCard( - title="模拟器启动设置", - content="设置启动模拟器的路径", + title=self.tr("模拟器启动设置"), + content=self.tr("设置启动模拟器的路径"), sub_view=expand.__dict__['emulatorConfig'], parent=self.basicGroup, config=self.config @@ -52,48 +64,48 @@ def __init__(self, parent=None, config=None): self.exploreGroupItems = [ SimpleSettingCard( - title='普通图推图设置', - content='根据你的推图需求,调整相应的参数。', + title=self.tr('普通图推图设置'), + content=self.tr('根据你的推图需求,调整相应的参数。'), sub_view=expand.__dict__['exploreConfig'], parent=self.exploreGroup, config=self.config ), SimpleSettingCard( - title='困难图推图设置', - content='根据你所需困难图刷关,设置参数。', + title=self.tr('困难图推图设置'), + content=self.tr('根据你所需困难图刷关,设置参数。'), sub_view=expand.__dict__['hardTaskConfig'], parent=self.exploreGroup, config=self.config ), SimpleSettingCard( - title='推剧情', - content='主线剧情,小组剧情,支线剧情', + title=self.tr('推剧情'), + content=self.tr('主线剧情,小组剧情,支线剧情'), sub_view=expand.__dict__['proceedPlot'], parent=self.exploreGroup, config=self.config ), SimpleSettingCard( - title='活动图设置', - content='推故事,推任务,推挑战', + title=self.tr('活动图设置'), + content=self.tr('推故事,推任务,推挑战'), sub_view=expand.__dict__['eventMapConfig'], parent=self.exploreGroup, config=self.config ), SimpleSettingCard( - title='其他设置', - content='其他的一些小功能与设置', + title=self.tr('其他设置'), + content=self.tr('其他的一些小功能与设置'), sub_view=expand.__dict__['otherConfig'], parent=self.exploreGroup, config=self.config ), SimpleSettingCard( - title='推送设置', - content='推送信息', + title=self.tr('推送设置'), + content=self.tr('推送信息'), sub_view=expand.__dict__['pushConfig'], parent=self.exploreGroup, config=self.config @@ -102,6 +114,7 @@ def __init__(self, parent=None, config=None): self.__initLayout() self.object_name = md5(f'{time.time()}%{random()}'.encode('utf-8')).hexdigest() self.setObjectName(self.object_name) + self.__connectSignalToSlot() def __initLayout(self): self.expandLayout.setSpacing(28) @@ -122,3 +135,18 @@ def __initLayout(self): self.expandLayout.addWidget(self.exploreGroup) self.setWidget(self.scrollWidget) + + def __showRestartTooltip(self): + """ show restart tooltip """ + if time.time() - window.LAST_NOTICE_TIME < 0.1: + return + notification.success( + 'Language updated successfully', + 'It will take effect after restart', + self.config + ) + window.LAST_NOTICE_TIME = time.time() + + def __connectSignalToSlot(self): + """ connect signal to slot """ + bt.cfg.appRestartSig.connect(self.__showRestartTooltip) diff --git a/gui/fragments/switch.py b/gui/fragments/switch.py index 2a17b9b7a..6f43d5256 100644 --- a/gui/fragments/switch.py +++ b/gui/fragments/switch.py @@ -25,7 +25,7 @@ def __init__(self, parent=None, config=None): # 创建一个ExpandLayout实例作为滚动区域的布局管理器 self.expandLayout = ExpandLayout(self.scrollWidget) # 创建一个标题为“调度设置”的TitleLabel实例 - self.settingLabel = TitleLabel(self.tr(f"配置设置 {self.config['name']}"), self.scrollWidget) + self.settingLabel = TitleLabel(self.tr(f"配置设置") + f" {self.config['name']}", self.scrollWidget) # 初始化basicGroup变量,_setting_cards列表 self.basicGroup = None self._setting_cards = [] @@ -102,7 +102,8 @@ def _create_card(self, name: str, tip: str, setting_name: str) -> TemplateSettin content=tip, parent=self.basicGroup, sub_view=expand.__dict__[setting_name] if setting_name else None, - config=self.config + config=self.config, + context='ConfigTranslation' ) # 创建TemplateSettingCard实例 # _switch_card.status_switch.setChecked(enabled) # 设置状态开关的选中状态 # _switch_card.statusChanged.connect(lambda x: self._change_status(name, x)) # 连接状态开关的状态更改信号和_change_status()方法 diff --git a/gui/i18n/en_US.qm b/gui/i18n/en_US.qm new file mode 100644 index 000000000..3260ad423 Binary files /dev/null and b/gui/i18n/en_US.qm differ diff --git a/gui/i18n/en_US.ts b/gui/i18n/en_US.ts new file mode 100644 index 000000000..e9b57dd47 --- /dev/null +++ b/gui/i18n/en_US.ts @@ -0,0 +1,1416 @@ + + + + + BAASTitleBar + + + 帮助 + Help + + + + ConfigTranslation + + + 每日特别委托 + Commissions + + + + 悬赏通缉 + Bounty + + + + 竞技场 + Tactical Challenge + + + + 收集每日体力 + Collect Daily AP + + + + 收集小组体力 + Collect Club AP + + + + 商店购买 + Shop (Normal) + + + + 日程 + Lesson + + + + 主线清除体力 + Mission + + + + 自动MomoTalk + MomoTalk + + + + 咖啡厅 + Cafe + + + + 查收邮箱 + Mailbox + + + + 自动制造 + Crafting + + + + 收集奖励 + Tasks + + + + 普通关清体力 + Mission (Normal) Sweep + + + + 困难关清体力 + Mission (Hard) Sweep + + + + 总力战 + Total Assault + + + + 学院交流会 + Scrimmage + + + + 凌晨四点重启 + Restart at 4am + + + + 活动扫荡 + Event Sweep + + + + 新的配置 + New Configuration + + + + 功能开关 + Schedule + + + + 竞技场商店购买 + Shop (Tactical Challenge) + + + + 扫荡及购买券设置 + Sweep and Purchase Tickets Settings + + + + 重要,此处为功能开关,控制各功能是否开启,启动前请检查是否开启。 + Control whether each task is turned on, +make sure to do it before starting the script. + + + + 帮助你收集咖啡厅体力和信用点 + Helps you collect cafe AP and Credits + + + + 自动每日日程 + Automatic daily lesson + + + + 商店里买东西 + Purchase in normal shop + + + + 竞技场商店里买东西 + Purchase in tactical challenge shop + + + + 主线关卡自动清除体力与每日困难 + Automatically use AP to sweep Normal and Hard stages + + + + 帮助你自动打竞技场 + Helps you automate tactical challenge + + + + 帮助你自动制造 + Help you automate crafting + + + + 总力战期间自动打总力战 + Automatic Total Assault during Total Assault + + + + 各种扫荡及购买券次数设置 + Various sweep and tickets purchase settings + + + + 官服 + CN + + + + B服 + Bilibili + + + + 国际服 + Global + + + + 日服 + JP + + + + 拖动礼物 + Drag the gift + + + + 初级经验书 + Novice Report + + + + 中级经验书 + Normal Report + + + + 高级经验书 + Advanced Report + + + + 特级经验书 + Superior Report + + + + 初级经验珠 + Lesser Stone + + + + 中级经验珠 + Normal Stone + + + + 高级经验珠 + Advanced Stone + + + + 特级经验珠 + Superior Stone + + + + 随机初级神秘古物 + Random Beginner Material + + + + 随机中级神秘古物 + Random Intermediate Material + + + + 静子神明文字x5 + Shizuko's Eleph + + + + 真白神明文字x5 + Mashiro's Eleph + + + + 纱绫神明文字x5 + Saya's Eleph + + + + 风香神明文字x5 + Fuuka's Eleph + + + + 歌原神明文字x5 + Utaha's Eleph + + + + 初级经验书x5 + Normal Report x5 + + + + 中级经验书x10 + Novice Report x10 + + + + 高级经验书x3 + Advanced Report x3 + + + + 特级经验书x1 + Superior Report x1 + + + + 信用点x5k + Credits x5k + + + + 信用点x75k + Credits x75k + + + + 信用点x125k + Credits x125k + + + + 暂无任务 + No Task + + + + MuMu模拟器 + MuMu Player + + + + 蓝叠模拟器 + BlueStacks CN + + + + 蓝叠国际版 + BlueStacks + + + + 日常小游戏 + Daily Game Activity + + + + 咖啡厅邀请 + Cafe Invitation + + + + DetailSettingMessageBox + + + 配置详情 + Detailed Configuration + + + + 优先级 + Priority + + + + 执行间隔 + Interval + + + + 每日重置 + Reset daily + + + + 禁用时间段 + Disable period + + + + 前置任务 + Pre task + + + + 后置任务 + Post-task + + + + 确定 + Confirm + + + + 取消 + Cancel + + + + EmulatorConfig + + + 在运行Baas时打开模拟器(启动模拟器的功能开关,关闭后不会启动模拟器) + <b>Open the emulator on running Baas</b> <br/>(The switch for start emulator. Emulator won't be started if closed) + + + + 等待模拟器启动时间(模拟器从开始启动到桌面加载完成的时间(秒),一般默认) + <b>The time waiting for emulator startup</b> <br/> +(The time(metered in seconds) from the start<br/> + to the desktop loaded status, regularly set unchanged) + + + + 是否模拟器多开(打开后无视已经启动的模拟器进程,将再启动一个模拟器)) + <b>Enable emulator multi-instance?</b> (ignore existing <br/> +emulator processes and start a new emulator if enabled) + + + + 是否启用内建的自动扫描模拟器功能(开启后将自动识别系统内已安装的模拟器) + <b>Enable auto emulator scanning function?</b> (will automatically <br/> +detect installed emulators on the system when enabled) + + + + EventMapConfig + + + 推故事 + Clear Story + + + + 推任务 + Clear Quest + + + + 推挑战 + Clear Challenge + + + + ExploreConfig + + + 是否手动boss战(进入关卡后暂停等待手操) + Manual boss battle? (Pause and Wait for + manual control after entering the battle) + + + + 是否不强制打到sss(启用后跳过已通过但未sss的关卡) + Skip getting SSS rank (If enabled, The script +will skip completed but unSSSed levels) + + + + 开启后强制打每一个指定的关卡(不管是否sss) + Force play each specified level if + enabled (regardless of SSSed rank) + + + + 爆发一队 + Explosive Team 1 + + + + 爆发二队 + Explosive Team 2 + + + + 贯穿一队 + Piercing Team 1 + + + + 贯穿二队 + Piercing Team 2 + + + + 神秘一队 + Mystic Team 1 + + + + 神秘二队 + Mystic Team 2 + + + + 振动一队 + Sonic Team 1 + + + + 振动二队 + Sonic Team 2 + + + + HardTaskConfig + + + 打到SSS + Aim 3 Stars + + + + 拿礼物 + Collect gift + + + + 完成成就任务 + Complete achievement tasks + + + + HistoryWindow + + + 内容 + Contents + + + + 贡献者 + Contributor + + + + 提交时间 + Date of submission + + + + 提交信息 + Submission of information + + + + 更新日志 + Changelog + + + + HomeFragment + + + 蔚蓝档案自动脚本 + Blue Archive Auto Script + + + + 无任务 + No task + + + + 启动 + Start + + + + 档案,启动 + BlueArchive, Launch + + + + 开始你的档案之旅 + Start Script + + + + 正在运行: + Running: + + + + Layout + + + 输入你需要对手比你低几级,高几级则填负数: + Enter how many ranks below or above you need the opponent to be. +Use positive number for below and negative for above: + + + + 输入你最多需要刷新几次: + Enter how many times you need to refresh: + + + + 确定 + Save + + + + 设置成功 + successfully set + + + + 刷新次数 + Number of Refreshes + + + + 是否使用邀请券: + Use invitation ticket: + + + + 是否有二号咖啡厅: + Is there a second cafe: + + + + 列表选择你要添加邀请的学生,修改后请点击确定: + The list selects the students you want to invite. Click Save to make changes: + + + + 添加学生 + Add students + + + + 选择摸头方式: + Select the touch method: + + + + 选择第二咖啡厅邀请的学生 + Select the students to be invited in the second cafe + + + + 目前制造物品优先级,排在前面的会优先选择 + Current manufacturing item priority, the first one will be selected first + + + + 是否使用加速券 + Whether to use booster tickets + + + + 推图选项 + Map-clear Options + + + + 请在下面填写要推的图,填写方式见-普通图自动推图说明- + Please enter the stages to be cleared. +See Clear Hard and Normal Stages in Help + + + + 开始推图 + Run + + + + 全部(不)启用 + All (not) enabled + + + + 刷新执行时间 + Refresh Execution Time + + + + 排序方式: + Sort by: + + + + 默认排序 + Default order + + + + 按下次执行时间排序 + Soonest + + + + 事件 + Chore + + + + 下次刷新时间 + Execution Time + + + + 启用 + Enable + + + + <b>困难图队伍属性和普通图相同(见普通图推图设置),请按照帮助中说明选择推困难图关卡并按对应图设置队伍</b> + <b>Hard stages follow the same unit requirements of Normal stages +(see Clear Hard and Normal Stages in Help)</b> + + + + 普通关卡与次数(如"1-1-1,1-2-3"表示关卡1-1打一次,然后关卡1-2打三次): + Normal stage and number of sweeps(e.g. "1-1-1,1-2-3" means that stage 1-1 is swept once, then stage 1-2 is swept three times): + + + + 困难关卡设置同上,注意:次数最多为3),逗号均为英文逗号,日服、国际服可填max: + Set hard stages as above, with a maximum of 3 sweeps. Use commas for separation. +For JP or Global server, you can use 'max': + + + + 根据学生添加关卡 + Add based on students + + + + 爱丽丝宝贝 + 爱丽丝宝贝 + + + + 优先做好感等级多的日程 + Prioritize lessons with higher affection levels + + + + 日程次数 + Number of tickets + + + + 区域名称 + Location + + + + 初级 + Novice + + + + 普通 + Normal + + + + 高级 + Advanced + + + + 特级 + Superior + + + + 请填写您的截图间隔: + Please fill in your screenshot interval: + + + + ADB地址(点击选择) + ADB address (click to select) + + + + 自动查询模拟器失败!请尝试手动输入端口 + Automatic query emulator failed! Please try entering the port manually + + + + adb地址获取失败 + adb address fetch failed + + + + 信用点 + Credits + + + + 青辉石 + Pyroxene + + + + 最高难度 + Highest Difficulty + + + + 普通关推图 + Normal Level Mainline Map Clear + + + + 更多配置 + More Configuration + + + + 困难关推图 + Hard Mainline Map Clear + + + + 设置失败 + Setup failed + + + + 截图间隔 + Screenshot Interval + + + + 详细配置 + Detailed Configuration + + + + 是否领取奖励: + Claim rewards? : + + + + 优先邀请券好感等级低的学生: + Is Priority given to low-affection-level students? : + + + + 是否允许学生更换服饰: + Allow students to change clothes? : + + + + 是否允许重复邀请: + Repeat invitations? : + + + + 选择模拟器地址 + Choose Emulator Path + + + + 选择 + Select + + + + 多开号 + Multi-account + + + + 选择模拟器类型 + Select the emulator type + + + + MainThread + + + 停止 + Stop + + + + 启动 + Start + + + + 困难图推图已完成 + Clear Hard Mission completed + + + + 普通图推图已完成 + Clear Normal Mission completed + + + + 反和谐成功,请重启BA下载资源 + Anti-harmony success, please restart BA download resources + + + + 主线剧情已完成 + Main Story Completed + + + + 小组剧情已完成 + Group Story Completed + + + + 支线剧情已完成 + Mini story completed + + + + 活动剧情已完成 + Event Story Completed + + + + 活动任务已完成 + Event Quest Completed + + + + 活动挑战推图已完成 + Event Challenge Completed + + + + 无任务 + No task + + + + 普通关推图 + Clear Normal Mission + + + + 自动主线剧情 + Main Story + + + + 自动小组剧情 + Group Story + + + + 自动支线剧情 + Mini Story + + + + 自动活动剧情 + Clear Event Story + + + + 自动活动任务 + Clear Event Quest + + + + 自动活动挑战 + Clear Event Challenge + + + + OtherConfig + + + 一键反和谐 + One-click anti-harmony + + + + 显示首页头图(下次启动时生效) + Show homepage header image (effective on next startup) + + + + 修复Mumu无法登录日服 + Fix Mumu Player unable to log into the Japanese server + + + + ProceedPlot + + + 主线剧情需要推的章节数 + The number of chapters to be pushed in the Main Story + + + + 开始推主线剧情 + Start pushing the Main Story + + + + 开始推小组剧情 + Start pushing the Group Story + + + + 开始推支线剧情 + Start pushing the Mini Story + + + + ProcessFragment + + + 调度状态 + Scheduling Status + + + + 执行中 + Executing + + + + 暂无正在执行的任务 + No active tasks + + + + 暂无队列中的任务 + There are no tasks in the queue + + + + 任务队列 + Task Queue + + + + PushConfig + + + 在运行出错时推送 + Send when running error + + + + 在全部任务完成时推送 + Send when all tasks are completed + + + + json 推送 + JSON notification + + + + ServerChan推送 + ServerChan notification + + + + SaveSettingMessageBox + + + 新建配置 + New Configuration + + + + 输入新建的配置名: + Enter the name of the new configuration: + + + + 确定 + OK + + + + 取消 + Cancel + + + + ServerConfig + + + 请选择您的服务器,请慎重切换服务器,切换服务器后请重新启动脚本 + Please restart the script after switching server + + + + 官服 + CN + + + + B服 + Bilibili + + + + 国际服 + Global + + + + 日服 + JP + + + + 请填写您的adb端口号 + Please fill in your adb port number + + + + 检测adb地址(检测目前开启的模拟器adb地址) + Detect the adb address of the currently opened emulator + + + + SettingsFragment + + + 普通设置 + General Settings + + + + 基本 + Basic + + + + 语言 + Language + + + + 设置界面的首选语言 + Set your preferred language for the GUI + + + + 应用相关设置 + Server & Emulator Settings + + + + 选择你的服务器平台,设置你的端口(不知道端口请设置为0) + Select your server platform and set your port (set to 0 if you don't know the port) + + + + 脚本相关设置 + Script Settings + + + + 根据你的电脑配置,调整相应的参数。 + Adjust the parameters according to your computer specs. + + + + 模拟器启动设置 + Emulator Startup Settings + + + + 设置启动模拟器的路径 + Set the path to start the emulator + + + + 相关设置 + Features + + + + 普通图推图设置 + Clear Normal Mission Settings + + + + 根据你的推图需求,调整相应的参数。 + Adjust the parameters according to your normal clear needs. + + + + 困难图推图设置 + Clear Hard Mission Settings + + + + 根据你所需困难图刷关,设置参数。 + Adjust the parameters according to your hard clear needs. + + + + 推剧情 + Push the Story Forward + + + + 主线剧情,小组剧情,支线剧情 + Main Story, Group Story, Mini Story + + + + 活动图设置 + Clear Event Settings + + + + 推故事,推任务,推挑战 + Clear Story, Clear Quest, Clear Challenge + + + + 其他设置 + Miscellaneous + + + + 其他的一些小功能与设置 + Some other small features and settings + + + + 推送设置 + Notifications Settings + + + + 推送信息 + send notifications + + + + SweepCountConfig + + + <b>各区域扫荡次数以英文逗号分隔</b> + <b>Number of sweeps by area separated by commas</b> + + + + <b>各区域扫荡次数以英文逗号分隔,扫荡次数可以为max</b> + <b>The number of sweeps in each area is separated by commas in English, and the number of sweeps can be max</b> + + + + 悬赏委托扫荡 + Bounty + + + + 学园交流会扫荡 + Scrimmage + + + + 活动关卡扫荡关卡 + Event Stage + + + + 活动关卡扫荡次数 + Event Sweeps + + + + 特殊委托扫荡 + Commissions + + + + 国服购买邀请券可在<b>商店购买</b>中实现 + CN server purchase invitation tickets can be realized in the<b> store purchase</b> + + + + <b>用券数目设置,下拉框选择</b> + <b>Number of tickets to buy, drop-down box selection</b> + + + + 悬赏委托扫荡券购买次数 + Number of tickets for Bounty + + + + 日程券购买次数 + Number of tickets for Lesson + + + + 学园交流会扫荡券购买次数 + Number of tickets for Scrimmage + + + + SwitchFragment + + + 配置设置 + Dailies Settings + + + + 功能开关 + Chores + + + + TemplateLayout + + + 执行 + Run + + + + 确定 + Save + + + + 设置成功 + successfully set + + + + Window + + + 主页 + Home + + + + 配置 + Dailies + + + + 设置 + Settings + + + + 是否要删除配置: + Do you want to delete the configuration: + + + + 你需要在确认后重启BAAS以完成更改。 + You will need to restart Baas after confirmation to complete the changes. + + + + 调度 + Schedule + + + + 设置失败 + Setup failed + + + + bt + + + ConfigTranslation + 拖动礼物 + ConfigTranslation + + + + ConfigTranslation + 普通 + ConfigTranslation + + + + TemplateLayout + TemplateLayout + + + + ConfigTranslation + ConfigTranslation + + + + MainThread + MainThread + + + + MainThread + 停止 + MainThread + + + + helpModal + + + 帮助 + Help + + + diff --git a/gui/i18n/ja_JP.qm b/gui/i18n/ja_JP.qm new file mode 100644 index 000000000..c7d8673f2 Binary files /dev/null and b/gui/i18n/ja_JP.qm differ diff --git a/gui/i18n/ja_JP.ts b/gui/i18n/ja_JP.ts new file mode 100644 index 000000000..b19f9d9ff --- /dev/null +++ b/gui/i18n/ja_JP.ts @@ -0,0 +1,1404 @@ + + + + + BAASTitleBar + + + 帮助 + ヘルプ + + + + ConfigTranslation + + + 每日特别委托 + 毎日の特別依頼 + + + + 悬赏通缉 + 指名手配 + + + + 竞技场 + 戦術対抗戦 + + + + 收集每日体力 + 毎日のAPを集める + + + + 收集小组体力 + グループAPを集める + + + + 商店购买 + しょっぷで買い物 + + + + 日程 + スケジュール + + + + 主线清除体力 + 本編ステージでAPをクリア + + + + 自动MomoTalk + 自動MomoTalk + + + + 咖啡厅 + カフェ + + + + 查收邮箱 + 自動メール確認 + + + + 自动制造 + 自動製造 + + + + 收集奖励 + 報酬を集める + + + + 普通关清体力 + 普通ステージでAPをクリア + + + + 困难关清体力 + ハードステージでAPをクリア + + + + 总力战 + 総力戦 + + + + 学院交流会 + 学園交流会 + + + + 凌晨四点重启 + 朝4時に再開 + + + + 活动扫荡 + イベントスイープ + + + + 暂无任务 + タスクなし + + + + 日常小游戏 + 毎日のゲーム + + + + 咖啡厅邀请 + カフェ招待 + + + + 新的配置 + 新しい設定 + + + + 功能开关 + 機能スイッチ + + + + 竞技场商店购买 + 戦術対抗戦ショップ購入 + + + + 扫荡及购买券设置 + スイープ・クーポン購入設定 + + + + 重要,此处为功能开关,控制各功能是否开启,启动前请检查是否开启。 + 重要、ここに各機能がオンになっているかどうかを制御する機能スイッ<bt/>チがありますので、開始する前に有効になっているかどうかを確認してください。 + + + + 帮助你收集咖啡厅体力和信用点 + カフェのAPとクレジットを集める + + + + 自动每日日程 + 自動毎日スケジュール + + + + 商店里买东西 + ショッピング + + + + 竞技场商店里买东西 + 戦術対抗戦ショップで物を買う + + + + 主线关卡自动清除体力与每日困难 + 本編ステージでAPをクリアと毎日ハードステージクリア + + + + 帮助你自动打竞技场 + アリーナをクリア + + + + 帮助你自动制造 + 自動製造 + + + + 总力战期间自动打总力战 + 総力戦中に自動的に総力戦を戦う + + + + 各种扫荡及购买券次数设置 + 各種スイープ・クーポン購入時間設定 + + + + 初级经验书 + 初級レポート + + + + 中级经验书 + 中級レポート + + + + 高级经验书 + 高級レポート + + + + 特级经验书 + 特級レポート + + + + 初级经验珠 + 初級強化珠 + + + + 中级经验珠 + 中級強化珠 + + + + 高级经验珠 + 高級強化珠 + + + + 特级经验珠 + 特級強化珠 + + + + 随机初级神秘古物 + ランダム初級神秘古物 + + + + 随机中级神秘古物 + ランダム中級神秘古物 + + + + 静子神明文字x5 + 静子 神名文字 x5 + + + + 真白神明文字x5 + 真白神名文字×5 + + + + 纱绫神明文字x5 + 紗綾 神名文字 x5 + + + + 风香神明文字x5 + 風香神名文字 x5 + + + + 歌原神明文字x5 + 歌原 神名文字 x5 + + + + 初级经验书x5 + 初级レポート x5 + + + + 中级经验书x10 + 中級レポート x10 + + + + 高级经验书x3 + 高級レポート x3 + + + + 特级经验书x1 + 特級レポート x1 + + + + 信用点x5k + クレジット x5k + + + + 信用点x75k + クレジットx75k + + + + 信用点x125k + クレジット x125k + + + + 官服 + 中国代理サーバー + + + + B服 + ビリビリサーバー + + + + 国际服 + 国際サーバー + + + + 日服 + 日本サーバー + + + + 拖动礼物 + ギフトドラッグ + + + + MuMu模拟器 + MuMuエミュレータ + + + + 蓝叠模拟器 + Blue Stack「中国」シミュレータ + + + + 蓝叠国际版 + Blue Stack「国際」シミュレータ + + + + DetailSettingMessageBox + + + 配置详情 + 構成の詳細 + + + + 优先级 + 優先権 + + + + 执行间隔 + 実行間隔 + + + + 每日重置 + 毎日のリセット + + + + 禁用时间段 + 無効期間 + + + + 前置任务 + 前提のタスク + + + + 后置任务 + ポストタスク + + + + 确定 + 決定 + + + + 取消 + キャンセル + + + + EmulatorConfig + + + 在运行Baas时打开模拟器(启动模拟器的功能开关,关闭后不会启动模拟器) + <b>Baas の実行中にエミュレータを起動するのか</b> (エミュレータの機<br/>能スイッチを起動し、オフにしてもエミュレータは起動しません) + + + + 是否模拟器多开(打开后无视已经启动的模拟器进程,将再启动一个模拟器)) + <b>エミュレータがマルチオープンかとうか</b>(すでに起動しているエミュレータプロセ<br/>スを無視して、エミュレータを開いた後、別のエミュレータが起動します)) + + + + 等待模拟器启动时间(模拟器从开始启动到桌面加载完成的时间(秒),一般默认) + <b>エミュレータの起動を待てる時間</b>(エミュレータの起動からデスクトッ<br/>プの読み込みが完了するまでの時間(秒単位、通常はデフォルト)です) + + + + 是否启用内建的自动扫描模拟器功能(开启后将自动识别系统内已安装的模拟器) + <b>内蔵の自動スキャンシミュレータ機能を有効にするかどうか</b>(有効にすると、<br/>インストールされているシミュレータがシステム内で自動的に認識されます) + + + + EventMapConfig + + + 推故事 + ストーリーをクリアする + + + + 推任务 + タスクをクリアする + + + + 推挑战 + 挑戦をクリアする + + + + ExploreConfig + + + 是否手动boss战(进入关卡后暂停等待手操) + 手動でボスと戦うかどうか(レベルに入ったら一時停止し、手動演習を待ちます) + + + + 是否不强制打到sss(启用后跳过已通过但未sss的关卡) + SSS を強制的にヒットさせないかどうか (有効にした後、SSS は通過したが SSS ではないレベルをスキップ) + + + + 开启后强制打每一个指定的关卡(不管是否sss) + 有効にすると、指定されたすべてのレベルを強制的にプレイします(SSSに関係なく) + + + + 爆发一队 + 第一爆発チーム + + + + 爆发二队 + 第二爆発チーム + + + + 贯穿一队 + 第一貫串チーム + + + + 贯穿二队 + 第二貫串チーム + + + + 神秘一队 + 第一神秘チーム + + + + 神秘二队 + 第二神秘チーム + + + + 振动一队 + 第一振动チーム + + + + 振动二队 + 第二振动チーム + + + + HardTaskConfig + + + 打到SSS + SSSを完成するのか + + + + 拿礼物 + ギフトを貰うのか + + + + 完成成就任务 + 達成ミッションをクリアするのか + + + + HistoryWindow + + + 内容 + コンテンツ + + + + 贡献者 + 貢献者 + + + + 提交时间 + 提出時間 + + + + 提交信息 + 提出メッセージ + + + + 更新日志 + 変更履歴 + + + + HomeFragment + + + 蔚蓝档案自动脚本 + ブルアカ 自動スクリプト + + + + 无任务 + タスクなし + + + + 启动 + 起動 + + + + 档案,启动 + ブルアカ、起動 + + + + 开始你的档案之旅 + アーカイブの旅を始めましょう + + + + 正在运行: + 実行中: + + + + Layout + + + 输入你需要对手比你低几级,高几级则填负数: + 対戦相手が自分より下にいるために必要なレベル数を入力し、数レベル上の場合は負の数を入力します: + + + + 输入你最多需要刷新几次: + 更新する必要がある最大回数を入力します: + + + + 确定 + 確認 + + + + 设置成功 + セットアップ成功 + + + + 刷新次数 + 更新の回数 + + + + 是否领取奖励: + 報酬を受け取るには: + + + + 是否使用邀请券: + 招待券を使用するのか: + + + + 优先邀请券好感等级低的学生: + 好意評価の低い学生に優先招待するのか: + + + + 是否允许学生更换服饰: + 生徒が服装を変えることができるのか: + + + + 是否有二号咖啡厅: + 二号カフェはありますか: + + + + 是否允许重复邀请: + 重複する招待を許可するのか: + + + + 列表选择你要添加邀请的学生,修改后请点击确定: + 招待状に追加する生徒を選択し、編集後に [確認] をクリックしよう: + + + + 添加学生 + 追加する生徒 + + + + 选择摸头方式: + 頭に触れる方法を選択します: + + + + 选择第二咖啡厅邀请的学生 + 2号カフェで招待する生徒を選択します + + + + 目前制造物品优先级,排在前面的会优先选择 + 現在、製造品目の優先順位は、リストの最初にある人に優先されます + + + + 是否使用加速券 + アクセラレータクーポンを使用するのか + + + + 选择模拟器地址 + シミュレータのアドレスを選択します + + + + 选择 + 選ぶ + + + + 多开号 + マルチアカウント + + + + 推图选项 + クリアオプション + + + + 请在下面填写要推的图,填写方式见-普通图自动推图说明- + 以下に押すステージを記入していただき、その記入方法は普通のステージと同じで説明を見てください + + + + 开始推图 + クリアを開始する + + + + 普通关推图 + 通常のステージのクリア + + + + 全部(不)启用 + すべて有効(無効) + + + + 刷新执行时间 + 更新実行時間 + + + + 排序方式: + 並び替え: + + + + 默认排序 + デフォルトの並べ替え + + + + 按下次执行时间排序 + 最終実行時刻で並べ替え + + + + 事件 + アクティビティ + + + + 下次刷新时间 + 次回の更新時刻 + + + + 启用 + エネーブル + + + + 更多配置 + その他の構成 + + + + 详细配置 + 詳細な設定 + + + + <b>困难图队伍属性和普通图相同(见普通图推图设置),请按照帮助中说明选择推困难图关卡并按对应图设置队伍</b> + <b>難易度ステージのチーム属性は普通のステージと同じです(普通のステージの設定を参照)ので、<br/>ヘルプの指示に従ってレベルを選択し、対応するステージに従ってチームを設定してください</b> + + + + 困难关推图 + ハードステージをクリア + + + + 普通关卡与次数(如"1-1-1,1-2-3"表示关卡1-1打一次,然后关卡1-2打三次): + 普通のステージ名時間(例:「1-1-1、1-2-3」は、レベルが1-1で1回プレイされ、その後、レベルが1-2で3回プレイされることを意味します): + + + + 困难关卡设置同上,注意:次数最多为3),逗号均为英文逗号,日服、国际服可填max: + ハードステージの設定は上記と同じですが、(注:最大回数は3回です)、カンマは英語のカンマで、日本サーバーと海外サーバーには「max」で入力できます: + + + + 根据学生添加关卡 + 学生に基づいてレベルを追加する + + + + 爱丽丝宝贝 + アリス・ベイビー + + + + 设置失败 + セットアップ失敗 + + + + 优先做好感等级多的日程 + 好感が多くのスケジュールが優先されます + + + + 日程次数 + スケジュールの回数 + + + + 区域名称 + 地域の名前 + + + + 初级 + ジュニア + + + + 普通 + 普通 + + + + 高级 + 高級 + + + + 特级 + 特級 + + + + 请填写您的截图间隔: + スクリーンショットの間隔を入力してください: + + + + 截图间隔 + スクリーンショットの間隔 + + + + ADB地址(点击选择) + ADBアドレス(クリックして選択) + + + + 自动查询模拟器失败!请尝试手动输入端口 + エミュレーターは見つからない。 ポートを手動で入力してください + + + + adb地址获取失败 + adbアドレスを取得できませんでした + + + + 信用点 + クレジット + + + + 青辉石 + 青煇石 + + + + 最高难度 + 最高難易度 + + + + 选择模拟器类型 + シミュレーターの種類を選択する + + + + MainThread + + + 停止 + 止める + + + + 启动 + 起動 + + + + 困难图推图已完成 + ハードステージがクリアしました + + + + 无任务 + タスクなし + + + + 普通关推图 + 普通ステージをクリアする + + + + 普通图推图已完成 + 普通ステージがクリアしました + + + + 反和谐成功,请重启BA下载资源 + アンチハーモニーが成功しました。BAを再起動してリソースをダウンロードしてください + + + + 自动主线剧情 + 本編プロットをクリアする + + + + 主线剧情已完成 + 本編プロットがクリアしました + + + + 自动小组剧情 + グループプロットをクリアする + + + + 小组剧情已完成 + グループストーリーがクリアしました + + + + 自动支线剧情 + サブプロットをクリアする + + + + 支线剧情已完成 + サブストーリーがクリアしました + + + + 自动活动剧情 + イベントプロットをクリアする + + + + 活动剧情已完成 + イベントプロットがクリアしました + + + + 自动活动任务 + イベントタスクをクリアする + + + + 活动任务已完成 + イベントタスクがクリアしました + + + + 自动活动挑战 + イベント挑戦をクリアする + + + + 活动挑战推图已完成 + イベントチャレンジがクリアしました + + + + OtherConfig + + + 一键反和谐 + アンチハーモニーをする + + + + 修复Mumu无法登录日服 + Mumuが日本サーバーにログインできない問題を修正する + + + + 显示首页头图(下次启动时生效) + ホームヘッダー画像を表示するのか(次回の起動時に有効) + + + + ProceedPlot + + + 主线剧情需要推的章节数 + クリアしたい本編プロット章の数 + + + + 开始推主线剧情 + 本編プロットをクリアする + + + + 开始推小组剧情 + グループプロットをクリアする + + + + 开始推支线剧情 + サブプロットをクリアする + + + + ProcessFragment + + + 调度状态 + スケジュールステータス + + + + 执行中 + 実行中 + + + + 暂无正在执行的任务 + 進行中のタスクはない + + + + 任务队列 + タスク隊列 + + + + 暂无队列中的任务 + 隊列にタスクがない + + + + PushConfig + + + 在运行出错时推送 + 実行中のエラー時に配信 + + + + 在全部任务完成时推送 + すべてのタスクが完了したときに配信します + + + + json 推送 + JSON配信 + + + + ServerChan推送 + 「ServerChan」配信 + + + + SaveSettingMessageBox + + + 新建配置 + 新しい設定を作成する + + + + 输入新建的配置名: + 新しい設定の名前を入力します: + + + + 确定 + 確認 + + + + 取消 + キャンセル + + + + ServerConfig + + + 请选择您的服务器,请慎重切换服务器,切换服务器后请重新启动脚本 + サーバーを選択し、サーバーを慎重に切り替え、サーバーを切り替えた後にスクリプトを再起動してください + + + + 官服 + 中国代理サーバー + + + + B服 + ビリビリサーバー + + + + 国际服 + 国際サーバー + + + + 日服 + 日本サーバー + + + + 请填写您的adb端口号 + ADBポート番号を入力してください + + + + 检测adb地址(检测目前开启的模拟器adb地址) + ADB アドレスの検出 (現在有効なエミュレータの ADB アドレスを確認してください) + + + + SettingsFragment + + + 普通设置 + 通常設定 + + + + 基本 + 基本 + + + + 语言 + 言語 + + + + 设置界面的首选语言 + 画面の優先言語を設定する + + + + 应用相关设置 + アプリ関連設定 + + + + 选择你的服务器平台,设置你的端口(不知道端口请设置为0) + サーバーを選択し、ポートを設定します(ポートがわからない場合は、0に設定してください) + + + + 脚本相关设置 + スクリプト関連設定 + + + + 根据你的电脑配置,调整相应的参数。 + PCの構成に応じてパラメータを調整します。 + + + + 模拟器启动设置 + エミュレータの起動設定 + + + + 设置启动模拟器的路径 + エミュレーターを起動するパスを設定する + + + + 相关设置 + 関連設定 + + + + 普通图推图设置 + 普通ステージのクリアの設定 + + + + 根据你的推图需求,调整相应的参数。 + プッシュのニーズに応じて、対応するパラメータを調整します。 + + + + 困难图推图设置 + ハードステージのクリアの設定 + + + + 根据你所需困难图刷关,设置参数。 + 必要な難易度に応じてパラメータを設定します。 + + + + 推剧情 + プロットをクリアする + + + + 主线剧情,小组剧情,支线剧情 + 本編プロット、グループプロット、サブプロット + + + + 活动图设置 + イベントクリアの設定 + + + + 推故事,推任务,推挑战 + ストーリークリア、タスククリア、挑戦クリア + + + + 其他设置 + その他の設定 + + + + 其他的一些小功能与设置 + その他の機能と設定 + + + + 推送设置 + 配信設定 + + + + 推送信息 + 配信メッセージ + + + + SweepCountConfig + + + <b>各区域扫荡次数以英文逗号分隔</b> + <b>各領域のスイープの数はコンマで区切られます</b> + + + + <b>各区域扫荡次数以英文逗号分隔,扫荡次数可以为max</b> + <b>各領域の掃引数はカンマで区切られ、掃引数は最大</b>にすることができます + + + + 悬赏委托扫荡 + 指名手配スイープ + + + + 学园交流会扫荡 + 学校交流会のスイープ + + + + 活动关卡扫荡关卡 + イベントステージスイープの名 + + + + 活动关卡扫荡次数 + イベントステージスイープの数 + + + + 特殊委托扫荡 + 特殊依頼スイープ + + + + 国服购买邀请券可在<b>商店购买</b>中实现 + 中国代理サーバー購入の招待券は<b>、店舗購入</b>で実現できます + + + + <b>用券数目设置,下拉框选择</b> + <b>使用するクーポンの数を設定し、ドロップダウンリストから選択します</b> + + + + 悬赏委托扫荡券购买次数 + 指名手配スイープチケットの購入回数 + + + + 日程券购买次数 + イベントのチケットを購入する回数 + + + + 学园交流会扫荡券购买次数 + 学校交流会のスイープチケット購入回数 + + + + SwitchFragment + + + 配置设置 + 構成の設定 + + + + 功能开关 + 機能スイッチ + + + + TemplateLayout + + + 执行 + 実行する + + + + 确定 + 確認 + + + + 设置成功 + セットアップ成功 + + + + Window + + + 主页 + ホーム + + + + 调度 + スケジュール + + + + 配置 + 構成 + + + + 设置 + 設定 + + + + 设置失败 + セットアップ失敗 + + + + 是否要删除配置: + 設定を削除しますか: + + + + 你需要在确认后重启BAAS以完成更改。 + 変更を完了するには、確認後に BAAS を再起動する必要があります。 + + + + bt + + + ConfigTranslation + 構成の翻訳 + + + + ConfigTranslation + 拖动礼物 + ギフトをドラグする + + + + ConfigTranslation + 普通 + 普通 + + + + TemplateLayout + 実行 + + + + MainThread + メイン・トレッド + + + + MainThread + 停止 + メイン・トレッド + + + + helpModal + + + 帮助 + ヘルプ + + + diff --git a/gui/util/config_set.py b/gui/util/config_set.py index b3bcb3b2b..c3b597788 100644 --- a/gui/util/config_set.py +++ b/gui/util/config_set.py @@ -1,5 +1,6 @@ import json from core.notification import notify +from gui.util.translator import baasTranslator as bt class ConfigSet: @@ -24,13 +25,15 @@ def _init_config(self): self.server_mode = 'Global' elif self.config['server'] == '日服': self.server_mode = 'JP' - + def get(self, key): self._init_config() - return self.config.get(key) + value = self.config.get(key) + return bt.tr('ConfigTranslation', value) def set(self, key, value): self._init_config() + value = bt.undo(value) self.config[key] = value with open(f'./config/{self.config_dir}/config.json', 'w', encoding='utf-8') as f: json.dump(self.config, f, indent=4, ensure_ascii=False) diff --git a/gui/util/config_translation.py b/gui/util/config_translation.py new file mode 100644 index 000000000..a7a0eaeb3 --- /dev/null +++ b/gui/util/config_translation.py @@ -0,0 +1,113 @@ +from PyQt5.QtCore import QObject + + +class ConfigTranslation(QObject): + """ Contains translations of config strings""" + + def __init__(self, parent=None): + super().__init__(parent) + self.entries = { + # display + self.tr("每日特别委托"): "每日特别委托", + self.tr("悬赏通缉"): "悬赏通缉", + self.tr("竞技场"): "竞技场", + self.tr("收集每日体力"): "收集每日体力", + self.tr("收集小组体力"): "收集小组体力", + self.tr("商店购买"): "商店购买", + self.tr("日程"): "日程", + self.tr("主线清除体力"): "主线清除体力", + self.tr("自动MomoTalk"): "自动MomoTalk", + self.tr("咖啡厅"): "咖啡厅", + self.tr("查收邮箱"): "查收邮箱", + self.tr("自动制造"): "自动制造", + self.tr("收集奖励"): "收集奖励", + + # event + self.tr("咖啡厅"): "咖啡厅", + self.tr("日程"): "日程", + self.tr("收集每日体力"): "收集每日体力", + self.tr("收集小组体力"): "收集小组体力", + self.tr("查收邮箱"): "查收邮箱", + self.tr("商店购买"): "商店购买", + self.tr("普通关清体力"): "普通关清体力", + self.tr("困难关清体力"): "困难关清体力", + self.tr("每日特别委托"): "每日特别委托", + self.tr("悬赏通缉"): "悬赏通缉", + self.tr("竞技场"): "竞技场", + self.tr("自动制造"): "自动制造", + self.tr("总力战"): "总力战", + self.tr("自动MomoTalk"): "自动MomoTalk", + self.tr("收集奖励"): "收集奖励", + self.tr("学院交流会"): "学院交流会", + self.tr("凌晨四点重启"): "凌晨四点重启", + self.tr("活动扫荡"): "活动扫荡", + self.tr("暂无任务"): "暂无任务", + self.tr("日常小游戏"): "日常小游戏", + self.tr("咖啡厅邀请"): "咖啡厅邀请", + + # switch + self.tr("新的配置"): "新的配置", + self.tr("功能开关"): "功能开关", + self.tr("咖啡厅"): "咖啡厅", + self.tr("日程"): "日程", + self.tr("商店购买"): "商店购买", + self.tr("竞技场商店购买"): "竞技场商店购买", + self.tr("主线清除体力"): "主线清除体力", + self.tr("竞技场"): "竞技场", + self.tr("自动制造"): "自动制造", + self.tr("总力战"): "总力战", + self.tr("扫荡及购买券设置"): "扫荡及购买券设置", + + # static + self.tr("重要,此处为功能开关,控制各功能是否开启,启动前请检查是否开启。"): "重要,此处为功能开关,控制各功能是否开启,启动前请检查是否开启。", + self.tr("帮助你收集咖啡厅体力和信用点"): "帮助你收集咖啡厅体力和信用点", + self.tr("自动每日日程"): "自动每日日程", + self.tr("商店里买东西"): "商店里买东西", + self.tr("竞技场商店里买东西"): "竞技场商店里买东西", + self.tr("主线关卡自动清除体力与每日困难"): "主线关卡自动清除体力与每日困难", + self.tr("帮助你自动打竞技场"): "帮助你自动打竞技场", + self.tr("帮助你自动制造"): "帮助你自动制造", + self.tr("总力战期间自动打总力战"): "总力战期间自动打总力战", + self.tr("各种扫荡及购买券次数设置"): "各种扫荡及购买券次数设置", + + # normal shop + self.tr('初级经验书'): '初级经验书', + self.tr('中级经验书'): '中级经验书', + self.tr('高级经验书'): '高级经验书', + self.tr('特级经验书'): '特级经验书', + self.tr('初级经验珠'): '初级经验珠', + self.tr('中级经验珠'): '中级经验珠', + self.tr('高级经验珠'): '高级经验珠', + self.tr('特级经验珠'): '特级经验珠', + self.tr('随机初级神秘古物'): '随机初级神秘古物', + self.tr('随机中级神秘古物'): '随机中级神秘古物', + + # tactical challenge shop + self.tr('静子神明文字x5'): '静子神明文字x5', + self.tr('真白神明文字x5'): '真白神明文字x5', + self.tr('纱绫神明文字x5'): '纱绫神明文字x5', + self.tr('风香神明文字x5'): '风香神明文字x5', + self.tr('歌原神明文字x5'): '歌原神明文字x5', + self.tr('初级经验书x5'): '初级经验书x5', + self.tr('中级经验书x10'): '中级经验书x10', + self.tr('高级经验书x3'): '高级经验书x3', + self.tr('特级经验书x1'): '特级经验书x1', + self.tr('信用点x5k'): '信用点x5k', + self.tr('信用点x75k'): '信用点x75k', + self.tr('信用点x125k'): '信用点x125k', + + # server combobox + self.tr('官服'): '官服', + self.tr('B服'): 'B服', + self.tr('国际服'): '国际服', + self.tr('日服'): '日服', + + # patstyles combobox + self.tr('拖动礼物'): '拖动礼物', + + # emulator combobox + self.tr('MuMu模拟器'): 'MuMu模拟器', + self.tr('蓝叠模拟器'): '蓝叠模拟器', + self.tr('蓝叠国际版'): '蓝叠国际版' + } + diff --git a/gui/util/config_translation_generator.py b/gui/util/config_translation_generator.py new file mode 100644 index 000000000..af50d21e7 --- /dev/null +++ b/gui/util/config_translation_generator.py @@ -0,0 +1,78 @@ +"""" +This is a program to generate ConfigTranslation from default_config. +DO NOT REPLACE ConfigTranslation with the file generated because +Combobox options will be lost and the code will be less readable. +Use it instead to get a portion of default_config and paste it in ConfigTranslation. + +Instructions: +go to root directory of project and enter in terminal: +python -m gui.util.config_translation_generator +""" + + +import re +import json + +from core.default_config import (DISPLAY_DEFAULT_CONFIG, + DEFAULT_CONFIG, + EVENT_DEFAULT_CONFIG, + STATIC_DEFAULT_CONFIG, + SWITCH_DEFAULT_CONFIG, + ) + + +def deserialize(l): + return [json.loads(dict) for dict in l] + +def contains_chinese(s): + return re.search("[\u4e00-\u9FFF]", s) + +def find_chinese_strings(data, chinese_strings=[]): + if isinstance(data, dict): + for key, value in data.items(): + find_chinese_strings(value, chinese_strings) + elif isinstance(data, list): + for item in data: + find_chinese_strings(item, chinese_strings) + elif isinstance(data, str) and contains_chinese(data): + chinese_strings.append(data) + return chinese_strings + +def remove_duplicates(chinese_strings): + """remove duplicates while preserving order""" + seen = set() + seen_add = seen.add + return [x for x in chinese_strings if not (x in seen or seen_add(x))] + +def create_translation_file(chinese_strings, filename): + with open(filename, "w") as f: + f.write("from PyQt5.QtCore import QObject\n\n") + + + f.write("class ConfigTranslation(QObject):\n") + f.write(" def __init__(self, parent=None):\n") + f.write(" super().__init__(parent=parent)\n") + f.write(" self.entries = {\n") + for s in chinese_strings: + f.write(f" self.tr('{s}'): '{s}',\n") + f.write(" }\n\n") + + +if __name__ == "__main__": + # data = deserialize([ + # DISPLAY_DEFAULT_CONFIG, + # DEFAULT_CONFIG, + # EVENT_DEFAULT_CONFIG, + # STATIC_DEFAULT_CONFIG, + # SWITCH_DEFAULT_CONFIG, + # ]) + + # chinese_strings = find_chinese_strings(data) + # create_translation_file(chinese_strings, 'test.py') + + data = json.loads(STATIC_DEFAULT_CONFIG) + data = data['tactical_challenge_shop_price_list']['Global'] + chinese_strings = find_chinese_strings(data) + chinese_strings = remove_duplicates(chinese_strings) + create_translation_file(chinese_strings, 'test.py') + diff --git a/gui/util/language.py b/gui/util/language.py new file mode 100644 index 000000000..102d639af --- /dev/null +++ b/gui/util/language.py @@ -0,0 +1,17 @@ +from enum import Enum +from PyQt5.QtCore import QLocale + + +class Language(Enum): + """ Language enumeration """ + + CHINESE_SIMPLIFIED = QLocale(QLocale.Chinese, QLocale.China) + ENGLISH = QLocale(QLocale.English, QLocale.UnitedStates) + JAPANESE = QLocale(QLocale.Japanese, QLocale.Japan) + + def combobox(): + return ['简体中文', 'English', '日本語'] + +if __name__ == "__main__": + for language in Language: + print(language.value.name()) diff --git a/gui/util/translator.py b/gui/util/translator.py new file mode 100644 index 000000000..9fb542d10 --- /dev/null +++ b/gui/util/translator.py @@ -0,0 +1,117 @@ +from typing import Union + +from PyQt5.QtCore import QLocale, QTranslator +from qfluentwidgets import ConfigSerializer, OptionsConfigItem, OptionsValidator, QConfig, qconfig + +from gui.util.config_translation import ConfigTranslation +from gui.util.language import Language + + +class LanguageSerializer(ConfigSerializer): + """ Language serializer """ + + def serialize(self, language): + return language.value.name() + + def deserialize(self, value: str): + return Language(QLocale(value)) + + +class Config(QConfig): + """ Language config """ + language = OptionsConfigItem( + "Translator", "Language", Language.ENGLISH, OptionsValidator(Language), LanguageSerializer(), restart=True) + + def __init__(self): + super().__init__() + + +class Translator(QTranslator): + def __init__(self, parent=None): + super().__init__(parent) + self.cfg = Config() + qconfig.load('config/language.json', self.cfg) + + self.locale = self.cfg.get(self.cfg.language).value + self.stringLang = self.locale.name() + self.__config_translation = None + # separate dictionary for students to not caouse conflicts with existing translations + self.__students = dict() + + def loadCfgTranslation(self): + self.__config_translation = ConfigTranslation() + + def isString(self, value): + return isinstance(value, str) + + def isBytes(self, value): + return isinstance(value, bytes) + + def toString(self, translation: Union[str, bytes]) -> str: + if self.isBytes(translation): + translation = self.decode(translation) + return translation + + def encode(self, *args): + return [arg.encode('utf-8') if self.isString(arg) else arg for arg in args] + + def decode(self, *args): + return [arg.decode('utf-8') if self.isBytes(arg) else arg for arg in args] + + def __get(self, text): + return self.__config_translation.entries.get(text) + + def isChinese(self): + return self.stringLang == 'zh_CN' + + def tr(self, + context: str, + sourceText: str, + disambiguation: Union[str, None] = None, + n: int = -1) -> str: + """ + Translate sourceText by looking in the qm file. + Use this to access specific context tags. + + Parameters + ---------- + context: str + context tag in .ts file e.g ConfigTranslation + + sourceText: str + text to translate + """ + if not self.isChinese() and self.isString(sourceText) and self.isString(context): + bytesArgs = self.encode(context, sourceText, disambiguation) + translation = super().translate(*bytesArgs, n) + if translation: + return self.toString(translation) + return sourceText + + def undo(self, text: str) -> str: + """ + Undo translations by looking in ConfigTranslation. + + Parameters + ---------- + text: str + text to undo translation + """ + if not self.isChinese() and self.isString(text) and self.__get(text): + text = self.__get(text) + return text + + def addStudent(self, chineseName, translatedName): + """ + Add student's translated name to be displayed in + hard_task_combobox in mainlinePriority + """ + self.__students[chineseName] = translatedName + + def getStudent(self, chineseName): + if self.__students.get(chineseName): + return self.__students[chineseName] + return chineseName + + +baasTranslator = Translator() diff --git a/i18n.pro b/i18n.pro new file mode 100644 index 000000000..95898d2a3 --- /dev/null +++ b/i18n.pro @@ -0,0 +1,35 @@ +SOURCES += \ + gui/components/expand/arenaPriority.py \ + gui/components/expand/arenaShopPriority.py \ + gui/components/expand/cafeInvite.py \ + gui/components/expand/createPriority.py \ + gui/components/expand/emulatorConfig.py \ + gui/components/expand/eventMapConfig.py \ + gui/components/expand/expandTemplate.py \ + gui/components/expand/exploreConfig.py \ + gui/components/expand/featureSwitch.py \ + gui/components/expand/hardTaskConfig.py \ + gui/components/expand/mainlinePriority.py \ + gui/components/expand/otherConfig.py \ + gui/components/expand/proceedPlot.py \ + gui/components/expand/pushConfig.py \ + gui/components/expand/schedulePriority.py \ + gui/components/expand/scriptConfig.py \ + gui/components/expand/serverConfig.py \ + gui/components/expand/shopPriority.py \ + gui/components/expand/sweepCountConfig.py \ + gui/components/expand/totalForceFightPriority.py \ + gui/components/dialog_panel.py \ + gui/components/template_card.py \ + gui/fragments/history.py \ + gui/fragments/home.py \ + gui/fragments/process.py \ + gui/fragments/readme.py \ + gui/fragments/settings.py \ + gui/fragments/switch.py \ + gui/util/config_translation.py \ + window.py \ + +TRANSLATIONS += gui/i18n/en_US.ts \ + gui/i18n/ja_JP.ts \ + diff --git a/module/main_story.py b/module/main_story.py index 7a8a2eef4..e6b5d787f 100644 --- a/module/main_story.py +++ b/module/main_story.py @@ -2,8 +2,7 @@ import os import time from core import color, picture, image -from module.explore_normal_task import start_action, to_formation_edit_i, start_mission, \ - to_normal_task_wait_to_begin_page, check_skip_fight_and_auto_over +from module.explore_normal_task import common_gird_method def implement(self): @@ -167,14 +166,7 @@ def clear_current_plot(self, skip_first_screenshot=False): return res if res == "normal_task_task-wait-to-begin-feature": stage_data = check_state_and_get_stage_data(self) - for i in range(0, len(stage_data['start'])): - to_formation_edit_i(self, i + 1, stage_data['start'][i]) - auto_choose_formation(self, True, {"formation_edit" + str(i + 1): (1183, 183)}, - "formation_edit" + str(i + 1)) - to_normal_task_wait_to_begin_page(self, True) - start_mission(self) - check_skip_fight_and_auto_over(self) - start_action(self, stage_data['actions']) + common_gird_method(self, stage_data) rgb_ends = "fighting_feature" img_possibles = {"plot_formation": (1157, 651)} if res == "plot_self-formation": diff --git a/requirements-i18n.txt b/requirements-i18n.txt new file mode 100644 index 000000000..f7392fefa --- /dev/null +++ b/requirements-i18n.txt @@ -0,0 +1,3 @@ +bs4 +lxml +translators \ No newline at end of file diff --git a/src/descriptions/en_US/Auto clear mainline plot settings.html b/src/descriptions/en_US/Auto clear mainline plot settings.html new file mode 100644 index 000000000..44dbb6dfd --- /dev/null +++ b/src/descriptions/en_US/Auto clear mainline plot settings.html @@ -0,0 +1,26 @@ + + + + +

Auto clear mainline plot settings

+

Autoplay can help walk the grid. But... some battles in the Final Episode cannot be fought automatically.

+

Numbers and the corresponding Episode

+

1 -> Episode I

+

2 -> Episode II

+

3 -> Episode III

+

4 -> Episode IV

+

5 -> Final Episode

+

6 -> Episode V

+

Use "," to separate the numbers to indicate each episode needed to be cleared.

+

Example:

+

1,2,3

+

Means clear Episode I, Episode III, Final Episode sequentially.

+

Default configuration(fill nothing in the box and click 'run' button):

+

CN : 1,2,3,4

+

Global : 1,2,3,4,5,4

+

JP: 1,2,3,4,5,4,6

+
+
 
+
+ + diff --git a/src/descriptions/en_US/Commonly used emulator adb address.html b/src/descriptions/en_US/Commonly used emulator adb address.html new file mode 100644 index 000000000..82dc376c3 --- /dev/null +++ b/src/descriptions/en_US/Commonly used emulator adb address.html @@ -0,0 +1,9 @@ + + + + + +
For Stimulator multi-instance, please check yourself.

Single Emulator Port

1. MuMu: 7555
2. Blue stacks/LDPlayer: 5555 (If you use Blue stack emulator check if adb port debug function is open in the settings)
3. NoxPlayer: 62001 / 59865
4. Mumu12:16384
5. memuplay: 21503
+


+ + diff --git a/src/descriptions/en_US/Description of normal graphs.html b/src/descriptions/en_US/Description of normal graphs.html new file mode 100644 index 000000000..4704f220d --- /dev/null +++ b/src/descriptions/en_US/Description of normal graphs.html @@ -0,0 +1,173 @@ + + + + +

+ Description of normal graphs: +

+

+ 1. Description of use: +

+

+ (1): Must + + + Unlock + + + Automatically end rounds and + + + Autofight. + + + (automated detection and opening) +

+

+ (2): Supported level main line ordinary + + + 4 - 25 + + +

+

+ (3): Teams move click coordinates and routes when BAAS slides are fixed and all moves are only one click, and because of the number of teams in the Blue Archive slides, the numbering coordinates and the order of movement vary according to the team. +

+

+ (4): As (3), when automatically extrapolating + + + You have to make sure the selection team numbers are smaller and bigger. + + I don't know. + + + +

+

+ + + (5): BAAS will choose the basis + + + < Normal Thumbnail Settings > + + + + + the selected group properties + + + + and + + + ♪ Team logic ♪ + + + Find the right configuration for the slide + +

+

+ The first of the corresponding properties in the following diagrams is [1] and the second is [2]. +

+

+ Team logic: +

+

+ 1 Prioritize the selection of the remaining team numbers on the basis of the relationship of restraint and gradually reduce the relationship of attribution to the remaining counterpart. +

+

+ 2 When selecting a team (4 - the team number) > = the number of remaining teams required. +

+

+ 3 Gradual reduction of the relationship of restraint among the [1] counterparts, if no assurance is provided for 1 or 2 +

+

+ 4 If some teams have been selected and 4 - the maximum number of these teams > = the number of remaining teams required, the remaining teams will be filled with an optional number. +

+

+ 5 None of the above conditions are met, and the selected team number is 1, 2, 3 +

+

+ + Example: + +

+

+ Selecting the order of the 23 [Explosion, Crossing] task force +

+

+ One team, one team. +

+

+ If an outbreak is numbered 3 and not selected in the above order, select 4 as the second +

+

+ Choose 12 as the final team if not elected +

+

+ + + Description of normal graph push-chart level: + + +

+

+ + 1. If + + + Could not close temporary folder: %s + + + , each number to be filled indicates the area to be pushed, and the program will judge whether each level in the area is to be hit according to whether the current level is sss + +

+

+ + Example: + +

+

+ + 15, 16, 14 + +

+

+ + This represents a roll-down of figure 15,16,14. + +

+

+ + 2. + + + If + + + Enable mandatory hits at each specified level + + + , enter a number to push the relevant card in the area once and enter a number-number to specify level + +

+

+ + Example: + +

+

+ + 15, 16-3 + +

+

+ + 15-1, 15-2, 15-3, 15-4, 15-5, 16-3 + +

+ + diff --git a/src/descriptions/en_US/Difficult Chart Configuration Description.html b/src/descriptions/en_US/Difficult Chart Configuration Description.html new file mode 100644 index 000000000..de6c80f23 --- /dev/null +++ b/src/descriptions/en_US/Difficult Chart Configuration Description.html @@ -0,0 +1,9 @@ + + + + +
+
The hardship map is used in the same way as the team logic and normal figure, and some of the difficult maps require three teams, all of which have the same attributes as the first for the region.

Fill in the following instructions:

The string that should be filled in the slide level should not exceed the characters or words "-", "sss", "present", "task", ",", and numbers
Split into several strings after commas
No keyword "sss", "present", "task"
Example: 15,12-2
Three switches (15-1, 15-2, 15-3, 12-2) according to the difficult map settings will be called to sss/take presents/take challenge tasks

2. A number and a string separated by "-"
Example: 15-sss-present
Will be called to sss with gifts (15-1, 15-2, 15-3)

3. Two numbers (specify the corresponding level)
Example: 15-3-sss-task
They'll call 15-3 to sss and complete the challenge.

4. Examples
Switches are all open, fill in: 7,8-sss, 9-3-task
It is indicated that the calls (7-1, 7-2, 7-3) to sss, the gifts and the challenging tasks, (8-1, 8-2, 8-3) to sss, 9-3
Note: Baas will automatically determine whether the level has reached sss, whether it has taken a gift or, if it has reached sss or has taken a gift, skips the level.
+
+ + diff --git a/src/descriptions/en_US/Guide for activity sweep fill in.html b/src/descriptions/en_US/Guide for activity sweep fill in.html new file mode 100644 index 000000000..69a51c3fb --- /dev/null +++ b/src/descriptions/en_US/Guide for activity sweep fill in.html @@ -0,0 +1,25 @@ + + + + +

Guide for activity sweep fill in:

+

Sweep One Quest:

+

Sweep Quest Number : 1 Integer in 1 - Maximum difficulty in current activity. 

+

Number of sweeps:

+

1. Integer Means sweep times

+

2. Decimal 0.5 indicates that the current AP*0.5 will be used to sweep the quest

+

3. Score 1/3 = using current AP*(1/3) to sweep the quest

+

Sweep Multiple Quests. :

+

Use ',' to join multiple quests, which means sweep them in turn

+

Example:

+

Sweep Quset:

+

9, 10, 11

+

Number of sweeps:

+

0.5, 3, 1/3

+

AP: 999

+

Means sweep in turn.

+

Quest 9  (999 * 0.5) / 20 = 25 times

+

Quest 10  3 times

+

Quest 11 (999 * 1/3) / 20 = 16 times

+ + diff --git a/src/descriptions/en_US/Internal settings in BlueArchive game (first-use must read).html b/src/descriptions/en_US/Internal settings in BlueArchive game (first-use must read).html new file mode 100644 index 000000000..c3e7877bb --- /dev/null +++ b/src/descriptions/en_US/Internal settings in BlueArchive game (first-use must read).html @@ -0,0 +1,37 @@ + + + + +

Blanche Files Game Internal Settings :

+

** Required** :

+

Option - > Graphics : Vertical Battle Screen Text Box : Off

+

Recollection Lobby : Don't choose Ako, Aru, Wakamo

+

Language(Global Server) : English

+

Recommended Selection (does not affect script running)

+ + + + + + + + + + + + + + + + + + + + + + + +
ResolutionHighest
FPS60
Accelerate rendering modeCompatibility
Post-processingON
Anti-aliasingON
+

 

+ + diff --git a/src/descriptions/en_US/Normal Sweeping Scanning Description.html b/src/descriptions/en_US/Normal Sweeping Scanning Description.html new file mode 100644 index 000000000..6314c8b75 --- /dev/null +++ b/src/descriptions/en_US/Normal Sweeping Scanning Description.html @@ -0,0 +1,68 @@ + + + + +

+ Each sweep configuration is like 'region ' - 'task number ' - 'sweep times ' +

+

+ Organisation + + Regional + + 'region' + + Level + + "task-number" + + Number of sweeps + + @sweeptimes +

+

+ Each configuration is separated by ', ' +

+

+ 1. + + + Available Sweep Levels + + + : +

+

+ All maps after Academy 1 and 5 +

+

+ 2. + + + Special description + + +

+

+ International, `sweep times' can be `max' +

+

+ The tutorial requires 'region' as a fixed string'tutorian' +

+

+ BAAS calculates whether the current level can be cleaned, depending on the current physical strength and the level of the level. +

+

+ Example: +

+

+ When the international uniform is physically adequate +

+

+ TUTORIAL-1-20, 15-3, 20-3-max +

+

+ It means cleaning the curriculum 1 20 times, then cleaning 15-3, 3 times, and then all the physical sweeps 20-3 times. +

+ + diff --git a/src/descriptions/en_US/Task force attributes required by region.html b/src/descriptions/en_US/Task force attributes required by region.html new file mode 100644 index 000000000..d04a49ad7 --- /dev/null +++ b/src/descriptions/en_US/Task force attributes required by region.html @@ -0,0 +1,8 @@ + + + + + +

25 [ Sonic        ,  Piercing   ]
24 [ Sonic        ,  Explosive ]
23 [ Explosive ,  Piercing   ]
22 [ Piercing   ,  Mystic      ]
21 [ Mystic      ,  Explosive ]
20 [ Explosive ,  Piercing   ]
19 [ Piercing   ,  Mystic      ]
18 [ Mystic      ,  Explosive ]
17 [ Explosive ,  Piercing   ]
16 [ Piercing   ,  Mystic      ]
15 [ Mystic      ,  Mystic      ]
14 [ Explosive ,  Mystic      ]
13 [ Piercing   ,  Piercing   ]
12 [ Mystic      ,  Explosive ]
11 [ Piercing   ,  Mystic      ]
10 [ Explosive ,  Mystic      ]
 9 [ Explosive  ,  Piercing   ]
 8 [ Piercing    ,  Piercing   ]
 7 [ Explosive  ,  Explosive ]
 6 [ Piercing    ,  Piercing   ]
 5 [ Explosive ]
 4 [ Piercing   ]
 3 [ Piercing   ]
 2 [ Explosive ]
 1 [ Explosive ]

+ + diff --git a/src/descriptions/en_US/reporting guidelines on issues (important).html b/src/descriptions/en_US/reporting guidelines on issues (important).html new file mode 100644 index 000000000..eda95dc6c --- /dev/null +++ b/src/descriptions/en_US/reporting guidelines on issues (important).html @@ -0,0 +1,92 @@ +

+ + Let's think about it before we report it: + +

+

+ + 1. This question has never arisen before and can I try to solve it myself (Baidu, curriculum). + +

+

+ + It can't be solved. + +

+

+ + 2. The question arises whether I am running every time. + +

+

+ + 3. How can I provide sufficient information for others to help me solve the problem? + +

+

+ + 4. The distribution of colour maps within the qq group may be more attractive to others to help solve problems. + +

+

+ + + Type of problem versus corresponding + + Reporting (yellow necessary) + + + +

+

+ + I'm stuck on page XXX! : + +

+

+ + (1). + + 1280 x 720 games when stuck + + + (Mumu on F9) + + +

+

+ (2). Baas Logshot +

+

+ (3). Try to switch pages to see if they only get stuck on this page +

+

+ + I can't move it! : + +

+

+ (1) Attempts to repulse the observation of one or two times whether each time the card is in one position. +

+

+ + + (1). Recording the complete video from the "start-up slide" to the time of the stop, with attention to the simulator and the Bas log interface being recorded on the same screen. + + +

+

+ + I set up the XXX configuration but didn't fight! I didn't set up XXX but I did! : + +

+

+ (1) Read the configuration instructions carefully to see if they correctly understand how to fill them out. +

+

+ + + (2) Configure screenshots and program logs. + + +

diff --git "a/src/descriptions/ja_JP/Azur Archives Game Internals (\345\210\235\343\202\201\343\201\246\350\252\255\343\202\200\343\203\246\343\203\274\343\202\266\343\203\274\343\201\257\345\277\205\350\252\255).html" "b/src/descriptions/ja_JP/Azur Archives Game Internals (\345\210\235\343\202\201\343\201\246\350\252\255\343\202\200\343\203\246\343\203\274\343\202\266\343\203\274\343\201\257\345\277\205\350\252\255).html" new file mode 100644 index 000000000..a4252f900 --- /dev/null +++ "b/src/descriptions/ja_JP/Azur Archives Game Internals (\345\210\235\343\202\201\343\201\246\350\252\255\343\202\200\343\203\246\343\203\274\343\202\266\343\203\274\343\201\257\345\277\205\350\252\255).html" @@ -0,0 +1,92 @@ + + + + + +

+ アズールアーカイブ + + ゲーム内の設定 + + : +

+

+ + + **必須** + + + : +

+

+ + オプション - >画像 + + :戦闘画面の上下の黒いバー:オフ +

+

+ + 記憶の殿堂 + + :赤穂、愛瑠、若茂は選ばない +

+

+ + 国際言語 + + :英語 +

+

+ + 推奨 + + (スクリプトの実行には影響しません) +

+ + + + + + + + + + + + + + + + + + + + + + + +
+ 解決 + + 最高 +
+ フレーム + + 60 +
+ 高速レンダリングモード + + コンパチ +
+ 後処理 + + 親切 +
+ アンチエイリアシング + + 親切 +
+

+

+ + diff --git "a/src/descriptions/ja_JP/\343\202\250\343\202\271\343\202\253\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\343\201\256\343\202\254\343\202\244\343\203\211\343\203\251\343\202\244\343\203\263(\351\207\215\350\246\201).html" "b/src/descriptions/ja_JP/\343\202\250\343\202\271\343\202\253\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\343\201\256\343\202\254\343\202\244\343\203\211\343\203\251\343\202\244\343\203\263(\351\207\215\350\246\201).html" new file mode 100644 index 000000000..ee2b2dc07 --- /dev/null +++ "b/src/descriptions/ja_JP/\343\202\250\343\202\271\343\202\253\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\343\201\256\343\202\254\343\202\244\343\203\211\343\203\251\343\202\244\343\203\263(\351\207\215\350\246\201).html" @@ -0,0 +1,96 @@ + + +

+ + 問題を報告する前に、次の点を考慮してください。 + +

+

+ + 1.この問題は以前に発生しましたか、そして私はそれを自分で解決しようとすることができますか(Baidu、チュートリアル)。 + +

+

+ + 解決できない場合 + +

+

+ + 2.今走るたびにこの問題が発生しますか? + +

+

+ + 3. 他の人が問題を解決するのを助けるのに十分な情報を提供するにはどうすればいいですか? + +

+

+ + 4. QQグループにカラーチャートを投稿すると、問題の解決に役立つ他の人にとってより魅力的になる場合があります。 + +

+

+ + + 問題の種類と対応 + + レポートの内容(黄色が必要) + + + +

+

+ + 1. XXXページで立ち往生して動かない! : + +

+

+ + (1). + + スタック時の1280x720ゲーム画面 + + + (MuMuがF9を押すスクリーンショット) + + +

+

+ (2). Baasログのスクリーンショット +

+

+ (3). ページを切り替えてみて、このページでしか動かなくなるかどうかを確認してみてください +

+

+ + 2.絵を押して、格子が立ち往生して動けなくなったら歩きました! : + +

+

+ (1). もう一度1〜2回押してみて、毎回1つの位置に動かないか確認します。 +

+

+ + + 「プッシュ開始」をクリックしてから動かなくなったときまでのビデオを録画し、エミュレーターゲームインターフェイスとBaasログインターフェイスの同じ画面記録に注意してください。 + + +

+

+ + 3. XXX設定をセットアップしましたが、ヒットしませんでした! /  XXXをセットしてないのに当たった! : + +

+

+ (1). 設定手順を注意深く読んで、正しく入力する方法を理解しているかどうかを確認してください。 +

+

+ + + (2). 設定とプログラムログのスクリーンショット。 + + +

+ + \ No newline at end of file diff --git "a/src/descriptions/ja_JP/\344\270\200\350\210\254\347\232\204\343\201\252\343\202\250\343\203\237\343\203\245\343\203\254\343\203\274\343\202\277 ADB \343\202\242\343\203\211\343\203\254\343\202\271.html" "b/src/descriptions/ja_JP/\344\270\200\350\210\254\347\232\204\343\201\252\343\202\250\343\203\237\343\203\245\343\203\254\343\203\274\343\202\277 ADB \343\202\242\343\203\211\343\203\254\343\202\271.html" new file mode 100644 index 000000000..6655babe7 --- /dev/null +++ "b/src/descriptions/ja_JP/\344\270\200\350\210\254\347\232\204\343\201\252\343\202\250\343\203\237\343\203\245\343\203\254\343\203\274\343\202\277 ADB \343\202\242\343\203\211\343\203\254\343\202\271.html" @@ -0,0 +1,8 @@ + + +

+

+
複数のポートはご自身でご確認ください

シミュレータポートを1つ開く

1.MuMu:7555
2.ブルースタック/サンダーボルト:5555(開いているadbポートデバッグ機能を確認するためのBlueStacksエミュレーター)
3.ナイトゴッド:62001/59865
4.むむ12:16384
5. MEmu: 21503
+


+ + \ No newline at end of file diff --git "a/src/descriptions/ja_JP/\345\220\204\345\234\260\345\237\237\343\201\253\345\277\205\350\246\201\343\201\252\343\203\201\343\203\274\343\203\240\345\261\236\346\200\247.html" "b/src/descriptions/ja_JP/\345\220\204\345\234\260\345\237\237\343\201\253\345\277\205\350\246\201\343\201\252\343\203\201\343\203\274\343\203\240\345\261\236\346\200\247.html" new file mode 100644 index 000000000..f43f0e5e8 --- /dev/null +++ "b/src/descriptions/ja_JP/\345\220\204\345\234\260\345\237\237\343\201\253\345\277\205\350\246\201\343\201\252\343\203\201\343\203\274\343\203\240\345\261\236\346\200\247.html" @@ -0,0 +1,165 @@ + + + + + +

+ + + 26 [ ミスティック , アウトブレイク ] + + +

+

+ + + 25[ 振動 , スルー ] + + +
+ + + 24[ 振動 ・ 破裂 ] + + +
+ + + 23[ 発生 、 を通じて ] + + +
+ + + 22 [ スルー , ミステリー ] + + +
+ + + 21[ ミステリー , アウトブレイク ] + + +
+ + + 20[ 発生 ・ 通し ] + + +
+ + + 19[ 通し , ミスティック ] + + +
+ + + 18[ ミスティック , アウトブレイク ] + + +
+ + + 17[ 発生 , 浸透] + + +
+ + + 16[ 通し 、 ミスティック ] + + +
+ + + 15[ ミステリー , ミステリー ] + + +
+ + + 14[ アウトブレイク , ミステリー ] + + +
+ + + 13[ スルー , スルー ] + + +
+ + + 12[ ミステリー , アウトブレイク ] + + +
+ + + 11[ スルー , ミステリー ] + + +
+ + + 10[ アウトブレイク , ミステリー ] + + +
+ + + 9 [ 発生 、 を通じて ] + + +
+ + + 8 [ 貫通 、 貫通 ] + + +
+ + + 7 [ アウトブレイク , アウトブレイク ] + + +
+ + + 6 [ スルー 、 スルー ] + + +
+ + + 5 [ アウトブレイク ] + + +
+ + + 4 [ から ] + + +
+ + + 3 [ から ] + + +
+ + + 2 [ アウトブレイク ] + + +
+ + + 1 [ アウトブレイク ] + + +

+ + diff --git "a/src/descriptions/ja_JP/\346\234\254\347\267\250\343\201\256\350\207\252\345\213\225\350\252\254\346\230\216.html" "b/src/descriptions/ja_JP/\346\234\254\347\267\250\343\201\256\350\207\252\345\213\225\350\252\254\346\230\216.html" new file mode 100644 index 000000000..ad46ad2e0 --- /dev/null +++ "b/src/descriptions/ja_JP/\346\234\254\347\267\250\343\201\256\350\207\252\345\213\225\350\252\254\346\230\216.html" @@ -0,0 +1,105 @@ + + + + + +

+ + + メインストーリーのパラメータ設定 + + +

+

+ + + プロットの自動プッシュは、グリッドの移動に役立ちます + + + だがしかし + + + 最終章では、一部の戦闘が自動でプレイできない + + +

+

+ + 番号はチャプターマッピングに対応 + +

+

+ + 1:チャプター1 + +

+

+ + 2: チャプター2 + +

+

+ + 3: チャプター3 + +

+

+ + 4:チャプター4 + +

+

+ + 5:最終章 + +

+

+ + 6: チャプター5 + +

+

+ + プッシュするチャプタは、""で区切って順番に示されます。 + +

+

+ + 例: + +

+

+ + 135年 + +

+

+ + 第1章、第3章、最終章が順番に押されるということです + +

+

+ + 何も残さないと、デフォルト設定が使用されます + +

+

+ + 代表ユニフォーム:1、2、3 + +

+

+ + 国際: 1, 2, 3, 4, 5, 4 + +

+

+ + 毎日: 1, 2, 3, 4, 5, 4, 6 + +

+
+
 
+
+ + diff --git "a/src/descriptions/ja_JP/\346\247\213\346\210\220\343\201\256\343\202\271\343\202\261\343\202\270\343\203\245\343\203\274\343\203\253\350\250\255\345\256\232\343\201\256\343\203\230\343\203\253\343\203\227.html" "b/src/descriptions/ja_JP/\346\247\213\346\210\220\343\201\256\343\202\271\343\202\261\343\202\270\343\203\245\343\203\274\343\203\253\350\250\255\345\256\232\343\201\256\343\203\230\343\203\253\343\203\227.html" new file mode 100644 index 000000000..6322c0ea8 --- /dev/null +++ "b/src/descriptions/ja_JP/\346\247\213\346\210\220\343\201\256\343\202\271\343\202\261\343\202\270\343\203\245\343\203\274\343\203\253\350\250\255\345\256\232\343\201\256\343\203\230\343\203\253\343\203\227.html" @@ -0,0 +1,77 @@ + + + + + +

+ + + スケジュール設定の入力に関するヘルプ: + + +

+

+ 1.優先度:キューに2つ以上のタスクがある場合、優先度の低いタスクが優先されます +

+

+ 2.実行間隔:整数0は1日の間隔を意味します。 +

+

+ 3.デイリーリセット: +

+

+ 対応するタスクをこれらの時刻に実行します (複数のタイムスタンプをコンマで区切ることができます)。 +

+

+ [[Ha, Mark, S]]の形式に入力します。 + + + (UTC時間) + + +

+

+ + + 例 + + :[ [ 0 , 0 , 0 ] , [ 20 , 0 , 0 ] ] + +

+

+ + 表示:北京時間(UTC + 8)8時、4時の固定実行 + +

+

+ 4.無効期間: +

+

+ 無効になっているすべての期間にタスクを実行しない (複数の期間をカンマで区切って指定できます) +

+

+ [ [ [ h1, m1, s1 ] , [ h2 , m2 , s1 ] ] の形式 に入力します。 + + + (UTC時間) + + +

+

+ + + 例 + + :[ [ 0 , 0 , 0 ] , [ 24, 0 , 0 ] ] + +

+

+ + 一日中やらないということ + +

+

+ 5. プレタスク、ポストタスク:プレタスクのすべてのタスクをタスクの前(後)に実行します +

+ + diff --git "a/src/descriptions/ja_JP/\351\200\232\345\270\270\343\201\256\343\203\200\343\202\244\343\202\242\343\202\260\343\203\251\343\203\240\343\202\271\343\202\244\343\203\274\343\203\227\343\202\222\345\237\213\343\202\201\343\202\213\346\211\213\351\240\206.html" "b/src/descriptions/ja_JP/\351\200\232\345\270\270\343\201\256\343\203\200\343\202\244\343\202\242\343\202\260\343\203\251\343\203\240\343\202\271\343\202\244\343\203\274\343\203\227\343\202\222\345\237\213\343\202\201\343\202\213\346\211\213\351\240\206.html" new file mode 100644 index 000000000..ad8341585 --- /dev/null +++ "b/src/descriptions/ja_JP/\351\200\232\345\270\270\343\201\256\343\203\200\343\202\244\343\202\242\343\202\260\343\203\251\343\203\240\343\202\271\343\202\244\343\203\274\343\203\227\343\202\222\345\237\213\343\202\201\343\202\213\346\211\213\351\240\206.html" @@ -0,0 +1,69 @@ + + + + + +

+ 各スイープ構成は、「Regin」-「Tasknon」-「Whiptims」のような形をしています。 +

+

+ 示す + + 地域 + + 'Regian' & Embuspu; + + レベル + + 'Tasker-Nongber' & Embusp; + + スイープの数 + + 'Swiptims' & Embuspu; +

+

+ 各構成は ',' で区切られます +

+

+ 1. + + + スイープレベルが利用可能です + + + : +

+

+ チュートリアル - 1 すべてのマップの後に 5 つのマップがある +

+

+ 2. + + + 特別な指示 + + +

+

+ 国際的、日本の「スニプティム」は「マックス」になることができます +

+

+ チュートリアルでは、文字列 'Tutoriar' を修正するために 'Regian' が必要です +

+

+ BAASは、現在のスタミナとレベルスタミナに基づいて現在のレベルをスイープできるかどうかを計算し、不足しているレベルや「最大」の数でスイープされたレベルは直接終了します +

+

+ 例: +

+

+ 国際線サービスで十分な場合 +

+

+ チュートリアル-1-20,15-3-3,20-3-MAX +

+

+ 最初にチュートリアル-1を20回クリーンアップし、次に15-3、3回スイープしてから、すべてのスタミナを20-3スイープすることを示します +

+ + diff --git "a/src/descriptions/ja_JP/\351\200\232\345\270\270\343\201\256\345\233\263\343\201\256\350\252\254\346\230\216\343\201\257\350\207\252\345\213\225\347\232\204\343\201\253\343\203\227\343\203\203\343\202\267\343\203\245\343\201\225\343\202\214\343\201\276\343\201\231.html" "b/src/descriptions/ja_JP/\351\200\232\345\270\270\343\201\256\345\233\263\343\201\256\350\252\254\346\230\216\343\201\257\350\207\252\345\213\225\347\232\204\343\201\253\343\203\227\343\203\203\343\202\267\343\203\245\343\201\225\343\202\214\343\201\276\343\201\231.html" new file mode 100644 index 000000000..1f8eddcd5 --- /dev/null +++ "b/src/descriptions/ja_JP/\351\200\232\345\270\270\343\201\256\345\233\263\343\201\256\350\252\254\346\230\216\343\201\257\350\207\252\345\213\225\347\232\204\343\201\253\343\203\227\343\203\203\343\202\267\343\203\245\343\201\225\343\202\214\343\201\276\343\201\231.html" @@ -0,0 +1,197 @@ + + +

+

+

+ 通常の図の自動プッシュの説明: +

+

+ 1.使用説明書: +

+

+ (1):必須 + + + アンロック + + + 自動的にラウンドを終了し、 + + + オートバトル + + + (自動検出してオン) +

+

+ (2):対応レベルのメインストーリーは正常 + + + 4 - 25 + + +

+

+ (3):BAASがマップを押すと、チームはクリック座標とルートを移動し、ブルーファイルゲームに複数のチームがある場合、ゲーム内のチームの数、サイズ座標、移動順序によって異なるため、すべての動きは1回しかクリックされません。 +

+

+ (4):(3)により、画像が自動的にプッシュされた場合 + + + 選択したチームの数が最小から最大であることを確認する必要があります + + 。 + + + +

+

+ + + (5):BAASはに従って選択します + + + 通常の画像プッシュ画像設定<> + + + + + 選択したチーム属性 + + + + そして + + + <チーム選択ロジック> + + + マップをプッシュするための適切な構成を見つける + +

+

+ + (6):プッシュ + + + 拍車 + + + レベルは保証される必要があります< + + + + 指定されたすべてのレベルを適用 + + + + >オプション + + + シャットダウン + + + +

+

+ 最初の属性は [1] で、2 番目の属性は [2] であることに注意してください。 +

+

+ チーム選択ロジック: +

+

+ 1 優先保証[1] 拘束関係に基づいて残りのチーム番号を選択し、残りの対応するチーム属性の拘束関係を徐々に減らします。 +

+

+ 2 チームを選択する場合 (4 - チーム番号) > = 必要な残りのチーム数。 +

+

+ 3 1と2が保証できない場合は、対応するチームの拘束関係を徐々に減らす[1] +

+

+ 4 一部のチームが選択され、4 - これらのチームの最大数 >= 残りの必須チーム数の場合、残りのチームはオプションの番号の順に入力されます。 +

+

+ 5 上記の条件のいずれも満たされない場合、1、2、3... 選択したチームに番号を付ける +

+

+ + 例: + +

+

+ 「23フィギュア[バースト、スルー]」のチームを選択する際の順番を試してみてください。 +

+

+ 最初のチームから抜け出す、最初のチームを通して->最初のチームから抜け出す、2番目のチームを通して->最初のチームから抜け出す、2番目のチームを抜ける->... +

+

+ ファーストチーム番号が3で、上記の順番で選ばれなかった場合は、4がセカンドチームとして選ばれる +

+

+ まだ選ばれていない場合は、1 2が最終チームとして選ばれます +

+

+ + + 通常のマッププッシュのレベルを埋めるための手順: + + +

+

+ + 1. もし + + + 特定のレベルごとに強制プレイが有効になっていません + + + 記入する各数字は押すエリアを示し、現在のレベルがSSSであるかどうかに応じて、エリア内の各レベルをプレイするかどうかをプログラムが判断します + +

+

+ + 例: + +

+

+ + 15,16,14 + +

+

+ + 15、16、14を順番に押すということです。 + +

+

+ + 2. + + + もし + + + 特定の各レベルを強制的にプレイできます + + + で、領域内のすべてのレベルを一度プッシュする数値を入力し、指定したレベルを示す数値 - 数値を入力します + +

+

+ + 例: + +

+

+ + 15,16-3 + +

+

+ + これは、15-1、15-2、15-3、15-4、15-5、16-3を順番にプレイすることを意味します + +

+ + \ No newline at end of file diff --git "a/src/descriptions/ja_JP/\351\233\243\346\230\223\345\272\246\345\233\263\346\247\213\346\210\220\343\201\256\350\252\254\346\230\216.html" "b/src/descriptions/ja_JP/\351\233\243\346\230\223\345\272\246\345\233\263\346\247\213\346\210\220\343\201\256\350\252\254\346\230\216.html" new file mode 100644 index 000000000..d79f3ff8a --- /dev/null +++ "b/src/descriptions/ja_JP/\351\233\243\346\230\223\345\272\246\345\233\263\346\247\213\346\210\220\343\201\256\350\252\254\346\230\216.html" @@ -0,0 +1,10 @@ + + + + + +
+
難易度マップの使用方法は、チーム選択ロジックやノーマルマップと同じで、一部の難易度マップには3つのチームが必要であり、3番目のチームの属性は、そのエリアに必要な属性の最初の属性と同じです

プッシュマップレベルに入力する手順:

プッシュマップレベルに入力される文字列は、これらの文字または単語 "-"、"s"、"precent"、"tasker"、"、"、および数字を超えてはなりません
コンマで分割し、複数の文字列に変換
1.文字列にキーワード「sss」、「present」、「task」がありません
例: 15、12-2
難易度マップに合わせて、マップ設定の3つのスイッチ(15-1、15-2、15-3、12-2)を押して、SSS/プレゼントをもらう/チャレンジタスクをクリアする

2. 数字の後に文字列が続き、"-"で区切られます。
例:15-sss-present
SSSに(15-1、15-2、15-3)ヒットしてプレゼントをもらう

3. 2つの数字(対応するレベルに割り当てられています)
例: 15-3-sss-task
SSSに15-3ヒットし、チャレンジを完了します

4. 事例紹介
スイッチがすべてオンになっているので、7,8-SSS、9-3-taskと入力します。
これは、(7-1、7-2、7-3)がSSSに当たり、ギフトをもらってチャレンジタスクを完了し、(8-1、8-2、8-3)がSSSにヒットし、9-3がチャレンジタスクを完了することを意味します
注:Baasは、レベルがsssにヒットしたかどうか、ギフトを受け取ったかどうかを自動的に判断し、sssがヒットしたかギフトを受け取った場合、レベルはスキップされます。
+
+ + diff --git "a/src/descriptions/zh_CN/\345\220\204\345\214\272\345\237\237\346\211\200\351\234\200\351\230\237\344\274\215\345\261\236\346\200\247.html" "b/src/descriptions/zh_CN/\345\220\204\345\214\272\345\237\237\346\211\200\351\234\200\351\230\237\344\274\215\345\261\236\346\200\247.html" new file mode 100644 index 000000000..aa78ad8d9 --- /dev/null +++ "b/src/descriptions/zh_CN/\345\220\204\345\214\272\345\237\237\346\211\200\351\234\200\351\230\237\344\274\215\345\261\236\346\200\247.html" @@ -0,0 +1,8 @@ + + + + + +

25[ 振动 , 贯穿 ]
24[ 振动 , 爆发 ]
23[ 爆发 , 贯穿 ]
22[ 贯穿 , 神秘 ]
21[ 神秘 , 爆发 ]
20[ 爆发 , 贯穿 ]
19[ 贯穿 , 神秘 ]
18[ 神秘 , 爆发 ]
17[ 爆发 , 贯穿 ]
16[ 贯穿 , 神秘 ] 
15[ 神秘 , 神秘 ] 
14[ 爆发 , 神秘 ] 
13[ 贯穿 , 贯穿 ] 
12[ 神秘 , 爆发 ] 
11[ 贯穿 , 神秘 ] 
10[ 爆发 , 神秘 ]
9  [ 爆发 , 贯穿 ]
8  [ 贯穿 , 贯穿 ]   
7  [ 爆发 , 爆发 ]    
6  [ 贯穿 , 贯穿 ]   
5  [ 爆发 ]
4  [ 贯穿 ]
3  [ 贯穿 ]
2  [ 爆发 ]
1  [ 爆发 ]

+ + diff --git "a/src/descriptions/zh_CN/\345\233\260\351\232\276\345\233\276\351\205\215\347\275\256\350\257\264\346\230\216.html" "b/src/descriptions/zh_CN/\345\233\260\351\232\276\345\233\276\351\205\215\347\275\256\350\257\264\346\230\216.html" new file mode 100644 index 000000000..cdf127eb5 --- /dev/null +++ "b/src/descriptions/zh_CN/\345\233\260\351\232\276\345\233\276\351\205\215\347\275\256\350\257\264\346\230\216.html" @@ -0,0 +1,10 @@ + + + + + +
+
困难图使用说明与选队逻辑和普通图相同,一些困难图需要三支队伍,第三支队伍的属性均与该区域所需属性的第一个属性相同

推图关卡填写说明:

推图关卡中填写的字符串不应该超出这些字符或单词 "-" , "sss", "present", "task", "," , 和数字
按逗号拆分后转化为若干字符串
1.字符串没有关键字"sss","present","task"
例子:15,12-2
根据困难图推图设置中三个的开关 将(15-1,15-2,15-3,12-2)打到sss/拿礼物/完成挑战任务

2.一个数字并跟字符串,且用"-"分隔
例子: 15-sss-present
会将(15-1,15-2,15-3)打到sss并拿礼物

3.两个数字(指定到对应关卡)
例子:15-3-sss-task
会将15-3打到sss并且完成挑战任务

4.例子
开关都开启,填写: 7,8-sss,9-3-task
表示依次执行(7-1,7-2,7-3)打到sss,拿礼物并完成挑战任务,(8-1,8-2,8-3)打到sss,9-3完成挑战任务
注:Baas会自动判断关卡是否已经打到sss,是否拿了礼物,如果已经打到sss或拿了礼物,则跳过该关卡。
+
+ + diff --git "a/src/descriptions/zh_CN/\345\270\270\350\247\201\346\250\241\346\213\237\345\231\250adb\345\234\260\345\235\200.html" "b/src/descriptions/zh_CN/\345\270\270\350\247\201\346\250\241\346\213\237\345\231\250adb\345\234\260\345\235\200.html" new file mode 100644 index 000000000..37481683f --- /dev/null +++ "b/src/descriptions/zh_CN/\345\270\270\350\247\201\346\250\241\346\213\237\345\231\250adb\345\234\260\345\235\200.html" @@ -0,0 +1,3 @@ +

 

+
多开端口请自行查询

单开模拟器端口

1.MuMu:7555
2.蓝叠/雷电:5555 (蓝叠模拟器要检查打开adb端口调试功能)
3.夜神:62001 / 59865
4.Mumu12:16384
5.逍遥:21503
+


diff --git "a/src/descriptions/zh_CN/\346\231\256\351\200\232\345\233\276\346\211\253\350\215\241\345\241\253\345\206\231\350\257\264\346\230\216.html" "b/src/descriptions/zh_CN/\346\231\256\351\200\232\345\233\276\346\211\253\350\215\241\345\241\253\345\206\231\350\257\264\346\230\216.html" new file mode 100644 index 000000000..d64dfe9d9 --- /dev/null +++ "b/src/descriptions/zh_CN/\346\231\256\351\200\232\345\233\276\346\211\253\350\215\241\345\241\253\345\206\231\350\257\264\346\230\216.html" @@ -0,0 +1,20 @@ + + + + + +

每个扫荡配置形如 ’region’ - ‘task number’ - ‘sweep times’

+

表示区域'region'  关卡 ‘task-number’  扫荡次数 ‘sweep times’ 

+

每个配置都用‘,’ 隔开

+

1.可用扫荡关卡:

+

教程-1与5图后 所有地图

+

2.特殊说明

+

国际服,日服 ‘sweep times’ 可以为 'max'

+

教程需要'region'为固定字符串'tutorial'

+

BAAS会根据当前体力和关卡体力计算当前关卡能否扫荡,不足或扫荡完次数为'max'的关卡会直接退出

+

例:

+

国际服体力充足情况下

+

tutorial-1-20,15-3-3,20-3-max

+

表示先清理教程-1 20次 ,然后扫荡15-3,3次 ,然后所有体力扫荡20-3

+ + diff --git "a/src/descriptions/zh_CN/\346\231\256\351\200\232\345\233\276\350\207\252\345\212\250\346\216\250\345\233\276\350\257\264\346\230\216.html" "b/src/descriptions/zh_CN/\346\231\256\351\200\232\345\233\276\350\207\252\345\212\250\346\216\250\345\233\276\350\257\264\346\230\216.html" new file mode 100644 index 000000000..d2a520e33 --- /dev/null +++ "b/src/descriptions/zh_CN/\346\231\256\351\200\232\345\233\276\350\207\252\345\212\250\346\216\250\345\233\276\350\257\264\346\230\216.html" @@ -0,0 +1,35 @@ + + + + + +

普通图自动推图说明:

+

1.使用说明:

+

(1):必须解锁自动结束回合和自动战斗(自动检测并开启)

+

(2):支持的关卡主线普通4 - 25

+

(3):BAAS推图时队伍移动点击坐标和路线是固定的,且所有移动只会点击一次,由于碧蓝档案游戏推图时若有多支队伍,则会根据队伍在游戏内编号大小坐标和移动次序不同。

+

(4):由于(3),自动推图时必须保证选择队的伍编号由小到大

+

(5):BAAS会选择根据<普通图推图设置>中选择的队伍属性<选队逻辑>寻找合适配置进行推图

+

记下列各图对应属性中第一个属性为[1],第二属性为[2]。

+

选队逻辑:

+

1 优先保证[1]克制关系基础上选择剩余队伍编号,逐渐降低剩余对应队伍属性克制关系。

+

2 选择一个队伍时 (4 - 该队伍编号)>= 剩余需要队伍数量。

+

3 若无法保证1和2,逐渐降低[1]对应队伍克制关系

+

4 如果已选出某些队伍,且 4-这些队伍中最大编号 >= 剩余需要队伍数量,则剩余队伍由可选编号依次填充。

+

5 上述条件均不满足,则以1, 2 , 3... 为选择的队伍编号 

+

例:

+

为 "23图 [ 爆发 , 贯穿 ]" 选择队伍时 尝试顺序

+

爆发一队,贯穿一队 -> 爆发一队,贯穿二队 -> 爆发一队,爆发二队 -> ...

+

如果爆发一队编号为3且按上述顺序未选出,则选择4为第二支队伍

+

还未选出则选择 1 2 为最终队伍

+

普通图推图关卡填写说明:

+

1.如果未启用强制打每一个指定关卡,填写的每一个数字表示要推图的区域,程序会根据当前关卡是否sss判断该区域每一关是否要打

+

例:

+

15,16,14

+

表示依次推15,16,14图。

+

2.如果启用强制打每一个指定关卡,则输入一个数字表示推该区域所有关卡一次,输入 数字-数字表示指定关卡

+

例:

+

15,16-3

+

表示依次打15-1,15-2,15-3,15-4,15-5,16-3

+ + diff --git "a/src/descriptions/zh_CN/\346\264\273\345\212\250\346\211\253\350\215\241\345\241\253\345\206\231\350\257\264\346\230\216.html" "b/src/descriptions/zh_CN/\346\264\273\345\212\250\346\211\253\350\215\241\345\241\253\345\206\231\350\257\264\346\230\216.html" new file mode 100644 index 000000000..a0b4a4aeb --- /dev/null +++ "b/src/descriptions/zh_CN/\346\264\273\345\212\250\346\211\253\350\215\241\345\241\253\345\206\231\350\257\264\346\230\216.html" @@ -0,0 +1,26 @@ + + + + + +

活动图扫荡填写说明:

+

扫荡一关

+

活动关卡扫荡关卡填写:1 - 最高难度 间一个 整数

+

扫荡次数:

+

1. 整数 表示扫荡次数

+

2. 小数 0.5 表示使用当前 体力*0.5 的 体力扫荡该关卡

+

3. 分数 1/3 表示使用当前体力的1/3扫荡该关卡

+

扫荡多关

+

将多个扫荡一关的关卡和次数用 ',' 隔开,表示依次扫荡这些关卡

+

例:

+

扫荡关卡:

+

9,10,11

+

扫荡次数:

+

0.5,3,1/3

+

体力: 999

+

表示依次扫荡

+

第9关 (999 * 0.5) / 20 = 25次

+

第10关 3 次

+

第11关 (999 * 1/3)/ 20 = 16次

+ + diff --git "a/src/descriptions/zh_CN/\347\242\247\350\223\235\346\241\243\346\241\210\346\270\270\346\210\217\345\206\205\351\203\250\350\256\276\347\275\256\357\274\210\345\210\235\346\254\241\344\275\277\347\224\250\345\277\205\350\257\273\357\274\211.html" "b/src/descriptions/zh_CN/\347\242\247\350\223\235\346\241\243\346\241\210\346\270\270\346\210\217\345\206\205\351\203\250\350\256\276\347\275\256\357\274\210\345\210\235\346\254\241\344\275\277\347\224\250\345\277\205\350\257\273\357\274\211.html" new file mode 100644 index 000000000..1de923e7f --- /dev/null +++ "b/src/descriptions/zh_CN/\347\242\247\350\223\235\346\241\243\346\241\210\346\270\270\346\210\217\345\206\205\351\203\250\350\256\276\347\275\256\357\274\210\345\210\235\346\254\241\344\275\277\347\224\250\345\277\205\350\257\273\357\274\211.html" @@ -0,0 +1,38 @@ + + + + + +

碧蓝档案游戏内部设置

+

**必选**

+

选项->图像:战斗画面上下黑边:OFF

+

记忆大厅:不选取亚子,爱露,若藻

+

国际服语言:英文

+

推荐选取(不影响脚本运行)   

+ + + + + + + + + + + + + + + + + + + + + + + +
分辨率最高
60
加速渲染模式兼容
后期处理ON
抗锯齿ON
+

 

+ + diff --git "a/src/descriptions/zh_CN/\350\207\252\345\212\250\344\270\273\347\272\277\345\211\247\346\203\205\350\257\264\346\230\216.html" "b/src/descriptions/zh_CN/\350\207\252\345\212\250\344\270\273\347\272\277\345\211\247\346\203\205\350\257\264\346\230\216.html" new file mode 100644 index 000000000..907c08871 --- /dev/null +++ "b/src/descriptions/zh_CN/\350\207\252\345\212\250\344\270\273\347\272\277\345\211\247\346\203\205\350\257\264\346\230\216.html" @@ -0,0 +1,27 @@ + + + + + +

主线剧情参数设置

+

自动推剧情可以帮助走格子 但是 最终章一些战斗无法自动打

+

数字与章节对应表

+

1:第一章

+

2:第二章

+

3:第三章

+

4:第四章

+

5:最终章

+

6:第五章

+

用","隔开数字表示依次要推的章节

+

例:

+

1,3,5

+

表示依次推第一章,第三章,最终章

+

什么都不填会用默认配置

+

国服:1,2,3

+

国际服:1,2,3,4,5,4

+

日服:1,2,3,4,5,4,6

+
+
 
+
+ + diff --git "a/src/descriptions/zh_CN/\351\227\256\351\242\230\344\270\212\346\212\245\346\214\207\345\215\227(\351\207\215\350\246\201).html" "b/src/descriptions/zh_CN/\351\227\256\351\242\230\344\270\212\346\212\245\346\214\207\345\215\227(\351\207\215\350\246\201).html" new file mode 100644 index 000000000..d6528e414 --- /dev/null +++ "b/src/descriptions/zh_CN/\351\227\256\351\242\230\344\270\212\346\212\245\346\214\207\345\215\227(\351\207\215\350\246\201).html" @@ -0,0 +1,17 @@ +

上报问题前请思考:

+

1.这个问题以前有没有出现过,我是否能自己尝试解决(Baidu,教程)。

+

如果不能解决

+

2.我现在是否每次运行都出现这个问题。

+

3.我该如何提供足够的信息来让其他人帮我解决问题。

+

4.在qq群内发色图或许更能吸引他人帮你解决问题。

+

问题类型与对应汇报内容(黄色必要)

+

1.我卡在XXX页面不动了!:

+

(1).卡住时1280x720游戏画面(MuMu按F9截图)

+

(2).Baas日志截图

+

(3).尝试切换页面,看一下是否只会卡在这个页面

+

2.我推图走格子卡住不动了!:

+

(1).尝试重新推1-2次观察是否每次都是卡在一个位置。

+

(1).录制完整从点击"开始推图"到卡住时视频,注意模拟器游戏界面和Baas日志界面同屏录制。

+

3.我设置了XXX配置但是没有打! /  我没设置XXX但是打了!:

+

(1).仔细阅读配置说明,查看是否正确理解该怎么填写。

+

(2).配置截图与程序日志截图。

diff --git a/src/descriptions_en_US/1) Common Emulator Adb addresses.html b/src/descriptions_en_US/1) Common Emulator Adb addresses.html new file mode 100644 index 000000000..a6c6eb1ed --- /dev/null +++ b/src/descriptions_en_US/1) Common Emulator Adb addresses.html @@ -0,0 +1,40 @@ + + + + + + +
+

Multiple Instance Ports (Please Refer to Specific Guides)

+

For multiple instance ports, please refer to specific guides for the appropriate port numbers.

+
+ +
+

Single Instance Emulator Ports

+ +
+ + diff --git a/src/descriptions_en_US/2) Blue Archive Internal Settings.html b/src/descriptions_en_US/2) Blue Archive Internal Settings.html new file mode 100644 index 000000000..fc7b323d4 --- /dev/null +++ b/src/descriptions_en_US/2) Blue Archive Internal Settings.html @@ -0,0 +1,58 @@ + + + + + + +

Blue Archive Internal Settings:

+

**Mandatory**:

+

Settings -> Graphics: Combat Screen Top and Bottom Black Bars: OFF

+

Memorial Lobby: Do not select Azi, Elu, Wakamo

+

Global Server Language: English

+

Recommended Settings (Does not affect script operation)

+ + + + + + + + + + + + + + + + + + + + + + + + + +
ResolutionVery High
FPS60
Accelerated Rendering ModeCompatibility
Post-processingON
Anti-aliasingON
+ + diff --git a/src/descriptions_en_US/3) Explanation of Sweep Configurations.html b/src/descriptions_en_US/3) Explanation of Sweep Configurations.html new file mode 100644 index 000000000..e83968816 --- /dev/null +++ b/src/descriptions_en_US/3) Explanation of Sweep Configurations.html @@ -0,0 +1,50 @@ + + + + + + +
+

Explanation of Sweep Configurations

+

Each sweeping configuration is in the form of 'area - stage number - sweep times'.

+

This represents area 'area', stage 'stage number', and sweep times 'sweep times'.

+

Each configuration is separated by ','.

+
+ +
+

Available Sweepable Stages:

+

After Tutorial-1 and 5-5, all maps are available for sweeping.

+
+ +
+

Special Instructions:

+

For Global and Japanese servers, 'sweep times' can be specified as 'max'.

+

Tutorial requires 'area' to be the fixed string 'tutorial'.

+

BAAS will calculate whether the current stage can be swept based on current AP and stage AP. Insufficient AP or 'max' sweep times will result in skipping.

+
+ +
+

Example:

+

Assuming sufficient AP on the Global server:

+

tutorial-1-20,15-3-3,20-3-max

+

This means first sweep Tutorial-1 20 times, then sweep 15-3 for 3 times, and finally sweep all available stamina on 20-3.

+
+ + diff --git a/src/descriptions_en_US/4) Event Stages Sweeping Instructions.html b/src/descriptions_en_US/4) Event Stages Sweeping Instructions.html new file mode 100644 index 000000000..be2e52c8a --- /dev/null +++ b/src/descriptions_en_US/4) Event Stages Sweeping Instructions.html @@ -0,0 +1,49 @@ + + + + + + +
+

Event Stages Sweeping Instructions:

+

Sweeping a Single Stage:

+

For sweeping event stages, specify: 1 - highest difficulty as an integer.

+

Sweeping Frequency:

+

1. Integer indicates the number of times to sweep.

+

2. Decimal like 0.5 indicates sweeping with current AP * 0.5.

+

3. Fraction like 1/3 indicates sweeping with 1/3 of current AP.

+
+ +
+

Sweeping Multiple Stages:

+

Separate multiple stages and sweep counts with ',', indicating sweeping these stages sequentially.

+

Example:

+

Sweeping Stages:

+

9,10,11

+

Sweeping Counts:

+

0.5,3,1/3

+

AP: 999

+

Represents sweeping:

+

Stage 9: (999 * 0.5) / 20 = 25 times

+

Stage 10: 3 times

+

Stage 11: (999 * 1/3) / 20 = 16 times

+
+ + diff --git a/src/descriptions_en_US/5) Clear Stage Logic & Instructions.html b/src/descriptions_en_US/5) Clear Stage Logic & Instructions.html new file mode 100644 index 000000000..e80fcd646 --- /dev/null +++ b/src/descriptions_en_US/5) Clear Stage Logic & Instructions.html @@ -0,0 +1,87 @@ + + + + + + +

5) Clear Stage Logic & Instructions:

+ +

1. Usage Instructions:

+

+ (1) Unlock auto end-turn and + auto battle (automatically detected and activated). +

+

(2) Supports campaign mainline levels 4 - 25.

+

+ (3) When BAAS clear stages, units movement coordinates and routes are fixed. All movements are single-clicks + because in Blue Archive, if there are multiple units, they are arranged based on the units's + internal numbering coordinates and order of movements. +

+

+ (4) Due to (3), during automatic clear, it is + essential to ensure that unit numbers are in ascending order + . +

+

(5) BAAS will select units based on <Clear Normal Mission Settings> + and Unit Selection Logic to find suitable configurations for the stage.

+ +

Note down the first type of each area corresponding to [1] and the second type corresponding to [2].

+ +

Unit Selection Logic:

+
    +
  1. Prioritize unit selection based on [1] restraint relationships, gradually decreasing + the restraint relationships of remaining unit numbers.
  2. +
  3. When selecting a unit, if (4 - unit number) >= remaining required number of units.
  4. +
  5. If unable to ensure (1) and (2), gradually decrease the restraint relationships of [1] + corresponding units.
  6. +
  7. If certain units have been selected and the maximum number of (4 - these units) >= + remaining required number of units, the remaining units will be filled in by optional numbers in sequence.
  8. +
  9. If none of the above conditions are met, units will be selected in order of 1, 2, 3...
  10. +
+ +

Example:

+

+ For "Area 23 [Burst, Penetrate]," unit selection sequence:
+ Explosive Unit 1, Piercing Unit 1 -> Explosive Unit 1, Piercing Unit 2 -> Explosive Unit 1, Explosive Unit 2 -> ... +

+

If Explosive Unit 1 is number 3 and not selected in the above sequence, then select Unit 4 as the second unit.

+

If still not selected, then Unit 1 and 2 will be the final units.

+ +

Explanation for Clear Normal Mission Options:

+

+ If forced to play each specified stage is disabled, each number + entered represents the area to be cleared. The program will determine whether each stage in this area needs to + be cleared based on the current stage. +

+

Example:

+

15,16,14

+

Represents playing stages 15, 16, and 14 sequentially.

+ +

+ If forced to play each stage is enabled, enter a number + to clear all stages in that area once, or enter a number-range to specify stages. +

+

Example:

+

15,16-3

+

Represents playing levels 15-1, 15-2, 15-3, 15-4, 15-5, and 16-3 sequentially.

+ + diff --git a/src/descriptions_en_US/6) Clear Hard and Normal Stages.html b/src/descriptions_en_US/6) Clear Hard and Normal Stages.html new file mode 100644 index 000000000..5594082a0 --- /dev/null +++ b/src/descriptions_en_US/6) Clear Hard and Normal Stages.html @@ -0,0 +1,55 @@ + + + + + + +
+

Instructions for Hard and Normal Stages

+

Hard stages use the same unit types as Normal stages. Some Hard stages require 3 units, and the 3rd unit's type should match the 1st unit type required for that area.

+
+ +
+

Instructions for Filling in Normal Stages:

+ + +

1. Strings without the keywords "sss", "present", "task":
+ Example: 15,12-2
+ Clear (15-1, 15-2, 15-3, 12-2) based on Hard stage settings.

+ +

2. A number followed by strings, separated by "-":
+ Example: 15-sss-present
+ Clear (15-1, 15-2, 15-3) while aiming "sss"(3 stars) and getting gifts.

+ +

3. Two numbers (specified for corresponding stages):
+ Example: 15-3-sss-task
+ Clear 15-3 to reach "sss" and complete challenge tasks.

+ +

4. Example:
+ All switches are on, fill in: 7,8-sss,9-3-task
+ Clear (7-1, 7-2, 7-3) while aiming "sss" and completing tasks. Clear (8-1, 8-2, 8-3) while aiming "sss" and completing the 9-3 challenge task.

+
+ +
+

Note: Baas will automatically check if a stage has reached "sss" or if gifts have been obtained. If these conditions are met, the stage will be skipped.

+
+ + diff --git a/src/descriptions_en_US/7) Unit Types Required by Area.html b/src/descriptions_en_US/7) Unit Types Required by Area.html new file mode 100644 index 000000000..6c1dd8575 --- /dev/null +++ b/src/descriptions_en_US/7) Unit Types Required by Area.html @@ -0,0 +1,43 @@ + + + + Weapon List + + + +

25 [Sonic, Piercing]

+

24 [Sonic, Explosive]

+

23 [Explosive, Piercing]

+

22 [Piercing, Mystic]

+

21 [Mystic, Explosive]

+

20 [Explosive, Piercing]

+

19 [Piercing, Mystic]

+

18 [Mystic, Explosive]

+

17 [Explosive, Piercing]

+

16 [Piercing, Mystic]

+

15 [Mystic, Mystic]

+

14 [Explosive, Mystic]

+

13 [Piercing, Piercing]

+

12 [Mystic, Explosive]

+

11 [Piercing, Mystic]

+

10 [Explosive, Mystic]

+

9 [Explosive, Piercing]

+

8 [Piercing, Piercing]

+

7 [Explosive, Explosive]

+

6 [Piercing, Piercing]

+

5 [Explosive]

+

4 [Piercing]

+

3 [Piercing]

+

2 [Explosive]

+

1 [Explosive]

+ + diff --git a/src/descriptions_en_US/8) Main Story Parameters Setting.html b/src/descriptions_en_US/8) Main Story Parameters Setting.html new file mode 100644 index 000000000..001dc7dd8 --- /dev/null +++ b/src/descriptions_en_US/8) Main Story Parameters Setting.html @@ -0,0 +1,45 @@ + + + + + + +
+

Main Story Parameters Setting

+

Baas can automatically progress through the story, but some battles in the final chapter cannot be automated.

+

Number-to-Chapter Reference:

+

1: Chapter 1

+

2: Chapter 2

+

3: Chapter 3

+

4: Chapter 4

+

5: Final Chapter

+

6: Chapter 5

+

Separate chapter numbers with "," to indicate the sequence to progress through.

+

Example:

+

1,3,5

+

Progress through Chapter 1, Chapter 3, and the Final Chapter sequentially.

+

Leaving it blank will use default configurations.

+

For different servers:

+

CN Server: 1,2,3

+

Global Server: 1,2,3,4,5,4

+

JP Server: 1,2,3,4,5,4,6

+
+ + diff --git a/src/descriptions_en_US/9) Reporting Guidelines on Issues.html b/src/descriptions_en_US/9) Reporting Guidelines on Issues.html new file mode 100644 index 000000000..fe604d860 --- /dev/null +++ b/src/descriptions_en_US/9) Reporting Guidelines on Issues.html @@ -0,0 +1,44 @@ + + + + + + +

Before Reporting an Issue, Consider:

+

1. Has this issue occurred before? Can I attempt to resolve it myself (using Baidu or tutorials)?

+

If Unable to Resolve:

+

2. Is this issue happening consistently every time I run?

+

3. How can I provide enough information to help others assist me in solving the problem?

+

4. Posting colorful images in the QQ group might attract more help to solve the problem.

+

Issue Types and Corresponding Reporting Contents (Yellow highlights are necessary)

+

1. I'm stuck on the XXX page and can't proceed!

+

(1). Take a screenshot of the 1280x720 game screen when stuck (Press F9 in MuMu to capture)

+

(2). Capture Baas logs

+

(3). Try switching pages to see if it's consistently stuck on this page

+

2. I'm stuck while progressing through the grid!

+

(1). Try restarting and observing 1-2 times to see if it gets stuck at the same spot.

+

(1). Record a complete video from clicking "Start Mission" until getting stuck, ensuring both the emulator game interface and Baas log interface are captured in the video.

+

3. I configured XXX but it didn't work! / I didn't configure XXX but it worked!

+

(1). Read the configuration instructions carefully to ensure correct understanding of how to fill them.

+

(2). Provide screenshots of the configuration and Baas logs.

+ + diff --git a/src/explore_task_data/main_story/main_story.py b/src/explore_task_data/main_story/main_story.py index b9b83eedf..40f680ecb 100644 --- a/src/explore_task_data/main_story/main_story.py +++ b/src/explore_task_data/main_story/main_story.py @@ -2,7 +2,7 @@ "Operation-Recapture-Schale-2": { "will-fight": False, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (571, 370), 'wait-over': True, 'desc': "upper right"}, {'t': 'click', 'p': (687, 373), 'wait-over': True, 'desc': "right"}, @@ -20,7 +20,7 @@ (693, 305), (645, 564) ], - "actions": [ + "action": [ {'t': 'click', 'p': (378, 422), 'wait-over': True, 'desc': "1 left"}, {'t': 'click', 'p': (698, 308), 'wait-over': True, 'desc': "2 upper right"}, {'t': 'click', 'p': (701, 472), 'wait-over': True, 'desc': "3 lower right"}, @@ -35,7 +35,7 @@ "The-First-Sanctum-Abydos-Desert-District": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (576, 368), 'wait-over': True, 'desc': "1 upper right"}, {'t': 'click', 'p': (698, 473), 'wait-over': True, 'desc': "2 lower right"}, {'t': 'click', 'p': (758, 391), 'ec': True, 'desc': "1 right"}, @@ -45,7 +45,7 @@ "The-Second-Sanctum-Millennium-Ruins-District": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (574, 365), 'wait-over': True, 'desc': "1 upper right"}, {'t': 'click', 'p': (759, 388), 'wait-over': True, 'desc': "2 right"}, @@ -59,7 +59,7 @@ "The-Third-Sanctum-Abandoned-Amusement-Park": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (562, 534), 'ec': True, 'desc': "1 lower right"}, {'t': 'click', 'p': (845, 499), 'wait-over': True, 'desc': "2 lower right"}, @@ -73,7 +73,7 @@ "The-Forth-Sanctum-Basilica-in-the-Catacomb": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (570, 541), 'ec': True, 'desc': "1 lower right"}, {'t': 'click', 'p': (680, 302), 'wait-over': True, 'desc': "2 right"}, @@ -84,7 +84,7 @@ "The-Fifth-Sanctum-Outskirts-of-the-City-of-Eridu": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (410, 483), 'wait-over': True, 'desc': "1 right"}, {'t': 'end-turn'}, @@ -95,7 +95,7 @@ "The-Final-Defense-Operation-Schale": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (641, 467), 'wait-over': True, 'desc': "1 right"}, {'t': 'end-turn'}, @@ -106,7 +106,7 @@ "Rush": { "will-fight": True, "start": [], - "actions": [ + "action": [ {'t': 'click', 'p': (637, 425), "ec": True, 'desc': "1 upper right"}, {'t': 'click', 'p': (458, 341), 'wait-over': True, 'desc': "2 upper left"}, {'t': 'click', 'p': (761, 391), 'wait-over': True, 'desc': "3 right"}, @@ -116,7 +116,7 @@ {'t': 'click', 'p': (615, 332), 'wait-over': True, 'desc': "1 upper right"}, {'t': 'click', 'p': (662, 361), 'wait-over': True, 'desc': "1 upper right"}, - {'end-turn'}, + {'t': 'end-turn'}, ] } } diff --git a/src/rgb_feature/rgb_feature_CN.json b/src/rgb_feature/rgb_feature_CN.json index 0e9901ca7..29ab0f89c 100644 --- a/src/rgb_feature/rgb_feature_CN.json +++ b/src/rgb_feature/rgb_feature_CN.json @@ -16,7 +16,7 @@ "formation_edit2":[[[121,201],[121,285],[121,357],[121,432],[9,201],[9,285],[9,357],[9,432]],[[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255]]], "formation_edit3":[[[121,201],[121,285],[121,357],[121,432],[9,201],[9,285],[9,357],[9,432]],[[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255]]], "formation_edit4":[[[121,201],[121,285],[121,357],[121,432],[9,201],[9,285],[9,357],[9,432]],[[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109]]], - "fighting_feature": [[[834, 694], [782, 678], [811,681]],[[35, 75, 187, 207, 235, 255],[0,67, 57,98,120, 200],[0,67, 57,99,120, 200]]], + "fighting_feature": [[[834, 694], [782, 678], [811,681]],[[35, 75, 187, 227, 235, 255],[0,67, 57,98,120, 200],[0,67, 57,99,120, 200]]], "total_assault_rank_info":[[[131,167],[613,174],[673,174],[1115,183]],[[245,255,245,255,245,255],[245,255,245,255,245,255],[159,179,214,234,234,254],[159,179,214,234,234,254]]], "total_assault_accumulated_point_reward": [[[131,167],[613,174],[673,174],[1115,183],[121,242],[352,235],[109, 308],[370, 306]],[[159,179,214,234,234,254],[159,179,214,234,234,254],[245,255,245,255,245,255],[245,255,245,255,245,255],[245,255,245,255,245,255],[245,255,245,255,245,255],[41,61,64,84,95,115],[41,61,64,84,95,115]]], "total_assault_rank_reward": [[[131,167],[613,174],[673,174],[1115,183],[121,242],[352,235],[109, 308],[370, 306]],[[159,179,214,234,234,254],[159,179,214,234,234,254],[245,255,245,255,245,255],[245,255,245,255,245,255],[41,61,64,84,95,115],[41,61,64,84,95,115],[245,255,245,255,245,255],[245,255,245,255,245,255]]], diff --git a/src/rgb_feature/rgb_feature_JP.json b/src/rgb_feature/rgb_feature_JP.json index af1fcb52b..661910105 100644 --- a/src/rgb_feature/rgb_feature_JP.json +++ b/src/rgb_feature/rgb_feature_JP.json @@ -16,7 +16,7 @@ "formation_edit2":[[[121,201],[121,285],[121,357],[121,432],[9,201],[9,285],[9,357],[9,432]],[[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255]]], "formation_edit3":[[[121,201],[121,285],[121,357],[121,432],[9,201],[9,285],[9,357],[9,432]],[[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255]]], "formation_edit4":[[[121,201],[121,285],[121,357],[121,432],[9,201],[9,285],[9,357],[9,432]],[[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109],[235,255,235,255,235,255],[235,255,235,255,235,255],[235,255,235,255,235,255],[34,54,59,79,89,109]]], - "fighting_feature": [[[834, 694], [782, 678], [814,668]],[[35, 75, 187, 207, 235, 255],[0,57, 57,92,120, 200],[0,57, 57,92,120, 200]]], + "fighting_feature": [[[834, 694], [782, 678], [811,681]],[[35, 75, 187, 227, 235, 255],[0,57, 57,92,120, 200],[0,57, 57,92,120, 200]]], "total_assault_rank_info":[[[131,167],[613,174],[673,174],[1115,183]],[[245,255,245,255,245,255],[245,255,245,255,245,255],[159,179,214,234,234,254],[159,179,214,234,234,254]]], "total_assault_accumulated_point_reward": [[[131,167],[613,174],[673,174],[1115,183],[121,242],[352,235],[109, 308],[370, 306]],[[159,179,214,234,234,254],[159,179,214,234,234,254],[245,255,245,255,245,255],[245,255,245,255,245,255],[245,255,245,255,245,255],[245,255,245,255,245,255],[41,61,64,84,95,115],[41,61,64,84,95,115]]], "total_assault_rank_reward": [[[131,167],[613,174],[673,174],[1115,183],[121,242],[352,235],[109, 308],[370, 306]],[[159,179,214,234,234,254],[159,179,214,234,234,254],[245,255,245,255,245,255],[245,255,245,255,245,255],[41,61,64,84,95,115],[41,61,64,84,95,115],[245,255,245,255,245,255],[245,255,245,255,245,255]]], diff --git a/window.py b/window.py index 2448e34ce..bef511031 100644 --- a/window.py +++ b/window.py @@ -7,19 +7,21 @@ import threading from functools import partial -from PyQt5.QtCore import Qt, QSize, QPoint, pyqtSignal +from PyQt5.QtCore import Qt, QLocale, QSize, QTranslator, QPoint, pyqtSignal from PyQt5.QtGui import QIcon, QColor from PyQt5.QtWidgets import QApplication, QHBoxLayout -from qfluentwidgets import FluentIcon as FIF, SplashScreen, MSFluentWindow, TabBar, \ - MSFluentTitleBar, MessageBox, TransparentToolButton +from qfluentwidgets import FluentIcon as FIF, FluentTranslator, SplashScreen, MSFluentWindow, TabBar, \ + MSFluentTitleBar, MessageBox, InfoBar, InfoBarIcon, InfoBarPosition, TransparentToolButton from qfluentwidgets import (SubtitleLabel, setFont, setThemeColor) from core import default_config from gui.components.dialog_panel import SaveSettingMessageBox from gui.fragments.process import ProcessFragment from gui.fragments.readme import ReadMeWindow + from gui.util import notification from gui.util.config_set import ConfigSet +from gui.util.translator import baasTranslator as bt # sys.stderr = open('error.log', 'w+', encoding='utf-8') # sys.stdout = open('output.log', 'w+', encoding='utf-8') @@ -27,7 +29,7 @@ # Offer the error to the error.log ICON_DIR = 'gui/assets/logo.png' - +LAST_NOTICE_TIME = 0 def update_config_reserve_old(config_old, config_new): # 保留旧配置原有的键,添加新配置中没有的,删除新配置中没有的键 for key in config_new: @@ -208,7 +210,7 @@ def __init__(self, parent): self.historyButton.clicked.connect(self.onHistoryButtonClicked) self.searchButton = TransparentToolButton(FIF.HELP.icon(), self) - self.searchButton.setToolTip('帮助') + self.searchButton.setToolTip(self.tr('帮助')) self.searchButton.clicked.connect(self.onHelpButtonClicked) # self.tabBar.tabCloseRequested.connect(self.tabRemoveRequest) @@ -299,10 +301,10 @@ def call_update(self): def initNavigation(self): self.navi_btn_list = [ - self.addSubInterface(self.homeInterface, FIF.HOME, '主页'), - self.addSubInterface(self.processInterface, FIF.CALENDAR, '调度'), - self.addSubInterface(self.schedulerInterface, FIF.CALENDAR, '配置'), - self.addSubInterface(self.settingInterface, FIF.SETTING, '设置') + self.addSubInterface(self.homeInterface, FIF.HOME, self.tr('主页')), + self.addSubInterface(self.processInterface, FIF.CALENDAR, self.tr('调度')), + self.addSubInterface(self.schedulerInterface, FIF.CALENDAR, self.tr('配置')), + self.addSubInterface(self.settingInterface, FIF.SETTING, self.tr('设置')) ] for ind, btn in enumerate(self.navi_btn_list): @@ -336,7 +338,7 @@ def closeEvent(self, event): @staticmethod def showHelpModal(): helpModal = ReadMeWindow() - helpModal.setWindowTitle('帮助') + helpModal.setWindowTitle(helpModal.tr('帮助')) helpModal.setWindowIcon(QIcon(ICON_DIR)) helpModal.resize(800, 600) helpModal.setFocus() @@ -381,7 +383,7 @@ def onTabAddRequested(self): if addDialog.exec_(): text = addDialog.pathLineEdit.text() if text in list(map(lambda x: x.config['name'], self.config_dir_list)): - notification.error('设置失败', f'名为“{text}”的配置已经存在!', self) + notification.error(self.tr('设置失败'), f'{self.tr("名为")}“{text}”{self.tr("的配置已经存在!")}', self) return serial_name = str(int(datetime.datetime.now().timestamp())) os.mkdir(f'./config/{serial_name}') @@ -409,8 +411,8 @@ def onTabAddRequested(self): def onTabCloseRequested(self, i0): config_name = self._sub_list[0][i0].config["name"] - title = f'是否要删除配置:{config_name}?' - content = """你需要在确认后重启BAAS以完成更改。""" + title = self.tr('是否要删除配置:') + f' {config_name}?' + content = self.tr("""你需要在确认后重启BAAS以完成更改。""") closeRequestBox = MessageBox(title, content, self) if closeRequestBox.exec(): shutil.rmtree(f'./config/{self._sub_list[0][i0].config.config_dir}') @@ -444,6 +446,16 @@ def start(): QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps) app = QApplication(sys.argv) + + # internationalization + translator = FluentTranslator(bt.locale) + bt.load("gui/i18n/" + bt.stringLang) + + app.installTranslator(translator) + app.installTranslator(bt) + + bt.loadCfgTranslation() + w = Window() # 聚焦窗口 w.setFocus(True)