diff --git a/assets/flutter_i18n/s2cfbb.py b/assets/flutter_i18n/s2cfbb.py new file mode 100644 index 00000000..abb84f66 --- /dev/null +++ b/assets/flutter_i18n/s2cfbb.py @@ -0,0 +1,228 @@ +import yaml +import json +import pypinyin +from collections import OrderedDict +from copy import deepcopy +from random import randint +import re + +table_change_alphabet = { + "l": 1, + "o": 0, + "a": 4, + "e": 3, + "t": 7, + "i": 1, + "g": 9, + "q": 9, + "s": 5, +} + +abstract_table = { + 'wu': ['🈚', '⑤'], + 'fei': ['💴'], + 'da': ['🐘'], + 'kai': ['🔓'], + 'hui': ['🩶'], + 'yi': ['①', 'Ⅰ', '🥻', '➖'], + 'er': ['②', 'Ⅱ', '👂🏻'], + 'san': ['③', 'Ⅲ', '🌂', '🥪', '☘', '📐'], + 'si': ['④', 'Ⅳ', '似', '☠️'], + 'wu': ['⑤', 'Ⅴ', '🕺🏻'], + 'liu': ['⑥', 'Ⅵ'], + 'qi': ['⑦', 'Ⅶ', '🚴🏿'], + 'ba': ['⑧', 'Ⅷ', '👨🏻'], + 'jiu': ['⑨', 'Ⅸ', '🍷'], + 'shi': ['⑩', 'Ⅹ', '🪨', '💩'], + 'zhi': ['🈯', '☞', '🧻', '📃'], + 'chou': ['🚬'], + 'xiang': ['🐘'], + 'biao': ['⌚'], + 'de': ['🉐'], + 'niu': ['🐂'], + 'hu': ['🐅'], + 'ma': ['🐎'], + 'yang': ['🐏', '☀'], + 'hou': ['🐒'], + 'mo': ['👺'], + 'ji': ['🐔', '✈️'], + 'gou': ['🐕', '🐶'], + 'suan': ['🍋'], + 'ku': ['🆒', '😭', '🥲'], + 'le': ['🤣'], + 'she': ['🐍'], + 'zhu': ['🐖'], + 'long': ['🐉'], + 'zhong': ['🀄️'], + 'hua': ['🌸'], + 'fa:': ['🇫🇷'], + 'fang': ['◻️'], + 'ran': ['🔥'], + 'shu': ['📕', '🐀', '📖'], + 'ru': ['🧴'], + 'ben': ['📕', '📖'], + 'jiao': ['🦵', '🔈', '🎺', *['🗣'] * 3], + 'chong': ['🏄‍'], + 'bi': ['🖊'], + 'gao': ['⛏'], + 'suo': ['🔒'], + 'jian': ['➖'], + 'jing': ['🚨'], + 'dao': ['🔪'], + 'guai': ['🧞'], + 'shuo': ['🗣'], + 'deng': ['🟰', '🛋️'], + 'chu': ['÷', '➗️'], + 'cheng': ['×', '❌', '✖'], + 'jia': ['+', '➕', '⛽', '🏠'], + 'wu': ['🈚️'], + 'you': ['👉', '🈶'], + 'ce': ['🚻'], + 'cao': ['🌿'], + 'lang': ['🌊', '🐺'], + 'tu': ['🐇'], + 'cai': ['👎', '🥬'], + 'men': ['🚪'], + 'ju': ['🍊'], + 'nao': ['🧠'], + 'bu': ['⛔', '🚫', '🖐🏻'], + 'guo': ['🍎'], + 'he': ['⚛️'], + 'sheng': ['🔊'], + 'xian': ['🧵'], + 'mu': ['🤱🏻'], + 'ma': ['🤱🏻'], + 'shou': ['🖐🏻', '📻'], + 'zai': ['♻️'], + 'shang': ['👆'], + 'xia': ['👇'], + 'zuo': ['👈'], + 'xiao': ['🏫'], + 'hei': ['👨🏿'], + 'kong': ['🈳'], + 'guan': ['📴'], + 'qing': ['🌤'], + 'dong': ['🕳'], + 'yao': ['💊'], + 'kan': ['👀'], +} + +abstract_table_multi = { + '啥b': '😅', + '可可': '🍥🥹可可', + '0xcafebabe': '☕👶🏻', + 'cafebabe': '☕👶🏻', + '我': '👴', + 'luo': '🐕', + '信号': '📶', + 'xkm': '🐱', + '电脑': '💻', + '企鹅': '🐧', + '厕所': '🚻', + 'wc': '🚾', + '?': '❓', + '?': '❓', + '豆腐': '🧈', +} + +# 函数:在保留大括号内容的情况下转换字符串 +def conv2a3(raw: str) -> str: + # 查找所有大括号内容 + curly_brace_matches = re.findall(r'\{.*?\}', raw) + + # 大括号内容的临时占位符,使用特殊格式以避免冲突 + placeholder_template = "哈哈哈哈哈哈" + placeholders = {f"{placeholder_template.format(i)}": match for i, match in enumerate(curly_brace_matches)} + + # 用占位符替换大括号内容 + for i, match in enumerate(curly_brace_matches): + raw = raw.replace(match, placeholder_template.format(i)) + + # 对不含大括号内容的字符串进行转换 + for (i, v) in abstract_table_multi.items(): + raw = raw.replace(i, v) + pin_ = pypinyin.core.Pinyin() + aa = list(deepcopy(raw)) + a3 = pypinyin.lazy_pinyin(aa) + a3_copy = deepcopy(a3) + + for i, v in enumerate(a3): + if v in abstract_table.keys(): + ll = abstract_table[v] + a3[i] = ll[randint(0, len(ll) - 1)] + + for i in range(len(a3_copy)): + if a3_copy[i] == a3[i]: + a3[i] = aa[i] + + for i in range(len(a3)): + for j in range(len(a3[i])): + change = randint(1919, 114514) <= 88100 + change2 = randint(0, 20) <= 10 + if change2 and change and a3[i][j].lower() == 'o': + a3[i] = a3[i][:j] + '⭕️' + a3[i][j+1:] + continue + if change and a3[i][j].lower() in table_change_alphabet: + a3[i] = a3[i][:j] + str(table_change_alphabet[a3[i][j].lower()]) + a3[i][1+j:] + continue + + converted_string = "".join(a3) + + # 将大括号内容重新插入转换后的字符串中 + for placeholder, original in placeholders.items(): + converted_string = converted_string.replace(placeholder, original) + + return converted_string + +# 自定义 YAML 加载器,以保持使用 OrderedDict 的顺序 +class OrderedLoader(yaml.SafeLoader): + pass + +def construct_mapping(loader, node): + loader.flatten_mapping(node) + return OrderedDict(loader.construct_pairs(node)) + +OrderedLoader.add_constructor( + yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, + construct_mapping +) + +# 自定义 YAML 转储器,以在写入时保留 OrderedDict +class OrderedDumper(yaml.SafeDumper): + pass + +def dict_representer(dumper, data): + return dumper.represent_dict(data.items()) + +OrderedDumper.add_representer(OrderedDict, dict_representer) + +# 函数:在保持顺序的情况下修改 YAML 元数据值 +def modify_yaml(filename: str): + # 以 OrderedDict 的形式加载 YAML 文件以保留顺序 + with open(filename, 'r', encoding='utf-8') as file: + yaml_data = yaml.load(file, Loader=OrderedLoader) + + # 递归修改字典中的值 + def recursive_modify(data): + if isinstance(data, dict): + for key, value in data.items(): + data[key] = recursive_modify(value) + elif isinstance(data, list): + data = [recursive_modify(item) for item in data] + elif isinstance(data, str): + # 仅对字符串值应用 conv2a3 转换 + data = conv2a3(data) + return data + + modified_data = recursive_modify(yaml_data) + + # 将修改后的数据保存在新的YAML文件,保持原本的顺序 + with open(f"modified_{filename}", 'w', encoding='utf-8') as file: + json.dump(modified_data, file) + #yaml.dump(modified_data, file, allow_unicode=True, Dumper=OrderedDumper) + + print(f"Modified YAML saved as 'modified_{filename}'") + +if __name__ == '__main__': + filename = input("Enter the YAML file name: ") + modify_yaml(filename) \ No newline at end of file diff --git a/assets/flutter_i18n/s2twp.py b/assets/flutter_i18n/s2twp.py new file mode 100644 index 00000000..13a20603 --- /dev/null +++ b/assets/flutter_i18n/s2twp.py @@ -0,0 +1,51 @@ +import opencc +import yaml +from collections import OrderedDict + +converter = opencc.OpenCC('s2twp.json') + +# 自定义 Loader,使用 OrderedDict 读取 YAML 文件 +class OrderedLoader(yaml.SafeLoader): + pass + +def construct_mapping(loader, node): + loader.flatten_mapping(node) + return OrderedDict(loader.construct_pairs(node)) + +OrderedLoader.add_constructor( + yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, + construct_mapping +) + +# 读取 YAML 文件并保持顺序 +with open('zh_CN.yaml', 'r', encoding='utf-8') as file: + yaml_content = yaml.load(file, Loader=OrderedLoader) + +# 遍历 YAML 内容并转换 +def convert_yaml(content): + if isinstance(content, dict): + return OrderedDict((key, convert_yaml(value)) for key, value in content.items()) + elif isinstance(content, list): + return [convert_yaml(item) for item in content] + elif isinstance(content, str): + return converter.convert(content) # 转换字符串中的汉字 + else: + return content + +# 对 YAML 文件的内容进行转换 +converted_content = convert_yaml(yaml_content) + +# 自定义 Dumper,确保输出时保持顺序 +class OrderedDumper(yaml.SafeDumper): + pass + +def dict_representer(dumper, data): + return dumper.represent_dict(data.items()) + +OrderedDumper.add_representer(OrderedDict, dict_representer) + +# 将转换后的内容写入新的 YAML 文件,并保持顺序 +with open('zh_TW.yaml', 'w', encoding='utf-8') as file: + yaml.dump(converted_content, file, Dumper=OrderedDumper, allow_unicode=True) + +print("YAML 文件中的中文已经转换并保持了顺序!") diff --git a/assets/flutter_i18n/zh_CN.yaml b/assets/flutter_i18n/zh_CN.yaml new file mode 100644 index 00000000..2a9464a8 --- /dev/null +++ b/assets/flutter_i18n/zh_CN.yaml @@ -0,0 +1,565 @@ +# Copyright 2024 BenderBlog Rodriguez and contributors. +# SPDX-License-Identifier: MPL-2.0 + +# EasyRefresh 下拉插件的玩意 +drag_text: "上拉请求更多" +ready_text: "正在加载......" +processing_text: "正在加载......" +processed_text: "请求成功" +no_more_text: "数据没有更多" +failed_text: "数据获取失败更多" + +# 公共组件 +choose_semester: "选择学期" +error_detected: "Ouch! 发生错误啦" +click_to_refresh: "点我刷新" + +# 取消和确定 +confirm_title: "确认对话框" +cancel: "取消" +confirm: "确定" + +# controller/model 里面可能需要给用户展示的 +network_error: "网络错误,可能是没联网,可能是学校服务器出现了故障:-P" +error_detect: "遇到错误: {e}" +query_failed: "查询失败" +not_school_network: "没有在校园网环境" +experiment_controller: + no_password: "没有物理实验密码" + login_failed: "登录失败" +cancel_exam: "取消考试资格:P" +electricity_session: + fetching: "正在获取" + not_school_network: "非校园网" + network_problem: "网络故障" + query_failed: "查询失败" + program_crash: "程序故障" +login_process: + ready_page: "准备获取登录网页" + get_encrypt: "获取密码加密密钥" + ready_login: "准备登录" + slider: "滑块验证" + after_process: "登录后处理" + failed: "登录失败,响应状态码:{statusCode}" +# TODO: ehall_exam_session data + +# main.dart 里面 Catcher 插件字符串 +catcher_detected: "发生错误" +catcher_description: "详情如下" + +# 日程表/课程表 +classtable: + weekday: + monday: "周一" + tuesday: "周二" + wednesday: "周三" + thursday: "周四" + friday: "周五" + saturday: "周六" + sunday: "周日" + partner_classtable: + override_dialog: "目前有搭子课表数据,是否要覆盖?" + no_file: "未发现导入文件" + no_permission: "未获取存储权限,无法读取文件" + problem: "好像导入文件有点问题:P" + success: "导入成功" + share_dialog: + title: "请不要随意分享" + content: "导出文件包括你的个人信息,请不要随意跟别人分享,或者发在大群里。" + save_dialog: + title: "保存日历文件到..." + success_message: "应该保存成功" + failure_message: "文件创建失败,保存取消" + delete_dialog: + title: "确认对话框" + message: "确定要清除共享课表吗?" + success_message: "删除共享课表成功" + page_title: "我的日程表" + partner_page_title: "搭子的日程表" + popup_menu: + not_arranged: "查看未安排课程信息" + class_changed: "查看课程安排调整信息" + add_class: "添加课程信息" + generate_ical: "生成日历文件" + generate_partner_file: "生成共享课表文件" + import_partner_file: "导入共享课表文件" + delete_partner_file: "删除共享课表文件" + class_change_page: + title: "课程调整" + empty_message: "目前没有调课信息" + teacher_change: "从{previous_teacher}变为{new_teacher}" + no_teacher_change: "教师信息没有改变" + 1: "一" + 2: "二" + 3: "三" + 4: "四" + 5: "五" + 6: "六" + 7: "日" + change_class_message: 调课信息,从第{originalAffectedWeeks}周 + 星期{weekChar_originalWeek}的{originalClassRangeStart}-{originalClassRangeEnd}节 + 调整为第{newAffectedWeeksListStr}周星期{weekChar_newWeek}的 + {newClassRangeStart}-{newClassRangeStop}节,{newClassroom}教室上课 + patch_class_message: 补课信息,从第{newAffectedWeeksListStr}周 + 星期{weekChar_newWeek}的{newClassRangeStart}-{newClassRangeStop}节, + {newClassroom}补课 + stop_class_message: 停课信息,第{originalAffectedWeeks}周 + 星期{weekChar_originalWeek}的{originalClassRangeStart}-{originalClassRangeEnd}节 + {originalClassroom}停课 + class_info: "编号: {classCode} | {classNumber} 班\n安排变更:{classChange}\n{teacherChange}" + not_arranged_page: + title: "没有时间安排的科目" + empty_message: "目前全部课程均有时间安排" + content: "编号: {classCode} | {classNumber} 班\n老师: {teacher}" + empty_class_message: "{semester_code} 学期没有课程" + week_title: "第{week}周" + noon_break: "午休" + supper_break: "晚休" + class_card: + title: "日程信息" + unknown_classroom: "未知教室" + remains_hint: "还有{remain_count}个日程" + class_add: + add_class_title: "添加课程" + change_class_title: "修改课程" + class_name_empty_message: "必须输入课程名" + wrong_time_message: "输入的时间不对" + save_button: "保存" + input_classname_hint: "课程名字(必填)" + input_teacher_hint: "老师姓名(选填)" + input_classroom_hint: "教室位置(选填)" + input_week_hint: "选择上课周次" + input_time_hint: "选择上课时间" + input_time_weekday_hint: "上课周次" + input_start_time_hint: "上课时间段" + input_end_time_hint: "下课时间段" + wheel_choose_hint: "第 {index} 节" + course_detail_card: + class_number_string: "{number} 班" + unknown_teacher: "老师未定" + unknown_place: "地点未定" + class_period: "{start}-{stop}节" + edit: "编辑" + delete: "删除" + delete_title: "是否删除课程信息?" + delete_content: "所有关于这个课的信息都会被删除,课表上关于这门课的信息将不复存在!" + +# 双创信息 +creative_job: + search_hint: "搜索需求" + choice_type: "选择种类" + position_type: "职位类型" + no_result: "没有搜索到结果" + please_search: "请在上面搜索框搜索" + query_for_person: "招募 {exceptNumber} 人 · " + end_time: "截止日期 {endTime}" + complete_choosing: "选择完毕" + job_description: "工作详情" + browser_hint: "如果用户感兴趣,请按右上角的按钮在浏览器中打开" + job_description_title: "岗位描述" + reward_title: "工作回报" + progress_title: "项目进度" + no_description: "没有描述" + +# 空闲教室 +empty_classroom: + title: "空闲教室" + date: "日期 {date}" + building: "教学楼 {building}" + search_hint: "教室名称或者教室代码" + classroom: "教室" + +# 考试信息 +exam: + title: "考试安排" + cache_hint: "已显示缓存考试安排信息" + not_finished: "未完成考试" + all_finished: "所有考试全部完成" + unable_to_exam: "无法完成考试" + finished: "已完成考试" + none_finished: "一门还没考呢" + no_exam_arrangement: "目前没有考试安排" + no_arrangement: + title: "目前无安排考试的科目" + all_arranged: "目前所有科目均已安排考试" + subtitle: "编号: {id}" + +# 物理实验 +experiment: + title: "物理实验" + ongoing: "正在进行实验" + not_finished: "未完成实验" + all_finished: "所有实验全部完成" + finished: "已完成实验" + score_sum: "目前分数总和:{sum}" + none_finished: "目前没有已经完成的实验" + not_provided: "未提供" + +# 主页 +homepage: + time_string: + morning: "早上好 准备出发" + before_noon: "上午好 祝万事如意" + at_noon: "中午好 一切还好吧" + afternoon: "下午好 今天如何" + night: "晚上好 祝你好梦" + midnight: "深宵了 我在陪你" + loading: "正在加载" + load_error: "加载错误" + on_holiday: "假期中" + on_weekday: "第 ${current} 周" + loading_message: "请稍候,正在刷新信息" + homepage: "主页" + planet: "博客星球" + setting: "设置" + input_partner_data: + route_not_exist: "导入路径不存在:P" + failed_get_file: "导入文件失败" + failed_import: "好像导入文件有点问题:P" + success_message: "导入成功,如果打开了课表页面请重新打开" + not_loaded: "还没加载课程表,等会再来吧……" + confirm_content: "目前有搭子课表数据,是否要覆盖?" + login_message: "登录中,暂时显示缓存数据" + successful_login_message: "登录成功" + password_wrong_title: "用户名或密码有误" + password_wrong_content: "是否重启应用后手动登录?" + password_wrong_denial: "否,进入离线模式" + offline_mode_title: "统一认证服务离线模式开启" + offline_mode_content: + "无法连接到统一认证服务服务器,所有和其相关的服务暂时不可用。 + 成绩查询,考试信息查询,欠费查询,校园卡查询关闭。课表显示缓存数据。其他功能暂不受影响。 + 如有不便,敬请谅解。" + offline_mode: "脱机模式下,一站式相关功能全部禁止使用" + notice_card: + empty_notice: "目前没有获取应用公告,请刷新" + no_notice_avaliable: "没有获取应用公告" + notice_list_title: "应用信息" + open_url: "访问该链接" + notice_page_title: "通知列表" + class_table_card: + current: "当前" + tomorrow: "明天" + later: "稍后" + more: "更多" + error_message: "遇到错误:{error}" + fetching_message: "正在获取课表" + error_infoText: "遇到错误" + fetching_infoText: "正在加载" + no_arrangement_infoText: "暂无日程" + electricity_card: + title: "电量信息" + current_electricity: "目前电量 " + kwh: " 度" + dialog_title: "水电信息" + dialog_content: "电费帐号:{account} + 电量信息:{value} {electricityInfo} + 欠费信息:{owe_value} + 长按可以重新加载,有欠费一般代表水费" + library_card: + title: "图书借阅" + current_borrow: "目前借书 " + unit_of_book: " 本" + error_occured: "获取借书信息发生错误" + fetching: "正在获取借书信息" + no_return: "目前没有待归还书籍" + need_return: "待归还{dued}本书籍" + no_info: "目前无法获取信息" + fetching_info: "正在查询信息中" + school_card_info_card: + error_toast: "遇到错误,请联系开发者" + fetching_toast: "正在获取信息,请稍后再来看" + bill: "流水" + balance: "校园卡余额 " + unit: " 元" + error_occured: "获取校园卡信息发生错误" + fetching: "正在获取校园卡信息" + bottom_text_success: "查询一卡通流水" + no_info: "目前无法获取信息" + fetching_info: "正在查询信息中" + toolbox: + creative: "双创竞赛" + empty_classroom: "空闲教室" + exam: "考试安排" + experiment: "物理实验" + score: "成绩查询" + sport: "体育信息" + toolbox: "其他功能" + score_cannot_reach: "脱机状态且无缓存成绩数据,无法访问" + exam_fetching: "请稍候,正在获取考试信息" + exam_error: "遇到错误,请联系开发者" + +# 图书馆 +library: + title: "图书馆信息" + borrow_state_title: "借书状态" + search_book_title: "查询藏书" + not_provided: "未提供相关信息" + author: "作者 " + publish_house: "出版社 " + call_number: "索书号 " + publish_date: "发行时间 " + isbn: "ISBN" + arrangement_code: "编排号码 " + avaliable_borrow: "可借" + storage: "馆藏" + on_shelve: "在架" + book_code: "书籍编号:{barCode}" + due_date: " 到期" + borrow_str: " 借阅" + after_due_date: " 天前到期" + before_due_date: " 天后" + can_be_renewable: "续借" + cannot_be_renewable: "不可续借" + renewing: "正在续借" + empty_borrow_list: "目前没有查询到在借图书\n不借书就要变成上面的小呆瓜咯" + borrow_list_info: "在借 {borrow} 本,其中已过期 {dued} 本" + search_book_window: + search_here: "在此搜索" + book_detail: "书籍详细信息" + no_result: "没有结果" + please_search: "请在上面搜索框搜索" + +# 登录界面 +login: + identity_number: "学号" + password: "一站式登录密码" + login: "登录" + incorrect_password_pattern: "用户名或密码不符合要求,学号必须 11 位且密码非空" + on_login_progress: "正在登录学校一站式" + complete_login: "登录成功" + failed_login_cannot_connect_to_server: "无法连接到服务器" + failed_login_with_code: "请求失败,响应状态码:{code}" + failed_login_with_message: "请求失败,报错信息:{message}" + failed_login_other: "未知错误,请联系开发者" + clear_cache: "清除登录缓存" + complete_clear_cache: "清理缓存成功" + see_inspector: "查看网络交互" + captcha_window: + title: "请输入验证码" + hint: "输入验证码" + message_on_empty: "请输入验证码" + slider_title: "服务器认证服务" + +# 校园卡流水 +school_card_window: + title: "校园卡流水信息" + income: "支出 {income}" + expense: "收入 {expense}" + select_range: "选择日期:从 {startDay} 到 {endDay}" + store_name: "商户名称" + balance: "金额" + time_with_sum: "时间(共{sum}元)" + +# 成绩 +score: + title: "成绩查询" + cache_message: "已显示缓存成绩信息" + # TODO:string in eval detected + all_semester: "所有学期" + chosen_semester: "学期 {chosen}" + all_type: "所有类型" + chosen_type: "类型 {type}" + score_choice: + title: "成绩单" + search_hint: "搜索成绩记录" + empty_list: "没有选择该学期的课程计入均分计算" + sum_dialog: + title: "小总结" + content: 所有科目的GPA:{gpa_all} + 所有科目的均分:{avg_all} + 所有科目的学分:{credit_all} + 未通过科目:{unpassed} + 公共选修课已经修得学分:{not_core_credit} + 本程序提供的数据仅供参考,开发者对其准确性不负责 + score_compose_card: + no_detail: "未提供详情信息" + fetching: "正在获取" + credit: "学分" + gpa: "GPA" + score: "成绩" + score_info_card: + title: "成绩详情" + original_course: "初修" + failed: "[挂] " + credit: "学分 {credit}" + gpa: "GPA {gpa}" + score: "成绩 {score}" + score_page: + title: "成绩查询" + search_hint: "搜索成绩记录" + no_record: "未筛查到合请求的记录" + select_all: "全选" + select_nothing: "全不选" + reset_select: "重置选择" + # 也许没用 + CET-4: "国家英语四级" + CET-6: "国家英语六级" + +# 设置 +setting: + # 最顶部 + about: "关于" + about_this_program: "关于本程序" + version: "版本号:{version_code}" + user_info: "用户信息" + # 界面设置 + ui_setting: "界面设置" + brightness_setting: "设置深浅色" + simplify_timeline: "简化日程时间轴" + simplify_timeline_description: "没有日程时 减少空间占用" + # 账号设置 + account_setting: "账号设置" + sport_password_setting: "体育系统密码设置" + experiment_password_setting: "物理实验系统密码设置" + electricity_password_setting: "电费帐号密码设置" + electricity_password_description: "非 123456 请设置" + # 课表相关设置 + classtable_setting: "课表相关设置" + background: "开启课表背景图" + no_background: "你先选个图片罢,就在下面" + choose_background: "课表背景图选择" + no_permission: "未获取存储权限,无法读取文件" + successful_setting: "设定成功" + failure_setting: "你没有选图片捏" + clear_user_class: "清除所有用户添加课程" + clear_user_class_dialog: + title: "确认对话框" + content: "是否要清除所有用户添加课程?这个功能对从学校获取的日程没有影响。" + clear: "已经清除完毕" + class_refresh: "强制刷新课表" + class_refresh_dialog: + title: "确认对话框" + content: "是否要强制刷新课表?同意后,将会从学校一站式后端重新获取课表,耗时会比较久。" + class_swift: "课程偏移设置" + class_swift_description: "正数错后开学日期 负数提前开学日期\n目前为 {swift}" + # 缓存登录设置 + core_setting: "缓存登录设置" + check_catcher: "测试错误拦截器" + check_logger: "查看网络拦截器和日志" + clear_and_restart: "清除缓存后重启" + clear_and_restart_dialog: + title: "确认对话框" + content: "确定清除缓存后重启程序?" + cleaning: "正在清理缓存" + clear: "缓存已被清除" + logout: "退出登录并重启应用" + logout_dialog: + title: "确认对话框" + content: "确定退出登录?你的所有数据将会被彻底删除!" + logging_out: "正在退出登录" + need_close_dialog: + title: "请关闭应用" + content: "因为技术限制,用户需要自行关闭窗口,然后重新打开应用。" + # 剩下乱七八糟的窗口 + change_brightness_dialog: + title: "颜色设置" + follow_setting: "跟随系统" + day_mode: "白天模式" + night_mode: "黑夜模式" + change_swift_dialog: + title: "课程偏移设置" + input_hint: "请在此输入数字" + change_electricity_title: "修改电费帐号密码" + change_experiment_title: "修改物理实验账号密码" + change_sport_title: "修改体育系统账号密码" + change_password_dialog: + input_hint: "请在此输入密码" + blank_input: "输入空白!" + easter_egg_page: + title: "你找到了彩蛋" + encrypt: "加密上面的文本" + listen: "听歌时间" + about_page: + benderblog: "主要开发者,iOS 小部件编写和拼接" + bellssgit: "支持:最佳&最久故障反馈者" + brackrat: "设计:主页,登录页,配色,iOS 小部件等" + breezeline: "支持:无价值无意义的产品经理(他自己的描述)" + cafebabe: “支持:提供彩蛋代码" + chitao1234: "开发:修复滑块不对齐问题" + dimole: "支持:辅助修复滑块问题" + elitewars: "设计:体育成绩页面" + godhu777777: "支持:繁体中文转换代码和彩蛋代码" + hancl777: "支持:繁体中文转换代码" + hhzm: "支持:提供彩蛋代码" + lsy223622: "设计:iOS 图标" + nancunchild: "开发:图书馆搜索功能" + pairman: "开发:成绩缓存功能和优化滑块算法" + reverierxu: "设计:用于信息展示的 ReX 卡片" + ray: "设计:开屏画面 / 支持:iOS 发行商 & 搭子课表" + shadowyingyi: "支持:两次鸽子公众号宣传" + stalomeow: "设计:首页时间轴 / 开发:异步登录" + xeonds: "设计:设置页面 / 开发:XDU Planet" + xiue233: "开发:Android 小部件和拼接" + zcwzy: "开发:修复丁香电费 / 支持:研究生版本开发" + homepage: "主页" + code: "开源代码" + know_more: "知道更多" + copyright_notice: + 本软件拷贝基于 traintime_pda 代码(或称 watermeter 代码)编译, + 代码按照 Mozilla Public License, v. 2.0 授权。 + 本程序和西安电子科技大学,体适能服务,书蜗,电表等服务无关。 + Copyright 2023-Present BenderBlog Rodriguez and contributors. + The Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. + If a copy of the MPL was not distributed with this file, + You can obtain one at https://mozilla.org/MPL/2.0/. + beian: "备案号" + sign_android: "安卓签名" + title: "关于本软件" + +# 体育查询 +sport: + fetching: "正在获取" + error: "坏事: {situation}" + title: "体育查询" + class_info: "课程信息" + test_score: "体测成绩" + # TODO: change sport score to support i18n + total_score: "四年总分" + semester: "{year} 第{gradeType}" + subject: "项目" + data: "数据" + score: "分数" + passed: "及格" + score_string: "{score}分" + +# 其他功能 +toolbox: + title: "其他功能" + payment: "缴费系统" + payment_description: "电费该交了吧" + repair: "后勤报修" + repair_description: "不要漏水断网" + reserve: "空间预约" + reserve_description: "找个地方打牌" + mobile: "移动门户" + mobile_description: "请假专用门户" + network: "网络查询" + network_description: "希望永不收费" + physics: "物理计算" + physics_description: "希望操作顺利" + discover: "睿思导航" + discover_description: "补充其他功能" + +# XDU Planet +xdu_planet: + # TODO:string in eval detected + all: "全部" + loading: "加载中,请稍等 <(=ω=)>" + unknown_author: "未知作者" + load_failed: "文章加载失败,如有需要可以点击右上方的按钮在浏览器里打开。" + no_comment: "暂无评论" + reply_audit: "回复评论 #{reply_to} 已被举报或删除" + reply: "回复评论 #{reply_to}:{content}" + have_been_audit: "本评论已经被举报" + audit: "举报" + confirm_audit_dialog: + title: "确认是否举报" + content: "三思而后行,确定您想举报吗?举报后该评论会有标签,不一定会删除。" + ongoing: "正在举报评论" + failed: "举报失败" + success: "举报成功" + comment: "回复" + comment_success: "评论成功" + comment_failed: "评论失败,请去网络查看器和日志查看器查看报错" + comment_canceled: "没想好要说啥嘛" + comment_loading: "加载评论中……" diff --git a/assets/flutter_i18n/zh_SG.yaml b/assets/flutter_i18n/zh_SG.yaml new file mode 100644 index 00000000..f525b31f --- /dev/null +++ b/assets/flutter_i18n/zh_SG.yaml @@ -0,0 +1,509 @@ +drag_text: 👆拉🌤求更多 +ready_text: 正♻️🏠♻️...... +processing_text: 正♻️➕♻️...... +processed_text: 🌤求×功 +no_more_text: 📕🍊没🈶更多 +failed_text: 🐀🍊获取⑩败更多 +choose_semester: 选择学🚴🏿 +error_detected: 0uch! 发🔊错🈚️啦 +click_to_refresh: 点👴刷新 +confirm_title: 确认对🌸框 +cancel: 取🏫 +confirm: 确定 +network_error: 网络错🈚️,可能💩没联网,可能💩学🏫服🈚️Ⅶ➗️🧵🤣故障:-P +error_detect: '遇🔪错🈚️: {e}' +query_failed: 查询💩败 +not_school_network: 没👉♻️🏫园网环🚨 +experiment_controller: + no_password: 没🈶🈚️理🪨验密🤱🏻 + login_failed: 🟰录💩败 +cancel_exam: 取🏫考🪨资格:P +electricity_session: + fetching: 正♻️获取 + not_school_network: 💴🏫园网 + network_problem: 网络故障 + query_failed: 查询🪨败 + program_crash: ×序故障 +login_process: + ready_page: 准备获取🛋️录网页 + get_encrypt: 获取密🤱🏻+密密💊 + ready_login: 准备🛋️录 + slider: 🌸块验证 + after_process: 🟰录🐒÷理 + failed: 🟰录💩败,🐘应状态🤱🏻:{statusCode} +catcher_detected: 发🔊错🈚️ +catcher_description: 🐘🌤🧴👇 +classtable: + weekday: + monday: 周🥻 + tuesday: 周Ⅱ + wednesday: 周🥪 + thursday: 周☠️ + friday: 周🈚️ + saturday: 周Ⅵ + sunday: 周日 + partner_classtable: + override_dialog: 🤱🏻前👉🐘子课⌚📖🍊,⑩否💊覆盖❓ + no_file: 未发🧵🔪🧴文➖ + no_permission: 未获取存➗️权🧵,🈚️法读取文➖ + problem: 好🐘🔪🧴文➖🈶点问题:P + success: 🔪🧴×功 + share_dialog: + title: 🌤🖐🏻💊随①分🐘 + content: 🔪➗️文➖包括你🉐个人信息,🌤🚫💊随➖跟别人分🐘,或者发♻️🐘群里。 + save_dialog: + title: 保存日历文➖🔪... + success_message: 应该保存×功 + failure_message: 文➖创➖💩败,保存取🏫 + delete_dialog: + title: 确认对🌸框 + message: 确定💊🌤÷共🐘课⌚🤱🏻❓ + success_message: 删➗️共🐘课⌚×功 + page_title: 👴🉐日×⌚ + partner_page_title: 🐘子🉐日×⌚ + popup_menu: + not_arranged: 查👀未安排课✖信息 + class_changed: 查👀课❌安排调整信息 + add_class: 添+课×信息 + generate_ical: 🔊×日历文➖ + generate_partner_file: 🔊❌共🐘课⌚文➖ + import_partner_file: 🔪🧴共🐘课⌚文➖ + delete_partner_file: 删÷共🐘课⌚文➖ + class_change_page: + title: 课✖调整 + empty_message: 🤱🏻前没🈶调课信息 + teacher_change: 从{new_teacher}变为{new_teacher} + no_teacher_change: 🎺💩信息没👉改变 + 1: ① + 2: 👂🏻 + 3: ③ + 4: ④ + 5: 🈚️ + 6: ⑥ + 7: 日 + change_class_message: 调课信息,从第{newClassroom}周 星⑦{newClassroom}🉐{newClassroom}-{newClassroom}节 + 调整为第{newClassroom}周星🚴🏿{newClassroom}🉐 {newClassroom}-{newClassroom}节,{newClassroom}🔈⑩👆课 + patch_class_message: 🚫课信息,从第{newClassroom}周 星⑦{newClassroom}🉐{newClassroom}-{newClassroom}节, + {newClassroom}⛔课 + stop_class_message: 停课信息,第{originalClassroom}周 星🚴🏿{originalClassroom}🉐{originalClassroom}-{originalClassroom}节 + {originalClassroom}停课 + class_info: '编号: {teacherChange} | {teacherChange} 班 + + 安排变更:{teacherChange} + + {teacherChange}' + not_arranged_page: + title: 没👉Ⅹ➖安排🉐科🤱🏻 + empty_message: 🤱🏻前全🖐🏻课❌均🈶⑩➖安排 + content: '编号: {teacher} | {teacher} 班 + + 老🪨: {teacher}' + empty_class_message: '{semester_code} 学🚴🏿没🈶课✖' + week_title: 第{week}周 + noon_break: 🈚️休 + supper_break: 晚休 + class_card: + title: 日✖信息 + unknown_classroom: 未🧻🗣💩 + remains_hint: 还🈶{remain_count}个日× + class_add: + add_class_title: 添➕课× + change_class_title: 修改课× + class_name_empty_message: 🖊须🐀🧴课×名 + wrong_time_message: 📖🧴🉐💩➖⛔对 + save_button: 保存 + input_classname_hint: 课×名字(🖊填) + input_teacher_hint: 老⑩姓名(选填) + input_classroom_hint: 🗣🪨位📃(选填) + input_week_hint: 选择👆课周次 + input_time_hint: 选择👆课🪨➖ + input_time_weekday_hint: 👆课周次 + input_start_time_hint: 👆课💩➖段 + input_end_time_hint: 👇课🪨➖段 + wheel_choose_hint: 第 {index} 节 + course_detail_card: + class_number_string: '{number} 班' + unknown_teacher: 老🪨未定 + unknown_place: 地点未定 + class_period: '{stop}-{stop}节' + edit: 编✈️ + delete: 删➗️ + delete_title: 🪨否删➗️课✖信息❓ + delete_content: 🔒🈶📴于这个课🉐信息都🩶被删÷,课⌚👆📴于这🚪课🉐信息将⛔复存♻️! +creative_job: + search_hint: 搜🔒需求 + choice_type: 选择🀄️类 + position_type: ☞位类型 + no_result: 没🈶搜🔒🔪结🍎 + please_search: 🌤♻️👆面搜🔒框搜🔒 + query_for_person: '招🤱🏻 {exceptNumber} 人 · ' + end_time: 截🈯日⑦ {endTime} + complete_choosing: 选择完🖊 + job_description: 工👈🐘🌤 + browser_hint: 🧴🍎用🐅感兴趣,🌤按👉👆🗣🉐按🐂♻️⑥览🚴🏿🀄️🐘🔓 + job_description_title: 岗位描🐀 + reward_title: 工👈🩶报 + progress_title: 🐘🤱🏻进度 + no_description: 没👉描🐀 +empty_classroom: + title: 🈳🧵🗣💩 + date: 日⑦ {date} + building: 🎺学楼 {building} + search_hint: 🦵💩名×或者🗣💩代🤱🏻 + classroom: 🦵⑩ +exam: + title: 考🪨安排 + cache_hint: 🥻🧵🪨缓存考💩安排信息 + not_finished: 未完✖考⑩ + all_finished: 🔒🈶考⑩全🖐🏻完✖ + unable_to_exam: 🈚️法完❌考⑩ + finished: ➖完❌考Ⅹ + none_finished: 🥻🚪还没考呢 + no_exam_arrangement: 🤱🏻前没🈶考🪨安排 + no_arrangement: + title: 🤱🏻前🈚️安排考🪨🉐科🤱🏻 + all_arranged: 🤱🏻前🔒🈶科🤱🏻均➖安排考⑩ + subtitle: '编号: {id}' +experiment: + title: 🈚️理🪨验 + ongoing: 正♻️进行Ⅹ验 + not_finished: 未完✖⑩验 + all_finished: 🔒🈶Ⅹ验全🚫完❌ + finished: Ⅰ完❌💩验 + score_sum: 🤱🏻前分🐀总⚛️:{sum} + none_finished: 🤱🏻前没🈶➖🚨完❌🉐⑩验 + not_provided: 未提供 +homepage: + time_string: + morning: 早👆好 准备➗️发 + before_noon: 👆🈚️好 🐖万Ⅹ🧴Ⅰ + at_noon: 🀄️🈚️好 ①切还好⑧ + afternoon: 👇🈚️好 今天🧴⚛️ + night: 晚👆好 🐖你好梦 + midnight: 深🏫🤣 👴♻️陪你 + loading: 正♻️🏠♻️ + load_error: ⛽♻️错🈚️ + on_holiday: +🚴🏿🀄️ + on_weekday: 第 ${current} 周 + loading_message: 🌤稍🐒,正♻️刷新信息 + homepage: 🐖页 + planet: 博客星球 + setting: 🐍🧻 + input_partner_data: + route_not_exist: 🔪🧴路🚨🚫存♻️:P + failed_get_file: 🔪🧴文➖Ⅹ败 + failed_import: 好🐘🔪🧴文➖👉点问题:P + success_message: 🔪🧴×功,🧴🍎🐘🔓🤣课⌚页面🌤🀄️新🐘🔓 + not_loaded: 还没⛽♻️课❌⌚,🟰🩶♻️来⑧…… + confirm_content: 🤱🏻前👉🐘子课⌚📕🍊,Ⅹ否💊覆盖❓ + login_message: 🛋️录🀄️,暂💩🧵🪨缓存📖🍊 + successful_login_message: 🟰录❌功 + password_wrong_title: 用🐅名或密🤱🏻🈶🈚️ + password_wrong_content: ⑩否🀄️🚴🏿应用🐒🖐🏻🕳🛋️录❓ + password_wrong_denial: 否,进🧴离🧵👺🪨 + offline_mode_title: 统Ⅰ认证服🈚️离🧵👺Ⅹ🔓Ⅶ + offline_mode_content: 🈚️法连接🔪统Ⅰ认证服🈚️服🈚️🚴🏿,🔒🈶⚛️Ⅶ🐘📴🉐服🈚️暂🪨🖐🏻可用。 ×✈️查询,考💩信息查询,欠💴查询,🏫园卡查询📴🖊。课⌚🧵⑩缓存🐀🍊。Ⅶ他功能暂🚫🖐🏻影🐘。 + 🧴🈶🖐🏻便,🚨🌤谅解。 + offline_mode: 脱✈️👺Ⅹ👇,➖站Ⅹ🐘📴功能全🖐🏻禁📃🪨用 + notice_card: + empty_notice: 🤱🏻前没🈶获取应用公⛏,🌤刷新 + no_notice_avaliable: 没🈶获取应用公⛏ + notice_list_title: 应用信息 + open_url: ◻️问该链接 + notice_page_title: 通🈯列⌚ + class_table_card: + current: 当前 + tomorrow: 明天 + later: 稍🐒 + more: 更多 + error_message: 遇🔪错🈚️:{error} + fetching_message: 正♻️获取课⌚ + error_infoText: 遇🔪错🈚️ + fetching_infoText: 正♻️⛽♻️ + no_arrangement_infoText: 暂🈚️日× + electricity_card: + title: 电量信息 + current_electricity: '🤱🏻前电量 ' + kwh: ' 度' + dialog_title: 水电信息 + dialog_content: 电💴帐号:{owe_value} 电量信息:{owe_value} {owe_value} 欠💴信息:{owe_value} + 长按可🥻🀄️新➕♻️,👉欠💴Ⅰ般代⌚水💴 + library_card: + title: 🐇📕借阅 + current_borrow: '🤱🏻前借📕 ' + unit_of_book: ' 📖' + error_occured: 获取借📖信息发🔊错🈚️ + fetching: 正♻️获取借📕信息 + no_return: 🤱🏻前没👉待归还🐀🐔 + need_return: 待归还{dued}📖📕✈️ + no_info: 🤱🏻前🈚️法获取信息 + fetching_info: 正♻️查询信息🀄️ + school_card_info_card: + error_toast: 遇🔪错🈚️,🌤联系🔓发者 + fetching_toast: 正♻️获取信息,🌤稍🐒♻️来👀 + bill: Ⅵ水 + balance: '🏫园卡余额 ' + unit: ' 元' + error_occured: 获取🏫园卡信息发🔊错🈚️ + fetching: 正♻️获取🏫园卡信息 + bottom_text_success: 查询➖卡通Ⅵ水 + no_info: 🤱🏻前🈚️法获取信息 + fetching_info: 正♻️查询信息🀄️ + toolbox: + creative: 双创🚨赛 + empty_classroom: 🈳🧵🗣🪨 + exam: 考💩安排 + experiment: 🈚️理💩验 + score: ✖🐔查询 + sport: 体育信息 + toolbox: Ⅶ他功能 + score_cannot_reach: 脱✈️状态且🈚️缓存✖✈️🐀🍊,🈚️法◻️问 + exam_fetching: 🌤稍🐒,正♻️获取考Ⅹ信息 + exam_error: 遇🔪错🈚️,🌤联系🔓发者 +library: + title: 🐇🐀📴信息 + borrow_state_title: 借📖状态 + search_book_title: 查询藏🐀 + not_provided: 未提供🐘📴信息 + author: '👈者 ' + publish_house: '➗️版🐍 ' + call_number: '🔒📕号 ' + publish_date: '发行🪨➖ ' + isbn: I5BN + arrangement_code: '编排号🤱🏻 ' + avaliable_borrow: 可借 + storage: 📴藏 + on_shelve: ♻️🏠 + book_code: 📖🐔编号:{barCode} + due_date: ' 🔪Ⅶ' + borrow_str: ' 借阅' + after_due_date: ' 天前🔪Ⅶ' + before_due_date: ' 天🐒' + can_be_renewable: 续借 + cannot_be_renewable: 🖐🏻可续借 + renewing: 正♻️续借 + empty_borrow_list: '🤱🏻前没👉查询🔪♻️借🐇🐀 + + ⛔借📕Ⅸ💊变❌👆面🉐🏫呆瓜咯' + borrow_list_info: ♻️借 {dued} 📕,🚴🏿🀄️①🍎🚴🏿 {dued} 📕 + search_book_window: null + search_here: ♻️此搜🔒 + book_detail: 🐀🐔🐘细信息 + no_result: 没🈶结🍎 + please_search: 🌤♻️👆面搜🔒框搜🔒 +login: + identity_number: 学号 + password: ➖站⑩🟰录密🤱🏻 + login: 🛋️录 + incorrect_password_pattern: 用🐅名或密🤱🏻🖐🏻符⚛️💊求,学号🖊须 11 位且密🤱🏻💴🈳 + on_login_progress: 正♻️🛋️录学🏫➖站💩 + complete_login: 🛋️录❌功 + failed_login_cannot_connect_to_server: 🈚️法连接🔪服🈚️🚴🏿 + failed_login_with_code: 🌤求🪨败,🐘应状态🤱🏻:{code} + failed_login_with_message: 🌤求⑩败,报错信息:{message} + failed_login_other: 未📃错🈚️,🌤联系🔓发者 + clear_cache: 🌤➗️🛋️录缓存 + complete_clear_cache: 🌤理缓存❌功 + see_inspector: 查👀网络🦵🐅 + captcha_window: + title: 🌤📖🧴验证🤱🏻 + hint: 📕🧴验证🤱🏻 + message_on_empty: 🌤📕🧴验证🤱🏻 + slider_title: 服🈚️Ⅶ认证服🈚️ +school_card_window: + title: 🏫园卡Ⅵ水信息 + income: 🧻÷ {income} + expense: 🖐🏻🧴 {expense} + select_range: 选择日⑦:从 {endDay} 🔪 {endDay} + store_name: 👆🐅名✖ + balance: 金额 + time_with_sum: ⑩➖(共{sum}元) +score: + title: ×✈️查询 + cache_message: ①🧵🪨缓存✖✈️信息 + all_semester: 🔒🈶学Ⅶ + chosen_semester: 学🚴🏿 {chosen} + all_type: 🔒🈶类型 + chosen_type: 类型 {type} + score_choice: + title: ×🐔单 + search_hint: 搜🔒❌✈️✈️录 + empty_list: 没🈶选择该学Ⅶ🉐课❌🐔🧴均分✈️🍋 + sum_dialog: + title: 🏫总结 + content: 🔒🈶科🤱🏻🉐9P4:{not_core_credit} 🔒👉科🤱🏻🉐均分:{not_core_credit} 🔒🈶科🤱🏻🉐学分:{not_core_credit} + 未通🍎科🤱🏻:{not_core_credit} 公共选修课①🚨修🉐学分:{not_core_credit} 📖❌序提供🉐📖🍊仅供参考,🔓发者对Ⅶ准确性⛔负责 + score_compose_card: + no_detail: 未提供🐘🌤信息 + fetching: 正♻️获取 + credit: 学分 + gpa: 9P4 + score: ✖🐔 + score_info_card: + title: ❌🐔🐘🌤 + original_course: ➗️修 + failed: '[挂] ' + credit: 学分 {credit} + gpa: 9P4 {gpa} + score: ❌✈️ {score} + score_page: + title: ×🐔查询 + search_hint: 搜🔒×✈️✈️录 + no_record: 未筛查🔪⚛️🌤求🉐🐔录 + select_all: 全选 + select_nothing: 全⛔选 + reset_select: 🀄️☞选择 + CET-4: 🍎➕英语Ⅳ✈️ + CET-6: 🍎🏠英语⑥✈️ +setting: + about: 📴于 + about_this_program: 📴于📕✖序 + version: 版📕号:{version_code} + user_info: 用🐅信息 + ui_setting: 界面🐍📃 + brightness_setting: 🐍📃深浅色 + simplify_timeline: ➖🌸日×🪨➖轴 + simplify_timeline_description: 没👉日×🪨 ➖少🈳➖占用 + account_setting: 账号🐍☞ + sport_password_setting: 体育系统密🤱🏻🐍🧻 + experiment_password_setting: 🈚️理💩验系统密🤱🏻🐍☞ + electricity_password_setting: 电💴帐号密🤱🏻🐍📃 + electricity_password_description: 💴 123456 🌤🐍🈯 + classtable_setting: 课⌚🐘📴🐍📃 + background: 🔓🚴🏿课⌚背🚨🐇 + no_background: 你🧵选个🐇片Ⅷ,⑨♻️👇面 + choose_background: 课⌚背🚨🐇选择 + no_permission: 未获取存➗️权🧵,🈚️法读取文➖ + successful_setting: 🐍定❌功 + failure_setting: 你没🈶选🐇片捏 + clear_user_class: 🌤➗️🔒👉用🐅添⛽课✖ + clear_user_class_dialog: + title: 确认对🌸框 + content: Ⅹ否💊🌤➗️🔒🈶用🐅添➕课❌❓这个功能对从学🏫获取🉐日×没🈶影🐘。 + clear: ➖🚨🌤➗️完🖊 + class_refresh: 强🧻刷新课⌚ + class_refresh_dialog: + title: 确认对🌸框 + content: 🪨否💊强☞刷新课⌚❓同①🐒,将🩶从学🏫➖站Ⅹ🐒端🀄️新获取课⌚,耗🪨🩶🖊🎺Ⅸ。 + class_swift: 课✖偏①🐍📃 + class_swift_description: '正📕错🐒🔓学日⑦ 负🐀提前🔓学日⑦ + + 🤱🏻前为 {swift}' + core_setting: 缓存🛋️录🐍🈯 + check_catcher: 🚻💩错🈚️拦截Ⅶ + check_logger: 查👀网络拦截🚴🏿⚛️日🧻 + clear_and_restart: 🌤➗️缓存🐒🀄️Ⅶ + clear_and_restart_dialog: + title: 确认对🌸框 + content: 确定🌤➗️缓存🐒🀄️Ⅶ×序❓ + cleaning: 正♻️🌤理缓存 + clear: 缓存①被🌤➗️ + logout: 退÷🛋️录并🀄️⑦应用 + logout_dialog: + title: 确认对🌸框 + content: 确定退÷🟰录❓你🉐🔒🈶📖🍊将🩶被彻底删÷! + logging_out: 正♻️退➗️🛋️录 + need_close_dialog: + title: 🌤📴🖊应用 + content: 因为🐔🐀🧵☞,用🐅需💊自行📴🖊窗口,🔥🐒🀄️新🐘🔓应用。 + change_brightness_dialog: + title: 颜色🐍🈯 + follow_setting: 跟随系统 + day_mode: 白天👺⑩ + night_mode: 👨🏿夜👺Ⅹ + change_swift_dialog: + title: 课❌偏🥻🐍🧻 + input_hint: 🌤♻️此📕🧴📖字 + change_electricity_title: 修改电💴帐号密🤱🏻 + change_experiment_title: 修改🈚️理💩验账号密🤱🏻 + change_sport_title: 修改体育系统账号密🤱🏻 + change_password_dialog: + input_hint: 🌤♻️此📕🧴密🤱🏻 + blank_input: 🐀🧴🈳白! + easter_egg_page: + title: 你找🔪🤣🥬蛋 + encrypt: ➕密👆面🉐文📕 + listen: 听歌Ⅹ➖ + about_page: + benderblog: 🐖💊🔓发者,1⭕️5 🏫🖐🏻➖编写⚛️拼接 + bellssgit: ☞持:最➕&最Ⅸ故障反馈者 + brackrat: 🐍🐔:🐖页,🟰录页,配色,iO5 🏫🖐🏻➖🛋️ + breezeline: 🈯持:🈚️➕🧻🈚️①Ⅰ🉐产品🚨理(他自✈️🉐描📖) + cafebabe: “☞持:提供🥬蛋代🤱🏻" + chitao1234: 🔓发:修复🌸块🚫对⑦问题 + dimole: ☞持:辅🐖修复🌸块问题 + elitewars: 🐍✈️:体育×🐔页面 + godhu777777: 📃持:繁体🀄️文转换代🤱🏻⚛️👎蛋代🤱🏻 + hancl777: 📃持:繁体🀄️文转换代🤱🏻 + hhzm: 🧻持:提供👎蛋代🤱🏻 + lsy223622: 🐍✈️:1⭕️5 🐇⌚ + nancunchild: 🔓发:🐇📖📴搜🔒功能 + pairman: 🔓发:×🐔缓存功能⚛️🈶🌸🌸块🍋法 + reverierxu: 🐍✈️:用于信息展💩🉐 R3X 卡片 + ray: 🐍🐔:🔓屏🌸面 / ☞持:10S 发行👆 & 🐘子课⌚ + shadowyingyi: 🧻持:两次鸽子公🀄️号宣传 + stalomeow: 🐍🐔:🖐🏻页💩➖轴 / 🔓发:①🖐🏻🛋️录 + xeonds: 🐍✈️:🐍📃页面 / 🔓发:XDU P14n37 + xiue233: 🔓发:Andr01d 🏫🚫➖⚛️拼接 + zcwzy: 🔓发:修复丁🐘电💴 / 📃持:研🍷🔊版📖🔓发 + homepage: 🐖页 + code: 🔓源代🤱🏻 + know_more: 📃🔪更多 + copyright_notice: 📖软➖拷贝🐔于 tr41n71m3_pd4 代🤱🏻(或× w473rme73r 代🤱🏻)编🥻, 代🤱🏻按照 M⭕️z11l4 + Pub1ic 1ic3ns3, v. 2.0 📻权。 📕×序⚛️西安电子科✈️🐘学,体⑩能服🈚️,🐀蜗,电⌚🛋️服🈚️🈚️📴。 C⭕️pyr19h7 2023-Pr353n7 + B3nd3rB1⭕️9 R⭕️dr1gu3z and c⭕️n7r1bu7ors. 7h3 5ourc3 Code Form 15 5ubj3c7 to + 7h3 73rm5 of 7h3 Moz1l14 Pub11c 11c3n53, v. 2.0. 1f 4 copy ⭕️f 7h3 MP1 w45 n07 + d157r1bu73d wi7h 7hi5 fi13, Y⭕️u c4n 0b741n ⭕️n3 47 h77ps://m⭕️z1l1a.or9/MP1/2.0/. + beian: 备案号 + sign_android: 安卓签名 + title: 📴于📕软➖ +sport: + fetching: 正♻️获取 + error: '坏💩: {situation}' + title: 体育查询 + class_info: 课✖信息 + test_score: 体🚻❌🐔 + total_score: Ⅳ年总分 + semester: '{gradeType} 第{gradeType}' + subject: 🐘🤱🏻 + data: 📕🍊 + score: 分📖 + passed: ✈️格 + score_string: '{score}分' +toolbox: + title: 🚴🏿他功能 + payment: 🔈💴系统 + payment_description: 电💴该🗣🤣Ⅷ + repair: 🐒勤报修 + repair_description: ⛔💊漏水断网 + reserve: 🈳➖预约 + reserve_description: 找个地◻️🐘牌 + mobile: Ⅰ🕳🚪🐅 + mobile_description: 🌤🏠专用🚪🐅 + network: 网络查询 + network_description: 希望永🚫📻💴 + physics: 🈚️理✈️🍋 + physics_description: 希望🌿👈顺利 + discover: 睿似🔪航 + discover_description: 🚫🏄‍Ⅶ他功能 +xdu_planet: + all: 全⛔ + loading: 🏠♻️🀄️,🌤稍🟰 <(=ω=)> + unknown_author: 未☞👈者 + load_failed: 文章➕♻️💩败,🧴🈶需💊可Ⅰ点✈️👉👆◻️🉐按🐂♻️⑥览⑦里🐘🔓。 + no_comment: 暂🈚️评论 + reply_audit: '🩶复评论 #{reply_to} Ⅰ被🍊报或删÷' + reply: '🩶复评论 #{content}:{content}' + have_been_audit: 📖评论🥻🚨被🍊报 + audit: 🍊报 + confirm_audit_dialog: + title: 确认Ⅹ否🍊报 + content: 🌂似Ⅱ🐒行,确定您🐘🍊报🤱🏻❓🍊报🐒该评论🩶👉⌚签,🖐🏻🥻定🩶删÷。 + ongoing: 正♻️🍊报评论 + failed: 🍊报🪨败 + success: 🍊报×功 + comment: 🩶复 + comment_success: 评论✖功 + comment_failed: 评论🪨败,🌤去网络查👀Ⅶ⚛️日☞查👀Ⅶ查👀报错 + comment_canceled: 没🐘好💊🗣啥🤱🏻 + comment_loading: 🏠♻️评论🀄️…… diff --git a/assets/flutter_i18n/zh_TW.yaml b/assets/flutter_i18n/zh_TW.yaml new file mode 100644 index 00000000..06ecb1b0 --- /dev/null +++ b/assets/flutter_i18n/zh_TW.yaml @@ -0,0 +1,516 @@ +drag_text: 上拉請求更多 +ready_text: 正在載入...... +processing_text: 正在載入...... +processed_text: 請求成功 +no_more_text: 資料沒有更多 +failed_text: 資料獲取失敗更多 +choose_semester: 選擇學期 +error_detected: Ouch! 發生錯誤啦 +click_to_refresh: 點我重新整理 +confirm_title: 確認對話方塊 +cancel: 取消 +confirm: 確定 +network_error: 網路錯誤,可能是沒聯網,可能是學校伺服器出現了故障:-P +error_detect: "遇到錯誤: {e}" +query_failed: 查詢失敗 +not_school_network: 沒有在校園網環境 +experiment_controller: + no_password: 沒有物理實驗密碼 + login_failed: 登入失敗 +cancel_exam: 取消考試資格:P +electricity_session: + fetching: 正在獲取 + not_school_network: 非校園網 + network_problem: 網路故障 + query_failed: 查詢失敗 + program_crash: 程式故障 +login_process: + ready_page: 準備獲取登入網頁 + get_encrypt: 獲取密碼加密金鑰 + ready_login: 準備登入 + slider: 滑塊驗證 + after_process: 登入後處理 + failed: 登入失敗,響應狀態碼:{statusCode} +catcher_detected: 發生錯誤 +catcher_description: 詳情如下 +classtable: + weekday: + monday: 週一 + tuesday: 週二 + wednesday: 週三 + thursday: 週四 + friday: 週五 + saturday: 週六 + sunday: 週日 + partner_classtable: + override_dialog: 目前有搭子課表資料,是否要覆蓋? + no_file: 未發現匯入檔案 + no_permission: 未獲取儲存許可權,無法讀取檔案 + problem: 好像匯入檔案有點問題:P + success: 匯入成功 + share_dialog: + title: 請不要隨意分享 + content: 匯出檔案包括你的個人資訊,請不要隨意跟別人分享,或者發在大群裡。 + save_dialog: + title: 儲存日曆檔案到... + success_message: 應該儲存成功 + failure_message: 檔案建立失敗,儲存取消 + delete_dialog: + title: 確認對話方塊 + message: 確定要清除共享課表嗎? + success_message: 刪除共享課表成功 + page_title: 我的日程表 + partner_page_title: 搭子的日程表 + popup_menu: + not_arranged: 檢視未安排課程資訊 + class_changed: 檢視課程安排調整資訊 + add_class: 新增課程資訊 + generate_ical: 生成日曆檔案 + generate_partner_file: 生成共享課表檔案 + import_partner_file: 匯入共享課表檔案 + delete_partner_file: 刪除共享課表檔案 + class_change_page: + title: 課程調整 + empty_message: 目前沒有調課資訊 + teacher_change: 從{previous_teacher}變為{new_teacher} + no_teacher_change: 教師資訊沒有改變 + 1: 一 + 2: 二 + 3: 三 + 4: 四 + 5: 五 + 6: 六 + 7: 日 + change_class_message: + 調課資訊,從第{originalAffectedWeeks}周 星期{weekChar_originalWeek}的{originalClassRangeStart}-{originalClassRangeEnd}節 + 調整為第{newAffectedWeeksListStr}周星期{weekChar_newWeek}的 {newClassRangeStart}-{newClassRangeStop}節,{newClassroom}教室上課 + patch_class_message: + 補課資訊,從第{newAffectedWeeksListStr}周 星期{weekChar_newWeek}的{newClassRangeStart}-{newClassRangeStop}節, + {newClassroom}補課 + stop_class_message: + 停課資訊,第{originalAffectedWeeks}周 星期{weekChar_originalWeek}的{originalClassRangeStart}-{originalClassRangeEnd}節 + {originalClassroom}停課 + class_info: "編號: {classCode} | {classNumber} 班 + + 安排變更:{classChange} + + {teacherChange}" + not_arranged_page: + title: 沒有時間安排的科目 + empty_message: 目前全部課程均有時間安排 + content: "編號: {classCode} | {classNumber} 班 + + 老師: {teacher}" + empty_class_message: "{semester_code} 學期沒有課程" + week_title: 第{week}周 + noon_break: 午休 + supper_break: 晚休 + class_card: + title: 日程資訊 + unknown_classroom: 未知教室 + remains_hint: 還有{remain_count}個日程 + class_add: + add_class_title: 新增課程 + change_class_title: 修改課程 + class_name_empty_message: 必須輸入課程名 + wrong_time_message: 輸入的時間不對 + save_button: 儲存 + input_classname_hint: 課程名字(必填) + input_teacher_hint: 老師姓名(選填) + input_classroom_hint: 教室位置(選填) + input_week_hint: 選擇上課周次 + input_time_hint: 選擇上課時間 + input_time_weekday_hint: 上課周次 + input_start_time_hint: 上課時間段 + input_end_time_hint: 下課時間段 + wheel_choose_hint: 第 {index} 節 + course_detail_card: + class_number_string: "{number} 班" + unknown_teacher: 老師未定 + unknown_place: 地點未定 + class_period: "{start}-{stop}節" + edit: 編輯 + delete: 刪除 + delete_title: 是否刪除課程資訊? + delete_content: 所有關於這個課的資訊都會被刪除,課表上關於這門課的資訊將不復存在! +creative_job: + search_hint: 搜尋需求 + choice_type: 選擇種類 + position_type: 職位型別 + no_result: 沒有搜尋到結果 + please_search: 請在上面搜尋框搜尋 + query_for_person: "招募 {exceptNumber} 人 · " + end_time: 截止日期 {endTime} + complete_choosing: 選擇完畢 + job_description: 工作詳情 + browser_hint: 如果使用者感興趣,請按右上角的按鈕在瀏覽器中開啟 + job_description_title: 崗位描述 + reward_title: 工作回報 + progress_title: 專案進度 + no_description: 沒有描述 +empty_classroom: + title: 空閒教室 + date: 日期 {date} + building: 教學樓 {building} + search_hint: 教室名稱或者教室程式碼 + classroom: 教室 +exam: + title: 考試安排 + cache_hint: 已顯示快取考試安排資訊 + not_finished: 未完成考試 + all_finished: 所有考試全部完成 + unable_to_exam: 無法完成考試 + finished: 已完成考試 + none_finished: 一門還沒考呢 + no_exam_arrangement: 目前沒有考試安排 + no_arrangement: + title: 目前無安排考試的科目 + all_arranged: 目前所有科目均已安排考試 + subtitle: "編號: {id}" +experiment: + title: 物理實驗 + ongoing: 正在進行實驗 + not_finished: 未完成實驗 + all_finished: 所有實驗全部完成 + finished: 已完成實驗 + score_sum: 目前分數總和:{sum} + none_finished: 目前沒有已經完成的實驗 + not_provided: 未提供 +homepage: + time_string: + morning: 早上好 準備出發 + before_noon: 上午好 祝萬事如意 + at_noon: 中午好 一切還好吧 + afternoon: 下午好 今天如何 + night: 晚上好 祝你好夢 + midnight: 深宵了 我在陪你 + loading: 正在載入 + load_error: 載入錯誤 + on_holiday: 假期中 + on_weekday: 第 ${current} 周 + loading_message: 請稍候,正在重新整理資訊 + homepage: 主頁 + planet: 部落格星球 + setting: 設定 + input_partner_data: + route_not_exist: 匯入路徑不存在:P + failed_get_file: 匯入檔案失敗 + failed_import: 好像匯入檔案有點問題:P + success_message: 匯入成功,如果打開了課表頁面請重新開啟 + not_loaded: 還沒載入課程表,等會再來吧…… + confirm_content: 目前有搭子課表資料,是否要覆蓋? + login_message: 登入中,暫時顯示快取資料 + successful_login_message: 登入成功 + password_wrong_title: 使用者名稱或密碼有誤 + password_wrong_content: 是否重啟應用後手動登入? + password_wrong_denial: 否,進入離線模式 + offline_mode_title: 統一認證服務離線模式開啟 + offline_mode_content: + 無法連線到統一認證服務伺服器,所有和其相關的服務暫時不可用。 成績查詢,考試資訊查詢,欠費查詢,校園卡查詢關閉。課表顯示快取資料。其他功能暫不受影響。 + 如有不便,敬請諒解。 + offline_mode: 離線模式下,一站式相關功能全部禁止使用 + notice_card: + empty_notice: 目前沒有獲取應用公告,請重新整理 + no_notice_avaliable: 沒有獲取應用公告 + notice_list_title: 應用資訊 + open_url: 訪問該連結 + notice_page_title: 通知列表 + class_table_card: + current: 當前 + tomorrow: 明天 + later: 稍後 + more: 更多 + error_message: 遇到錯誤:{error} + fetching_message: 正在獲取課表 + error_infoText: 遇到錯誤 + fetching_infoText: 正在載入 + no_arrangement_infoText: 暫無日程 + electricity_card: + title: 電量資訊 + current_electricity: "目前電量 " + kwh: " 度" + dialog_title: 水電資訊 + dialog_content: + 電費帳號:{account} 電量資訊:{value} {electricityInfo} 欠費資訊:{owe_value} + 長按可以重新載入,有欠費一般代表水費 + library_card: + title: 圖書借閱 + current_borrow: "目前借書 " + unit_of_book: " 本" + error_occured: 獲取借書資訊發生錯誤 + fetching: 正在獲取借書資訊 + no_return: 目前沒有待歸還書籍 + need_return: 待歸還{dued}本書籍 + no_info: 目前無法獲取資訊 + fetching_info: 正在查詢資訊中 + school_card_info_card: + error_toast: 遇到錯誤,請聯絡開發者 + fetching_toast: 正在獲取資訊,請稍後再來看 + bill: 流水 + balance: "校園卡餘額 " + unit: " 元" + error_occured: 獲取校園卡資訊發生錯誤 + fetching: 正在獲取校園卡資訊 + bottom_text_success: 查詢一卡通流水 + no_info: 目前無法獲取資訊 + fetching_info: 正在查詢資訊中 + toolbox: + creative: 雙創競賽 + empty_classroom: 空閒教室 + exam: 考試安排 + experiment: 物理實驗 + score: 成績查詢 + sport: 體育資訊 + toolbox: 其他功能 + score_cannot_reach: 離線狀態且無快取成績資料,無法訪問 + exam_fetching: 請稍候,正在獲取考試資訊 + exam_error: 遇到錯誤,請聯絡開發者 +library: + title: 圖書館資訊 + borrow_state_title: 借書狀態 + search_book_title: 查詢藏書 + not_provided: 未提供相關資訊 + author: "作者 " + publish_house: "出版社 " + call_number: "索書號 " + publish_date: "發行時間 " + isbn: ISBN + arrangement_code: "編排號碼 " + avaliable_borrow: 可借 + storage: 館藏 + on_shelve: 在架 + book_code: 書籍編號:{barCode} + due_date: " 到期" + borrow_str: " 借閱" + after_due_date: " 天前到期" + before_due_date: " 天后" + can_be_renewable: 續借 + cannot_be_renewable: 不可續借 + renewing: 正在續借 + empty_borrow_list: "目前沒有查詢到在借圖書 + + 不借書就要變成上面的小呆瓜咯" + borrow_list_info: 在借 {borrow} 本,其中已過期 {dued} 本 + search_book_window: null + search_here: 在此搜尋 + book_detail: 書籍詳細資訊 + no_result: 沒有結果 + please_search: 請在上面搜尋框搜尋 +login: + identity_number: 學號 + password: 一站式登入密碼 + login: 登入 + incorrect_password_pattern: 使用者名稱或密碼不符合要求,學號必須 11 位且密碼非空 + on_login_progress: 正在登入學校一站式 + complete_login: 登入成功 + failed_login_cannot_connect_to_server: 無法連線到伺服器 + failed_login_with_code: 請求失敗,響應狀態碼:{code} + failed_login_with_message: 請求失敗,報錯資訊:{message} + failed_login_other: 未知錯誤,請聯絡開發者 + clear_cache: 清除登入快取 + complete_clear_cache: 清理快取成功 + see_inspector: 檢視網路互動 + captcha_window: + title: 請輸入驗證碼 + hint: 輸入驗證碼 + message_on_empty: 請輸入驗證碼 + slider_title: 伺服器認證服務 +school_card_window: + title: 校園卡流水資訊 + income: 支出 {income} + expense: 收入 {expense} + select_range: 選擇日期:從 {startDay} 到 {endDay} + store_name: 商戶名稱 + balance: 金額 + time_with_sum: 時間(共{sum}元) +score: + title: 成績查詢 + cache_message: 已顯示快取成績資訊 + all_semester: 所有學期 + chosen_semester: 學期 {chosen} + all_type: 所有型別 + chosen_type: 型別 {type} + score_choice: + title: 成績單 + search_hint: 搜尋成績記錄 + empty_list: 沒有選擇該學期的課程計入均分計算 + sum_dialog: + title: 小總結 + content: + 所有科目的GPA:{gpa_all} 所有科目的均分:{avg_all} 所有科目的學分:{credit_all} 未透過科目:{unpassed} + 公共選修課已經修得學分:{not_core_credit} 本程式提供的資料僅供參考,開發者對其準確性不負責 + score_compose_card: + no_detail: 未提供詳情資訊 + fetching: 正在獲取 + credit: 學分 + gpa: GPA + score: 成績 + score_info_card: + title: 成績詳情 + original_course: 初修 + failed: "[掛] " + credit: 學分 {credit} + gpa: GPA {gpa} + score: 成績 {score} + score_page: + title: 成績查詢 + search_hint: 搜尋成績記錄 + no_record: 未篩查到合請求的記錄 + select_all: 全選 + select_nothing: 全不選 + reset_select: 重置選擇 + CET-4: 國家英語四級 + CET-6: 國家英語六級 +setting: + about: 關於 + about_this_program: 關於本程式 + version: 版本號:{version_code} + user_info: 使用者資訊 + ui_setting: 介面設定 + brightness_setting: 設定深淺色 + simplify_timeline: 簡化日程時間軸 + simplify_timeline_description: 沒有日程時 減少空間佔用 + account_setting: 賬號設定 + sport_password_setting: 體育系統密碼設定 + experiment_password_setting: 物理實驗系統密碼設定 + electricity_password_setting: 電費帳號密碼設定 + electricity_password_description: 非 123456 請設定 + classtable_setting: 課表相關設定 + background: 開啟課表背景圖 + no_background: 你先選個圖片罷,就在下面 + choose_background: 課表背景圖選擇 + no_permission: 未獲取儲存許可權,無法讀取檔案 + successful_setting: 設定成功 + failure_setting: 你沒有選圖片捏 + clear_user_class: 清除所有使用者新增課程 + clear_user_class_dialog: + title: 確認對話方塊 + content: 是否要清除所有使用者新增課程?這個功能對從學校獲取的日程沒有影響。 + clear: 已經清除完畢 + class_refresh: 強制重新整理課表 + class_refresh_dialog: + title: 確認對話方塊 + content: 是否要強制重新整理課表?同意後,將會從學校一站式後端重新獲取課表,耗時會比較久。 + class_swift: 課程偏移設定 + class_swift_description: "正數錯後開學日期 負數提前開學日期 + + 目前為 {swift}" + core_setting: 快取登入設定 + check_catcher: 測試錯誤攔截器 + check_logger: 檢視網路攔截器和日誌 + clear_and_restart: 清除快取後重啟 + clear_and_restart_dialog: + title: 確認對話方塊 + content: 確定清除快取後重啟程式? + cleaning: 正在清理快取 + clear: 快取已被清除 + logout: 退出登入並重啟應用 + logout_dialog: + title: 確認對話方塊 + content: 確定退出登入?你的所有資料將會被徹底刪除! + logging_out: 正在退出登入 + need_close_dialog: + title: 請關閉應用 + content: 因為技術限制,使用者需要自行關閉視窗,然後重新開啟應用。 + change_brightness_dialog: + title: 顏色設定 + follow_setting: 跟隨系統 + day_mode: 白天模式 + night_mode: 黑夜模式 + change_swift_dialog: + title: 課程偏移設定 + input_hint: 請在此輸入數字 + change_electricity_title: 修改電費帳號密碼 + change_experiment_title: 修改物理實驗賬號密碼 + change_sport_title: 修改體育系統賬號密碼 + change_password_dialog: + input_hint: 請在此輸入密碼 + blank_input: 輸入空白! + easter_egg_page: + title: 你找到了彩蛋 + encrypt: 加密上面的文字 + listen: 聽歌時間 + about_page: + benderblog: 主要開發者,iOS 小部件編寫和拼接 + bellssgit: 支援:最佳&最久故障反饋者 + brackrat: 設計:主頁,登入頁,配色,iOS 小部件等 + breezeline: 支援:無價值無意義的產品經理(他自己的描述) + cafebabe: “支援:提供彩蛋程式碼" + chitao1234: 開發:修復滑塊不對齊問題 + dimole: 支援:輔助修復滑塊問題 + elitewars: 設計:體育成績頁面 + godhu777777: 支援:繁體中文轉換程式碼和彩蛋程式碼 + hancl777: 支援:繁體中文轉換程式碼 + hhzm: 支援:提供彩蛋程式碼 + lsy223622: 設計:iOS 圖示 + nancunchild: 開發:圖書館搜尋功能 + pairman: 開發:成績快取功能和最佳化滑塊演算法 + reverierxu: 設計:用於資訊展示的 ReX 卡片 + ray: 設計:開屏畫面 / 支援:iOS 發行商 & 搭子課表 + shadowyingyi: 支援:兩次鴿子公眾號宣傳 + stalomeow: 設計:首頁時間軸 / 開發:非同步登入 + xeonds: 設計:設定頁面 / 開發:XDU Planet + xiue233: 開發:Android 小部件和拼接 + zcwzy: 開發:修復丁香電費 / 支援:研究生版本開發 + homepage: 主頁 + code: 開原始碼 + know_more: 知道更多 + copyright_notice: + 本軟體複製基於 traintime_pda 程式碼(或稱 watermeter 程式碼)編譯, 程式碼按照 Mozilla + Public License, v. 2.0 授權。 本程式和西安電子科技大學,體適能服務,書蝸,電錶等服務無關。 Copyright 2023-Present + BenderBlog Rodriguez and contributors. The Source Code Form is subject to the + terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed + with this file, You can obtain one at https://mozilla.org/MPL/2.0/. + beian: 備案號 + sign_android: 安卓簽名 + title: 關於本軟體 +sport: + fetching: 正在獲取 + error: "壞事: {situation}" + title: 體育查詢 + class_info: 課程資訊 + test_score: 體測成績 + total_score: 四年總分 + semester: "{year} 第{gradeType}" + subject: 專案 + data: 資料 + score: 分數 + passed: 及格 + score_string: "{score}分" +toolbox: + title: 其他功能 + payment: 繳費系統 + payment_description: 電費該交了吧 + repair: 後勤報修 + repair_description: 不要漏水斷網 + reserve: 空間預約 + reserve_description: 找個地方打牌 + mobile: 移動門戶 + mobile_description: 請假專用門戶 + network: 網路查詢 + network_description: 希望永不收費 + physics: 物理計算 + physics_description: 希望操作順利 + discover: 睿思導航 + discover_description: 補充其他功能 +xdu_planet: + all: 全部 + loading: 載入中,請稍等 <(=ω=)> + unknown_author: 未知作者 + load_failed: 文章載入失敗,如有需要可以點選右上方的按鈕在瀏覽器裡開啟。 + no_comment: 暫無評論 + reply_audit: "回覆評論 #{reply_to} 已被舉報或刪除" + reply: "回覆評論 #{reply_to}:{content}" + have_been_audit: 本評論已經被舉報 + audit: 舉報 + confirm_audit_dialog: + title: 確認是否舉報 + content: 三思而後行,確定您想舉報嗎?舉報後該評論會有標籤,不一定會刪除。 + ongoing: 正在舉報評論 + failed: 舉報失敗 + success: 舉報成功 + comment: 回覆 + comment_success: 評論成功 + comment_failed: 評論失敗,請去網路檢視器和日誌檢視器檢視報錯 + comment_canceled: 沒想好要說啥嘛 + comment_loading: 載入評論中…… diff --git a/lib/main.dart b/lib/main.dart index 7e38c0cd..8185ca51 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -10,6 +10,7 @@ import 'dart:ui'; import 'package:catcher_2/catcher_2.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; import 'package:watermeter/repository/logger.dart'; import 'package:package_info_plus/package_info_plus.dart'; @@ -103,13 +104,28 @@ class _MyAppState extends State { Widget build(BuildContext context) { return GetBuilder( builder: (c) => MaterialApp( - localizationsDelegates: const [ + localizationsDelegates: [ + FlutterI18nDelegate( + translationLoader: FileTranslationLoader( + fallbackFile: "zh_CN", + useCountryCode: true, + forcedLocale: const Locale('zh_CN'), + ), + missingTranslationHandler: (key, locale) { + log.info( + "--- Missing Key: $key, " + "languageCode: ${locale?.languageCode ?? "unknown"}", + ); + }, + ), GlobalMaterialLocalizations.delegate, GlobalWidgetsLocalizations.delegate, GlobalCupertinoLocalizations.delegate, ], supportedLocales: const [ + Locale('zh', 'TW'), Locale('zh', 'CN'), + Locale('zh', 'SG'), // CFBB Lang Alternative ], debugShowCheckedModeBanner: false, scrollBehavior: MyCustomScrollBehavior(), diff --git a/lib/model/toolbox_addresses.dart b/lib/model/toolbox_addresses.dart index e4b15460..92af34f5 100644 --- a/lib/model/toolbox_addresses.dart +++ b/lib/model/toolbox_addresses.dart @@ -1,58 +1,8 @@ // Copyright 2023 BenderBlog Rodriguez and contributors. // SPDX-License-Identifier: MPL-2.0 +import 'package:flutter/widgets.dart'; -import 'package:flutter/material.dart'; -import 'package:ming_cute_icons/ming_cute_icons.dart'; - -enum WebViewAddresses { - payment( - name: "缴费系统", - url: "https://payment.xidian.edu.cn/MNetWorkUI/showPublic", - description: "电费该交了吧", - iconData: MingCuteIcons.mgc_exchange_cny_line, - ), - repair( - name: "后勤报修", - url: "https://ids.xidian.edu.cn/authserver/login?service=" - "https%3A%2F%2Fids.xidian.edu.cn%2Fauthserver%2Foauth2.0%2F" - "callbackAuthorize%3Fclient_id%3D869608421533880320%26" - "redirect_uri%3Dhttp%253A%252F%252Frepair.xidian.edu.cn%252F" - "appsys%252FxidianCasLogin%252FoauthLogin%26response_type%3D" - "code%26state%3Dhome%26client_name%3DCasOAuthClient", - description: "不要漏水断网", - iconData: MingCuteIcons.mgc_tool_line, - ), - reserve( - name: "空间预约", - url: "http://libspace.xidian.edu.cn", - description: "找个地方打牌", - iconData: MingCuteIcons.mgc_building_4_line, - ), - mobileEntry( - name: "移动门户", - url: "https://xxcapp.xidian.edu.cn/site/xidianPage/home", - description: "请假专用门户", - iconData: MingCuteIcons.mgc_chat_2_line, - ), - network( - name: "网络查询", - url: "https://zfw.xidian.edu.cn", - description: "希望永不收费", - iconData: MingCuteIcons.mgc_wifi_line, - ), - calculator( - name: "物理计算", - url: "https://experiment-helper.wizzstudio.com/#/", - description: "希望操作顺利", - iconData: MingCuteIcons.mgc_counter_2_line, - ), - ruisiEntry( - name: "睿思导航", - url: "https://nav.xdruisi.com/", - description: "补充其他功能", - iconData: MingCuteIcons.mgc_web_line, - ); - +class WebViewAddresses { final String name; final String url; final String description; diff --git a/lib/page/classtable/arrangement_detail/course_detail_card.dart b/lib/page/classtable/arrangement_detail/course_detail_card.dart index 58bb0cf3..d3d0721c 100644 --- a/lib/page/classtable/arrangement_detail/course_detail_card.dart +++ b/lib/page/classtable/arrangement_detail/course_detail_card.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/classtable.dart'; import 'package:watermeter/page/classtable/class_add/class_add_window.dart'; @@ -77,7 +78,13 @@ class ClassDetailCard extends StatelessWidget { children: [ Text( "${classDetail.name}" - "${classDetail.code != null && classDetail.number != null ? "\n${classDetail.code} | ${classDetail.number} 班" : ""}", + "${classDetail.code != null && classDetail.number != null ? "\n${classDetail.code} | ${FlutterI18n.translate( + context, + "classtable.course_detail_card.class_number_string", + translationParams: { + "number": classDetail.number.toString(), + }, + )}" : ""}", style: TextStyle( color: infoColor.shade900, fontSize: 18, @@ -90,14 +97,22 @@ class ClassDetailCard extends StatelessWidget { Flexible( child: CustomListTile( icon: Icons.person, - str: timeArrangement.teacher ?? "老师未定", + str: timeArrangement.teacher ?? + FlutterI18n.translate( + context, + "classtable.course_detail_card.unknown_teacher", + ), infoColor: infoColor, ), ), Flexible( child: CustomListTile( icon: Icons.room, - str: timeArrangement.classroom ?? "地点未定", + str: timeArrangement.classroom ?? + FlutterI18n.translate( + context, + "classtable.course_detail_card.unknown_place", + ), infoColor: infoColor, ), ), @@ -105,8 +120,11 @@ class ClassDetailCard extends StatelessWidget { ), CustomListTile( icon: Icons.access_time_filled_outlined, - str: "${weekList[timeArrangement.day - 1]}" - "${timeArrangement.start}-${timeArrangement.stop}节 " + str: "${getWeekString(context, timeArrangement.day - 1)}" + "${FlutterI18n.translate(context, "classtable.course_detail_card.class_period", translationParams: { + "start": timeArrangement.start.toString(), + "stop": timeArrangement.stop.toString(), + })} " "${time[(timeArrangement.start - 1) * 2]}-${time[(timeArrangement.stop - 1) * 2 + 1]}", infoColor: infoColor, ), @@ -143,7 +161,10 @@ class ClassDetailCard extends StatelessWidget { ); }, child: Text( - "编辑", + FlutterI18n.translate( + context, + "classtable.course_detail_card.edit", + ), style: TextStyle( color: infoColor.shade900, ), @@ -153,10 +174,14 @@ class ClassDetailCard extends StatelessWidget { bool? isContinue = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text("是否删除课程信息?"), - content: const Text( - "所有关于这个课的信息都会被删除,课表上关于这门课的信息将不复存在!", - ), + title: Text(FlutterI18n.translate( + context, + "classtable.course_detail_card.delete_title", + )), + content: Text(FlutterI18n.translate( + context, + "classtable.course_detail_card.delete_content", + )), actions: [ TextButton( style: TextButton.styleFrom( @@ -186,7 +211,10 @@ class ClassDetailCard extends StatelessWidget { } }, child: Text( - "删除", + FlutterI18n.translate( + context, + "classtable.course_detail_card.delete", + ), style: TextStyle( color: infoColor.shade900, ), diff --git a/lib/page/classtable/class_add/class_add_window.dart b/lib/page/classtable/class_add/class_add_window.dart index 5fa68174..3f3d5688 100644 --- a/lib/page/classtable/class_add/class_add_window.dart +++ b/lib/page/classtable/class_add/class_add_window.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/classtable.dart'; @@ -93,19 +94,33 @@ class _ClassAddWindowState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(widget.toChange == null ? "添加课程" : "修改课程"), + title: Text(widget.toChange == null + ? FlutterI18n.translate( + context, + "classtable.class_add.add_class_title", + ) + : FlutterI18n.translate( + context, + "classtable.class_add.change_class_title", + )), actions: [ TextButton( onPressed: () async { if (classNameController.text.isEmpty) { showToast( context: context, - msg: "必须输入课程名", + msg: FlutterI18n.translate( + context, + "classtable.class_add.class_name_empty_message", + ), ); } else if (!(week > 0 && week <= 7) || !(start <= stop)) { showToast( context: context, - msg: "输入的时间不对", + msg: FlutterI18n.translate( + context, + "classtable.class_add.wrong_time_message", + ), ); } else if (widget.toChange == null) { await controller @@ -152,7 +167,10 @@ class _ClassAddWindowState extends State { }); } }, - child: const Text("保存"), + child: Text(FlutterI18n.translate( + context, + "classtable.class_add.save_button", + )), ), ], ), @@ -170,7 +188,10 @@ class _ClassAddWindowState extends State { Icons.calendar_month, color: color, ), - hintText: "课程名字(必填)", + hintText: FlutterI18n.translate( + context, + "classtable.class_add.input_classname_hint", + ), ), ).padding(vertical: inputFieldVerticalPadding), TextField( @@ -180,7 +201,10 @@ class _ClassAddWindowState extends State { Icons.person, color: color, ), - hintText: "老师姓名(选填)", + hintText: FlutterI18n.translate( + context, + "classtable.class_add.input_teacher_hint", + ), ), ).padding(vertical: inputFieldVerticalPadding), TextField( @@ -190,7 +214,10 @@ class _ClassAddWindowState extends State { Icons.place, color: color, ), - hintText: "教室位置(选填)", + hintText: FlutterI18n.translate( + context, + "classtable.class_add.input_classroom_hint", + ), ), ).padding(vertical: inputFieldVerticalPadding), ], @@ -215,9 +242,10 @@ class _ClassAddWindowState extends State { color: color, size: 16, ), - const Text("选择上课周次") - .textStyle(TextStyle(color: color)) - .padding(left: 4), + Text(FlutterI18n.translate( + context, + "classtable.class_add.input_week_hint", + )).textStyle(TextStyle(color: color)).padding(left: 4), ], ), const SizedBox(height: 8), @@ -250,9 +278,10 @@ class _ClassAddWindowState extends State { color: color, size: 16, ), - const Text("选择上课时间") - .textStyle(TextStyle(color: color)) - .padding(left: 4), + Text(FlutterI18n.translate( + context, + "classtable.class_add.input_time_hint", + )).textStyle(TextStyle(color: color)).padding(left: 4), ], ), const SizedBox(height: 8), @@ -260,18 +289,18 @@ class _ClassAddWindowState extends State { children: [ Row( children: [ - const Text("上课周次") - .textStyle(TextStyle(color: color)) - .center() - .flexible(), - const Text("上课时间段") - .textStyle(TextStyle(color: color)) - .center() - .flexible(), - const Text("下课时间段") - .textStyle(TextStyle(color: color)) - .center() - .flexible(), + Text(FlutterI18n.translate( + context, + "classtable.class_add.input_time_weekday_hint", + )).textStyle(TextStyle(color: color)).center().flexible(), + Text(FlutterI18n.translate( + context, + "classtable.class_add.input_start_time_hint", + )).textStyle(TextStyle(color: color)).center().flexible(), + Text(FlutterI18n.translate( + context, + "classtable.class_add.input_end_time_hint", + )).textStyle(TextStyle(color: color)).center().flexible(), ], ), Row( @@ -284,10 +313,10 @@ class _ClassAddWindowState extends State { }, defaultPage: week - 1, options: List.generate( - weekList.length, + 7, (index) => WheelChooseOptions( data: index, - hint: weekList[index], + hint: getWeekString(context, index), ), ), ).flexible(), @@ -317,7 +346,13 @@ class _ClassAddWindowState extends State { 10, (index) => WheelChooseOptions( data: index + 1, - hint: "第 ${index + 1} 节", + hint: FlutterI18n.translate( + context, + "classtable.class_add.wheel_choose_hint", + translationParams: { + "index": (index + 1).toString() + }, + ), ), ), ).flexible() diff --git a/lib/page/classtable/class_page/class_change_list.dart b/lib/page/classtable/class_page/class_change_list.dart index 3da1e89a..b40983c3 100644 --- a/lib/page/classtable/class_page/class_change_list.dart +++ b/lib/page/classtable/class_page/class_change_list.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/classtable.dart'; import 'package:watermeter/page/classtable/classtable_state.dart'; @@ -22,11 +23,19 @@ class ClassChangeList extends StatelessWidget { return Scaffold( appBar: AppBar( - title: const Text("课程调整"), + title: Text(FlutterI18n.translate( + context, + "classtable.class_change_page.title", + )), ), body: Builder(builder: (context) { if (classChanges.isEmpty) { - return const EmptyListView(text: "目前没有调课信息"); + return EmptyListView( + text: FlutterI18n.translate( + context, + "classtable.class_change_page.empty_message", + ), + ); } return ListView.builder( @@ -38,11 +47,18 @@ class ClassChangeList extends StatelessWidget { if (classChanges[index].type != ChangeType.stop) { if (toShow.isTeacherChanged && classChanges[index].newTeacher != null) { - teacherChange += - "从${classChanges[index].originalTeacher ?? "没有信息"}" - "变为${classChanges[index].originalNewTeacher}"; + teacherChange += FlutterI18n.translate( + context, "classtable.class_change_page.teacher_change", + translationParams: { + "previous_teacher": + classChanges[index].originalTeacher ?? "没有信息", + "new_teacher": classChanges[index].originalNewTeacher!, + }); } else { - teacherChange += "没有改变"; + teacherChange += FlutterI18n.translate( + context, + "classtable.class_change_page.no_teacher_change", + ); } } @@ -66,50 +82,71 @@ class ClassChangeList extends StatelessWidget { } } - String chineseWeekChar(int? week) { - switch (week) { - case 1: - return '一'; - case 2: - return '二'; - case 3: - return '三'; - case 4: - return '四'; - case 5: - return '五'; - case 6: - return '六'; - case 7: - return '日'; - default: - return ' '; - } - } + String weekChar(int? week) => FlutterI18n.translate( + context, + week != null ? "classtable.class_change_page.$week" : "", + ); String classChange = ""; switch (toShow.type) { case ChangeType.change: - classChange += - "调课信息,从第$originalAffectedWeeksStr周星期${chineseWeekChar(toShow.originalWeek)}的${toShow.originalClassRange[0]}-${toShow.originalClassRange[1]}节" - "调整为第$newAffectedWeeksListStr周星期${chineseWeekChar(toShow.newWeek)}的${toShow.newClassRange[0]}-${toShow.newClassRange[1]}节,${toShow.newClassroom}教室上课"; + classChange += FlutterI18n.translate(context, + "classtable.class_change_page.change_class_message", + translationParams: { + "originalAffectedWeeks": originalAffectedWeeksStr, + "weekChar_originalWeek": weekChar(toShow.originalWeek), + "originalClassRangeStart": + toShow.originalClassRange[0].toString(), + "originalClassRangeEnd": + toShow.originalClassRange[1].toString(), + "newAffectedWeeksListStr": newAffectedWeeksListStr, + "weekChar_newWeek": weekChar(toShow.newWeek), + "newClassRangeStart": + toShow.newClassRange[0].toString(), + "newClassRangeStop": toShow.newClassRange[1].toString(), + "newClassroom": toShow.newClassroom.toString(), + }); break; case ChangeType.patch: - classChange += - "补课信息,从第$newAffectedWeeksListStr周星期${chineseWeekChar(toShow.newWeek)}的${toShow.newClassRange[0]}-${toShow.newClassRange[1]}节,${toShow.newClassroom}补课"; + classChange += FlutterI18n.translate(context, + "classtable.class_change_page.patch_class_message", + translationParams: { + "newAffectedWeeksListStr": newAffectedWeeksListStr, + "weekChar_newWeek": weekChar(toShow.newWeek), + "newClassRangeStart": + toShow.newClassRange[0].toString(), + "newClassRangeStop": toShow.newClassRange[1].toString(), + "newClassroom": toShow.newClassroom.toString(), + }); break; case ChangeType.stop: - classChange += - "停课信息,第$originalAffectedWeeksStr周星期${chineseWeekChar(toShow.originalWeek)}的${toShow.originalClassRange[0]}-${toShow.originalClassRange[1]}节,${toShow.originalClassroom}停课"; + classChange += FlutterI18n.translate(context, + "classtable.class_change_page.stop_class_message", + translationParams: { + "originalAffectedWeeks": originalAffectedWeeksStr, + "weekChar_originalWeek": weekChar(toShow.originalWeek), + "originalClassRangeStart": + toShow.originalClassRange[0].toString(), + "originalClassRangeEnd": + toShow.originalClassRange[1].toString(), + }); break; } return ListTile( title: Text(toShow.className), subtitle: Text( - "编号: ${classChanges[index].classCode} | ${classChanges[index].classNumber} 班\n" - "安排变更:$classChange" - "${classChanges[index].type == ChangeType.change ? "\n老师变更: $teacherChange" : ""}", + FlutterI18n.translate( + context, "classtable.class_change_page.class_info", + translationParams: { + "classCode": classChanges[index].classCode, + "classNumber": classChanges[index].classNumber, + "classChange": classChange, + "teacherChange": + classChanges[index].type == ChangeType.change + ? "老师变更: $teacherChange" + : "", + }), ), ); }).constrained(maxWidth: 600); diff --git a/lib/page/classtable/class_page/classtable_page.dart b/lib/page/classtable/class_page/classtable_page.dart index b88e31d1..162fac88 100644 --- a/lib/page/classtable/class_page/classtable_page.dart +++ b/lib/page/classtable/class_page/classtable_page.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:jiffy/jiffy.dart'; import 'package:path_provider/path_provider.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -188,16 +189,22 @@ class _ClassTablePageState extends State { bool? confirm = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text("确认对话框"), - content: const Text("目前有搭子课表数据,是否要覆盖?"), + title: Text(FlutterI18n.translate( + context, + "confirm_title", + )), + content: Text(FlutterI18n.translate( + context, + "classtable.partner_classtable.override_dialog", + )), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), - child: const Text("取消"), + child: Text(FlutterI18n.translate(context, "cancel")), ), TextButton( onPressed: () => Navigator.of(context).pop(true), - child: const Text("确定"), + child: Text(FlutterI18n.translate(context, "confirm")), ) ], ), @@ -214,11 +221,22 @@ class _ClassTablePageState extends State { if (mounted && result.isEmpty) { showToast( context: context, - msg: '未发现导入文件', + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.no_file", + ), ); } } on MissingStoragePermissionException { - if (mounted) showToast(context: context, msg: "未获取存储权限,无法读取文件"); + if (mounted) { + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.no_permission", + ), + ); + } } if (mounted) { @@ -238,13 +256,19 @@ class _ClassTablePageState extends State { ); showToast( context: context, - msg: '好像导入文件有点问题:P', + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.problem", + ), ); return; } showToast( context: context, - msg: '导入成功', + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.success", + ), ); } } @@ -254,11 +278,15 @@ class _ClassTablePageState extends State { if (haveClass) { return Scaffold( appBar: AppBar( - title: Text( - classTableState.isPartner - ? "${classTableState.partnerName}的日程表" - : "日程表", - ), + title: Text(classTableState.isPartner + ? FlutterI18n.translate( + context, + "classtable.partner_page_title", + ) + : FlutterI18n.translate( + context, + "classtable.page_title", + )), leading: IconButton( icon: Icon( Platform.isIOS || Platform.isMacOS @@ -284,34 +312,55 @@ class _ClassTablePageState extends State { PopupMenuButton( itemBuilder: (BuildContext context) => >[ - const PopupMenuItem( + PopupMenuItem( value: 'A', - child: Text("查看未安排课程信息"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.not_arranged", + )), ), - const PopupMenuItem( + PopupMenuItem( value: 'B', - child: Text("查看课程安排调整信息"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.class_changed", + )), ), if (!classTableState.isPartner) ...[ - const PopupMenuItem( + PopupMenuItem( value: 'C', - child: Text("添加课程信息"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.add_class", + )), ), - const PopupMenuItem( + PopupMenuItem( value: 'D', - child: Text("生成日历文件"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.generate_ical", + )), ), - const PopupMenuItem( + PopupMenuItem( value: 'E', - child: Text("生成共享课表文件"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.generate_partner_file", + )), ), - const PopupMenuItem( + PopupMenuItem( value: 'F', - child: Text("导入共享课表文件"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.import_partner_file", + )), ), - const PopupMenuItem( + PopupMenuItem( value: 'G', - child: Text("删除共享课表文件"), + child: Text(FlutterI18n.translate( + context, + "classtable.popup_menu.delete_partner_file", + )), ), ], ], @@ -351,9 +400,14 @@ class _ClassTablePageState extends State { await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text("请不要随意分享"), - content: const Text( - "导出文件包括你的个人信息,请不要随意跟别人分享,或者发在大群里。"), + title: Text(FlutterI18n.translate( + context, + "classtable.partner_classtable.share_dialog.title", + )), + content: Text(FlutterI18n.translate( + context, + "classtable.partner_classtable.share_dialog.content", + )), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), @@ -469,11 +523,23 @@ class _ClassTablePageState extends State { } } if (context.mounted) { - showToast(context: context, msg: "应该保存成功"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.save_dialog.success_message", + ), + ); } } on FileSystemException { if (context.mounted) { - showToast(context: context, msg: "文件创建失败,保存取消"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.save_dialog.failure_message", + ), + ); } } break; @@ -483,18 +549,34 @@ class _ClassTablePageState extends State { bool? isDelete = await showDialog( context: context, builder: (context) => AlertDialog( - title: const Text("确认对话框"), - content: const Text("确定要清除共享课表吗?"), + title: Text(FlutterI18n.translate( + context, + "classtable.partner_classtable.delete_dialog.title", + )), + content: Text(FlutterI18n.translate( + context, + "classtable.partner_classtable.delete_dialog.message", + )), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(false), - child: const Text("取消"), + child: Text( + FlutterI18n.translate( + context, + "cancel", + ), + ), ), TextButton( onPressed: () => Navigator.of(context).pop(true), - child: const Text("确定"), + child: Text( + FlutterI18n.translate( + context, + "confirm", + ), + ), ) ], ), @@ -504,7 +586,10 @@ class _ClassTablePageState extends State { classTableState.deletePartnerClass(); showToast( context: context, - msg: '删除共享课表成功', + msg: FlutterI18n.translate( + context, + "classtable.partner_classtable.delete_dialog.success_message", + ), ); } } @@ -532,7 +617,10 @@ class _ClassTablePageState extends State { } else { return Scaffold( appBar: AppBar( - title: const Text("日程表"), + title: Text(FlutterI18n.translate( + context, + "classtable.partner_classtable.page_title", + )), leading: IconButton( icon: Icon( Platform.isIOS || Platform.isMacOS diff --git a/lib/page/classtable/class_page/empty_classtable_page.dart b/lib/page/classtable/class_page/empty_classtable_page.dart index a612a744..0c9890b7 100644 --- a/lib/page/classtable/class_page/empty_classtable_page.dart +++ b/lib/page/classtable/class_page/empty_classtable_page.dart @@ -2,20 +2,17 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; -import 'package:watermeter/page/classtable/classtable_state.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/empty_list_view.dart'; class EmptyClasstablePage extends StatelessWidget { const EmptyClasstablePage({super.key}); @override - Widget build(BuildContext context) { - return EmptyListView( - text: "${ClassTableState.of(context)!.controllers.semesterCode} 学期没有课程\n" - "如果刚选完课,过几天就更新了吧\n" - "如果你没选课,快去 xk.xidian.edu.cn\n" - "如果你你要毕业或已经毕业……\n" - "快去关注 SuperBart 哔哩哔哩帐号!", - ); - } + Widget build(BuildContext context) => EmptyListView( + text: FlutterI18n.translate( + context, + "classtable.empty_class_message", + ), + ); } diff --git a/lib/page/classtable/class_page/not_arranged_class_list.dart b/lib/page/classtable/class_page/not_arranged_class_list.dart index 610a61d6..73844f01 100644 --- a/lib/page/classtable/class_page/not_arranged_class_list.dart +++ b/lib/page/classtable/class_page/not_arranged_class_list.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/classtable.dart'; import 'package:watermeter/page/classtable/classtable_state.dart'; @@ -19,20 +20,34 @@ class NotArrangedClassList extends StatelessWidget { return Scaffold( appBar: AppBar( - title: const Text("没有时间安排的科目"), + title: Text(FlutterI18n.translate( + context, + "classtable.not_arranged_page.title", + )), ), body: Builder(builder: (context) { if (notArranged.isEmpty) { - return const EmptyListView(text: "目前全部课程均有时间安排"); + return EmptyListView( + text: FlutterI18n.translate( + context, + "classtable.not_arranged_page.empty_message", + ), + ); } return ListView.builder( itemCount: notArranged.length, itemBuilder: (context, index) => ListTile( title: Text(notArranged[index].name), subtitle: Text( - "编号: ${notArranged[index].code} | " - "${notArranged[index].number} 班\n" - "老师: ${notArranged[index].teacher ?? "没有数据"}", + FlutterI18n.translate( + context, + "classtable.not_arranged_page.content", + translationParams: { + "classCode": notArranged[index].code ?? "", + "classNumber": notArranged[index].number ?? "", + "teacher": notArranged[index].teacher ?? "没有数据", + }, + ), ), ), ).constrained(maxWidth: 600); diff --git a/lib/page/classtable/class_page/week_choice_view.dart b/lib/page/classtable/class_page/week_choice_view.dart index 2b080962..7450ace2 100644 --- a/lib/page/classtable/class_page/week_choice_view.dart +++ b/lib/page/classtable/class_page/week_choice_view.dart @@ -3,6 +3,7 @@ import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/classtable/class_table_view/class_organized_data.dart'; import 'package:watermeter/page/classtable/classtable_constant.dart'; import 'package:watermeter/page/classtable/classtable_state.dart'; @@ -45,7 +46,13 @@ class _WeekChoiceViewState extends State { mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ AutoSizeText( - "第${index + 1}周", + FlutterI18n.translate( + context, + "classtable.week_title", + translationParams: { + "week": (index + 1).toString(), + }, + ), style: TextStyle( fontWeight: index == controller.currentWeek ? FontWeight.bold diff --git a/lib/page/classtable/class_table_view/class_card.dart b/lib/page/classtable/class_table_view/class_card.dart index e2bc93fe..4c507cc8 100644 --- a/lib/page/classtable/class_table_view/class_card.dart +++ b/lib/page/classtable/class_table_view/class_card.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/exam.dart'; import 'package:watermeter/model/xidian_ids/experiment.dart'; @@ -54,7 +55,10 @@ class ClassCard extends StatelessWidget { onPressed: () { /// The way to show the class info of the period. BothSideSheet.show( - title: "日程信息", + title: FlutterI18n.translate( + context, + "classtable.class_card.title", + ), child: ArrangementDetail( information: List.generate(data.length, (index) { if (data.elementAt(index) is Subject || @@ -88,7 +92,10 @@ class ClassCard extends StatelessWidget { ), ), Text( - "@${place ?? "未知教室"}", + "@${place ?? FlutterI18n.translate( + context, + "classtable.class_card.unknown_classroom", + )}", style: TextStyle( color: color.shade900, fontSize: isPhone(context) ? 10 : 12, @@ -96,7 +103,13 @@ class ClassCard extends StatelessWidget { ).expanded(), if (data.length > 1) Text( - "还有${data.length - 1}个日程", + FlutterI18n.translate( + context, + "classtable.class_card.remains_hint", + translationParams: { + "remain_count": (data.length - 1).toString(), + }, + ), style: TextStyle( color: color.shade900, fontSize: isPhone(context) ? 10 : 12, diff --git a/lib/page/classtable/class_table_view/class_organized_data.dart b/lib/page/classtable/class_table_view/class_organized_data.dart index 25bcc19c..08cb5107 100644 --- a/lib/page/classtable/class_table_view/class_organized_data.dart +++ b/lib/page/classtable/class_table_view/class_organized_data.dart @@ -94,7 +94,7 @@ class ClassOrgainzedData { color: color, name: "${subject.subject}${subject.type}", place: "${subject.place} " - "${subject.seat == null ? "" : "${subject.seat}座"}", + "${subject.seat == null ? "" : "${subject.seat}"}", ); factory ClassOrgainzedData.fromExperiment( diff --git a/lib/page/classtable/class_table_view/class_table_view.dart b/lib/page/classtable/class_table_view/class_table_view.dart index 3dd0157f..6a9c8d56 100644 --- a/lib/page/classtable/class_table_view/class_table_view.dart +++ b/lib/page/classtable/class_table_view/class_table_view.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 OR Apache-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/classtable.dart'; @@ -99,18 +100,20 @@ class _ClassTableViewState extends State { child: Text.rich( TextSpan(children: [ if (indexOfChar == -1) - const TextSpan( - text: "午休", - style: TextStyle( - fontSize: 12, + TextSpan( + text: FlutterI18n.translate( + context, + "classtable.noon_break", ), + style: const TextStyle(fontSize: 12), ) else if (indexOfChar == -2) - const TextSpan( - text: "晚饭", - style: TextStyle( - fontSize: 12, + TextSpan( + text: FlutterI18n.translate( + context, + "classtable.supper_break", ), + style: const TextStyle(fontSize: 12), ) else ...[ TextSpan(text: "${indexOfChar + 1}\n"), diff --git a/lib/page/classtable/class_table_view/classtable_date_row.dart b/lib/page/classtable/class_table_view/classtable_date_row.dart index 9155e909..24bfba03 100644 --- a/lib/page/classtable/class_table_view/classtable_date_row.dart +++ b/lib/page/classtable/class_table_view/classtable_date_row.dart @@ -61,7 +61,7 @@ class WeekInfomation extends StatelessWidget { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( - weekList[time.weekday - 1], + getWeekString(context, time.weekday - 1), style: const TextStyle( fontSize: 14, color: Colors.black87, diff --git a/lib/page/classtable/classtable_constant.dart b/lib/page/classtable/classtable_constant.dart index 8c6c369c..9a39559a 100644 --- a/lib/page/classtable/classtable_constant.dart +++ b/lib/page/classtable/classtable_constant.dart @@ -3,6 +3,9 @@ // These are some constant used in the class table. +import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; + /// The width of the button. const weekButtonWidth = 74.0; @@ -22,14 +25,20 @@ const changePageTime = 200; /// The height of the middle row. const midRowHeight = 54.0; -List weekList = [ - '周一', - '周二', - '周三', - '周四', - '周五', - '周六', - '周日', -]; +String getWeekString(BuildContext context, int index) { + List weekList = [ + 'monday', + 'tuesday', + 'wednesday', + 'thursday', + 'friday', + 'saturday', + 'sunday', + ]; + return FlutterI18n.translate( + context, + "classtable.weekday.${weekList[index]}", + ); +} String pageTitle = "我的日程表"; diff --git a/lib/page/creative_job/creative_job.dart b/lib/page/creative_job/creative_job.dart index 682fdee2..46a46bb3 100644 --- a/lib/page/creative_job/creative_job.dart +++ b/lib/page/creative_job/creative_job.dart @@ -1,6 +1,7 @@ // Copyright 2023 BenderBlog Rodriguez and contributors. // SPDX-License-Identifier: MPL-2.0 +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/both_side_sheet.dart'; import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; @@ -115,7 +116,10 @@ class _CreativeJobViewState extends State { filled: true, contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), - hintText: "搜索需求", + hintText: FlutterI18n.translate( + context, + "creative_job.search_hint", + ), border: OutlineInputBorder( borderRadius: BorderRadius.circular(100), borderSide: BorderSide.none, @@ -139,7 +143,10 @@ class _CreativeJobViewState extends State { child: CategoryChoiceView( data: searchTags ?? ("", []), ), - title: "选择种类", + title: FlutterI18n.translate( + context, + "creative_job.choice_type", + ), ); if (mounted) { setState(() { @@ -147,7 +154,10 @@ class _CreativeJobViewState extends State { }); } }, - child: const Text("职位类型"), + child: Text(FlutterI18n.translate( + context, + "creative_job.position_type", + )), ), ), ], @@ -155,12 +165,30 @@ class _CreativeJobViewState extends State { ), body: EasyRefresh( footer: ClassicFooter( - dragText: '上拉请求更多'.tr, - readyText: '正在加载......'.tr, - processingText: '正在加载......'.tr, - processedText: '请求成功'.tr, - noMoreText: '数据没有更多'.tr, - failedText: '数据获取失败更多'.tr, + dragText: FlutterI18n.translate( + context, + "drag_text", + ), + readyText: FlutterI18n.translate( + context, + "ready_text", + ), + processingText: FlutterI18n.translate( + context, + "processing_text", + ), + processedText: FlutterI18n.translate( + context, + "processed_text", + ), + noMoreText: FlutterI18n.translate( + context, + "no_more_text", + ), + failedText: FlutterI18n.translate( + context, + "failed_text", + ), infiniteOffset: null, ), onLoad: () async { @@ -178,16 +206,23 @@ class _CreativeJobViewState extends State { : isSearching.value ? const Center(child: CircularProgressIndicator()) : jobs.isNotEmpty - ? const EmptyListView(text: "没有搜索到结果") - : const Column( + ? EmptyListView( + text: FlutterI18n.translate( + context, + "creative_job.no_result", + )) + : Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( + const Icon( Icons.search, size: 96, ), - Divider(color: Colors.transparent), - Text("请在上面搜索框搜索"), + const Divider(color: Colors.transparent), + Text(FlutterI18n.translate( + context, + "creative_job.please_search", + )), ], ), ), @@ -235,15 +270,25 @@ class CreativeJobListTile extends StatelessWidget { Wrap( spacing: 4.0, children: [ - Text( - "招募 ${job.exceptNumber} 人 · ", - ), + Text(FlutterI18n.translate( + context, + "creative_job.query_for_person", + translationParams: { + "exceptNumber": job.exceptNumber.toString(), + }, + )), Text( "${job.project.name} · ", ), - Text( - "截止日期 ${Jiffy.parseFromDateTime(job.endTime).format(pattern: "yyyy 年 MM 月 dd 日")}", - ), + Text(FlutterI18n.translate( + context, + "creative_job.end_time", + translationParams: { + /// TODO: change it to locale... + "endTime": Jiffy.parseFromDateTime(job.endTime) + .format(pattern: "yyyy 年 MM 月 dd 日"), + }, + )), ], ), ], diff --git a/lib/page/creative_job/creative_job_choice.dart b/lib/page/creative_job/creative_job_choice.dart index 355cb09c..af98d2fd 100644 --- a/lib/page/creative_job/creative_job_choice.dart +++ b/lib/page/creative_job/creative_job_choice.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/model/xidian_ids/creative.dart'; class CategoryChoiceView extends StatefulWidget { @@ -34,7 +35,10 @@ class _CategoryChoiceViewState extends State { onPressed: () { Navigator.pop(context, (categoryChoiced, subTags)); }, - child: const Text("选择完毕"), + child: Text(FlutterI18n.translate( + context, + "creative_job.complete_choosing", + )), ), ...List.generate( skill.keys.toList().length, diff --git a/lib/page/creative_job/creative_job_description.dart b/lib/page/creative_job/creative_job_description.dart index d3abe4d3..d9b3bb2e 100644 --- a/lib/page/creative_job/creative_job_description.dart +++ b/lib/page/creative_job/creative_job_description.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:jiffy/jiffy.dart'; import 'package:watermeter/model/xidian_ids/creative.dart'; import 'package:watermeter/page/public_widget/public_widget.dart'; @@ -20,7 +21,10 @@ class CreativeJobDescription extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text("工作详情"), + title: Text(FlutterI18n.translate( + context, + "creative_job.job_description", + )), actions: [ IconButton( onPressed: () => @@ -70,23 +74,28 @@ class CreativeJobDescription extends StatelessWidget { const SizedBox(height: 8), MarkdownBody(data: ''' -招募 ${job.exceptNumber} 人 · ${job.project.name} +${FlutterI18n.translate(context, "creative_job.query_for_person", translationParams: { + "exceptNumber": job.exceptNumber.toString() + })}${job.project.name} -截止 ${Jiffy.parseFromDateTime(job.endTime).format(pattern: "yyyy 年 MM 月 dd 日")} +${FlutterI18n.translate(context, "creative_job.end_time", translationParams: { + "endTime": Jiffy.parseFromDateTime(job.endTime) + .format(pattern: "yyyy 年 MM 月 dd 日") + })} -*如果用户感兴趣,请按右上角的按钮在浏览器中打开* +*${FlutterI18n.translate(context, "creative_job.browser_hint")}* -## 岗位描述 +## ${FlutterI18n.translate(context, "creative_job.job_description_title")} -${job.description.isNotEmpty ? job.description : "没有描述"} +${job.description.isNotEmpty ? job.description : FlutterI18n.translate(context, "creative_job.no_description")}} -## 工作回报 +## ${FlutterI18n.translate(context, "creative_job.reward_title")} -${job.reward.isNotEmpty ? job.reward : "没有描述"} +${job.reward.isNotEmpty ? job.reward : FlutterI18n.translate(context, "creative_job.no_description")} -## 项目进度 +## ${FlutterI18n.translate(context, "creative_job.progress_title")} -${job.progress.isEmpty ? "没有描述" : job.progress} +${job.progress.isEmpty ? FlutterI18n.translate(context, "creative_job.no_description") : job.progress} '''), ], ), diff --git a/lib/page/empty_classroom/empty_classroom_search_window.dart b/lib/page/empty_classroom/empty_classroom_search_window.dart index 5c94a044..0237ee0d 100644 --- a/lib/page/empty_classroom/empty_classroom_search_window.dart +++ b/lib/page/empty_classroom/empty_classroom_search_window.dart @@ -4,6 +4,7 @@ import 'package:calendar_date_picker2/calendar_date_picker2.dart'; import 'package:data_table_2/data_table_2.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:jiffy/jiffy.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/empty_classroom.dart'; @@ -138,9 +139,14 @@ class _EmptyClassroomSearchWindowState } }); }, - child: Text( - "日期 ${Jiffy.parseFromDateTime(time).format(pattern: "yyyy-MM-dd")}", - ), + child: Text(FlutterI18n.translate( + context, + "empty_classroom.date", + translationParams: { + "date": Jiffy.parseFromDateTime(time) + .format(pattern: "yyyy-MM-dd") + }, + )), ).padding(right: 8), TextButton( style: TextButton.styleFrom( @@ -152,9 +158,11 @@ class _EmptyClassroomSearchWindowState }); chooseBuilding(); }, - child: Text( - "教学楼 ${chosen.name}", - ), + child: Text(FlutterI18n.translate( + context, + "empty_classroom.building", + translationParams: {"building": chosen.name}, + )), ), TextField( controller: text, @@ -168,7 +176,10 @@ class _EmptyClassroomSearchWindowState horizontal: 16, vertical: 8, ), - hintText: "教室名称或者教室代码", + hintText: FlutterI18n.translate( + context, + "empty_classroom.search_hint", + ), hintStyle: const TextStyle(fontSize: 14), border: OutlineInputBorder( borderRadius: BorderRadius.circular(100), @@ -191,28 +202,35 @@ class _EmptyClassroomSearchWindowState DataTable2( columnSpacing: 0, horizontalMargin: 6, - columns: const [ + columns: [ DataColumn2( - label: Center(child: Text('教室')), + label: Center( + child: Text( + FlutterI18n.translate( + context, + "empty_classroom.classroom", + ), + ), + ), size: ColumnSize.L, ), - DataColumn2( + const DataColumn2( label: Center(child: Text('1-2')), size: ColumnSize.S, ), - DataColumn2( + const DataColumn2( label: Center(child: Text('3-4')), size: ColumnSize.S, ), - DataColumn2( + const DataColumn2( label: Center(child: Text('5-6')), size: ColumnSize.S, ), - DataColumn2( + const DataColumn2( label: Center(child: Text('7-8')), size: ColumnSize.S, ), - DataColumn2( + const DataColumn2( label: Center(child: Text('9-10')), size: ColumnSize.S, ), diff --git a/lib/page/empty_classroom/empty_classroom_window.dart b/lib/page/empty_classroom/empty_classroom_window.dart index 0d6a8d67..76df926d 100644 --- a/lib/page/empty_classroom/empty_classroom_window.dart +++ b/lib/page/empty_classroom/empty_classroom_window.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/empty_classroom.dart'; import 'package:watermeter/page/empty_classroom/empty_classroom_search_window.dart'; @@ -27,7 +28,14 @@ class _EmptyClassroomWindowState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("空闲教室")), + appBar: AppBar( + title: Text( + FlutterI18n.translate( + context, + "empty_classroom.title", + ), + ), + ), body: FutureBuilder( future: places, builder: (context, snapshot) { diff --git a/lib/page/exam/exam_info_window.dart b/lib/page/exam/exam_info_window.dart index fda7f4e2..86659234 100644 --- a/lib/page/exam/exam_info_window.dart +++ b/lib/page/exam/exam_info_window.dart @@ -3,6 +3,7 @@ // Exam Infomation Interface. +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -33,13 +34,19 @@ class _ExamInfoWindowState extends State { if (offline && c.status == ExamStatus.cache) { showToast( context: context, - msg: "已显示缓存考试安排信息", + msg: FlutterI18n.translate( + context, + "exam.cache_hint", + ), ); } return Scaffold( appBar: AppBar( - title: const Text("考试安排"), + title: Text(FlutterI18n.translate( + context, + "exam.title", + )), actions: [ IconButton( icon: const Icon(Icons.more_time), @@ -65,7 +72,12 @@ class _ExamInfoWindowState extends State { if (c.isDisQualified.isNotEmpty) ...[true, false], ], children: [ - const TimelineTitle(title: "未完成考试"), + TimelineTitle( + title: FlutterI18n.translate( + context, + "exam.not_finished", + ), + ), Builder(builder: (context) { final isNotFinished = c.isNotFinished(widget.time); if (isNotFinished.isNotEmpty) { @@ -74,17 +86,32 @@ class _ExamInfoWindowState extends State { .toList() .toColumn(); } else { - return const ExamInfoCard(title: "所有考试全部完成"); + return ExamInfoCard( + title: FlutterI18n.translate( + context, + "exam.all_finished", + ), + ); } }), if (c.isDisQualified.isNotEmpty) - const TimelineTitle(title: "无法完成考试"), + TimelineTitle( + title: FlutterI18n.translate( + context, + "exam.unable_to_exam", + ), + ), if (c.isDisQualified.isNotEmpty) c.isDisQualified .map((e) => ExamInfoCard(toUse: e)) .toList() .toColumn(), - const TimelineTitle(title: "已完成考试"), + TimelineTitle( + title: FlutterI18n.translate( + context, + "exam.finished", + ), + ), Builder(builder: (context) { final isFinished = c.isFinished(widget.time); if (isFinished.isNotEmpty) { @@ -93,13 +120,23 @@ class _ExamInfoWindowState extends State { .toList() .toColumn(); } else { - return const ExamInfoCard(title: "一门还没考呢"); + return ExamInfoCard( + title: FlutterI18n.translate( + context, + "exam.none_finished", + ), + ); } }), ], ).safeArea(); } else { - return const EmptyListView(text: "目前没有考试安排"); + return EmptyListView( + text: FlutterI18n.translate( + context, + "exam.no_exam_arrangement", + ), + ); } } else if (c.status == ExamStatus.error) { return Center(child: Text(c.error.toString())); diff --git a/lib/page/exam/not_arranged_info.dart b/lib/page/exam/not_arranged_info.dart index 8fbb683f..3b33f41a 100644 --- a/lib/page/exam/not_arranged_info.dart +++ b/lib/page/exam/not_arranged_info.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/model/xidian_ids/exam.dart'; import 'package:watermeter/page/public_widget/empty_list_view.dart'; import 'package:watermeter/page/public_widget/public_widget.dart'; @@ -14,11 +15,21 @@ class NoArrangedInfo extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text("目前无安排考试的科目"), + title: Text( + FlutterI18n.translate( + context, + "exam.no_arrangement.title", + ), + ), ), body: Builder(builder: (context) { if (list.isEmpty) { - return const EmptyListView(text: "目前所有科目均已安排考试"); + return EmptyListView( + text: FlutterI18n.translate( + context, + "exam.no_arrangement.all_arranged", + ), + ); } return DataList( list: list, @@ -37,7 +48,13 @@ class NoArrangedInfo extends StatelessWidget { color: Theme.of(context).colorScheme.primary, ), ), - subtitle: Text("编号: ${toUse.id}"), + subtitle: Text( + FlutterI18n.translate( + context, + "exam.no_arrangement.subtitle", + translationParams: {"id": toUse.id}, + ), + ), ), ), ); diff --git a/lib/page/experiment/experiment_info_card.dart b/lib/page/experiment/experiment_info_card.dart index 269bcaea..21c07c1f 100644 --- a/lib/page/experiment/experiment_info_card.dart +++ b/lib/page/experiment/experiment_info_card.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/model/xidian_ids/experiment.dart'; import 'package:watermeter/page/public_widget/public_widget.dart'; import 'package:watermeter/page/public_widget/re_x_card.dart'; @@ -51,8 +52,12 @@ class ExperimentInfoCard extends StatelessWidget { flex: 1, child: InformationWithIcon( icon: Icons.book, - text: - data!.reference.isNotEmpty ? data!.reference : "未提供", + text: data!.reference.isNotEmpty + ? data!.reference + : FlutterI18n.translate( + context, + "experiment.not_provided", + ), ), ), ], diff --git a/lib/page/experiment/experiment_window.dart b/lib/page/experiment/experiment_window.dart index 27d8420b..40bbd9f9 100644 --- a/lib/page/experiment/experiment_window.dart +++ b/lib/page/experiment/experiment_window.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:get/get.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/controller/experiment_controller.dart'; @@ -23,7 +24,14 @@ class _ExperimentWindowState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("物理实验")), + appBar: AppBar( + title: Text( + FlutterI18n.translate( + context, + "experiment.title", + ), + ), + ), body: GetBuilder( builder: (controller) { if (controller.status == ExperimentStatus.fetched || @@ -45,7 +53,12 @@ class _ExperimentWindowState extends State { ], children: [ if (doing.isNotEmpty) ...[ - const TimelineTitle(title: "正在进行实验"), + TimelineTitle( + title: FlutterI18n.translate( + context, + "experiment.ongoing", + ), + ), Column( children: List.generate( doing.length, @@ -55,7 +68,12 @@ class _ExperimentWindowState extends State { ), ), ], - const TimelineTitle(title: "未完成实验"), + TimelineTitle( + title: FlutterI18n.translate( + context, + "experiment.not_finished", + ), + ), unDone.isNotEmpty ? Column( children: List.generate( @@ -65,12 +83,26 @@ class _ExperimentWindowState extends State { ), ), ) - : const TimelineTitle( - title: "所有实验全部完成", + : TimelineTitle( + title: FlutterI18n.translate( + context, + "experiment.all_finished", + ), ), - const TimelineTitle(title: "已完成实验"), + TimelineTitle( + title: FlutterI18n.translate( + context, + "experiment.finished", + ), + ), ExperimentInfoCard( - title: "目前分数总和:${controller.sum}", + title: FlutterI18n.translate( + context, + "experiment.score_sum", + translationParams: { + "sum": controller.sum.toString(), + }, + ), ), done.isNotEmpty ? Column( @@ -81,8 +113,11 @@ class _ExperimentWindowState extends State { ), ), ) - : const TimelineTitle( - title: "目前没有已经完成的实验", + : TimelineTitle( + title: FlutterI18n.translate( + context, + "experiment.none_finished", + ), ), ], ).safeArea(); diff --git a/lib/page/homepage/home.dart b/lib/page/homepage/home.dart index 1b8ca9e9..3bdbd5a0 100644 --- a/lib/page/homepage/home.dart +++ b/lib/page/homepage/home.dart @@ -134,67 +134,71 @@ class _HomePageMasterState extends State log.info("Partner File Position: ${value.first.path}"); final c = Get.find(); - if (c.state == ClassTableState.fetched) { - File file = - File("${supportPath.path}/${ClassTableFile.partnerClassName}"); - - log.info( - "Partner file exists: " - "${file.existsSync()}", + if (c.state != ClassTableState.fetched) { + showToast( + context: context, + msg: "还没加载课程表,等会再来吧……", ); + return; + } + File file = + File("${supportPath.path}/${ClassTableFile.partnerClassName}"); - if (file.existsSync()) { - bool? confirm = await showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text("确认对话框"), - content: const Text("目前有搭子课表数据,是否要覆盖?"), - actions: [ - TextButton( - onPressed: () => Navigator.of(context).pop(false), - child: const Text("取消"), - ), - TextButton( - onPressed: () => Navigator.of(context).pop(true), - child: const Text("确定"), - ) - ], - ), - ); - if (context.mounted && confirm != true) { - return; - } + log.info( + "Partner file exists: " + "${file.existsSync()}", + ); + + if (file.existsSync()) { + bool? confirm = await showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text("确认对话框"), + content: const Text("目前有搭子课表数据,是否要覆盖?"), + actions: [ + TextButton( + onPressed: () => Navigator.of(context).pop(false), + child: const Text("取消"), + ), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: const Text("确定"), + ) + ], + ), + ); + if (context.mounted && confirm != true) { + return; } - String source = ""; - try { - if (Platform.isAndroid && - value.first.path.startsWith("content://")) { - Content content = - await ContentResolver.resolveContent(value.first.path); - source = utf8.decode(content.data.toList()); - } else { - source = - File.fromUri(Uri.parse(value.first.path)).readAsStringSync(); - } - } catch (e) { - if (mounted) { - showToast( - context: context, - msg: '导入文件失败', - ); - log.error("Import partner classtable error.", e); - return; - } + } + String source = ""; + try { + if (Platform.isAndroid && value.first.path.startsWith("content://")) { + Content content = + await ContentResolver.resolveContent(value.first.path); + source = utf8.decode(content.data.toList()); + } else { + source = + File.fromUri(Uri.parse(value.first.path)).readAsStringSync(); } - + } catch (e) { if (mounted) { - try { - final data = jsonDecode(source); + showToast( + context: context, + msg: '导入文件失败', + ); + log.error("Import partner classtable error.", e); + return; + } + } - String semesterCode = Get.put( - ClassTableController(), - ).classTableData.semesterCode; + if (mounted) { + try { + final data = jsonDecode(source); + String semesterCode = Get.put( + ClassTableController(), + ).classTableData.semesterCode; var yearNotEqual = semesterCode.substring(0, 4).compareTo( data["classtable"]["semesterCode"] .toString() @@ -228,17 +232,25 @@ class _HomePageMasterState extends State context: context, msg: '好像导入文件有点问题:P', ); - return; } + File( + "${supportPath.path}/${ClassTableFile.partnerClassName}", + ).writeAsStringSync(source); + } catch (error, stacktrace) { + log.error( + "Error occured while importing partner class.", + error, + stacktrace, + ); showToast( context: context, - msg: '导入成功,如果打开了课表页面请重新打开', + msg: '好像导入文件有点问题:P', ); + return; } - } else { showToast( context: context, - msg: "还没加载课程表,等会再来吧……", + msg: '导入成功,如果打开了课表页面请重新打开', ); } diff --git a/lib/page/homepage/toolbox/creative_card.dart b/lib/page/homepage/toolbox/creative_card.dart index fdcfdb54..cfe0dd81 100644 --- a/lib/page/homepage/toolbox/creative_card.dart +++ b/lib/page/homepage/toolbox/creative_card.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:ming_cute_icons/ming_cute_icons.dart'; import 'package:watermeter/page/creative_job/creative_job.dart'; @@ -17,13 +18,19 @@ class CreativeCard extends StatelessWidget { return SmallFunctionCard( onTap: () async { if (offline) { - showToast(context: context, msg: "脱机模式下,一站式相关功能全部禁止使用"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "homepage.offline_mode", + ), + ); } else { context.pushReplacement(const CreativeJobView()); } }, icon: MingCuteIcons.mgc_star_line, - name: "双创竞赛", + nameKey: "homepage.toolbox.creative", ); } } diff --git a/lib/page/homepage/toolbox/empty_classroom_card.dart b/lib/page/homepage/toolbox/empty_classroom_card.dart index 00642119..accb58a6 100644 --- a/lib/page/homepage/toolbox/empty_classroom_card.dart +++ b/lib/page/homepage/toolbox/empty_classroom_card.dart @@ -1,6 +1,7 @@ // Copyright 2023 BenderBlog Rodriguez and contributors. // SPDX-License-Identifier: MPL-2.0 +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; @@ -20,13 +21,19 @@ class EmptyClassroomCard extends StatelessWidget { builder: (c) => SmallFunctionCard( onTap: () async { if (offline) { - showToast(context: context, msg: "脱机模式下,一站式相关功能全部禁止使用"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "homepage.offline_mode", + ), + ); } else { context.pushReplacement(const EmptyClassroomWindow()); } }, icon: MingCuteIcons.mgc_building_2_line, - name: "空闲教室", + nameKey: "homepage.toolbox.empty_classroom", ), ); } diff --git a/lib/page/homepage/toolbox/exam_card.dart b/lib/page/homepage/toolbox/exam_card.dart index df961a6a..3f4aa5b4 100644 --- a/lib/page/homepage/toolbox/exam_card.dart +++ b/lib/page/homepage/toolbox/exam_card.dart @@ -4,6 +4,7 @@ import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:get/get.dart'; import 'package:ming_cute_icons/ming_cute_icons.dart'; @@ -25,9 +26,21 @@ class ExamCard extends StatelessWidget { if (c.status == ExamStatus.cache || c.status == ExamStatus.fetched) { context.pushReplacement(ExamInfoWindow(time: updateTime)); } else if (c.status != ExamStatus.error) { - showToast(context: context, msg: "请稍候,正在获取考试信息"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "homepage.toolbox.exam_fetching", + ), + ); } else if (offline) { - showToast(context: context, msg: "脱机模式下,一站式相关功能全部禁止使用"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "homepage.offline_mode", + ), + ); } else { ScaffoldMessenger.of(context).showSnackBar( SnackBar( @@ -37,11 +50,17 @@ class ExamCard extends StatelessWidget { )), ), ); - showToast(context: context, msg: "遇到错误,请联系开发者"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "homepage.toolbox.exam_error", + ), + ); } }, icon: MingCuteIcons.mgc_calendar_line, - name: "考试安排", + nameKey: "homepage.toolbox.exam", ), ); } diff --git a/lib/page/homepage/toolbox/experiment_card.dart b/lib/page/homepage/toolbox/experiment_card.dart index c7b0e1e9..4465eb70 100644 --- a/lib/page/homepage/toolbox/experiment_card.dart +++ b/lib/page/homepage/toolbox/experiment_card.dart @@ -34,7 +34,7 @@ class ExperimentCard extends StatelessWidget { } }, icon: MingCuteIcons.mgc_science_line, - name: "物理实验", + nameKey: "homepage.toolbox.experiment", ); } } diff --git a/lib/page/homepage/toolbox/score_card.dart b/lib/page/homepage/toolbox/score_card.dart index 63687d8c..c6487694 100644 --- a/lib/page/homepage/toolbox/score_card.dart +++ b/lib/page/homepage/toolbox/score_card.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:watermeter/page/public_widget/context_extension.dart'; import 'package:watermeter/page/score/score.dart'; @@ -17,13 +18,19 @@ class ScoreCard extends StatelessWidget { return SmallFunctionCard( onTap: () { if (offline && !ScoreSession.isCacheExist) { - showToast(context: context, msg: "脱机状态且无缓存成绩数据,无法访问"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "homepage.toolbox.score_cannot_reach", + ), + ); } else { context.pushReplacement(const ScoreWindow()); } }, icon: Icons.grading_rounded, - name: "成绩查询", + nameKey: "homepage.toolbox.score", ); } } diff --git a/lib/page/homepage/toolbox/small_function_card.dart b/lib/page/homepage/toolbox/small_function_card.dart index c1f7d26f..3955d249 100644 --- a/lib/page/homepage/toolbox/small_function_card.dart +++ b/lib/page/homepage/toolbox/small_function_card.dart @@ -2,19 +2,20 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/page/homepage/home_card_padding.dart'; class SmallFunctionCard extends StatelessWidget { final IconData icon; - final String name; + final String nameKey; final void Function()? onTap; final void Function()? onLongPress; const SmallFunctionCard({ super.key, required this.icon, - required this.name, + required this.nameKey, this.onTap, this.onLongPress, }); @@ -29,7 +30,10 @@ class SmallFunctionCard extends StatelessWidget { ), const SizedBox(height: 4), Text( - name, + FlutterI18n.translate( + context, + nameKey, + ), style: TextStyle( fontSize: 14, color: Theme.of(context).colorScheme.primary, diff --git a/lib/page/homepage/toolbox/sport_card.dart b/lib/page/homepage/toolbox/sport_card.dart index b065bcc7..595d76f2 100644 --- a/lib/page/homepage/toolbox/sport_card.dart +++ b/lib/page/homepage/toolbox/sport_card.dart @@ -32,7 +32,7 @@ class SportCard extends StatelessWidget { } }, icon: MingCuteIcons.mgc_run_fill, - name: "体育信息", + nameKey: "homepage.toolbox.sport", ); } } diff --git a/lib/page/homepage/toolbox/toolbox_card.dart b/lib/page/homepage/toolbox/toolbox_card.dart index 14a5b30d..94c75179 100644 --- a/lib/page/homepage/toolbox/toolbox_card.dart +++ b/lib/page/homepage/toolbox/toolbox_card.dart @@ -17,7 +17,7 @@ class ToolboxCard extends StatelessWidget { context.pushReplacement(const ToolBoxPage()); }, icon: MingCuteIcons.mgc_tool_line, - name: "其他功能", + nameKey: "homepage.toolbox.toolbox", ); } } diff --git a/lib/page/library/book_detail_card.dart b/lib/page/library/book_detail_card.dart index 4a9138ea..ea52fc25 100644 --- a/lib/page/library/book_detail_card.dart +++ b/lib/page/library/book_detail_card.dart @@ -4,6 +4,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/library.dart'; import 'package:watermeter/page/library/book_place_card.dart'; @@ -79,16 +80,23 @@ class _BookDetailCardState extends State { const SizedBox(height: 8), Text.rich( TextSpan(children: [ - const TextSpan( - text: "作者 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.author", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), ), ), TextSpan( - text: widget.toUse.author ?? "没有提供", + text: widget.toUse.author ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, @@ -97,16 +105,23 @@ class _BookDetailCardState extends State { ]), ), Text.rich(TextSpan(children: [ - const TextSpan( - text: "出版社 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.publish_house", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), ), ), TextSpan( - text: widget.toUse.publisherHouse ?? "没有相关信息", + text: widget.toUse.publisherHouse ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, @@ -114,9 +129,12 @@ class _BookDetailCardState extends State { ), ])), Text.rich(TextSpan(children: [ - const TextSpan( - text: "索书号 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.call_number", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), @@ -131,16 +149,23 @@ class _BookDetailCardState extends State { ), ])), Text.rich(TextSpan(children: [ - const TextSpan( - text: "发行时间 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.publish_date", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), ), ), TextSpan( - text: widget.toUse.publishYear ?? "没有相关信息", + text: widget.toUse.publishYear ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, @@ -148,16 +173,23 @@ class _BookDetailCardState extends State { ), ])), Text.rich(TextSpan(children: [ - const TextSpan( - text: "ISBN ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.isbn", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), ), ), TextSpan( - text: widget.toUse.isbn ?? "没有提供", + text: widget.toUse.isbn ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, @@ -165,9 +197,12 @@ class _BookDetailCardState extends State { ), ])), Text.rich(TextSpan(children: [ - const TextSpan( - text: "编排号码 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.arrangement_code", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), diff --git a/lib/page/library/book_info_card.dart b/lib/page/library/book_info_card.dart index 1b5839c8..6fe5b0b1 100644 --- a/lib/page/library/book_info_card.dart +++ b/lib/page/library/book_info_card.dart @@ -6,6 +6,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/library.dart'; import 'package:watermeter/repository/logger.dart'; @@ -62,16 +63,23 @@ class BookInfoCard extends StatelessWidget { const SizedBox(height: 2), Text.rich( TextSpan(children: [ - const TextSpan( - text: "作者 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.author", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), ), ), TextSpan( - text: toUse.author ?? "没有提供", + text: toUse.author ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, @@ -82,16 +90,23 @@ class BookInfoCard extends StatelessWidget { overflow: TextOverflow.ellipsis, ), Text.rich(TextSpan(children: [ - const TextSpan( - text: "出版社 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.publish_house", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), ), ), TextSpan( - text: toUse.publisherHouse ?? "没有相关信息", + text: toUse.publisherHouse ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, @@ -99,9 +114,12 @@ class BookInfoCard extends StatelessWidget { ), ])), Text.rich(TextSpan(children: [ - const TextSpan( - text: "索书号 ", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.call_number", + ), + style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), @@ -128,9 +146,12 @@ class BookInfoCard extends StatelessWidget { fontWeight: FontWeight.w600, ), ), - const TextSpan( - text: "可借", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.avaliable_borrow", + ), + style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), @@ -155,9 +176,12 @@ class BookInfoCard extends StatelessWidget { fontWeight: FontWeight.w600, ), ), - const TextSpan( - text: "馆藏", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.storage", + ), + style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Color(0xFFBFBFBF), @@ -179,11 +203,4 @@ class BookInfoCard extends StatelessWidget { .clipRRect(all: 16) .padding(all: 4); } - - String validateList(List? inputList) { - if (inputList == null || inputList.isEmpty) { - return "没有相关信息"; - } - return inputList.first; - } } diff --git a/lib/page/library/book_place_card.dart b/lib/page/library/book_place_card.dart index efe12db9..92790e65 100644 --- a/lib/page/library/book_place_card.dart +++ b/lib/page/library/book_place_card.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:ming_cute_icons/ming_cute_icons.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/model/xidian_ids/library.dart'; @@ -29,7 +30,11 @@ class BookPlaceCard extends StatelessWidget { ), const SizedBox(width: 8), Text( - toUse.locationName ?? "没有位置信息", + toUse.locationName ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), style: TextStyle( fontWeight: FontWeight.w400, fontSize: 16, @@ -41,7 +46,17 @@ class BookPlaceCard extends StatelessWidget { ].toRow(), const SizedBox(height: 8), Text( - "书籍编号:${toUse.barCode}", + FlutterI18n.translate( + context, + "library.book_code", + translationParams: { + "barCode": toUse.barCode ?? + FlutterI18n.translate( + context, + "library.not_provided", + ), + }, + ), style: TextStyle( fontWeight: FontWeight.w400, color: toUse.processType == "在架" diff --git a/lib/page/library/borrow_info_card.dart b/lib/page/library/borrow_info_card.dart index ef763fa6..3c2ff7d7 100644 --- a/lib/page/library/borrow_info_card.dart +++ b/lib/page/library/borrow_info_card.dart @@ -6,6 +6,7 @@ import 'package:cached_network_image/cached_network_image.dart'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:sn_progress_dialog/progress_dialog.dart'; import 'package:styled_widget/styled_widget.dart'; @@ -82,9 +83,12 @@ class BorrowInfoCard extends StatelessWidget { ), ) ]), - const TextSpan( - text: " 借阅", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.borrow_str", + ), + style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.blueGrey, @@ -120,9 +124,12 @@ class BorrowInfoCard extends StatelessWidget { fontWeight: FontWeight.w600, ), ), - const TextSpan( - text: " 到期", - style: TextStyle( + TextSpan( + text: FlutterI18n.translate( + context, + "library.due_date", + ), + style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w600, color: Colors.blueGrey, @@ -150,7 +157,15 @@ class BorrowInfoCard extends StatelessWidget { ), ), TextSpan( - text: isOverdue ? " 天前到期" : " 天后", + text: isOverdue + ? FlutterI18n.translate( + context, + "library.after_due_date", + ) + : FlutterI18n.translate( + context, + "library.before_due_date", + ), style: const TextStyle( fontSize: 12, fontWeight: FontWeight.w600, @@ -159,7 +174,15 @@ class BorrowInfoCard extends StatelessWidget { ), ])); final button = Text( - isOverdue ? "不可续借" : "续借", + isOverdue + ? FlutterI18n.translate( + context, + "library.cannot_be_renewable", + ) + : FlutterI18n.translate( + context, + "library.can_be_renewable", + ), style: TextStyle( color: Theme.of(context).colorScheme.onPrimary, fontWeight: FontWeight.w600, @@ -174,7 +197,12 @@ class BorrowInfoCard extends StatelessWidget { onTap: () { if (!isOverdue) { ProgressDialog pd = ProgressDialog(context: context); - pd.show(msg: "正在续借"); + pd.show( + msg: FlutterI18n.translate( + context, + "library.renewing", + ), + ); LibrarySession().renew(toUse.loanId).then((value) { if (context.mounted) { pd.close(); diff --git a/lib/page/library/borrow_list_window.dart b/lib/page/library/borrow_list_window.dart index feb51fa7..be16b3dc 100644 --- a/lib/page/library/borrow_list_window.dart +++ b/lib/page/library/borrow_list_window.dart @@ -3,6 +3,7 @@ // Borrow list, shows the user's borrowlist. +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -72,7 +73,12 @@ class BorrowListDetail extends StatelessWidget { ), ); } else { - return const EmptyListView(text: "目前没有查询到在借图书\n不借书就要变成上面的小呆瓜咯"); + return EmptyListView( + text: FlutterI18n.translate( + context, + "library.empty_borrow_list", + ), + ); } }), bottomNavigationBar: BottomAppBar( @@ -80,8 +86,12 @@ class BorrowListDetail extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - Text( - "在借 ${borrow_info.borrowList.length} 本,其中已过期 ${borrow_info.dued} 本", + I18nText( + "library.borrow_list_info", + translationParams: { + "borrow": borrow_info.borrowList.length.toString(), + "dued": borrow_info.dued.toString(), + }, ), ], ), diff --git a/lib/page/library/library_window.dart b/lib/page/library/library_window.dart index 2867b155..67d4fb56 100644 --- a/lib/page/library/library_window.dart +++ b/lib/page/library/library_window.dart @@ -3,6 +3,7 @@ // Library Window. import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/library/borrow_list_window.dart'; import 'package:watermeter/page/library/search_book_window.dart'; @@ -15,14 +16,20 @@ class LibraryWindow extends StatelessWidget { length: 2, child: Scaffold( appBar: AppBar( - title: const Text("图书馆信息"), - bottom: const TabBar( + title: Text(FlutterI18n.translate(context, "library.title")), + bottom: TabBar( tabs: [ Tab( - text: "借书状态", + text: FlutterI18n.translate( + context, + "library.borrow_state_title", + ), ), Tab( - text: "查询藏书", + text: FlutterI18n.translate( + context, + "library.search_book_title", + ), ), ], ), diff --git a/lib/page/library/search_book_window.dart b/lib/page/library/search_book_window.dart index c1a4729b..acbc6960 100644 --- a/lib/page/library/search_book_window.dart +++ b/lib/page/library/search_book_window.dart @@ -1,6 +1,7 @@ // Copyright 2023 BenderBlog Rodriguez and contributors. // SPDX-License-Identifier: MPL-2.0 +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/both_side_sheet.dart'; import 'package:easy_refresh/easy_refresh.dart'; import 'package:flutter/material.dart'; @@ -80,14 +81,17 @@ class _SearchBookWindowState extends State constraints: const BoxConstraints(maxWidth: 480), child: TextFormField( controller: text, - decoration: const InputDecoration( + decoration: InputDecoration( filled: true, fillColor: Colors.transparent, - hintText: "在此搜索", + hintText: FlutterI18n.translate( + context, + "library.search_here", + ), isDense: false, - contentPadding: EdgeInsets.symmetric(vertical: 8.0), - prefixIcon: Icon(Icons.search), - border: OutlineInputBorder( + contentPadding: const EdgeInsets.symmetric(vertical: 8.0), + prefixIcon: const Icon(Icons.search), + border: const OutlineInputBorder( borderRadius: BorderRadius.all(Radius.circular(10)), ), ), @@ -105,12 +109,30 @@ class _SearchBookWindowState extends State ), EasyRefresh( footer: ClassicFooter( - dragText: '上拉请求更多'.tr, - readyText: '正在加载......'.tr, - processingText: '正在加载......'.tr, - processedText: '请求成功'.tr, - noMoreText: '数据没有更多'.tr, - failedText: '数据获取失败更多'.tr, + dragText: FlutterI18n.translate( + context, + "drag_text", + ), + readyText: FlutterI18n.translate( + context, + "ready_text", + ), + processingText: FlutterI18n.translate( + context, + "processing_text", + ), + processedText: FlutterI18n.translate( + context, + "processed_text", + ), + noMoreText: FlutterI18n.translate( + context, + "no_more_text", + ), + failedText: FlutterI18n.translate( + context, + "failed_text", + ), infiniteOffset: null, ), onLoad: () async { @@ -124,7 +146,10 @@ class _SearchBookWindowState extends State child: BookInfoCard(toUse: searchList[index]), onTap: () => BothSideSheet.show( context: context, - title: "书籍详细信息", + title: FlutterI18n.translate( + context, + "library.book_detail", + ), child: BookDetailCard( toUse: searchList[index], ), @@ -147,17 +172,25 @@ class _SearchBookWindowState extends State } else if (isSearching.value) { return const Center(child: CircularProgressIndicator()); } else if (search.value.isNotEmpty) { - return const EmptyListView(text: "没有结果"); + return EmptyListView( + text: FlutterI18n.translate( + context, + "library.no_result", + ), + ); } else { - return const Column( + return Column( mainAxisAlignment: MainAxisAlignment.center, children: [ - Icon( + const Icon( Icons.search, size: 96, ), - Divider(color: Colors.transparent), - Text("请在上面搜索框搜索"), + const Divider(color: Colors.transparent), + Text(FlutterI18n.translate( + context, + "library.please_search", + )), ], ); } diff --git a/lib/page/login/bottom_buttons.dart b/lib/page/login/bottom_buttons.dart index 46875031..3c5bc7a7 100644 --- a/lib/page/login/bottom_buttons.dart +++ b/lib/page/login/bottom_buttons.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:talker_flutter/talker_flutter.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:watermeter/repository/logger.dart'; @@ -23,15 +24,32 @@ class ButtomButtons extends StatelessWidget { alignment: WrapAlignment.center, children: [ TextButton( - child: Text('清除登录缓存', style: _bottomTextStyle), + child: Text( + FlutterI18n.translate(context, "login.clear_cache"), + style: _bottomTextStyle, + ), onPressed: () { NetworkSession().clearCookieJar().then((value) { - if (context.mounted) showToast(context: context, msg: '清理缓存成功'); + if (context.mounted) { + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "login.complete_clear_cache", + ), + ); + } }); }, ), TextButton( - child: Text('查看网络交互', style: _bottomTextStyle), + child: Text( + FlutterI18n.translate( + context, + "login.see_inspector", + ), + style: _bottomTextStyle, + ), onPressed: () { Navigator.of(context).push(MaterialPageRoute( builder: (context) => TalkerScreen(talker: log), diff --git a/lib/page/login/captcha_input_dialog.dart b/lib/page/login/captcha_input_dialog.dart index 52fef75d..c7638839 100644 --- a/lib/page/login/captcha_input_dialog.dart +++ b/lib/page/login/captcha_input_dialog.dart @@ -4,6 +4,7 @@ // A captcha input dialog. import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; class CaptchaInputDialog extends StatelessWidget { @@ -20,7 +21,10 @@ class CaptchaInputDialog extends StatelessWidget { ); return AlertDialog( - title: const Text('请输入验证码'), + title: Text(FlutterI18n.translate( + context, + "login.captcha_window.title", + )), titleTextStyle: const TextStyle( fontSize: 20, color: Colors.black, @@ -35,7 +39,10 @@ class CaptchaInputDialog extends StatelessWidget { style: const TextStyle(fontSize: 20), controller: _captchaController, decoration: InputDecoration( - hintText: "输入验证码", + hintText: FlutterI18n.translate( + context, + "login.captcha_window.hint", + ), fillColor: Colors.grey.withOpacity(0.4), filled: true, contentPadding: const EdgeInsets.symmetric(horizontal: 20), @@ -49,16 +56,28 @@ class CaptchaInputDialog extends StatelessWidget { ), actions: [ TextButton( - child: const Text('取消'), + child: Text(FlutterI18n.translate( + context, + "cancel", + )), onPressed: () { Navigator.pop(context); }, ), TextButton( - child: const Text('提交'), + child: Text(FlutterI18n.translate( + context, + "confirm", + )), onPressed: () async { if (_captchaController.text.isEmpty) { - showToast(context: context, msg: '请输入验证码'); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "login.captcha_window.message_on_empty", + ), + ); } else { Navigator.of(context).pop(_captchaController.text); } diff --git a/lib/page/login/jc_captcha.dart b/lib/page/login/jc_captcha.dart index 6bb097a8..767d48f7 100644 --- a/lib/page/login/jc_captcha.dart +++ b/lib/page/login/jc_captcha.dart @@ -9,6 +9,7 @@ import 'dart:typed_data'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:image/image.dart' as img; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/repository/logger.dart'; @@ -245,7 +246,10 @@ class _CaptchaWidgetState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text("服务器认证服务"), + title: Text(FlutterI18n.translate( + context, + "login.slider_title", + )), ), body: FutureBuilder( future: provider, diff --git a/lib/page/login/login_window.dart b/lib/page/login/login_window.dart index fb313348..225e140e 100644 --- a/lib/page/login/login_window.dart +++ b/lib/page/login/login_window.dart @@ -6,6 +6,7 @@ import 'dart:math'; import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/setting/about_page/about_page.dart'; import 'package:watermeter/repository/logger.dart'; import 'package:watermeter/page/public_widget/toast.dart'; @@ -74,7 +75,7 @@ class _LoginWindowState extends State { controller: _idsAccountController, decoration: _inputDecoration( iconData: MingCuteIcons.mgc_user_3_fill, - hintText: "学号", + hintText: FlutterI18n.translate(context, "login.identity_number"), ), style: TextStyle( fontSize: _inputFieldFontSize, @@ -101,7 +102,7 @@ class _LoginWindowState extends State { ), decoration: _inputDecoration( iconData: MingCuteIcons.mgc_safe_lock_fill, - hintText: "一站式登录密码", + hintText: FlutterI18n.translate(context, "login.password"), suffixIcon: IconButton( icon: Icon( _couldNotView ? Icons.visibility : Icons.visibility_off, @@ -148,7 +149,13 @@ class _LoginWindowState extends State { if (_idsPasswordController.text.isNotEmpty) { await login(); } else { - showToast(context: context, msg: '用户名或密码不符合要求,学号必须 11 位且密码非空'); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "login.incorrect_password_pattern", + ), + ); } }, ), @@ -161,10 +168,18 @@ class _LoginWindowState extends State { bool isGood = true; ProgressDialog pd = ProgressDialog(context: context); pd.show( - msg: '正在登录学校一站式', + msg: FlutterI18n.translate( + context, + "login.on_login_progress", + ), max: 100, hideValue: true, - completed: Completed(completedMsg: "登录成功"), + completed: Completed( + completedMsg: FlutterI18n.translate( + context, + "login.complete_login", + ), + ), ); EhallSession ses = EhallSession(); @@ -227,14 +242,36 @@ class _LoginWindowState extends State { } else if (e is DioException) { if (e.message == null) { if (e.response == null) { - showToast(context: context, msg: "无法连接到服务器。"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "login.failed_login_cannot_connect_to_server", + ), + ); } else { showToast( - context: context, - msg: "请求失败,响应状态码:${e.response!.statusCode}。"); + context: context, + msg: FlutterI18n.translate( + context, + "login.failed_login_with_code", + translationParams: { + "code": e.response!.statusCode.toString() + }, + ), + ); } } else { - showToast(context: context, msg: "请求失败。${e.message}"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "login.failed_login_with_message", + translationParams: { + "message": e.message.toString(), + }, + ), + ); } } else { log.warning( @@ -256,7 +293,10 @@ class _LoginWindowState extends State { ); showToast( context: context, - msg: "未知错误,请联系开发者。", + msg: FlutterI18n.translate( + context, + "login.failed_login_other", + ), ); } } diff --git a/lib/page/schoolcard/school_card_window.dart b/lib/page/schoolcard/school_card_window.dart index b660a56d..b07c1b89 100644 --- a/lib/page/schoolcard/school_card_window.dart +++ b/lib/page/schoolcard/school_card_window.dart @@ -2,6 +2,7 @@ // SPDX-License-Identifier: MPL-2.0 // School card log list. +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; import 'package:calendar_date_picker2/calendar_date_picker2.dart'; @@ -30,9 +31,17 @@ class _SchoolCardWindowState extends State { sumUp += double.parse(element.money); } if (sumUp.isLowerThan(0)) { - return "支出 ${(sumUp * -1).toStringAsFixed(2)}"; + return FlutterI18n.translate( + context, + "school_card_window.income", + translationParams: {"income": (sumUp * -1).toStringAsFixed(2)}, + ); } else { - return "收入 ${sumUp.toStringAsFixed(2)}"; + return FlutterI18n.translate( + context, + "school_card_window.expense", + translationParams: {"expense": sumUp.toStringAsFixed(2)}, + ); } } @@ -57,7 +66,12 @@ class _SchoolCardWindowState extends State { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("校园卡流水信息")), + appBar: AppBar( + title: Text(FlutterI18n.translate( + context, + "school_card_window.title", + )), + ), body: Column( children: [ TextButton( @@ -65,10 +79,14 @@ class _SchoolCardWindowState extends State { backgroundColor: Theme.of(context).colorScheme.secondaryContainer, ), - child: Text( - "选择日期:从 ${Jiffy.parseFromDateTime(timeRange[0]!).format(pattern: "yyyy-MM-dd")} " - "到 ${Jiffy.parseFromDateTime(timeRange[1]!).format(pattern: "yyyy-MM-dd")}", - ), + child: Text(FlutterI18n.translate( + context, "school_card_window.select_range", + translationParams: { + "startDay": Jiffy.parseFromDateTime(timeRange[0]!) + .format(pattern: "yyyy-MM-dd"), + "endDay": Jiffy.parseFromDateTime(timeRange[1]!) + .format(pattern: "yyyy-MM-dd"), + })), onPressed: () async { await showCalendarDatePicker2Dialog( context: context, @@ -104,22 +122,36 @@ class _SchoolCardWindowState extends State { columnSpacing: 0, horizontalMargin: 6, columns: [ - const DataColumn2( + DataColumn2( size: ColumnSize.S, label: Center( - child: Text('商户名称'), + child: Text(FlutterI18n.translate( + context, + "school_card_window.store_name", + )), ), ), - const DataColumn2( + DataColumn2( size: ColumnSize.S, label: Center( - child: Text('金额'), + child: Text(FlutterI18n.translate( + context, + "school_card_window.balance", + )), ), ), DataColumn2( size: ColumnSize.L, label: Center( - child: Text('时间(共${moneySunUp(snapshot.data!)}元)'), + child: Text( + FlutterI18n.translate( + context, + "school_card_window.balance", + translationParams: { + "sum": moneySunUp(snapshot.data!) + }, + ), + ), ), ), ], diff --git a/lib/page/setting/about_page/about_page.dart b/lib/page/setting/about_page/about_page.dart index 480e3f2d..e4248537 100644 --- a/lib/page/setting/about_page/about_page.dart +++ b/lib/page/setting/about_page/about_page.dart @@ -4,6 +4,7 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:watermeter/page/public_widget/app_icon.dart'; import 'package:watermeter/page/public_widget/re_x_card.dart'; @@ -12,167 +13,224 @@ import 'package:watermeter/page/setting/about_page/developer_widget.dart'; import 'package:watermeter/page/setting/about_page/link_widget.dart'; import 'package:watermeter/repository/preference.dart' as preference; -class AboutPage extends StatelessWidget { - final List getDevelopers = const [ - Developer( - "BenderBlog Rodriguez", - "https://avatars.githubusercontent.com/u/14026321", - "主要开发者,iOS 小部件编写和拼接", - "https://space.bilibili.com/284290692", - ), - Developer( - "BellssGit", - "https://avatars.githubusercontent.com/u/107785251", - "支持:最佳&最久故障反馈者", - "https://space.bilibili.com/17772726", - ), - Developer( - "BrackRat", - "https://avatars.githubusercontent.com/u/35328547", - "设计:主页,登录页,配色,iOS 小部件等", - "https://github.com/BrackRat", - ), - Developer( - "Breezeline", - "https://avatars.githubusercontent.com/u/74224286", - "支持:无价值无意义的产品经理(他自己的描述)", - "mailto:ydzhang.ruc@gmail.com", - ), - Developer( - "0xCAFEBABE", - "https://blog.hxzzz.asia/usr/uploads/2024/05/1717631110.jpg", - "支持:提供彩蛋代码", - "https://blog.hxzzz.asia/", - ), - Developer( - "chitao1234", - "https://avatars.githubusercontent.com/u/25598632", - "开发:修复滑块不对齐问题", - "https://github.com/chitao1234", - ), - Developer( - "Dimole", - "https://avatars.githubusercontent.com/u/24828354", - "开发支持:辅助修复滑块问题", - "https://github.com/Dimole", - ), - Developer( - "EliteWars", - "https://avatars.githubusercontent.com/u/44139545", - "设计:体育成绩页面", - "https://space.bilibili.com/49892391/", - ), - Developer( - "Elliot", - "https://img.moegirl.org.cn/common/thumb/6/64/Hirasawa_yui_1.jpg/800px-Hirasawa_yui_1.jpg", - "开发支持:搭子课表功能开发指导", - "https://www.bilibili.com/bangumi/play/ss1172/", - ), - Developer( - "GodHu777777", - "https://avatars.githubusercontent.com/u/111997394", - "开发支持:繁体中文转换代码和彩蛋代码(多语言仍在开发)", - "https://github.com/GodHu777777", - ), - Developer( - "Hancl777", - "https://avatars.githubusercontent.com/u/74408609", - "开发支持:繁体中文转换代码(多语言仍在开发)", - "https://github.com/Hancl777", - ), - Developer( - "hhzm (闪电豹猫)", - "https://avatars.githubusercontent.com/u/19224718", - "开发支持:提供彩蛋代码,电费查询账号计算", - "https://hhzm.win/", - ), - Developer( - "lsy223622 (木生睡不着)", - "https://avatars.githubusercontent.com/u/57913213", - "设计:iOS 和 Android 图标 / 支持:冠名 XDYou for iOS", - "https://lsy223622.com/", - ), - Developer( - "NanCunChild", - "https://avatars.githubusercontent.com/u/85873278?v=4", - "开发:图书馆搜索功能", - "https://github.com/NanCunChild", - ), - Developer( - "Pairman", - "https://avatars.githubusercontent.com/u/18365163", - "开发:成绩缓存功能和优化滑块算法", - "https://github.com/Pairman", - ), - Developer( - "ReverierXu", - "https://blog.woooo.tech/img/avatar.png", - "设计:用于信息展示的 ReX 卡片 / 开发支持:研究生课表", - "https://blog.woooo.tech/", - ), - Developer( - "Rrrilac", - "https://avatars.githubusercontent.com/u/128341096", - "开发支持:电费查询", - "https://github.com/Rrrilac", - ), - Developer( - "Ray (Elliot Edition)", - "https://raay.xyz/wp-content/uploads/2023/07/4882705B-3C57-4B46-A3DA-F75C2E0DCE5B.jpeg", - "设计:开屏画面 / 支持:iOS 发行商 / 开发支持:搭子课表功能开发指导", - "https://raay.xyz/", - ), - Developer( - "shadowyingyi", - "https://avatars.githubusercontent.com/u/42831635", - "支持:两次鸽子公众号宣传", - "https://github.com/shadowyingyi", - ), - Developer( - "stalomeow", - "https://avatars.githubusercontent.com/u/47203031", - "设计:首页时间轴 / 开发:异步登录", - "https://stalomeow.com", - ), - Developer( - "xeonds", - "https://avatars.githubusercontent.com/u/68117734", - "设计:设置页面 / 开发:XDU Planet", - "https://mxts.jiujiuer.xyz", - ), - Developer( - "Xiue233", - "https://xiue233.github.io/images/avatar.png", - "开发:Android 小部件和拼接", - "https://xiue233.github.io/", - ), - Developer( - "ZCWzy", - "https://avatars.githubusercontent.com/u/87163986", - "开发:修复丁香电费 / 开发支持:研究生版本开发", - "https://github.com/ZCWzy", - ), - ]; +class AboutPage extends StatefulWidget { + const AboutPage({super.key}); - final List linkData = const [ - Link( - icon: Icon(Icons.home), - name: "主页", - url: "https://legacy.superbart.top/xdyou.html", - ), - Link( - icon: Icon(Icons.code), - name: "开源代码", - url: "https://github.com/BenderBlog/traintime_pda", - ), - Link( - icon: Icon(Icons.redeem), - name: "给我捐款", - url: "https://afdian.com/a/benderblog", - ), - ]; + @override + State createState() => _AboutPageState(); +} - const AboutPage({super.key}); +class _AboutPageState extends State { + List getDevelopers() => [ + Developer( + "BenderBlog Rodriguez", + "https://avatars.githubusercontent.com/u/14026321", + FlutterI18n.translate( + context, + "setting.about_page.benderblog", + ), + "https://space.bilibili.com/284290692", + ), + Developer( + "BellssGit", + "https://avatars.githubusercontent.com/u/107785251", + FlutterI18n.translate( + context, + "setting.about_page.bellssgit", + ), + "https://space.bilibili.com/17772726", + ), + Developer( + "BrackRat", + "https://avatars.githubusercontent.com/u/35328547", + FlutterI18n.translate( + context, + "setting.about_page.brackrat", + ), + "https://github.com/BrackRat", + ), + Developer( + "Breezeline", + "https://avatars.githubusercontent.com/u/74224286", + FlutterI18n.translate( + context, + "setting.about_page.breezeline", + ), + "mailto:ydzhang.ruc@gmail.com", + ), + Developer( + "0xCAFEBABE", + "https://blog.hxzzz.asia/usr/uploads/2024/05/1717631110.jpg", + FlutterI18n.translate( + context, + "setting.about_page.cafebabe", + ), + "https://blog.hxzzz.asia/", + ), + Developer( + "chitao1234", + "https://avatars.githubusercontent.com/u/25598632", + FlutterI18n.translate( + context, + "setting.about_page.chitao1234", + ), + "https://github.com/chitao1234", + ), + Developer( + "Dimole", + "https://avatars.githubusercontent.com/u/24828354", + FlutterI18n.translate( + context, + "setting.about_page.dimole", + ), + "https://github.com/Dimole", + ), + Developer( + "EliteWars", + "https://avatars.githubusercontent.com/u/44139545", + FlutterI18n.translate( + context, + "setting.about_page.elitewars", + ), + "https://space.bilibili.com/49892391/", + ), + Developer( + "GodHu777777", + "https://avatars.githubusercontent.com/u/111997394", + FlutterI18n.translate( + context, + "setting.about_page.godhu777777", + ), + "https://github.com/GodHu777777", + ), + Developer( + "Hancl777", + "https://avatars.githubusercontent.com/u/74408609", + FlutterI18n.translate( + context, + "setting.about_page.hancl777", + ), + "https://github.com/Hancl777", + ), + Developer( + "hhzm (闪电豹猫)", + "https://avatars.githubusercontent.com/u/19224718", + FlutterI18n.translate( + context, + "setting.about_page.hhzm", + ), + "https://hhzm.win/", + ), + Developer( + "lsy223622 (木生睡不着)", + "https://avatars.githubusercontent.com/u/57913213", + FlutterI18n.translate( + context, + "setting.about_page.lsy223622", + ), + "https://lsy223622.com/", + ), + Developer( + "NanCunChild", + "https://avatars.githubusercontent.com/u/85873278?v=4", + FlutterI18n.translate( + context, + "setting.about_page.nancunchild", + ), + "https://github.com/NanCunChild", + ), + Developer( + "Pairman", + "https://avatars.githubusercontent.com/u/18365163", + FlutterI18n.translate( + context, + "setting.about_page.pairman", + ), + "https://github.com/Pairman", + ), + Developer( + "ReverierXu", + "https://blog.woooo.tech/img/avatar.png", + FlutterI18n.translate( + context, + "setting.about_page.reverierxu", + ), + "https://blog.woooo.tech/", + ), + Developer( + "Ray (Elliot Edition)", + "https://raay.xyz/wp-content/uploads/2023/07/4882705B-3C57-4B46-A3DA-F75C2E0DCE5B.jpeg", + FlutterI18n.translate( + context, + "setting.about_page.ray", + ), + "https://raay.xyz/", + ), + Developer( + "shadowyingyi", + "https://avatars.githubusercontent.com/u/42831635", + FlutterI18n.translate( + context, + "setting.about_page.shadowyingyi", + ), + "https://github.com/shadowyingyi", + ), + Developer( + "stalomeow", + "https://avatars.githubusercontent.com/u/47203031", + FlutterI18n.translate( + context, + "setting.about_page.stalomeow", + ), + "https://stalomeow.com", + ), + Developer( + "xeonds", + "https://avatars.githubusercontent.com/u/68117734", + FlutterI18n.translate( + context, + "setting.about_page.xeonds", + ), + "https://mxts.jiujiuer.xyz", + ), + Developer( + "Xiue233", + "https://xiue233.github.io/images/avatar.png", + FlutterI18n.translate( + context, + "setting.about_page.xiue233", + ), + "https://xiue233.github.io/", + ), + Developer( + "ZCWzy", + "https://avatars.githubusercontent.com/u/87163986", + FlutterI18n.translate( + context, + "setting.about_page.zcwzy", + ), + "https://github.com/ZCWzy", + ), + ]; + + List linkData() => [ + Link( + icon: const Icon(Icons.home), + name: FlutterI18n.translate( + context, + "setting.about_page.homepage", + ), + url: "https://legacy.superbart.top/xdyou.html", + ), + Link( + icon: const Icon(Icons.code), + name: FlutterI18n.translate( + context, + "setting.about_page.code", + ), + url: "https://github.com/BenderBlog/traintime_pda", + ), + ]; Widget _title(context) => [ const AppIconWidget(), @@ -211,27 +269,27 @@ class AboutPage extends StatelessWidget { ); Widget get _developerList => ReXCard( - title: Text("Made with love from ${getDevelopers.length} people") + title: Text("Made with love from ${getDevelopers().length} people") .padding( bottom: 8, ) .center(), remaining: const [], - bottomRow: getDevelopers + bottomRow: getDevelopers() .map((e) => DeveloperWidget(developer: e)) .toList() .toColumn(), ); Widget _moreList(context) => ReXCard( - title: const Text("知道更多") + title: Text(FlutterI18n.translate(context, "setting.about_page.title")) .padding( bottom: 8, ) .center(), remaining: const [], bottomRow: [ - ...linkData.map((e) => LinkWidget( + ...linkData().map((e) => LinkWidget( icon: e.icon, name: e.name, url: e.url, @@ -240,7 +298,12 @@ class AboutPage extends StatelessWidget { minLeadingWidth: 0, contentPadding: EdgeInsets.zero, leading: const Icon(Icons.balance), - title: const Text("开源协议和授权信息"), + title: Text( + FlutterI18n.translate( + context, + "setting.about_page.know_more", + ), + ), onTap: () => showLicensePage( context: context, applicationName: Platform.isIOS || Platform.isMacOS @@ -248,30 +311,32 @@ class AboutPage extends StatelessWidget { : "Traintime PDA", applicationVersion: "v${preference.packageInfo.version}+" "${preference.packageInfo.buildNumber}", - applicationLegalese: - "本软件拷贝基于 traintime_pda 代码(或称 watermeter 代码)编译," - "代码按照 Mozilla Public License, v. 2.0 授权。\n\n" - "本程序和西安电子科技大学,体适能服务,书蜗,电表等服务无关。\n\n" - "Copyright 2023-Present BenderBlog Rodriguez and contributors. " - "The Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. " - "If a copy of the MPL was not distributed with this file, " - "You can obtain one at https://mozilla.org/MPL/2.0/.", + applicationLegalese: FlutterI18n.translate( + context, + "setting.setting.about_page.copyright_notice", + ), ), ), if (Platform.isIOS || Platform.isMacOS) - const ListTile( + ListTile( minLeadingWidth: 0, contentPadding: EdgeInsets.zero, - leading: Icon(Icons.code), - title: Text("备案号"), - subtitle: Text("陕ICP备2024026116号-1A"), + leading: const Icon(Icons.code), + title: Text(FlutterI18n.translate( + context, + "setting.about_page.beian", + )), + subtitle: const Text("陕ICP备2024026116号-1A"), ), if (Platform.isAndroid) ListTile( minLeadingWidth: 0, contentPadding: EdgeInsets.zero, leading: const Icon(Icons.code), - title: const Text("安卓签名"), + title: Text(FlutterI18n.translate( + context, + "setting.about_page.sign_android", + )), subtitle: Text(preference.packageInfo.buildSignature), ), ].toList().toColumn(), @@ -280,7 +345,14 @@ class AboutPage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("关于本软件")), + appBar: AppBar( + title: Text( + FlutterI18n.translate( + context, + "setting.about_page.title", + ), + ), + ), body: Builder(builder: (context) { if (MediaQuery.sizeOf(context).width > 600 && MediaQuery.sizeOf(context).width / diff --git a/lib/page/setting/about_page/easter_egg_page.dart b/lib/page/setting/about_page/easter_egg_page.dart index aaed4062..715abc2c 100644 --- a/lib/page/setting/about_page/easter_egg_page.dart +++ b/lib/page/setting/about_page/easter_egg_page.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'dart:math'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:url_launcher/url_launcher.dart'; import 'package:pinyin/pinyin.dart'; @@ -185,6 +186,7 @@ class EasterEggPage extends StatefulWidget { } class _EasterEggPageState extends State { + final String urlApple = "https://www.bilibili.com/video/BV1wN4y1L7Ut"; final String urlOthers = "https://www.bilibili.com/video/BV1HN411Y7Ct?p=7"; @@ -349,7 +351,14 @@ Don't know how time flies, she made he faster in running, attacking. With the po @override Widget build(BuildContext context) { return Scaffold( - appBar: AppBar(title: const Text("你找到了彩蛋")), + appBar: AppBar( + title: Text( + FlutterI18n.translate( + context, + "setting.easter_egg_page.title", + ), + ), + ), body: [ const SizedBox(height: 16.0), TextFormField( @@ -373,7 +382,10 @@ Don't know how time flies, she made he faster in running, attacking. With the po [ TextButton( onPressed: onSubmitted, - child: const Text("加密上面的文本"), + child: Text(FlutterI18n.translate( + context, + "setting.easter_egg_page.encrypt", + )), ), TextButton( onPressed: () => launchUrl( @@ -382,7 +394,10 @@ Don't know how time flies, she made he faster in running, attacking. With the po ), mode: LaunchMode.externalApplication, ), - child: const Text("听歌时间"), + child: Text(FlutterI18n.translate( + context, + "setting.easter_egg_page.listen", + )), ), TextButton( onPressed: () => launchUrl( diff --git a/lib/page/setting/dialogs/change_brightness_dialog.dart b/lib/page/setting/dialogs/change_brightness_dialog.dart index 24c7b33a..3d223517 100644 --- a/lib/page/setting/dialogs/change_brightness_dialog.dart +++ b/lib/page/setting/dialogs/change_brightness_dialog.dart @@ -2,10 +2,10 @@ // SPDX-License-Identifier: MPL-2.0 // Change app brightness. +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:get/get.dart'; import 'package:flutter/material.dart'; -import 'package:watermeter/themes/demo_blue.dart'; import 'package:watermeter/controller/theme_controller.dart'; import 'package:watermeter/repository/preference.dart' as preference; @@ -19,8 +19,26 @@ class ChangeBrightnessDialog extends StatefulWidget { class _ChangeBrightnessDialogState extends State { @override Widget build(BuildContext context) { + List demoBlueModeName = [ + FlutterI18n.translate( + context, + "setting.change_brightness_dialog.follow_setting", + ), + FlutterI18n.translate( + context, + "setting.change_brightness_dialog.day_mode", + ), + FlutterI18n.translate( + context, + "setting.change_brightness_dialog.night_mode", + ), + ]; + return AlertDialog( - title: const Text('颜色设置'), + title: Text(FlutterI18n.translate( + context, + "setting.change_brightness_dialog.title", + )), titleTextStyle: TextStyle( fontSize: 20, color: Theme.of(context).colorScheme.onSurface, @@ -49,7 +67,10 @@ class _ChangeBrightnessDialogState extends State { ), actions: [ TextButton( - child: const Text('改完了'), + child: Text(FlutterI18n.translate( + context, + "confirm", + )), onPressed: () { Navigator.pop(context); }, diff --git a/lib/page/setting/dialogs/change_swift_dialog.dart b/lib/page/setting/dialogs/change_swift_dialog.dart index f9d479c0..ba4efa38 100644 --- a/lib/page/setting/dialogs/change_swift_dialog.dart +++ b/lib/page/setting/dialogs/change_swift_dialog.dart @@ -5,6 +5,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/repository/preference.dart' as preference; class ChangeSwiftDialog extends StatelessWidget { @@ -27,7 +28,10 @@ class ChangeSwiftDialog extends StatelessWidget { @override Widget build(BuildContext context) { return AlertDialog( - title: const Text('课程偏移设置'), + title: Text(FlutterI18n.translate( + context, + "setting.change_swift_dialog.title", + )), content: TextField( autofocus: true, controller: _getNumberController, @@ -36,20 +40,21 @@ class ChangeSwiftDialog extends StatelessWidget { FilteringTextInputFormatter.allow(RegExp(r'^[-+]?[0-9]*')) ], maxLines: 1, - decoration: const InputDecoration( - hintText: "请在此输入数字", - border: OutlineInputBorder(), + decoration: InputDecoration( + hintText: FlutterI18n.translate( + context, + "setting.change_swift_dialog.input_hint", + ), + border: const OutlineInputBorder(), ), ), actions: [ TextButton( - child: const Text('取消'), - onPressed: () { - Navigator.pop(context); - }, + child: Text(FlutterI18n.translate(context, "cancel")), + onPressed: () => Navigator.pop(context), ), TextButton( - child: const Text('提交'), + child: Text(FlutterI18n.translate(context, "confirm")), onPressed: () async { if (_getNumberController.text.isEmpty) { await preference.setInt(preference.Preference.swift, 0); diff --git a/lib/page/setting/dialogs/electricity_password_dialog.dart b/lib/page/setting/dialogs/electricity_password_dialog.dart index 6be4c3a7..23160560 100644 --- a/lib/page/setting/dialogs/electricity_password_dialog.dart +++ b/lib/page/setting/dialogs/electricity_password_dialog.dart @@ -4,6 +4,7 @@ // Electricity password dialog. import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:watermeter/repository/preference.dart' as preference; @@ -33,42 +34,60 @@ class _ElectricityPasswordDialogState extends State { @override Widget build(BuildContext context) { return AlertDialog( - title: const Text('修改电费帐号密码'), + title: Text(FlutterI18n.translate( + context, + "setting.change_electricity_title", + )), content: TextField( autofocus: true, controller: _sportPasswordController, obscureText: _couldView, decoration: InputDecoration( - hintText: "请在此输入密码", + hintText: FlutterI18n.translate( + context, + "setting.change_password_dialog.input_hint", + ), border: const OutlineInputBorder(), suffixIcon: IconButton( - icon: Icon(_couldView ? Icons.visibility : Icons.visibility_off), - onPressed: () { - setState(() { - _couldView = !_couldView; - }); - }), + icon: Icon(_couldView ? Icons.visibility : Icons.visibility_off), + onPressed: () => setState(() => _couldView = !_couldView), + ), ), ), actions: [ TextButton( - child: const Text('取消'), + child: Text( + FlutterI18n.translate( + context, + "cancel", + ), + ), onPressed: () { Navigator.pop(context); }, ), TextButton( - child: const Text('提交'), + child: Text( + FlutterI18n.translate( + context, + "confirm", + ), + ), onPressed: () async { - if (_sportPasswordController.text.isNotEmpty) { - preference.setString( - preference.Preference.electricityPassword, - _sportPasswordController.text, + if (_sportPasswordController.text.isEmpty) { + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "setting.change_password_dialog.blank_input", + ), ); - Navigator.of(context).pop(); - } else { - showToast(context: context, msg: "输入空白!"); } + preference.setString( + preference.Preference.electricityPassword, + _sportPasswordController.text, + ); + Navigator.of(context).pop(); }, ), ], diff --git a/lib/page/setting/dialogs/experiment_password_dialog.dart b/lib/page/setting/dialogs/experiment_password_dialog.dart index e2a86c10..ea7a7d52 100644 --- a/lib/page/setting/dialogs/experiment_password_dialog.dart +++ b/lib/page/setting/dialogs/experiment_password_dialog.dart @@ -4,6 +4,7 @@ // Experiment password dialog. import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:watermeter/repository/preference.dart' as user_perference; @@ -38,13 +39,19 @@ class _ExperimentPasswordDialogState extends State { @override Widget build(BuildContext context) { return AlertDialog( - title: const Text('修改物理实验系统密码'), + title: Text(FlutterI18n.translate( + context, + "setting.change_experiment_title", + )), content: TextField( autofocus: true, controller: _experimentPasswordController, obscureText: _couldView, decoration: InputDecoration( - hintText: "请在此输入密码", + hintText: FlutterI18n.translate( + context, + "setting.change_password_dialog.input_hint", + ), border: const OutlineInputBorder(), suffixIcon: IconButton( icon: Icon(_couldView ? Icons.visibility : Icons.visibility_off), @@ -57,13 +64,19 @@ class _ExperimentPasswordDialogState extends State { ), actions: [ TextButton( - child: const Text('取消'), + child: Text(FlutterI18n.translate( + context, + "cancel", + )), onPressed: () { Navigator.pop(context, false); }, ), TextButton( - child: const Text('提交'), + child: Text(FlutterI18n.translate( + context, + "confirm", + )), onPressed: () async { if (_experimentPasswordController.text.isNotEmpty) { user_perference.setString( @@ -72,7 +85,13 @@ class _ExperimentPasswordDialogState extends State { ); Navigator.of(context).pop(true); } else { - showToast(context: context, msg: "输入空白!"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "setting.change_password_dialog.blank_input", + ), + ); } }, ), diff --git a/lib/page/setting/dialogs/sport_password_dialog.dart b/lib/page/setting/dialogs/sport_password_dialog.dart index dc04b6e2..0a122ef0 100644 --- a/lib/page/setting/dialogs/sport_password_dialog.dart +++ b/lib/page/setting/dialogs/sport_password_dialog.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:watermeter/page/public_widget/toast.dart'; import 'package:watermeter/repository/preference.dart' as user_perference; @@ -40,13 +41,19 @@ class _SportPasswordDialogState extends State { Widget build(BuildContext context) { return PopScope( child: AlertDialog( - title: const Text('修改体育系统密码'), + title: Text(FlutterI18n.translate( + context, + "setting.change_sport_title", + )), content: TextField( autofocus: true, controller: _sportPasswordController, obscureText: _couldView, decoration: InputDecoration( - hintText: "请在此输入密码", + hintText: FlutterI18n.translate( + context, + "setting.change_password_dialog.input_hint", + ), border: const OutlineInputBorder(), suffixIcon: IconButton( icon: Icon(_couldView ? Icons.visibility : Icons.visibility_off), @@ -60,13 +67,19 @@ class _SportPasswordDialogState extends State { ), actions: [ TextButton( - child: const Text('取消'), + child: Text(FlutterI18n.translate( + context, + "cancel", + )), onPressed: () { Navigator.of(context).pop(false); // 返回 false }, ), TextButton( - child: const Text('提交'), + child: Text(FlutterI18n.translate( + context, + "confirm", + )), onPressed: () async { if (_sportPasswordController.text.isNotEmpty) { await user_perference.setString( @@ -77,7 +90,13 @@ class _SportPasswordDialogState extends State { Navigator.of(context).pop(true); // 返回 true } } else { - showToast(context: context, msg: "输入空白!"); + showToast( + context: context, + msg: FlutterI18n.translate( + context, + "setting.change_password_dialog.blank_input", + ), + ); } }, ), diff --git a/lib/page/setting/setting.dart b/lib/page/setting/setting.dart index 56e90604..1f66ad7d 100644 --- a/lib/page/setting/setting.dart +++ b/lib/page/setting/setting.dart @@ -7,6 +7,7 @@ import 'dart:io'; import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; import 'package:styled_widget/styled_widget.dart'; import 'package:talker_flutter/talker_flutter.dart'; import 'package:watermeter/controller/experiment_controller.dart'; @@ -63,9 +64,15 @@ class _SettingWindowState extends State { showDialog( barrierDismissible: false, context: context, - builder: (context) => const AlertDialog( - title: Text("请关闭应用"), - content: Text("因为技术限制,用户需要自行关闭窗口,然后重新打开应用。"), + builder: (context) => AlertDialog( + title: Text(FlutterI18n.translate( + context, + "setting.need_close_dialog.title", + )), + content: Text(FlutterI18n.translate( + context, + "setting.need_close_dialog.content", + )), ), ); } @@ -73,6 +80,20 @@ class _SettingWindowState extends State { @override Widget build(BuildContext context) { + List demoBlueModeName = [ + FlutterI18n.translate( + context, + "setting.change_brightness_dialog.follow_setting", + ), + FlutterI18n.translate( + context, + "setting.change_brightness_dialog.day_mode", + ), + FlutterI18n.translate( + context, + "setting.change_brightness_dialog.night_mode", + ), + ]; return Scaffold( body: ListView( padding: const EdgeInsets.all(16), @@ -153,37 +174,38 @@ class _SettingWindowState extends State { ), const Divider(), ListTile( - title: const Text('用户信息'), - subtitle: Text( - "${preference.getString(preference.Preference.name)} ${preference.getString(preference.Preference.execution)}\n" - "${preference.getString(preference.Preference.institutes)} ${preference.getString(preference.Preference.subject)}", + title: Text(FlutterI18n.translate( + context, + "setting.simplify_timeline", + )), + subtitle: Text(FlutterI18n.translate( + context, + "setting.simplify_timeline_description", + )), + trailing: Switch( + value: preference.getBool( + preference.Preference.simplifiedClassTimeline), + onChanged: (bool value) { + setState(() { + preference + .setBool( + preference.Preference.simplifiedClassTimeline, + value, + ) + .then( + (value) => + ClassTableCard.reloadSettingsFromPref(), + ); + }); + }, ), ), - ], + ])), + ReXCard( + title: _buildListSubtitle(FlutterI18n.translate( + context, + "setting.account_setting", )), - const SizedBox(height: 20), - // ReXCard( - // title: _buildListSubtitle('颜色设置'), - // remaining: [], - // bottomRow: Column( - // children: [ - // ListTile( - // title: const Text('设置程序主题色'), - // subtitle: Text(ColorSeed - // .values[ - // preference.getInt(preference.Preference.color)] - // .label), - // onTap: () { - // showDialog( - // context: context, - // builder: (context) => const ChangeColorDialog(), - // ); - // }), - // ], - // ), - // ), - ReXCard( - title: _buildListSubtitle('界面设置'), remaining: const [], bottomRow: Column(children: [ ListTile( @@ -226,7 +248,10 @@ class _SettingWindowState extends State { children: [ if (!preference.getBool(preference.Preference.role)) ...[ ListTile( - title: const Text('体育系统密码设置'), + title: Text(FlutterI18n.translate( + context, + "setting.sport_password_setting", + )), trailing: const Icon(Icons.navigate_next), onTap: () { showDialog( @@ -237,7 +262,10 @@ class _SettingWindowState extends State { }), const Divider(), ListTile( - title: const Text('物理实验系统密码设置'), + title: Text(FlutterI18n.translate( + context, + "setting.experiment_password_setting", + )), trailing: const Icon(Icons.navigate_next), onTap: () { showDialog( @@ -251,7 +279,14 @@ class _SettingWindowState extends State { if (preference.getBool(preference.Preference.role)) ...[ const Divider(), ListTile( - title: const Text('电费账号设置'), + title: Text(FlutterI18n.translate( + context, + "setting.electricity_password_setting", + )), + subtitle: Text(FlutterI18n.translate( + context, + "setting.electricity_password_description", + )), trailing: const Icon(Icons.navigate_next), onTap: () { showDialog( @@ -474,10 +509,8 @@ class _SettingWindowState extends State { "No cookies.", ); } - /// Clean cache. _removeCache(); - if (context.mounted) { showToast(context: context, msg: '缓存已被清除'); Restart.restartApp(); @@ -534,16 +567,19 @@ class _SettingWindowState extends State { ThemeController toChange = Get.put(ThemeController()); toChange.onUpdate(); - - /// Restart app - if (mounted) { - pd.close(); - Restart.restartApp(); - } - }, - child: const Text('确定'), - ), - ], + /// Restart app + if (mounted) { + pd.close(); + Restart.restartApp(); + } + }, + child: Text(FlutterI18n.translate( + context, + "confirm", + )), + ), + ], + ), ), ), ), diff --git a/lib/page/toolbox/toolbox_page.dart b/lib/page/toolbox/toolbox_page.dart index ac0b1fa9..4a43fbd2 100644 --- a/lib/page/toolbox/toolbox_page.dart +++ b/lib/page/toolbox/toolbox_page.dart @@ -4,18 +4,25 @@ import 'dart:io'; import 'package:flutter/material.dart'; +import 'package:flutter_i18n/flutter_i18n.dart'; +import 'package:ming_cute_icons/ming_cute_icons.dart'; import 'package:watermeter/model/toolbox_addresses.dart'; import 'package:watermeter/page/public_widget/context_extension.dart'; import 'package:watermeter/page/toolbox/webview_list_tile.dart'; -class ToolBoxPage extends StatelessWidget { +class ToolBoxPage extends StatefulWidget { const ToolBoxPage({super.key}); + @override + State createState() => _ToolBoxPageState(); +} + +class _ToolBoxPageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: const Text("其他功能"), + title: I18nText("toolbox.title"), leading: IconButton( icon: Icon( Platform.isIOS || Platform.isMacOS @@ -26,9 +33,76 @@ class ToolBoxPage extends StatelessWidget { ), ), body: ListView( - children: WebViewAddresses.values - .map((e) => WebViewListTile(data: e)) - .toList(), + children: [ + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.payment"), + url: "https://payment.xidian.edu.cn/MNetWorkUI/showPublic", + description: FlutterI18n.translate( + context, + "toolbox.payment_description", + ), + iconData: MingCuteIcons.mgc_exchange_cny_line, + ), + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.repair"), + url: "https://ids.xidian.edu.cn/authserver/login?service=" + "https%3A%2F%2Fids.xidian.edu.cn%2Fauthserver%2Foauth2.0%2F" + "callbackAuthorize%3Fclient_id%3D869608421533880320%26" + "redirect_uri%3Dhttp%253A%252F%252Frepair.xidian.edu.cn%252F" + "appsys%252FxidianCasLogin%252FoauthLogin%26response_type%3D" + "code%26state%3Dhome%26client_name%3DCasOAuthClient", + description: FlutterI18n.translate( + context, + "toolbox.repair_description", + ), + iconData: MingCuteIcons.mgc_tool_line, + ), + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.reserve"), + url: "http://libspace.xidian.edu.cn", + description: FlutterI18n.translate( + context, + "toolbox.reserve_description", + ), + iconData: MingCuteIcons.mgc_building_4_line, + ), + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.mobile"), + url: "https://xxcapp.xidian.edu.cn/site/xidianPage/home", + description: FlutterI18n.translate( + context, + "toolbox.mobile_description", + ), + iconData: MingCuteIcons.mgc_chat_2_line, + ), + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.network"), + url: "https://zfw.xidian.edu.cn", + description: FlutterI18n.translate( + context, + "toolbox.network_description", + ), + iconData: MingCuteIcons.mgc_wifi_line, + ), + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.physics"), + url: "https://experiment-helper.wizzstudio.com/#/", + description: FlutterI18n.translate( + context, + "toolbox.physics_description", + ), + iconData: MingCuteIcons.mgc_counter_2_line, + ), + WebViewAddresses( + name: FlutterI18n.translate(context, "toolbox.discover"), + url: "https://nav.xdruisi.com/", + description: FlutterI18n.translate( + context, + "toolbox.discover_description", + ), + iconData: MingCuteIcons.mgc_web_line, + ), + ].map((e) => WebViewListTile(data: e)).toList(), ), ); } diff --git a/lib/repository/xidian_ids/library_session.dart b/lib/repository/xidian_ids/library_session.dart index 56aac143..cf0bd234 100644 --- a/lib/repository/xidian_ids/library_session.dart +++ b/lib/repository/xidian_ids/library_session.dart @@ -205,7 +205,8 @@ class LibrarySession extends IDSSession { ).then((value) => jsonDecode(value.data)); if (!isSuccess["status"]) { - throw NotFetchLibraryException(message: "登陆失败: ${isSuccess["status"]}"); + throw NotFetchLibraryException( + message: "Login failed: ${isSuccess["status"]}"); } response = await dio.get(destinationURL, queryParameters: { @@ -242,5 +243,5 @@ class LibrarySession extends IDSSession { class NotFetchLibraryException implements Exception { final String message; - NotFetchLibraryException({this.message = "发生错误"}); + NotFetchLibraryException({this.message = "Error detected."}); } diff --git a/lib/themes/demo_blue.dart b/lib/themes/demo_blue.dart index a665b93b..f705e978 100644 --- a/lib/themes/demo_blue.dart +++ b/lib/themes/demo_blue.dart @@ -4,12 +4,6 @@ import 'package:chinese_font_library/chinese_font_library.dart'; import 'package:flutter/material.dart'; -const demoBlueModeName = [ - "跟随系统", - "白天模式", - "黑夜模式", -]; - const demoBlueModeMap = { 0: ThemeMode.system, 1: ThemeMode.light, diff --git a/pubspec.lock b/pubspec.lock index a1e650d5..89581f6f 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -454,6 +454,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.4.1" + flutter_i18n: + dependency: "direct main" + description: + name: flutter_i18n + sha256: "37334bfabd05655895dc0c90a38022e4e588eefb848ffc9d382f37439a44be46" + url: "https://pub.dev" + source: hosted + version: "0.36.2" flutter_launcher_icons: dependency: "direct dev" description: @@ -1387,6 +1395,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.1" + toml: + dependency: transitive + description: + name: toml + sha256: "9968de24e45b632bf1a654fe1ac7b6fe5261c349243df83fd262397799c45a2d" + url: "https://pub.dev" + source: hosted + version: "0.15.0" tuple: dependency: transitive description: @@ -1595,6 +1611,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.5.0" + xml2json: + dependency: transitive + description: + name: xml2json + sha256: dbe79a85d902674d95c7608c8048355ce2ec5846640da1c0f91389ccdad5b5a8 + url: "https://pub.dev" + source: hosted + version: "6.2.4" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index d0ce843c..ca8cae4d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -46,9 +46,6 @@ dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 - flutter_localizations: - sdk: flutter - intl: package_info_plus: ^8.0.0 flutter_markdown: ^0.7.2 flutter_svg: ^2.0.10+1 @@ -77,7 +74,12 @@ dependencies: fwfh_url_launcher: ^0.9.1 latext: ^0.4.1 permission_handler: ^11.3.1 + # internationalized device_info_plus: ^10.1.2 + flutter_i18n: ^0.36.2 + flutter_localizations: + sdk: flutter + intl: dev_dependencies: flutter_test: @@ -109,3 +111,7 @@ flutter: - assets/icon.png - assets/CP1919.svg.vec - assets/Icon-App-iTunes-Background.png + - assets/flutter_i18n/zh_CN.yaml + - assets/flutter_i18n/zh_TW.yaml + - assets/flutter_i18n/zh_SG.json +