diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ad7787e6..278e1e08 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -114,6 +114,7 @@ jobs: Import-Module (Join-Path $vsPath "Common7\Tools\Microsoft.VisualStudio.DevShell.dll") Enter-VsDevShell -VsInstallPath $vsPath -SkipAutomaticLocation -DevCmdArguments '-arch=${{ matrix.msvc_arch }} -host_arch=x64' $additionalConfigureArgs += '-DPKG_CONFIG_EXECUTABLE:FILEPATH=./build/vcpkg_installed/x64-windows/tools/pkgconf/pkgconf.exe' + $additionalConfigureArgs += '-DMSGFMT_EXECUTABLE:FILEPATH=./build/vcpkg_installed/x64-windows/tools/gettext/bin/msgfmt.exe' } if ($vcpkgTargetTriplet) { $additionalConfigureArgs += "-DVCPKG_TARGET_TRIPLET:STRING=$vcpkgTargetTriplet" diff --git a/.gitignore b/.gitignore index 25231ae4..8c5aa457 100644 --- a/.gitignore +++ b/.gitignore @@ -40,8 +40,16 @@ CMakeUserPresets.json # CMake build directory /build /out -/.vscode/settings.json -action-cli +# IDE settings +.vscode/settings.json +.idea +.vs +# Windows build output +action-cli *.rc + +# i18n files +*.mo +*.pot \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 72bafef0..44afa99f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,6 +19,7 @@ endif() project(sast-evento VERSION ${VERSION_SEMANTIC} LANGUAGES CXX) set(SLINT_STYLE "material" CACHE STRING "Slint style" FORCE) +set(SLINT_FEATURE_GETTEXT ON CACHE BOOL "Slint gettext feature" FORCE) if (WIN32) # Target Windows 7 @@ -53,6 +54,7 @@ find_package(spdlog REQUIRED) find_package(Boost REQUIRED COMPONENTS system url beast process) find_package(OpenSSL 3.3.0 REQUIRED) find_package(nlohmann_json REQUIRED) +find_package(Intl REQUIRED) find_package(PkgConfig REQUIRED) pkg_check_modules(tomlplusplus REQUIRED IMPORTED_TARGET tomlplusplus) @@ -62,6 +64,9 @@ if (NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/3rdpart/sast-link-cxx-sdk/CMakeLists message(FATAL_ERROR "Git submodule not found. Run `git submodule update --init` from the source tree to fetch the submodule contents.") endif() +# i18n +set(SOURCE_LOCALE_DIR "${CMAKE_SOURCE_DIR}/ui/locale") + # source code add_subdirectory(src) # sast-link-sdk @@ -76,6 +81,8 @@ set(BUILD_SHARED_LIBS ON) file(WRITE ${CMAKE_BINARY_DIR}/sast-evento-version.txt ${VERSION_SEMANTIC}) install(FILES ${CMAKE_BINARY_DIR}/sast-evento-version.txt DESTINATION .) install(FILES ${CMAKE_SOURCE_DIR}/LICENSE DESTINATION .) +install(FILES ${SOURCE_LOCALE_DIR}/en/LC_MESSAGES/sast-evento.mo DESTINATION ./locale/en/LC_MESSAGES) +install(FILES ${SOURCE_LOCALE_DIR}/zh/LC_MESSAGES/sast-evento.mo DESTINATION ./locale/zh/LC_MESSAGES) install(TARGETS ${PROJECT_NAME} BUNDLE DESTINATION . LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0e4198f9..62280214 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -50,6 +50,7 @@ target_compile_definitions(${PROJECT_NAME} $<$:EVENTO_DEBUG> $<$:EVENTO_RELEASE> ${PLATFORM} + LOCALE_DIR="${CMAKE_SOURCE_DIR}/ui/locale" ) target_link_libraries(${PROJECT_NAME} @@ -67,6 +68,7 @@ target_link_libraries(${PROJECT_NAME} keychain Slint::Slint version::version + Intl::Intl ${URING_LIBRARIES} ) @@ -75,4 +77,13 @@ if (WIN32) add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy $ $ COMMAND_EXPAND_LISTS) endif() +find_program(MSGFMT_EXECUTABLE msgfmt REQUIRED) + +add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${SOURCE_LOCALE_DIR}/en/LC_MESSAGES + COMMAND ${MSGFMT_EXECUTABLE} ${SOURCE_LOCALE_DIR}/en.po -o ${SOURCE_LOCALE_DIR}/en/LC_MESSAGES/sast-evento.mo + COMMAND ${CMAKE_COMMAND} -E make_directory ${SOURCE_LOCALE_DIR}/zh/LC_MESSAGES + COMMAND ${MSGFMT_EXECUTABLE} ${SOURCE_LOCALE_DIR}/zh.po -o ${SOURCE_LOCALE_DIR}/zh/LC_MESSAGES/sast-evento.mo +) + add_subdirectory(Tray) diff --git a/src/Controller/View/SettingPage.cc b/src/Controller/View/SettingPage.cc index 0657c98d..e1412ef1 100644 --- a/src/Controller/View/SettingPage.cc +++ b/src/Controller/View/SettingPage.cc @@ -11,9 +11,7 @@ SettingPage::SettingPage(slint::ComponentHandle uiEntry, UiBridge& void SettingPage::onCreate() { auto& self = *this; - const auto [languageIdx, minimalToTray, noticeBegin, noticeEnd, themeIdx] = evento::settings; - - self->set_language_index(languageIdx); + const auto [minimalToTray, noticeBegin, noticeEnd, themeIdx] = evento::settings; self->set_minimal_to_tray(minimalToTray); self->set_notice_begin(noticeBegin); self->set_notice_end(noticeEnd); @@ -23,19 +21,12 @@ void SettingPage::onCreate() { config.insert_or_assign("setting", toml::table{ - {"language", languageIdx}, {"minimal-to-tray", minimalToTray}, {"notice-begin", noticeBegin}, {"notice-end", noticeEnd}, {"theme", themeIdx}, }); - self->on_language_changed([&self = *this]() { - auto& setting = config["setting"].ref(); - setting.insert_or_assign("language", self->get_language_index()); - evento::settings.language = self->get_language_index(); - }); - self->on_minimal_to_tray_changed([&self = *this]() { auto& setting = config["setting"].ref(); setting.insert_or_assign("minimal-to-tray", self->get_minimal_to_tray()); @@ -69,7 +60,6 @@ void SettingPage::onCreate() { void SettingPage::onShow() { auto& self = *this; - self->set_language_index(evento::settings.language); self->set_minimal_to_tray(evento::settings.minimalToTray); self->set_notice_begin(evento::settings.noticeBegin); self->set_notice_end(evento::settings.noticeEnd); diff --git a/src/Infrastructure/Utils/Config.h b/src/Infrastructure/Utils/Config.h index e0e60f9d..417c72f4 100644 --- a/src/Infrastructure/Utils/Config.h +++ b/src/Infrastructure/Utils/Config.h @@ -1,5 +1,6 @@ #pragma once +#include #include #include #include @@ -14,7 +15,6 @@ user-id = expire = [setting] -language = minimal-to-tray = notice-begin = notice-end = @@ -36,15 +36,21 @@ const std::filesystem::path configDir = inline toml::table config; -inline struct { - int language; +const std::filesystem::path localePath = +#ifdef EVENTO_DEBUG + LOCALE_DIR; +#else + std::filesystem::path{(boost::dll::program_location().parent_path() / "locale").string()}; +#endif // EVENTO_DEBUG + +inline struct Settings { bool minimalToTray; bool noticeBegin; bool noticeEnd; int theme; } settings; -inline struct { +inline struct Account { std::string userId; toml::date_time expire; } account; @@ -55,10 +61,6 @@ static void loadSetting() { } auto& setting = config["setting"].ref(); - auto languageIdx = setting["language"].value_or(0); - if (languageIdx > 2) { - languageIdx = 0; - } auto themeIdx = setting["theme"].value_or(0); if (themeIdx > 2) { themeIdx = 0; @@ -68,7 +70,6 @@ static void loadSetting() { auto minimalToTray = setting["minimal-to-tray"].value_or(false); evento::settings = { - .language = languageIdx, .minimalToTray = minimalToTray, .noticeBegin = noticeBegin, .noticeEnd = noticeEnd, diff --git a/src/main.cc b/src/main.cc index c15581cb..1e116621 100644 --- a/src/main.cc +++ b/src/main.cc @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include int main(int argc, char** argv) { @@ -13,6 +15,9 @@ int main(int argc, char** argv) { evento::initConfig(); spdlog::info("SAST Evento version: v" VERSION_FULL); + bindtextdomain("sast-evento", evento::localePath.string().c_str()); + std::locale::global(std::locale("")); + evento::UiBridge uiBridge(App::create()); evento::SocketClient socketClient({ diff --git a/ui/app.slint b/ui/app.slint index 009e8a06..28cc3e7e 100644 --- a/ui/app.slint +++ b/ui/app.slint @@ -229,17 +229,17 @@ export component App inherits Window { nav-views: [ { icon:Token.image.icon.home, - content:"活动广场", + content: @tr("活动广场"), target:ViewName.DiscoveryPage, }, { icon:Token.image.icon.department, - content:"部门活动", + content: @tr("部门活动"), target:ViewName.SearchPage, }, { icon:Token.image.icon.schedule, - content:"活动日程", + content: @tr("活动日程"), target:ViewName.MyEventPage, }, ]; diff --git a/ui/locale/en.po b/ui/locale/en.po new file mode 100644 index 00000000..a323c451 --- /dev/null +++ b/ui/locale/en.po @@ -0,0 +1,350 @@ +# SPDX-FileCopyrightText: 2024 serein +msgid "" +msgstr "" +"Project-Id-Version: \n" +"POT-Creation-Date: 2024-09-24 09:31+0000\n" +"PO-Revision-Date: 2024-09-24 17:57+0800\n" +"Last-Translator: \n" +"Language-Team: English (British) <(nothing)>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: en_GB\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 24.08.1\n" + +#: views/overlay/login.slint:70 +msgctxt "LoginOverlay" +msgid "使用 Link 登录" +msgstr "Login by Link" + +#: views/overlay/login.slint:91 +msgctxt "LoginOverlay" +msgid "访客登录" +msgstr "guest" + +#: views/overlay/login.slint:121 +msgctxt "LoginOverlay" +msgid "SAST.C++组开发" +msgstr "Developed by SAST.C++ Group" + +#: views/overlay/menu.slint:166 +msgctxt "MenuOverlay" +msgid "请登录" +msgstr "Please Login first" + +#: views/overlay/menu.slint:207 +msgctxt "MenuOverlay" +msgid "个人资料" +msgstr "Profile" + +#: views/overlay/menu.slint:214 +msgctxt "MenuOverlay" +msgid "历史活动" +msgstr "History" + +#: views/overlay/menu.slint:221 +msgctxt "MenuOverlay" +msgid "纪念卡" +msgstr "Souvenir Card" + +#: views/overlay/menu.slint:224 +msgctxt "MenuOverlay" +msgid "功能还在开发中,咕咕咕 😣" +msgstr "It's still in development" + +#: views/overlay/menu.slint:230 +msgctxt "MenuOverlay" +msgid "设置" +msgstr "Setting" + +#: views/overlay/menu.slint:238 +msgctxt "MenuOverlay" +msgid "关于" +msgstr "About" + +#: views/overlay/menu.slint:247 +msgctxt "MenuOverlay" +msgid "退出登录" +msgstr "Logout" + +#: views/page/about.slint:103 +msgctxt "AboutPage" +msgid "更新日志" +msgstr "Update Log" + +#: views/page/about.slint:104 +msgctxt "AboutPage" +msgid "更新" +msgstr "Update" + +#: views/page/about.slint:105 +msgctxt "AboutPage" +msgid "取消" +msgstr "Cancel" + +#: views/page/about.slint:135 +msgctxt "AboutPage" +msgid "关于" +msgstr "About" + +#: views/page/about.slint:163 +msgctxt "AboutPage" +msgid "版本信息 " +msgstr "Version" + +#: views/page/about.slint:173 +msgctxt "AboutPage" +msgid "检查更新" +msgstr "Check Update" + +#: views/page/about.slint:189 +msgctxt "AboutPage" +msgid "漏洞报告" +msgstr "Bugs Report" + +#: views/page/about.slint:217 +msgctxt "AboutPage" +msgid "网页端" +msgstr "Web Link" + +#: views/page/about.slint:238 +msgctxt "AboutPage" +msgid "GitHub 仓库" +msgstr "GitHub Repo" + +#: views/page/about.slint:259 +msgctxt "AboutPage" +msgid "项目依赖" +msgstr "Dependencies" + +#: views/page/about.slint:320 +msgctxt "AboutPage" +msgid "开源协议" +msgstr "Open Source License" + +#: views/page/about.slint:346 +msgctxt "AboutPage" +msgid "贡献者" +msgstr "Contributors" + +#: views/page/about.slint:356 +msgctxt "AboutPage" +msgid "重新加载" +msgstr "Reload" + +#: views/page/discovery.slint:106 +msgctxt "DiscoveryPage" +msgid "暂时还没有活动哦" +msgstr "Nothing" + +#: views/page/discovery.slint:113 +msgctxt "DiscoveryPage" +msgid " 正在进行的活动" +msgstr " Active Events" + +#: views/page/discovery.slint:120 views/page/discovery.slint:154 +msgctxt "DiscoveryPage" +msgid "重新加载" +msgstr "Reload" + +#: views/page/discovery.slint:147 +msgctxt "DiscoveryPage" +msgid " 最新的活动" +msgstr " Latest Events" + +#: views/page/setting.slint:65 +msgctxt "SettingPage" +msgid "设置" +msgstr "Setting" + +#: views/page/setting.slint:77 +msgctxt "SettingPage" +msgid "主题" +msgstr "Theme" + +#: views/page/setting.slint:80 +msgctxt "SettingPage" +msgid "跟随系统" +msgstr "Follow System" + +#: views/page/setting.slint:80 +msgctxt "SettingPage" +msgid "浅色" +msgstr "Light" + +#: views/page/setting.slint:80 +msgctxt "SettingPage" +msgid "深色" +msgstr "Dark" + +#: views/page/setting.slint:85 +msgctxt "SettingPage" +msgid "下次启动时生效" +msgstr "It will take effect on next startup" + +#: views/page/setting.slint:95 +msgctxt "SettingPage" +msgid "活动开始前提醒" +msgstr "Remind before event" + +#: views/page/setting.slint:105 +msgctxt "SettingPage" +msgid "活动结束后提醒反馈" +msgstr "Remind after event" + +#: views/page/setting.slint:115 +msgctxt "SettingPage" +msgid "关闭窗口后最小化到托盘" +msgstr "Minimal to Tray" + +#: views/page/setting.slint:127 +msgctxt "SettingPage" +msgid "磁盘缓存:" +msgstr "Disk Cache: " + +#: views/page/setting.slint:129 +msgctxt "SettingPage" +msgid "清除缓存" +msgstr "Clear" + +#: views/page/setting.slint:132 +msgctxt "SettingPage" +msgid "缓存已清除" +msgstr "Cache has been cleared" + +#: views/page/detail.slint:42 +msgctxt "HighlightBlock" +msgid "报名中" +msgstr "Signing Up" + +#: views/page/detail.slint:44 +msgctxt "HighlightBlock" +msgid "进行中" +msgstr "Active" + +#: views/page/detail.slint:46 +msgctxt "HighlightBlock" +msgid "已结束" +msgstr "Finished" + +#: views/page/detail.slint:48 +msgctxt "HighlightBlock" +msgid "已取消" +msgstr "Cancelled" + +#: views/page/detail.slint:50 +msgctxt "HighlightBlock" +msgid "未知状态" +msgstr "UNKNOWN" + +#: views/page/detail.slint:106 views/page/detail.slint:116 +#: views/page/detail.slint:234 +msgctxt "DetailPage" +msgid "签到" +msgstr "Check In" + +#: views/page/detail.slint:112 +msgctxt "DetailPage" +msgid "请输入签到码" +msgstr "Enter the check-in code" + +#: views/page/detail.slint:117 +msgctxt "DetailPage" +msgid "取消" +msgstr "Cancel" + +#: views/page/detail.slint:161 +msgctxt "DetailPage" +msgid "重新加载" +msgstr "Reload" + +#: views/page/detail.slint:178 +msgctxt "DetailPage" +msgid "反馈" +msgstr "Feedback" + +#: views/page/detail.slint:189 +msgctxt "DetailPage" +msgid "参与完本次活动,有什么想说的吗,快告诉我们吧" +msgstr "What you wanna suggest us" + +#: views/page/detail.slint:197 +msgctxt "DetailPage" +msgid "提交" +msgstr "Submit" + +#: views/page/detail.slint:221 +msgctxt "DetailPage" +msgid "取消报名" +msgstr "Cancel Sign Up" + +#: views/page/detail.slint:221 +msgctxt "DetailPage" +msgid "报名" +msgstr "Sign Up" + +#: views/page/detail.slint:234 +msgctxt "DetailPage" +msgid "已签到" +msgstr "Checked In" + +#: views/page/history.slint:36 +msgctxt "CommentItem" +msgid "参与完本次活动,有什么想说的吗,快告诉我们吧" +msgstr "What you wanna suggest us" + +#: views/page/history.slint:41 +msgctxt "CommentItem" +msgid "提交" +msgstr "Submit" + +#: views/page/history.slint:52 +msgctxt "CommentItem" +msgid "网络错误 X.X" +msgstr "Network Error :(" + +#: views/page/history.slint:148 +msgctxt "HistoryPage" +msgid "历史活动" +msgstr "History" + +#: views/page/history.slint:163 +msgctxt "HistoryPage" +msgid "重新加载" +msgstr "Reload" + +#: views/page/search.slint:46 +msgctxt "SearchPage" +msgid "在找什么部门呢" +msgstr "What department are you looking for" + +#: views/page/search.slint:68 views/page/search.slint:123 +msgctxt "SearchPage" +msgid "重新加载" +msgstr "Reload" + +#: views/page/search.slint:107 +msgctxt "SearchPage" +msgid "这个部门还没有活动哦" +msgstr "Nothing" + +#: views/page/search.slint:132 +msgctxt "SearchPage" +msgid "什么都没有呢" +msgstr "Nothing" + +#: app.slint:232 +msgctxt "App" +msgid "活动广场" +msgstr "Plaza" + +#: app.slint:237 +msgctxt "App" +msgid "部门活动" +msgstr "Department" + +#: app.slint:242 +msgctxt "App" +msgid "活动日程" +msgstr "Schedule" diff --git a/ui/locale/zh.po b/ui/locale/zh.po new file mode 100644 index 00000000..3cf302f3 --- /dev/null +++ b/ui/locale/zh.po @@ -0,0 +1,350 @@ +# SPDX-FileCopyrightText: 2024 serein +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"POT-Creation-Date: 2024-09-24 11:20+0000\n" +"PO-Revision-Date: 2024-09-24 19:27+0800\n" +"Last-Translator: \n" +"Language-Team: English (British) <(nothing)>\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Language: zh_CN\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" +"X-Generator: Lokalize 24.08.1\n" + +#: views/overlay/login.slint:70 +msgctxt "LoginOverlay" +msgid "使用 Link 登录" +msgstr "使用 Link 登录" + +#: views/overlay/login.slint:91 +msgctxt "LoginOverlay" +msgid "访客登录" +msgstr "访客登录" + +#: views/overlay/login.slint:121 +msgctxt "LoginOverlay" +msgid "SAST.C++组开发" +msgstr "SAST.C++组开发" + +#: views/overlay/menu.slint:166 +msgctxt "MenuOverlay" +msgid "请登录" +msgstr "请登录" + +#: views/overlay/menu.slint:207 +msgctxt "MenuOverlay" +msgid "个人资料" +msgstr "个人资料" + +#: views/overlay/menu.slint:214 +msgctxt "MenuOverlay" +msgid "历史活动" +msgstr "历史活动" + +#: views/overlay/menu.slint:221 +msgctxt "MenuOverlay" +msgid "纪念卡" +msgstr "纪念卡" + +#: views/overlay/menu.slint:224 +msgctxt "MenuOverlay" +msgid "功能还在开发中,咕咕咕 😣" +msgstr "功能还在开发中,咕咕咕 😣" + +#: views/overlay/menu.slint:230 +msgctxt "MenuOverlay" +msgid "设置" +msgstr "设置" + +#: views/overlay/menu.slint:238 +msgctxt "MenuOverlay" +msgid "关于" +msgstr "关于" + +#: views/overlay/menu.slint:247 +msgctxt "MenuOverlay" +msgid "退出登录" +msgstr "退出登录" + +#: views/page/about.slint:103 +msgctxt "AboutPage" +msgid "更新日志" +msgstr "更新日志" + +#: views/page/about.slint:104 +msgctxt "AboutPage" +msgid "更新" +msgstr "更新" + +#: views/page/about.slint:105 +msgctxt "AboutPage" +msgid "取消" +msgstr "取消" + +#: views/page/about.slint:135 +msgctxt "AboutPage" +msgid "关于" +msgstr "关于" + +#: views/page/about.slint:163 +msgctxt "AboutPage" +msgid "版本信息 " +msgstr "版本信息 " + +#: views/page/about.slint:173 +msgctxt "AboutPage" +msgid "检查更新" +msgstr "检查更新" + +#: views/page/about.slint:189 +msgctxt "AboutPage" +msgid "漏洞报告" +msgstr "漏洞报告" + +#: views/page/about.slint:217 +msgctxt "AboutPage" +msgid "网页端" +msgstr "网页端" + +#: views/page/about.slint:238 +msgctxt "AboutPage" +msgid "GitHub 仓库" +msgstr "GitHub 仓库" + +#: views/page/about.slint:259 +msgctxt "AboutPage" +msgid "项目依赖" +msgstr "项目依赖" + +#: views/page/about.slint:320 +msgctxt "AboutPage" +msgid "开源协议" +msgstr "开源协议" + +#: views/page/about.slint:346 +msgctxt "AboutPage" +msgid "贡献者" +msgstr "贡献者" + +#: views/page/about.slint:356 +msgctxt "AboutPage" +msgid "重新加载" +msgstr "重新加载" + +#: views/page/discovery.slint:106 +msgctxt "DiscoveryPage" +msgid "暂时还没有活动哦" +msgstr "暂时还没有活动哦" + +#: views/page/discovery.slint:113 +msgctxt "DiscoveryPage" +msgid " 正在进行的活动" +msgstr " 正在进行的活动" + +#: views/page/discovery.slint:120 views/page/discovery.slint:154 +msgctxt "DiscoveryPage" +msgid "重新加载" +msgstr "重新加载" + +#: views/page/discovery.slint:147 +msgctxt "DiscoveryPage" +msgid " 最新的活动" +msgstr " 最新的活动" + +#: views/page/setting.slint:65 +msgctxt "SettingPage" +msgid "设置" +msgstr "设置" + +#: views/page/setting.slint:77 +msgctxt "SettingPage" +msgid "主题" +msgstr "主题" + +#: views/page/setting.slint:80 +msgctxt "SettingPage" +msgid "跟随系统" +msgstr "跟随系统" + +#: views/page/setting.slint:80 +msgctxt "SettingPage" +msgid "浅色" +msgstr "浅色" + +#: views/page/setting.slint:80 +msgctxt "SettingPage" +msgid "深色" +msgstr "深色" + +#: views/page/setting.slint:85 +msgctxt "SettingPage" +msgid "下次启动时生效" +msgstr "下次启动时生效" + +#: views/page/setting.slint:95 +msgctxt "SettingPage" +msgid "活动开始前提醒" +msgstr "活动开始前提醒" + +#: views/page/setting.slint:105 +msgctxt "SettingPage" +msgid "活动结束后提醒反馈" +msgstr "活动结束后提醒反馈" + +#: views/page/setting.slint:115 +msgctxt "SettingPage" +msgid "关闭窗口后最小化到托盘" +msgstr "关闭窗口后最小化到托盘" + +#: views/page/setting.slint:127 +msgctxt "SettingPage" +msgid "磁盘缓存:" +msgstr "磁盘缓存:" + +#: views/page/setting.slint:129 +msgctxt "SettingPage" +msgid "清除缓存" +msgstr "清除缓存" + +#: views/page/setting.slint:132 +msgctxt "SettingPage" +msgid "缓存已清除" +msgstr "缓存已清除" + +#: views/page/detail.slint:42 +msgctxt "HighlightBlock" +msgid "报名中" +msgstr "报名中" + +#: views/page/detail.slint:44 +msgctxt "HighlightBlock" +msgid "进行中" +msgstr "进行中" + +#: views/page/detail.slint:46 +msgctxt "HighlightBlock" +msgid "已结束" +msgstr "已结束" + +#: views/page/detail.slint:48 +msgctxt "HighlightBlock" +msgid "已取消" +msgstr "已取消" + +#: views/page/detail.slint:50 +msgctxt "HighlightBlock" +msgid "未知状态" +msgstr "未知状态" + +#: views/page/detail.slint:106 views/page/detail.slint:116 +#: views/page/detail.slint:234 +msgctxt "DetailPage" +msgid "签到" +msgstr "签到" + +#: views/page/detail.slint:112 +msgctxt "DetailPage" +msgid "请输入签到码" +msgstr "请输入签到码" + +#: views/page/detail.slint:117 +msgctxt "DetailPage" +msgid "取消" +msgstr "取消" + +#: views/page/detail.slint:161 +msgctxt "DetailPage" +msgid "重新加载" +msgstr "重新加载" + +#: views/page/detail.slint:178 +msgctxt "DetailPage" +msgid "反馈" +msgstr "反馈" + +#: views/page/detail.slint:189 +msgctxt "DetailPage" +msgid "参与完本次活动,有什么想说的吗,快告诉我们吧" +msgstr "参与完本次活动,有什么想说的吗,快告诉我们吧" + +#: views/page/detail.slint:197 +msgctxt "DetailPage" +msgid "提交" +msgstr "提交" + +#: views/page/detail.slint:221 +msgctxt "DetailPage" +msgid "取消报名" +msgstr "取消报名" + +#: views/page/detail.slint:221 +msgctxt "DetailPage" +msgid "报名" +msgstr "报名" + +#: views/page/detail.slint:234 +msgctxt "DetailPage" +msgid "已签到" +msgstr "已签到" + +#: views/page/history.slint:36 +msgctxt "CommentItem" +msgid "参与完本次活动,有什么想说的吗,快告诉我们吧" +msgstr "参与完本次活动,有什么想说的吗,快告诉我们吧" + +#: views/page/history.slint:41 +msgctxt "CommentItem" +msgid "提交" +msgstr "提交" + +#: views/page/history.slint:52 +msgctxt "CommentItem" +msgid "网络错误 X.X" +msgstr "网络错误 X.X" + +#: views/page/history.slint:148 +msgctxt "HistoryPage" +msgid "历史活动" +msgstr "历史活动" + +#: views/page/history.slint:163 +msgctxt "HistoryPage" +msgid "重新加载" +msgstr "重新加载" + +#: views/page/search.slint:46 +msgctxt "SearchPage" +msgid "在找什么部门呢" +msgstr "在找什么部门呢" + +#: views/page/search.slint:68 views/page/search.slint:123 +msgctxt "SearchPage" +msgid "重新加载" +msgstr "重新加载" + +#: views/page/search.slint:107 +msgctxt "SearchPage" +msgid "这个部门还没有活动哦" +msgstr "这个部门还没有活动哦" + +#: views/page/search.slint:132 +msgctxt "SearchPage" +msgid "什么都没有呢" +msgstr "什么都没有呢" + +#: app.slint:232 +msgctxt "App" +msgid "活动广场" +msgstr "活动广场" + +#: app.slint:237 +msgctxt "App" +msgid "部门活动" +msgstr "部门活动" + +#: app.slint:242 +msgctxt "App" +msgid "活动日程" +msgstr "活动日程" diff --git a/ui/views/overlay/login.slint b/ui/views/overlay/login.slint index c72bb4cd..7ec2a296 100644 --- a/ui/views/overlay/login.slint +++ b/ui/views/overlay/login.slint @@ -67,7 +67,7 @@ export component LoginOverlay inherits Overlay { type: ButtonType.filled; width: 240px; height: 55px; - content: "使用 Link 登录"; + content: @tr("使用 Link 登录"); font: Token.font.headline.small; have-icon: true; icon-size: 32px; @@ -88,7 +88,7 @@ export component LoginOverlay inherits Overlay { // TODO: guest login if false: _guest-button := Rectangle { Button { - content: "访客登录"; + content: @tr("访客登录"); font: Token.font.body.large; have-icon: true; icon-size: 30px; @@ -118,7 +118,7 @@ export component LoginOverlay inherits Overlay { vertical-stretch: 0.35; _developer-label := Rectangle { Text { - text: "SAST-C++组开发"; + text: @tr("SAST.C++组开发"); font-size: Token.font.label.large.size; font-weight: Token.font.label.large.weight; color: Token.color.on-surface; diff --git a/ui/views/overlay/menu.slint b/ui/views/overlay/menu.slint index 9947eb90..b6838683 100644 --- a/ui/views/overlay/menu.slint +++ b/ui/views/overlay/menu.slint @@ -4,7 +4,7 @@ import { Token } from "../../global.slint"; export global MenuOverlayBridge { in-out property is-show: false; - in-out property user-name:"用户名"; + in-out property user-name: "用户名"; in-out property user-signature: "个性签名"; in-out property user-avatar: Token.image.display.avatar; callback open-link-web(); @@ -163,7 +163,7 @@ export component MenuOverlay inherits Overlay { spacing: 5px; padding-top: 5px; if !AccountManager.is-login:Text { - text: "请登录"; + text: @tr("请登录"); font-size: 40px; font-weight: Token.font.title.large.weight; color: Token.color.on-surface; @@ -204,30 +204,30 @@ export component MenuOverlay inherits Overlay { if AccountManager.is-login:MenuItem { icon: Token.image.icon.me; - label: "个人资料"; + label: @tr("个人资料"); clicked => { MenuOverlayBridge.open-link-web(); } } if AccountManager.is-login:MenuItem { icon: Token.image.icon.history; - label: "历史活动"; + label: @tr("历史活动"); clicked => { fold-then-navigate(ViewName.HistoryPage); } } if AccountManager.is-login:MenuItem { icon: Token.image.icon.card; - label: "纪念卡"; + label: @tr("纪念卡"); clicked => { // NOTE: Unsupport - MessageManager.show-message("功能还在开发中,咕咕咕 😣", MessageType.info); + MessageManager.show-message(@tr("功能还在开发中,咕咕咕 😣"), MessageType.info); } } if AccountManager.is-login:Divider { } MenuItem { icon: Token.image.icon.setting; - label: "设置"; + label: @tr("设置"); clicked => { fold-then-navigate(ViewName.SettingPage); } @@ -235,7 +235,7 @@ export component MenuOverlay inherits Overlay { MenuItem { icon: Token.image.icon.info; - label: "关于"; + label: @tr("关于"); clicked => { fold-then-navigate(ViewName.AboutPage); } @@ -244,7 +244,7 @@ export component MenuOverlay inherits Overlay { if AccountManager.is-login:Divider { } if AccountManager.is-login:MenuItem { icon: Token.image.icon.logout; - label: "退出登录"; + label: @tr("退出登录"); label-color: Token.color.error; clicked => { MenuOverlayBridge.is-show = false; diff --git a/ui/views/page/about.slint b/ui/views/page/about.slint index da1de1cd..90e667d6 100644 --- a/ui/views/page/about.slint +++ b/ui/views/page/about.slint @@ -100,9 +100,9 @@ export component AboutPage inherits Page { z: 999; width: root.width; height: root.height; - dialog-title: "更新日志"; - confirm-btn-text: "更新"; - cancel-btn-text: "取消"; + dialog-title: @tr("更新日志"); + confirm-btn-text: @tr("更新"); + cancel-btn-text: @tr("取消"); is-show <=> AboutPageBridge.show-popup; ScrollView { VerticalLayout { @@ -132,7 +132,7 @@ export component AboutPage inherits Page { padding: 50px; spacing: 20px; Text { - text: "关于"; + text: @tr("关于"); font-size: Token.font.display.medium.size; font-weight: Token.font.display.medium.weight; } @@ -160,7 +160,7 @@ export component AboutPage inherits Page { HorizontalLayout { alignment: space-between; Text { - text: "版本信息 " + AboutPageBridge.version; + text: @tr("版本信息 ") + AboutPageBridge.version; font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -170,7 +170,7 @@ export component AboutPage inherits Page { Button { have-icon: AboutPageBridge.check-update-status == PageState.loading; type: ButtonType.text; - content: "检查更新"; + content: @tr("检查更新"); LoadingAnimation { color: parent.on-surface; } @@ -186,7 +186,7 @@ export component AboutPage inherits Page { HorizontalLayout { alignment: space-between; Text { - text: "漏洞报告 / 功能建议"; + text: @tr("漏洞报告"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -214,7 +214,7 @@ export component AboutPage inherits Page { HorizontalLayout { alignment: space-between; Text { - text: "网页端"; + text: @tr("网页端"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -235,7 +235,7 @@ export component AboutPage inherits Page { HorizontalLayout { alignment: space-between; Text { - text: "GitHub 仓库"; + text: @tr("GitHub 仓库"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -256,7 +256,7 @@ export component AboutPage inherits Page { VerticalLayout { spacing: 10px; Text { - text: "项目依赖"; + text: @tr("项目依赖"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -317,7 +317,7 @@ export component AboutPage inherits Page { HorizontalLayout { alignment: space-between; Text { - text: "开源协议"; + text: @tr("开源协议"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -343,7 +343,7 @@ export component AboutPage inherits Page { padding: 20px; spacing: 15px; Text { - text: "贡献者"; + text: @tr("贡献者"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.on-surface; @@ -353,7 +353,7 @@ export component AboutPage inherits Page { if AboutPageBridge.contributors-status == PageState.error: Rectangle { Button { type: ButtonType.filled-tonal; - content: "重新加载"; + content: @tr("重新加载"); clicked => { AboutPageBridge.load-contributors(); } diff --git a/ui/views/page/detail.slint b/ui/views/page/detail.slint index 733e6fa5..89c9aa67 100644 --- a/ui/views/page/detail.slint +++ b/ui/views/page/detail.slint @@ -39,15 +39,15 @@ component IconText { component HighlightBlock { pure function state-to-text(state: EventState) -> string { if (state == EventState.SigningUp) { - return "报名中"; + return @tr("报名中"); } else if (state == EventState.Active) { - return "进行中"; + return @tr("进行中"); } else if (state == EventState.Completed) { - return "已结束"; + return @tr("已结束"); } else if (state == EventState.Cancelled) { - return "已取消"; + return @tr("已取消"); } else { - return "未知状态"; + return @tr("未知状态"); } } in property state; @@ -103,18 +103,18 @@ export component DetailPage inherits Page { width: 100%; height: 100%; is-show: false; - dialog-title: "签到"; + dialog-title: @tr("签到"); text-edit := LineEdit { width: 100%; height: 58px; font-size: Token.font.body.large.size; - placeholder-text: "请输入签到码"; + placeholder-text: @tr("请输入签到码"); horizontal-alignment: center; } - confirm-btn-text: "签到"; - cancel-btn-text: "取消"; + confirm-btn-text: @tr("签到"); + cancel-btn-text: @tr("取消"); confirm => { DetailPageBridge.check-in(text-edit.text); @@ -158,7 +158,7 @@ export component DetailPage inherits Page { if DetailPageBridge.state == PageState.error: Rectangle { Button { type: filled-tonal; - content: "重新加载"; + content: @tr("重新加载"); clicked => { DetailPageBridge.load-feedback(); } @@ -175,7 +175,7 @@ export component DetailPage inherits Page { VerticalLayout { spacing: 10px; Text { - text: "反馈"; + text: @tr("反馈"); font-size: Token.font.title.large.size; font-weight: Token.font.title.large.weight; } @@ -186,7 +186,7 @@ export component DetailPage inherits Page { content := LineEdit { font-size: Token.font.body.large.size; - placeholder-text: "参与完本次活动,有什么想说的吗,快告诉我们吧"; + placeholder-text: @tr("参与完本次活动,有什么想说的吗,快告诉我们吧"); text: DetailPageBridge.feedback-model.content; } @@ -194,7 +194,7 @@ export component DetailPage inherits Page { alignment: end; Button { type: filled-tonal; - content: "提交"; + content: @tr("提交"); disable: DetailPageBridge.feedback-model.rate == 0 || DetailPageBridge.feedback-model.has-feedbacked; have-icon: DetailPageBridge.feedback-state == PageState.loading; LoadingAnimation { @@ -218,7 +218,7 @@ export component DetailPage inherits Page { Button { have-icon: DetailPageBridge.subscribe-state == PageState.loading; type: filled; - content: DetailPageBridge.event-model.is-subscribed ? "取消报名" : "报名"; + content: DetailPageBridge.event-model.is-subscribed ? @tr("取消报名") : @tr("报名"); disable: DetailPageBridge.event-model.state != EventState.SigningUp; LoadingAnimation { color: Token.color.on-surface; @@ -231,7 +231,7 @@ export component DetailPage inherits Page { Button { type: filled; - content: DetailPageBridge.event-model.is-check-in ? "已签到" : "签到"; + content: DetailPageBridge.event-model.is-check-in ? @tr("已签到") : @tr("签到"); disable: DetailPageBridge.event-model.is-check-in || DetailPageBridge.event-model.state == EventState.Completed || DetailPageBridge.event-model.state == EventState.Cancelled; clicked => { dialog.open(); diff --git a/ui/views/page/discovery.slint b/ui/views/page/discovery.slint index 908ba601..49d7cde5 100644 --- a/ui/views/page/discovery.slint +++ b/ui/views/page/discovery.slint @@ -89,21 +89,21 @@ export component DiscoveryPage inherits Page { font-weight: Token.font.label.large.weight; horizontal-alignment: center; vertical-alignment: center; - text: "暂时还没有活动哦"; + text: @tr("暂时还没有活动哦"); } if DiscoveryPageBridge.active-events.length != 0 || DiscoveryPageBridge.active-events-state != PageState.normal: Text { color: Token.color.inverse-surface; font-size: Token.font.title.large.size; font-weight: Token.font.label.large.weight; - text: " 正在进行的活动"; + text: @tr(" 正在进行的活动"); } Rectangle { if DiscoveryPageBridge.active-events-state == PageState.error: Rectangle { Button { type: ButtonType.filled-tonal; - content: "重新加载"; + content: @tr("重新加载"); clicked => { DiscoveryPageBridge.load-active-events(); } @@ -130,14 +130,14 @@ export component DiscoveryPage inherits Page { color: Token.color.inverse-surface; font-size: Token.font.title.large.size; font-weight: Token.font.label.large.weight; - text: " 最新的活动"; + text: @tr(" 最新的活动"); } Rectangle { if DiscoveryPageBridge.latest-events-state == PageState.error: Rectangle { Button { type: ButtonType.filled-tonal; - content: "重新加载"; + content: @tr("重新加载"); clicked => { DiscoveryPageBridge.load-latest-events(); } diff --git a/ui/views/page/history.slint b/ui/views/page/history.slint index 039869f3..e30ed6da 100644 --- a/ui/views/page/history.slint +++ b/ui/views/page/history.slint @@ -33,12 +33,12 @@ component CommentItem { height: 40px; font-size: Token.font.body.large.size; text: feedback.content; - placeholder-text: "参与完本次活动,有什么想说的吗,快告诉我们吧"; + placeholder-text: @tr("参与完本次活动,有什么想说的吗,快告诉我们吧"); enabled: !feedback.has-feedbacked; } Button { - content: "评价"; + content: @tr("提交"); type: ButtonType.filled-tonal; disable: feedback.has-feedbacked || star.score == 0; clicked => { @@ -49,7 +49,7 @@ component CommentItem { } if !feedback.success: Rectangle { Text { - text: "网络错误 X.X"; + text: @tr("网络错误 X.X"); font-size: Token.font.label.large.size; horizontal-alignment: center; vertical-alignment: center; @@ -145,7 +145,7 @@ export component HistoryPage inherits Page { padding: 50px; spacing: 15px; Text { - text: "历史活动"; + text: @tr("历史活动"); font-size: Token.font.headline.medium.size; font-weight: Token.font.headline.medium.weight; } @@ -160,7 +160,7 @@ export component HistoryPage inherits Page { if HistoryPageBridge.state == PageState.error: Rectangle { Button { type: ButtonType.filled-tonal; - content: "重新加载"; + content: @tr("重新加载"); clicked => { HistoryPageBridge.load-events(HistoryPageBridge.current-page-index, HistoryPageBridge.page-size); } diff --git a/ui/views/page/search.slint b/ui/views/page/search.slint index 6774e470..1ded4e5e 100644 --- a/ui/views/page/search.slint +++ b/ui/views/page/search.slint @@ -43,7 +43,7 @@ export component SearchPage inherits Page { width: 260px; height: 50px; font-size: Token.font.body.large.size; - placeholder-text: "在找什么部门呢"; + placeholder-text: @tr("在找什么部门呢"); enabled: SearchPageBridge.list-state == PageState.normal; edited(keyword) => { debug("search keyword: " + keyword); @@ -65,7 +65,7 @@ export component SearchPage inherits Page { } if SearchPageBridge.list-state == PageState.error: Rectangle { Button { - text: "重新加载"; + text: @tr("重新加载"); clicked => { SearchPageBridge.load-department-list(); } @@ -104,7 +104,7 @@ export component SearchPage inherits Page { if SearchPageBridge.list-state == PageState.normal && SearchPageBridge.events-state == PageState.normal && SearchPageBridge.event-model.length == 0: Rectangle { Text { - text: "这个部门还没有活动哦"; + text: @tr("这个部门还没有活动哦"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.outline; @@ -120,7 +120,7 @@ export component SearchPage inherits Page { if SearchPageBridge.events-state == PageState.error: Rectangle { Button { - text: "重新加载"; + text: @tr("重新加载"); clicked => { SearchPageBridge.load-department-events(current-page-index); } @@ -129,7 +129,7 @@ export component SearchPage inherits Page { if SearchPageBridge.list-state != PageState.normal || SearchPageBridge.event-model.length == 0: Rectangle { Text { - text: "什么都没有呢"; + text: @tr("什么都没有呢"); font-size: Token.font.body.large.size; font-weight: Token.font.body.large.weight; color: Token.color.outline; diff --git a/ui/views/page/setting.slint b/ui/views/page/setting.slint index 6581b172..c07ad7ea 100644 --- a/ui/views/page/setting.slint +++ b/ui/views/page/setting.slint @@ -4,11 +4,10 @@ import { Switch, ComboBox, ScrollView } from "std-widgets.slint"; import { MessageManager, MessageType } from "../../logic/index.slint"; export global SettingPageBridge { - in-out property language-index: 0; - in-out property theme-index: 0; - in-out property notice-begin: false; - in-out property notice-end: false; - in-out property minimal-to-tray: false; + in-out property theme-index; + in-out property notice-begin; + in-out property notice-end; + in-out property minimal-to-tray; in property cache-size: "0B"; public function change-theme() { if (theme-index == 1) { @@ -17,7 +16,6 @@ export global SettingPageBridge { Token.set-display-mode(ColorScheme.dark); } } - callback language-changed(); callback theme-changed(); callback notice-begin-changed(); callback notice-end-changed(); @@ -55,7 +53,6 @@ export component SettingPage inherits Page { pointer-event(e) => { if (e.button == PointerEventButton.left) { theme-box.clear-focus(); - language-box.clear-focus(); } } } @@ -65,7 +62,7 @@ export component SettingPage inherits Page { padding: 50px; spacing: 10px; Text { - text: "设置"; + text: @tr("设置"); font-size: Token.font.display.medium.size; font-weight: Token.font.display.medium.weight; } @@ -77,39 +74,25 @@ export component SettingPage inherits Page { Divider { } SettingItem { - name: "主题"; + name: @tr("主题"); theme-box := ComboBox { width: 200px; - model: ["跟随系统", "浅色", "深色"]; + model: [@tr("跟随系统"), @tr("浅色"), @tr("深色")]; current-index <=> SettingPageBridge.theme-index; selected => { SettingPageBridge.change-theme(); if (SettingPageBridge.theme-index == 0) { - MessageManager.show-message("下次启动时生效", MessageType.info); + MessageManager.show-message(@tr("下次启动时生效"), MessageType.info); } SettingPageBridge.theme-changed(); } } } - SettingItem { - name: "语言"; - supported: false; - language-box := ComboBox { - width: 200px; - enabled: false; - model: ["简体中文", "繁體中文", "English"]; - current-index <=> SettingPageBridge.language-index; - selected => { - SettingPageBridge.language-changed(); - } - } - } - Divider { } SettingItem { - name: "活动开始前提醒"; + name: @tr("活动开始前提醒"); Switch { checked <=> SettingPageBridge.notice-begin; toggled => { @@ -119,7 +102,7 @@ export component SettingPage inherits Page { } SettingItem { - name: "活动结束后提醒反馈"; + name: @tr("活动结束后提醒反馈"); Switch { checked <=> SettingPageBridge.notice-end; toggled => { @@ -129,7 +112,7 @@ export component SettingPage inherits Page { } SettingItem { - name: "关闭窗口后最小化到托盘"; + name: @tr("关闭窗口后最小化到托盘"); Switch { checked <=> SettingPageBridge.minimal-to-tray; toggled => { @@ -141,12 +124,12 @@ export component SettingPage inherits Page { Divider { } SettingItem { - name: "磁盘缓存:" + SettingPageBridge.cache-size; + name: @tr("磁盘缓存:") + SettingPageBridge.cache-size; Button { - content: "清除缓存"; + content: @tr("清除缓存"); clicked => { SettingPageBridge.clear-cache(); - MessageManager.show-message("缓存已清除", MessageType.success); + MessageManager.show-message(@tr("缓存已清除"), MessageType.success); } } } diff --git a/vcpkg.json b/vcpkg.json index 58d04993..1b102ef8 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -10,6 +10,14 @@ "nlohmann-json", "spdlog", "tomlplusplus", + { + "name": "gettext", + "features": [ + "tools" + ], + "host": true + }, + "gettext-libintl", { "name": "pkgconf", "host": true