diff --git a/.gitmodules b/.gitmodules index 8b198a1b..332375b5 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "vendor/luasocket"] path = vendor/luasocket url = https://github.com/diegonehab/luasocket.git +[submodule "vendor/tinygettext"] + path = vendor/tinygettext + url = https://github.com/tinygettext/tinygettext.git diff --git a/ThirdParty_LICENSES b/ThirdParty_LICENSES index b9fcd297..52160360 100644 --- a/ThirdParty_LICENSES +++ b/ThirdParty_LICENSES @@ -586,4 +586,41 @@ and desktop fonts contain some icons that are redistributed under the Apache licenses or are distributed under the Apache 2.0 license. # Code: MIT (https://opensource.org/licenses/MIT) -The MIT license applies to all non-font and non-icon files. \ No newline at end of file +The MIT license applies to all non-font and non-icon files. + +================== tinygettext ================ + +tinygettext - A gettext replacement that works directly on .po files + +Copyright (c) 2004-2016 + +* Bastiaan Zapf +* Christoph Sommer +* Georg Kilzer (leper) +* Ingo Ruhnke +* Mathnerd314 +* Matt McCutchen +* Matthias Braun +* Nathan Phillip Brink +* Poren Chiang +* Ravu al Hemio +* Ryan Flegel +* Tim Goya +* Tobias Markus +* Wolfgang Becker + +This software is provided 'as-is', without any express or implied +warranty. In no event will the authors be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgement in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. diff --git a/Translation.md b/Translation.md new file mode 100644 index 00000000..c35052e1 --- /dev/null +++ b/Translation.md @@ -0,0 +1,92 @@ +# Translation + +Instructions on how to create and update the language files for CET. + +## For translators + +The language files have the extension name of ".po". The file names are generally using [two-letter language codes](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. en, fr, de). For languages that have different writing systems or to differentiate by country, the file name needs to be a locale with an underscore (e.g. zh_CN, zh_TW). + +### Use Crowdin + +Todo + + +### Use commandline scripts: + +### Create a new language file +To create a new language, use the following command: +```sh +xmake i18n-po create filename +``` +This will generate a new po file under the `languages/` directory. Make sure the filename follows the rules above. Otherwise, the language name won't be parsed by CET correctly. + +### Update the language files +To update those files, use the following command: +```sh +xmake i18n-po update +``` +This will add new translatable strings from `template.pot` file to all `.po` files. + +### Edit the language files +To edit the language files, you can either edit them on Crowdin or open them in a text editor or a PO editor. + +### Test the translations +You can reload the translations from `Settings->CET Development Settings->Reload translation`. + +If you are editing the language files from the project directory. Use the following command to copy the language files to your game directory: +```sh +xmake i18n-install +``` + +## Format + +The language files are using the GNU gettext PO format. Detailed documentation can be found [here](https://www.gnu.org/software/gettext/manual/html_node/PO-Files.html). +```po +white-space +# translator-comments +#. extracted-comments +#: reference… +#, flag… +#| msgid previous-untranslated-string +msgid untranslated-string +msgstr translated-string +``` +## For developers + +There are two macros you can use the mark the translatable strings. + +To translate normal strings, use: +```cpp +_t("This string will be translated."); +``` + +To translate strings with plural forms: +```cpp +_t("There is %d apple.", "There are %d apples.", number); +``` + +If you have strings inside a container that you want to translate. You can use the `_noop("string")` to mark it for translation. For example: +```cpp +std::vector fruits = { + _noop("apple"), + _noop("banana"), + _noop("orange") +}; + +for (const auto& fruit : list) +{ + Log::Info(_t(fruit)); +} +``` + +Always remember to update the `template.pot` file before you commit the changes you made to the translatable strings. So translators can start to work on updating the translations. + +### Update the template file + +The template file `template.pot` is auto-generated from the source files. It includes all the translatable strings in the source files. + +To update this file, use the following command: +```sh +xmake i18n-pot +``` +This will also auto-update the `en.po` file. `en.po` is always auto-generated from the template file, so there's no need to edit it. \ No newline at end of file diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 00000000..c79f43e3 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,10 @@ +pull_request_title: Update Translation +commit_message: '[ci skip]' +files: + - source: /languages/template.pot + translation: /languages/%two_letters_code%.po + update_option: update_as_unapproved + languages_mapping: + two_letters_code: + zh-CN: zh_CN + zh-TW: zh_TW diff --git a/languages/en.po b/languages/en.po new file mode 100644 index 00000000..ffaeffe0 --- /dev/null +++ b/languages/en.po @@ -0,0 +1,465 @@ +# English translations for CyberEngineTweaks package. +# Copyright (C) 2023 yamashi +# This file is distributed under the same license as the CyberEngineTweaks package. +# Automatically generated, 2023. +# +msgid "" +msgstr "" +"Project-Id-Version: CyberEngineTweaks \n" +"Report-Msgid-Bugs-To: https://github.com/maximegmd/CyberEngineTweaks/issues\n" +"POT-Creation-Date: 2023-07-01 16:05+0800\n" +"PO-Revision-Date: 2023-05-29 08:27+0800\n" +"Last-Translator: Automatically generated\n" +"Language-Team: none\n" +"Language: en\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Translators: Type in your language name in it's own language. (e.g. French -> Français) +#: src\I18n.cpp:61 +msgid "Localized Language Name" +msgstr "English" + +#: src\overlay\Overlay.cpp:300 +msgid "Console" +msgstr "Console" + +#: src\overlay\Overlay.cpp:309 +msgid "Bindings" +msgstr "Bindings" + +#: src\overlay\Overlay.cpp:318 +msgid "Settings" +msgstr "Settings" + +#: src\overlay\Overlay.cpp:327 +msgid "TweakDB Editor" +msgstr "TweakDB Editor" + +#: src\overlay\Overlay.cpp:336 +msgid "Game Log" +msgstr "Game Log" + +#: src\overlay\Overlay.cpp:345 +msgid "ImGui Debug" +msgstr "ImGui Debug" + +#: src\overlay\Overlay.cpp:353 +msgid "Reload all mods" +msgstr "Reload all mods" + +#: src\overlay\widgets\Bindings.cpp:93 src\overlay\widgets\Settings.cpp:186 +msgid "Save" +msgstr "Save" + +#: src\overlay\widgets\Bindings.cpp:96 +msgid "Reset changes" +msgstr "Reset changes" + +#: src\overlay\widgets\Bindings.cpp:168 src\overlay\widgets\Bindings.cpp:170 +msgid "CET First Time Setup" +msgstr "CET First Time Setup" + +#: src\overlay\widgets\Bindings.cpp:172 src\overlay\widgets\Bindings.cpp:178 +msgid "Combo can be composed from up to 4 keys." +msgstr "Combo can be composed from up to 4 keys." + +#: src\overlay\widgets\Bindings.cpp:173 src\overlay\widgets\Bindings.cpp:176 +msgid "Please, bind some key combination for toggling overlay!" +msgstr "Please, bind some key combination for toggling overlay!" + +#: src\overlay\widgets\Bindings.cpp:362 src\overlay\widgets\Bindings.cpp:399 +msgid "Currently unable to draw this tooltip. Wait for a bit please..." +msgstr "Currently unable to draw this tooltip. Wait for a bit please..." + +#: src\overlay\widgets\Bindings.cpp:428 +msgid "Uncheck this checkbox to unbind this binding." +msgstr "Uncheck this checkbox to unbind this binding." + +#: src\overlay\widgets\Bindings.cpp:474 src\overlay\widgets\Bindings.cpp:475 +msgid "Hotkeys" +msgstr "Hotkeys" + +#: src\overlay\widgets\Bindings.cpp:477 +msgid "Hotkeys react after assigned key combination has been pressed and subsequently released. You can bind up to 4 key combination to them." +msgstr "Hotkeys react after assigned key combination has been pressed and subsequently released. You can bind up to 4 key combination to them." + +#: src\overlay\widgets\Bindings.cpp:498 src\overlay\widgets\Bindings.cpp:499 +msgid "Inputs" +msgstr "Inputs" + +#: src\overlay\widgets\Bindings.cpp:501 +msgid "Inputs react when key is pressed and released. You can bind single key to them." +msgstr "Inputs react when key is pressed and released. You can bind single key to them." + +#: src\overlay\widgets\Console.cpp:113 +msgid "Command failed to execute!" +msgstr "Command failed to execute!" + +#: src\overlay\widgets\LogWindow.cpp:20 +msgid "Clear output" +msgstr "Clear output" + +#: src\overlay\widgets\LogWindow.cpp:28 +msgid "Auto-scroll" +msgstr "Auto-scroll" + +#: src\overlay\widgets\Settings.cpp:56 +msgid "Patches" +msgstr "Patches" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "AMD SMT Patch" +msgstr "AMD SMT Patch" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)." +msgstr "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Remove Pedestrians" +msgstr "Remove Pedestrians" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Removes most of the pedestrians and traffic (requires restart to take effect)." +msgstr "Removes most of the pedestrians and traffic (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:69 +msgid "Disable Async Compute" +msgstr "Disable Async Compute" + +#: src\overlay\widgets\Settings.cpp:70 +msgid "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)." +msgstr "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Disable Anti-aliasing" +msgstr "Disable Anti-aliasing" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Completely disables anti-aliasing (requires restart to take effect)." +msgstr "Completely disables anti-aliasing (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skip Start Menu" +msgstr "Skip Start Menu" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)." +msgstr "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Suppress Intro Movies" +msgstr "Suppress Intro Movies" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Disables logos played at the beginning (requires restart to take effect)." +msgstr "Disables logos played at the beginning (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disable Vignette" +msgstr "Disable Vignette" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disables vignetting along screen borders (requires restart to take effect)." +msgstr "Disables vignetting along screen borders (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Disable Boundary Teleport" +msgstr "Disable Boundary Teleport" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Allows players to access out-of-bounds locations (requires restart to take effect)." +msgstr "Allows players to access out-of-bounds locations (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disable V-Sync (Windows 7 only)" +msgstr "Disable V-Sync (Windows 7 only)" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)." +msgstr "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix Minimap Flicker" +msgstr "Fix Minimap Flicker" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix minimap flickering (requires restart to take effect)." +msgstr "Fix minimap flickering (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:97 +msgid "CET Language Settings" +msgstr "CET Language Settings" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Language" +msgstr "Language" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Display language for CET." +msgstr "Display language for CET." + +#: src\overlay\widgets\Settings.cpp:108 +msgid "CET Font Settings" +msgstr "CET Font Settings" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main Font" +msgstr "Main Font" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main display font for CET." +msgstr "Main display font for CET." + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaced Font" +msgstr "Monospaced Font" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET." +msgstr "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET." + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Font Size" +msgstr "Font Size" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Changes the size of the font, default value is 18px." +msgstr "Changes the size of the font, default value is 18px." + +#: src\overlay\widgets\Settings.cpp:125 +msgid "Advance Settings" +msgstr "Advance Settings" + +#: src\overlay\widgets\Settings.cpp:132 +msgid "Oversample Horizontal" +msgstr "Oversample Horizontal" + +#: src\overlay\widgets\Settings.cpp:133 +msgid "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)" + +#: src\overlay\widgets\Settings.cpp:136 +msgid "Oversample Vertical" +msgstr "Oversample Vertical" + +#: src\overlay\widgets\Settings.cpp:137 +msgid "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)" + +#: src\overlay\widgets\Settings.cpp:146 +msgid "CET Development Settings" +msgstr "CET Development Settings" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Remove Dead Bindings" +msgstr "Remove Dead Bindings" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)." +msgstr "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)." + +#: src\overlay\widgets\Settings.cpp:156 +msgid "Enable ImGui Assertions" +msgstr "Enable ImGui Assertions" + +#: src\overlay\widgets\Settings.cpp:157 +msgid "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be used to check mods before shipping!)." +msgstr "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be used to check mods before shipping!)." + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Enable Debug Build" +msgstr "Enable Debug Build" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Sets internal flags to disguise as debug build (requires restart to take effect)." +msgstr "Sets internal flags to disguise as debug build (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dump Game Options" +msgstr "Dump Game Options" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dumps all game options into main log file (requires restart to take effect)." +msgstr "Dumps all game options into main log file (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Enable Translation Log" +msgstr "Enable Translation Log" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Show logs when there's a missing translation (requires restart to take effect)." +msgstr "Show logs when there's a missing translation (requires restart to take effect)." + +#: src\overlay\widgets\Settings.cpp:170 +msgid "Reload translation" +msgstr "Reload translation" + +#: src\overlay\widgets\Settings.cpp:170 +msgid "Reload translation files." +msgstr "Reload translation files." + +#: src\overlay\widgets\Settings.cpp:183 +msgid "Load" +msgstr "Load" + +#: src\overlay\widgets\Settings.cpp:189 +msgid "Defaults" +msgstr "Defaults" + +#: src\overlay\widgets\Settings.cpp:365 src\overlay\widgets\Settings.cpp:373 +msgctxt "Settings" +msgid "Default" +msgstr "Default" + +#: src\overlay\widgets\Settings.cpp:401 src\overlay\widgets\Settings.cpp:410 +msgctxt "Settings" +msgid "System" +msgstr "System" + +#: src\overlay\widgets\TweakDBEditor.cpp:134 +msgid "TweakDB is not initialized yet" +msgstr "TweakDB is not initialized yet" + +#: src\overlay\widgets\TweakDBEditor.cpp:148 +msgid "Records" +msgstr "Records" + +#: src\overlay\widgets\TweakDBEditor.cpp:156 +msgid "Queries" +msgstr "Queries" + +#: src\overlay\widgets\TweakDBEditor.cpp:164 +msgid "Flats" +msgstr "Flats" + +#: src\overlay\widgets\TweakDBEditor.cpp:172 +msgid "Advanced" +msgstr "Advanced" + +#: src\overlay\widgets\TweakDBEditor.cpp:472 +#: src\overlay\widgets\TweakDBEditor.cpp:1129 +#: src\overlay\widgets\TweakDBEditor.cpp:1385 +#: src\overlay\widgets\TweakDBEditor.cpp:1511 +#: src\overlay\widgets\TweakDBEditor.cpp:1637 +msgid "Search" +msgstr "Search" + +#: src\overlay\widgets\TweakDBEditor.cpp:574 +#, c-format +msgid "'%s' is not found in TweakDB" +msgstr "'%s' is not found in TweakDB" + +#: src\overlay\widgets\TweakDBEditor.cpp:634 +#, c-format +msgid "unsupported type: %s" +msgstr "unsupported type: %s" + +#: src\overlay\widgets\TweakDBEditor.cpp:667 +#, c-format +msgid "[%s] %u item" +msgid_plural "[%s] %u items" +msgstr[0] "[%s] %u item" +msgstr[1] "[%s] %u items" + +#: src\overlay\widgets\TweakDBEditor.cpp:669 +msgid "clear" +msgstr "clear" + +#: src\overlay\widgets\TweakDBEditor.cpp:680 +msgid "edit" +msgstr "edit" + +#: src\overlay\widgets\TweakDBEditor.cpp:692 +msgid "cancel" +msgstr "cancel" + +#: src\overlay\widgets\TweakDBEditor.cpp:705 +msgid "save" +msgstr "save" + +#: src\overlay\widgets\TweakDBEditor.cpp:769 +msgid "add new" +msgstr "add new" + +#: src\overlay\widgets\TweakDBEditor.cpp:815 +msgid "ERROR_RECORD_NOT_FOUND" +msgstr "ERROR_RECORD_NOT_FOUND" + +#: src\overlay\widgets\TweakDBEditor.cpp:909 +msgid "Roll " +msgstr "Roll " + +#: src\overlay\widgets\TweakDBEditor.cpp:914 +msgid "Pitch" +msgstr "Pitch" + +#: src\overlay\widgets\TweakDBEditor.cpp:919 +msgid "Yaw " +msgstr "Yaw " + +#: src\overlay\widgets\TweakDBEditor.cpp:1038 +msgid "'Color' is not supported yet" +msgstr "'Color' is not supported yet" + +#: src\overlay\widgets\TweakDBEditor.cpp:1074 +msgid "This is a LocalizationKey" +msgstr "This is a LocalizationKey" + +#: src\overlay\widgets\TweakDBEditor.cpp:1232 +msgid "Game is expecting specific values." +msgstr "Game is expecting specific values." + +#: src\overlay\widgets\TweakDBEditor.cpp:1384 +#: src\overlay\widgets\TweakDBEditor.cpp:1390 +#: src\overlay\widgets\TweakDBEditor.cpp:1510 +#: src\overlay\widgets\TweakDBEditor.cpp:1516 +msgid "Regex" +msgstr "Regex" + +#: src\overlay\widgets\TweakDBEditor.cpp:1455 +#: src\overlay\widgets\TweakDBEditor.cpp:1573 +msgid "ERROR_FLAT_NOT_FOUND" +msgstr "ERROR_FLAT_NOT_FOUND" + +#: src\overlay\widgets\TweakDBEditor.cpp:1595 +msgid "'Flats' Grouping depth" +msgstr "'Flats' Grouping depth" + +#: src\overlay\widgets\TweakDBEditor.cpp:1601 +msgid "ComboBox dropdown height" +msgstr "ComboBox dropdown height" + +#: src\overlay\widgets\TweakDBEditor.cpp:1603 +msgid "Refresh all" +msgstr "Refresh all" + +#: src\overlay\widgets\TweakDBEditor.cpp:1624 +msgid "Record name" +msgstr "Record name" + +#: src\overlay\widgets\TweakDBEditor.cpp:1626 +msgid "Delete Record" +msgstr "Delete Record" + +#: src\overlay\widgets\TweakDBEditor.cpp:1634 +msgid "Record type to create" +msgstr "Record type to create" + +#: src\overlay\widgets\TweakDBEditor.cpp:1664 +msgid "Create record" +msgstr "Create record" + +#: src\overlay\widgets\TweakDBEditor.cpp:1672 +msgid "Record to clone" +msgstr "Record to clone" + +#: src\overlay\widgets\TweakDBEditor.cpp:1674 +msgid "Clone record" +msgstr "Clone record" + +#~ msgid "Reload" +#~ msgstr "Reload" diff --git a/languages/ja.po b/languages/ja.po new file mode 100644 index 00000000..2a05a44b --- /dev/null +++ b/languages/ja.po @@ -0,0 +1,454 @@ +msgid "" +msgstr "" +"Project-Id-Version: cyber-engine-tweaks\n" +"Report-Msgid-Bugs-To: https://github.com/maximegmd/CyberEngineTweaks/issues\n" +"POT-Creation-Date: 2023-05-31 17:59+0800\n" +"PO-Revision-Date: 2023-05-31 11:04\n" +"Last-Translator: \n" +"Language-Team: Japanese\n" +"Language: ja_JP\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: cyber-engine-tweaks\n" +"X-Crowdin-Project-ID: 591959\n" +"X-Crowdin-Language: ja\n" +"X-Crowdin-File: /i18n/languages/template.pot\n" +"X-Crowdin-File-ID: 9\n" + +#. Translators: Type in your language name in it's own language. (e.g. French -> Français) +#: src\I18n.cpp:61 +msgid "Localized Language Name" +msgstr "日本語" + +#: src\overlay\Overlay.cpp:300 +msgid "Console" +msgstr "コンソール" + +#: src\overlay\Overlay.cpp:309 +msgid "Bindings" +msgstr "バインド設定" + +#: src\overlay\Overlay.cpp:318 +msgid "Settings" +msgstr "設定" + +#: src\overlay\Overlay.cpp:327 +msgid "TweakDB Editor" +msgstr "TweakDBエディター" + +#: src\overlay\Overlay.cpp:336 +msgid "Game Log" +msgstr "ゲームログ" + +#: src\overlay\Overlay.cpp:345 +msgid "ImGui Debug" +msgstr "ImGui デバッグ" + +#: src\overlay\Overlay.cpp:353 +msgid "Reload all mods" +msgstr "全MODをリロード" + +#: src\overlay\widgets\Bindings.cpp:93 src\overlay\widgets\Settings.cpp:184 +msgid "Save" +msgstr "保存" + +#: src\overlay\widgets\Bindings.cpp:96 +msgid "Reset changes" +msgstr "リセット変更" + +#: src\overlay\widgets\Bindings.cpp:168 src\overlay\widgets\Bindings.cpp:170 +msgid "CET First Time Setup" +msgstr "CET初回セットアップ" + +#: src\overlay\widgets\Bindings.cpp:172 src\overlay\widgets\Bindings.cpp:178 +msgid "Combo can be composed from up to 4 keys." +msgstr "4つのキーまででコンボを構成できます。" + +#: src\overlay\widgets\Bindings.cpp:173 src\overlay\widgets\Bindings.cpp:176 +msgid "Please, bind some key combination for toggling overlay!" +msgstr "CETのオーバーレイを切り替えるためにホットキーを設定してください!" + +#: src\overlay\widgets\Bindings.cpp:362 src\overlay\widgets\Bindings.cpp:399 +msgid "Currently unable to draw this tooltip. Wait for a bit please..." +msgstr "現在このツールチップを描くことができません。少しお待ちください..." + +#: src\overlay\widgets\Bindings.cpp:428 +msgid "Uncheck this checkbox to unbind this binding." +msgstr "このバインドを解除するにはチェックボックスをオフにしてください。" + +#: src\overlay\widgets\Bindings.cpp:474 src\overlay\widgets\Bindings.cpp:475 +msgid "Hotkeys" +msgstr "ホットキー" + +#: src\overlay\widgets\Bindings.cpp:477 +msgid "Hotkeys react after assigned key combination has been pressed and subsequently released. You can bind up to 4 key combination to them." +msgstr "設定されたキーの組み合わせを押してから離すと、ホットキーが反応します。最大4つのキーの組み合わせを設定することができます。" + +#: src\overlay\widgets\Bindings.cpp:498 src\overlay\widgets\Bindings.cpp:499 +msgid "Inputs" +msgstr "インプット" + +#: src\overlay\widgets\Bindings.cpp:501 +msgid "Inputs react when key is pressed and released. You can bind single key to them." +msgstr "キーが押されたり、離されたりすると、インプットが反応します。一つのキーをバインドすることができます。" + +#: src\overlay\widgets\Console.cpp:113 +msgid "Command failed to execute!" +msgstr "コマンドの実行に失敗しました!" + +#: src\overlay\widgets\LogWindow.cpp:20 +msgid "Clear output" +msgstr "出力をクリア" + +#: src\overlay\widgets\LogWindow.cpp:28 +msgid "Auto-scroll" +msgstr "自動スクロール" + +#: src\overlay\widgets\Settings.cpp:56 +msgid "Patches" +msgstr "パッチ" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "AMD SMT Patch" +msgstr "AMD SMT パッチ" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)." +msgstr "CDPRのパッチ後のパフォーマンス向上がなかったAMD CPUのために(再起動が必要)。" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Remove Pedestrians" +msgstr "歩行者を取り除く" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Removes most of the pedestrians and traffic (requires restart to take effect)." +msgstr "歩行者と交通のほとんどを取り除きます(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:69 +msgid "Disable Async Compute" +msgstr "非同期計算を無効にする" + +#: src\overlay\widgets\Settings.cpp:70 +msgid "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)." +msgstr "非同期計算を無効にする。Nvidia 10xx シリーズなどの古いGPUに対してブーストすることができます (再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Disable Anti-aliasing" +msgstr "アンチエイリアスを無効にする" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Completely disables anti-aliasing (requires restart to take effect)." +msgstr "完全にアンチエイリアスを無効にします(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skip Start Menu" +msgstr "スタートメニューをスキップ" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)." +msgstr "スペースキーを押して続行するよう要求される「侵入中...」メニューをスキップします(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Suppress Intro Movies" +msgstr "イントロ動画をスキップ" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Disables logos played at the beginning (requires restart to take effect)." +msgstr "最初に再生されたロゴ動画をスキップします(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disable Vignette" +msgstr "ヴィネットを無効にする" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disables vignetting along screen borders (requires restart to take effect)." +msgstr "画面境界を暗くする効果を無効にします(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Disable Boundary Teleport" +msgstr "境界線転移を無効にする" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Allows players to access out-of-bounds locations (requires restart to take effect)." +msgstr "範囲外の場所にアクセスできるようにします(再起動が必要です)" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disable V-Sync (Windows 7 only)" +msgstr "垂直同期を無効にする (Windows 7 のみ)" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)." +msgstr "Windows 7 で垂直同期を無効にして60 FPSの制限を上回ります(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix Minimap Flicker" +msgstr "ミニマップのフリックを修正" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix minimap flickering (requires restart to take effect)." +msgstr "ミニマップのフリック問題を修正(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:97 +msgid "CET Language Settings" +msgstr "CET 言語設定" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Language" +msgstr "言語" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Display language for CET." +msgstr "CETの表示言語です。" + +#: src\overlay\widgets\Settings.cpp:108 +msgid "CET Font Settings" +msgstr "CET フォント設定" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main Font" +msgstr "主要フォント" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main display font for CET." +msgstr "CETの主要表示フォント。" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaced Font" +msgstr "等幅フォント" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET." +msgstr "CETの等幅フォント、コンソールやゲームログでテキストを表示するために使用されます。" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Font Size" +msgstr "文字サイズ" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Changes the size of the font, default value is 18px." +msgstr "フォントのサイズを変更します。既定値は18pxです。" + +#: src\overlay\widgets\Settings.cpp:125 +msgid "Advance Settings" +msgstr "詳細設定" + +#: src\overlay\widgets\Settings.cpp:132 +msgid "Oversample Horizontal" +msgstr "水平オーバーサンプリング" + +#: src\overlay\widgets\Settings.cpp:133 +msgid "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "水平方向にフォントをオーバーサンプリングします。デフォルト値は3倍です。(フォントのクリア度を高めることができますが、メモリ使用量が増加します。)" + +#: src\overlay\widgets\Settings.cpp:136 +msgid "Oversample Vertical" +msgstr "垂直オーバーサンプリング" + +#: src\overlay\widgets\Settings.cpp:137 +msgid "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "垂直方向にフォントをオーバーサンプリングします。デフォルト値は1倍です。(フォントのクリア度を高めることができますが、メモリ使用量が増加します。)" + +#: src\overlay\widgets\Settings.cpp:146 +msgid "CET Development Settings" +msgstr "CET 開発設定" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Remove Dead Bindings" +msgstr "無効バインディングを削除" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)." +msgstr "無効になったすべてのバインディングを削除します(Modの問題をデバッグするときに、このオプションを無効にすると便利です)。" + +#: src\overlay\widgets\Settings.cpp:156 +msgid "Enable ImGui Assertions" +msgstr "ImGuiアサーションを有効にする" + +#: src\overlay\widgets\Settings.cpp:157 +msgid "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be used to check mods before shipping!)." +msgstr "すべての ImGui アサーションを有効にします。アサーションは、トリガーしたModのログファイルに記録されます (ImGuiの問題のデバッグ時に便利です。 リリース前にModをチェックするためにも使用するべきです!)。" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Enable Debug Build" +msgstr "デバッグビルドを有効にする" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Sets internal flags to disguise as debug build (requires restart to take effect)." +msgstr "内部フラグをデバッグビルドに変装させるように設定します (再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dump Game Options" +msgstr "ゲームオプションをエクスポートする" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dumps all game options into main log file (requires restart to take effect)." +msgstr "すべてのゲームオプションをメインログファイルに出力します(再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Enable Translation Log" +msgstr "翻訳ログを有効にする" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Show logs when there's a missing translation (requires restart to take effect)." +msgstr "翻訳が不足している場合にログを表示します (再起動が必要です)。" + +#: src\overlay\widgets\Settings.cpp:181 +msgid "Load" +msgstr "読み込み" + +#: src\overlay\widgets\Settings.cpp:187 +msgid "Defaults" +msgstr "デフォルト値" + +#: src\overlay\widgets\Settings.cpp:334 src\overlay\widgets\Settings.cpp:342 +msgctxt "Settings" +msgid "Default" +msgstr "デフォルト" + +#: src\overlay\widgets\Settings.cpp:369 src\overlay\widgets\Settings.cpp:378 +msgctxt "Settings" +msgid "System" +msgstr "システム" + +#: src\overlay\widgets\TweakDBEditor.cpp:134 +msgid "TweakDB is not initialized yet" +msgstr "TweakDBはまだ初期化されていません" + +#: src\overlay\widgets\TweakDBEditor.cpp:146 +msgid "Records" +msgstr "レコード" + +#: src\overlay\widgets\TweakDBEditor.cpp:154 +msgid "Queries" +msgstr "クエリ" + +#: src\overlay\widgets\TweakDBEditor.cpp:162 +msgid "Flats" +msgstr "フラット" + +#: src\overlay\widgets\TweakDBEditor.cpp:170 +msgid "Advanced" +msgstr "詳細設定" + +#: src\overlay\widgets\TweakDBEditor.cpp:442 +#: src\overlay\widgets\TweakDBEditor.cpp:1099 +#: src\overlay\widgets\TweakDBEditor.cpp:1355 +#: src\overlay\widgets\TweakDBEditor.cpp:1481 +#: src\overlay\widgets\TweakDBEditor.cpp:1607 +msgid "Search" +msgstr "検索" + +#: src\overlay\widgets\TweakDBEditor.cpp:544 +#, c-format +msgid "'%s' is not found in TweakDB" +msgstr "'%s' は TweakDB に見つかりません" + +#: src\overlay\widgets\TweakDBEditor.cpp:604 +#, c-format +msgid "unsupported type: %s" +msgstr "サポートされていないタイプ: %s" + +#: src\overlay\widgets\TweakDBEditor.cpp:637 +#, c-format +msgid "[%s] %u item" +msgid_plural "[%s] %u items" +msgstr[0] "[%s] %u 個のアイテム" + +#: src\overlay\widgets\TweakDBEditor.cpp:639 +msgid "clear" +msgstr "削除" + +#: src\overlay\widgets\TweakDBEditor.cpp:650 +msgid "edit" +msgstr "編集" + +#: src\overlay\widgets\TweakDBEditor.cpp:662 +msgid "cancel" +msgstr "キャンセル" + +#: src\overlay\widgets\TweakDBEditor.cpp:675 +msgid "save" +msgstr "保存" + +#: src\overlay\widgets\TweakDBEditor.cpp:739 +msgid "add new" +msgstr "新規" + +#: src\overlay\widgets\TweakDBEditor.cpp:785 +msgid "ERROR_RECORD_NOT_FOUND" +msgstr "エラー:レコードが見つかりませんでした。" + +#: src\overlay\widgets\TweakDBEditor.cpp:879 +msgid "Roll " +msgstr "横揺れ角 " + +#: src\overlay\widgets\TweakDBEditor.cpp:884 +msgid "Pitch" +msgstr "縦揺れ角" + +#: src\overlay\widgets\TweakDBEditor.cpp:889 +msgid "Yaw " +msgstr "偏揺れ角 " + +#: src\overlay\widgets\TweakDBEditor.cpp:1008 +msgid "'Color' is not supported yet" +msgstr "「Color」はまだサポートされていません" + +#: src\overlay\widgets\TweakDBEditor.cpp:1044 +msgid "This is a LocalizationKey" +msgstr "これはLocalizationKeyです" + +#: src\overlay\widgets\TweakDBEditor.cpp:1202 +msgid "Game is expecting specific values." +msgstr "ゲームは特定の値を期待しています。" + +#: src\overlay\widgets\TweakDBEditor.cpp:1354 +#: src\overlay\widgets\TweakDBEditor.cpp:1360 +#: src\overlay\widgets\TweakDBEditor.cpp:1480 +#: src\overlay\widgets\TweakDBEditor.cpp:1486 +msgid "Regex" +msgstr "正規表現" + +#: src\overlay\widgets\TweakDBEditor.cpp:1425 +#: src\overlay\widgets\TweakDBEditor.cpp:1543 +msgid "ERROR_FLAT_NOT_FOUND" +msgstr "エラー:フラットが見つかりませんでした。" + +#: src\overlay\widgets\TweakDBEditor.cpp:1565 +msgid "'Flats' Grouping depth" +msgstr "「フラット」グループの深さ" + +#: src\overlay\widgets\TweakDBEditor.cpp:1571 +msgid "ComboBox dropdown height" +msgstr "コンボボックスのドロップダウンの高さ" + +#: src\overlay\widgets\TweakDBEditor.cpp:1573 +msgid "Refresh all" +msgstr "全て更新" + +#: src\overlay\widgets\TweakDBEditor.cpp:1594 +msgid "Record name" +msgstr "レコード名" + +#: src\overlay\widgets\TweakDBEditor.cpp:1596 +msgid "Delete Record" +msgstr "レコードを削除" + +#: src\overlay\widgets\TweakDBEditor.cpp:1604 +msgid "Record type to create" +msgstr "作成するレコードの種類" + +#: src\overlay\widgets\TweakDBEditor.cpp:1634 +msgid "Create record" +msgstr "レコードを作成" + +#: src\overlay\widgets\TweakDBEditor.cpp:1642 +msgid "Record to clone" +msgstr "複製するレコード" + +#: src\overlay\widgets\TweakDBEditor.cpp:1644 +msgid "Clone record" +msgstr "レコードを複製" + diff --git a/languages/template.pot b/languages/template.pot new file mode 100644 index 00000000..c8122ffd --- /dev/null +++ b/languages/template.pot @@ -0,0 +1,463 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR yamashi +# This file is distributed under the same license as the CyberEngineTweaks package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: CyberEngineTweaks \n" +"Report-Msgid-Bugs-To: https://github.com/maximegmd/CyberEngineTweaks/issues\n" +"POT-Creation-Date: 2023-07-01 16:05+0800\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n" + +#. Translators: Type in your language name in it's own language. (e.g. French -> Français) +#: src\I18n.cpp:61 +msgid "Localized Language Name" +msgstr "" + +#: src\overlay\Overlay.cpp:300 +msgid "Console" +msgstr "" + +#: src\overlay\Overlay.cpp:309 +msgid "Bindings" +msgstr "" + +#: src\overlay\Overlay.cpp:318 +msgid "Settings" +msgstr "" + +#: src\overlay\Overlay.cpp:327 +msgid "TweakDB Editor" +msgstr "" + +#: src\overlay\Overlay.cpp:336 +msgid "Game Log" +msgstr "" + +#: src\overlay\Overlay.cpp:345 +msgid "ImGui Debug" +msgstr "" + +#: src\overlay\Overlay.cpp:353 +msgid "Reload all mods" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:93 src\overlay\widgets\Settings.cpp:186 +msgid "Save" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:96 +msgid "Reset changes" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:168 src\overlay\widgets\Bindings.cpp:170 +msgid "CET First Time Setup" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:172 src\overlay\widgets\Bindings.cpp:178 +msgid "Combo can be composed from up to 4 keys." +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:173 src\overlay\widgets\Bindings.cpp:176 +msgid "Please, bind some key combination for toggling overlay!" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:362 src\overlay\widgets\Bindings.cpp:399 +msgid "Currently unable to draw this tooltip. Wait for a bit please..." +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:428 +msgid "Uncheck this checkbox to unbind this binding." +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:474 src\overlay\widgets\Bindings.cpp:475 +msgid "Hotkeys" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:477 +msgid "Hotkeys react after assigned key combination has been pressed and subsequently released. You can bind up to 4 key combination to them." +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:498 src\overlay\widgets\Bindings.cpp:499 +msgid "Inputs" +msgstr "" + +#: src\overlay\widgets\Bindings.cpp:501 +msgid "Inputs react when key is pressed and released. You can bind single key to them." +msgstr "" + +#: src\overlay\widgets\Console.cpp:113 +msgid "Command failed to execute!" +msgstr "" + +#: src\overlay\widgets\LogWindow.cpp:20 +msgid "Clear output" +msgstr "" + +#: src\overlay\widgets\LogWindow.cpp:28 +msgid "Auto-scroll" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:56 +msgid "Patches" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "AMD SMT Patch" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Remove Pedestrians" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Removes most of the pedestrians and traffic (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:69 +msgid "Disable Async Compute" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:70 +msgid "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Disable Anti-aliasing" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Completely disables anti-aliasing (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skip Start Menu" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Suppress Intro Movies" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Disables logos played at the beginning (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disable Vignette" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disables vignetting along screen borders (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Disable Boundary Teleport" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Allows players to access out-of-bounds locations (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disable V-Sync (Windows 7 only)" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix Minimap Flicker" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix minimap flickering (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:97 +msgid "CET Language Settings" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Language" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Display language for CET." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:108 +msgid "CET Font Settings" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main Font" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main display font for CET." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaced Font" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Font Size" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Changes the size of the font, default value is 18px." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:125 +msgid "Advance Settings" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:132 +msgid "Oversample Horizontal" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:133 +msgid "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:136 +msgid "Oversample Vertical" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:137 +msgid "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:146 +msgid "CET Development Settings" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Remove Dead Bindings" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:156 +msgid "Enable ImGui Assertions" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:157 +msgid "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be used to check mods before shipping!)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Enable Debug Build" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Sets internal flags to disguise as debug build (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dump Game Options" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dumps all game options into main log file (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Enable Translation Log" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Show logs when there's a missing translation (requires restart to take effect)." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:170 +msgid "Reload translation" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:170 +msgid "Reload translation files." +msgstr "" + +#: src\overlay\widgets\Settings.cpp:183 +msgid "Load" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:189 +msgid "Defaults" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:365 src\overlay\widgets\Settings.cpp:373 +msgctxt "Settings" +msgid "Default" +msgstr "" + +#: src\overlay\widgets\Settings.cpp:401 src\overlay\widgets\Settings.cpp:410 +msgctxt "Settings" +msgid "System" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:134 +msgid "TweakDB is not initialized yet" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:148 +msgid "Records" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:156 +msgid "Queries" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:164 +msgid "Flats" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:172 +msgid "Advanced" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:472 +#: src\overlay\widgets\TweakDBEditor.cpp:1129 +#: src\overlay\widgets\TweakDBEditor.cpp:1385 +#: src\overlay\widgets\TweakDBEditor.cpp:1511 +#: src\overlay\widgets\TweakDBEditor.cpp:1637 +msgid "Search" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:574 +#, c-format +msgid "'%s' is not found in TweakDB" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:634 +#, c-format +msgid "unsupported type: %s" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:667 +#, c-format +msgid "[%s] %u item" +msgid_plural "[%s] %u items" +msgstr[0] "" +msgstr[1] "" + +#: src\overlay\widgets\TweakDBEditor.cpp:669 +msgid "clear" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:680 +msgid "edit" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:692 +msgid "cancel" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:705 +msgid "save" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:769 +msgid "add new" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:815 +msgid "ERROR_RECORD_NOT_FOUND" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:909 +msgid "Roll " +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:914 +msgid "Pitch" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:919 +msgid "Yaw " +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1038 +msgid "'Color' is not supported yet" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1074 +msgid "This is a LocalizationKey" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1232 +msgid "Game is expecting specific values." +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1384 +#: src\overlay\widgets\TweakDBEditor.cpp:1390 +#: src\overlay\widgets\TweakDBEditor.cpp:1510 +#: src\overlay\widgets\TweakDBEditor.cpp:1516 +msgid "Regex" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1455 +#: src\overlay\widgets\TweakDBEditor.cpp:1573 +msgid "ERROR_FLAT_NOT_FOUND" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1595 +msgid "'Flats' Grouping depth" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1601 +msgid "ComboBox dropdown height" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1603 +msgid "Refresh all" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1624 +msgid "Record name" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1626 +msgid "Delete Record" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1634 +msgid "Record type to create" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1664 +msgid "Create record" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1672 +msgid "Record to clone" +msgstr "" + +#: src\overlay\widgets\TweakDBEditor.cpp:1674 +msgid "Clone record" +msgstr "" diff --git a/languages/zh_CN.po b/languages/zh_CN.po new file mode 100644 index 00000000..5ccd4d87 --- /dev/null +++ b/languages/zh_CN.po @@ -0,0 +1,454 @@ +msgid "" +msgstr "" +"Project-Id-Version: cyber-engine-tweaks\n" +"Report-Msgid-Bugs-To: https://github.com/maximegmd/CyberEngineTweaks/issues\n" +"POT-Creation-Date: 2023-05-31 17:59+0800\n" +"PO-Revision-Date: 2023-05-31 11:04\n" +"Last-Translator: \n" +"Language-Team: Chinese Simplified\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: cyber-engine-tweaks\n" +"X-Crowdin-Project-ID: 591959\n" +"X-Crowdin-Language: zh-CN\n" +"X-Crowdin-File: /i18n/languages/template.pot\n" +"X-Crowdin-File-ID: 9\n" + +#. Translators: Type in your language name in it's own language. (e.g. French -> Français) +#: src\I18n.cpp:61 +msgid "Localized Language Name" +msgstr "中文(简体)" + +#: src\overlay\Overlay.cpp:300 +msgid "Console" +msgstr "控制台" + +#: src\overlay\Overlay.cpp:309 +msgid "Bindings" +msgstr "按键绑定" + +#: src\overlay\Overlay.cpp:318 +msgid "Settings" +msgstr "设置" + +#: src\overlay\Overlay.cpp:327 +msgid "TweakDB Editor" +msgstr "TweakDB编辑器" + +#: src\overlay\Overlay.cpp:336 +msgid "Game Log" +msgstr "游戏日志" + +#: src\overlay\Overlay.cpp:345 +msgid "ImGui Debug" +msgstr "ImGui调试" + +#: src\overlay\Overlay.cpp:353 +msgid "Reload all mods" +msgstr "重载所有Mod" + +#: src\overlay\widgets\Bindings.cpp:93 src\overlay\widgets\Settings.cpp:184 +msgid "Save" +msgstr "保存" + +#: src\overlay\widgets\Bindings.cpp:96 +msgid "Reset changes" +msgstr "重置更改" + +#: src\overlay\widgets\Bindings.cpp:168 src\overlay\widgets\Bindings.cpp:170 +msgid "CET First Time Setup" +msgstr "CET首次使用设置" + +#: src\overlay\widgets\Bindings.cpp:172 src\overlay\widgets\Bindings.cpp:178 +msgid "Combo can be composed from up to 4 keys." +msgstr "按键组合可以最多由4个键组成。" + +#: src\overlay\widgets\Bindings.cpp:173 src\overlay\widgets\Bindings.cpp:176 +msgid "Please, bind some key combination for toggling overlay!" +msgstr "请绑定快捷键以切换CET界面!" + +#: src\overlay\widgets\Bindings.cpp:362 src\overlay\widgets\Bindings.cpp:399 +msgid "Currently unable to draw this tooltip. Wait for a bit please..." +msgstr "目前无法渲染这个工具提示,请稍等..." + +#: src\overlay\widgets\Bindings.cpp:428 +msgid "Uncheck this checkbox to unbind this binding." +msgstr "取消勾选此复选框以解除此绑定。" + +#: src\overlay\widgets\Bindings.cpp:474 src\overlay\widgets\Bindings.cpp:475 +msgid "Hotkeys" +msgstr "快捷键" + +#: src\overlay\widgets\Bindings.cpp:477 +msgid "Hotkeys react after assigned key combination has been pressed and subsequently released. You can bind up to 4 key combination to them." +msgstr "快捷键只能短按。你可以最多设置4个按键的组合。" + +#: src\overlay\widgets\Bindings.cpp:498 src\overlay\widgets\Bindings.cpp:499 +msgid "Inputs" +msgstr "输入键" + +#: src\overlay\widgets\Bindings.cpp:501 +msgid "Inputs react when key is pressed and released. You can bind single key to them." +msgstr "输入键可以长按。你可以绑定单个按键。" + +#: src\overlay\widgets\Console.cpp:113 +msgid "Command failed to execute!" +msgstr "命令执行失败!" + +#: src\overlay\widgets\LogWindow.cpp:20 +msgid "Clear output" +msgstr "清空输出" + +#: src\overlay\widgets\LogWindow.cpp:28 +msgid "Auto-scroll" +msgstr "自动滚屏" + +#: src\overlay\widgets\Settings.cpp:56 +msgid "Patches" +msgstr "补丁" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "AMD SMT Patch" +msgstr "AMD SMT补丁" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)." +msgstr "用于打了CDPR的官方补丁之后没有得到性能提升的AMD CPU(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Remove Pedestrians" +msgstr "移除行人" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Removes most of the pedestrians and traffic (requires restart to take effect)." +msgstr "移除大部分的行人和交通(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:69 +msgid "Disable Async Compute" +msgstr "禁用异步计算" + +#: src\overlay\widgets\Settings.cpp:70 +msgid "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)." +msgstr "禁用异步计算,这可能对旧的GPU带来提升,例如Nvidia GTX10XX系列(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Disable Anti-aliasing" +msgstr "禁用抗锯齿" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Completely disables anti-aliasing (requires restart to take effect)." +msgstr "完全禁用抗锯齿(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skip Start Menu" +msgstr "跳过启动菜单" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)." +msgstr "跳过需要你按空格键继续的”正在入侵“菜单,需要你按空格键继续的(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Suppress Intro Movies" +msgstr "禁止启动视频" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Disables logos played at the beginning (requires restart to take effect)." +msgstr "禁用开始时播放的徽标视频(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disable Vignette" +msgstr "禁用暗角效果" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disables vignetting along screen borders (requires restart to take effect)." +msgstr "禁用屏幕边缘的暗角效果(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Disable Boundary Teleport" +msgstr "禁用边界传送" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Allows players to access out-of-bounds locations (requires restart to take effect)." +msgstr "允许玩家进入超出边界的位置(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disable V-Sync (Windows 7 only)" +msgstr "禁用垂直同步(仅限Windows 7)" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)." +msgstr "在Windows 7上禁用垂直同步,以绕过60FPS的限制(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix Minimap Flicker" +msgstr "修复小地图闪烁" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix minimap flickering (requires restart to take effect)." +msgstr "修复小地图的闪烁问题(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:97 +msgid "CET Language Settings" +msgstr "CET语言设置" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Language" +msgstr "语言" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Display language for CET." +msgstr "CET的界面语言" + +#: src\overlay\widgets\Settings.cpp:108 +msgid "CET Font Settings" +msgstr "CET字体设置" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main Font" +msgstr "主字体" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main display font for CET." +msgstr "CET的主字体" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaced Font" +msgstr "等宽字体" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET." +msgstr "CET的等宽字体,用于显示控制台于游戏日志中的文本。" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Font Size" +msgstr "字体大小" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Changes the size of the font, default value is 18px." +msgstr "改变字体的大小,默认值为18px。" + +#: src\overlay\widgets\Settings.cpp:125 +msgid "Advance Settings" +msgstr "高级设置" + +#: src\overlay\widgets\Settings.cpp:132 +msgid "Oversample Horizontal" +msgstr "水平过采样" + +#: src\overlay\widgets\Settings.cpp:133 +msgid "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "对字体进行水平过采样,默认值为3倍。(可能会增加字体的清晰度,但代价是增加内存占用。)" + +#: src\overlay\widgets\Settings.cpp:136 +msgid "Oversample Vertical" +msgstr "垂直过采样" + +#: src\overlay\widgets\Settings.cpp:137 +msgid "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "对字体进行垂直过采样,默认值为1倍。(可能会增加字体的清晰度,但代价是增加内存占用。)" + +#: src\overlay\widgets\Settings.cpp:146 +msgid "CET Development Settings" +msgstr "CET开发设置" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Remove Dead Bindings" +msgstr "移除失效快捷键" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)." +msgstr "删除所有不再有效的按键绑定(在调试Mod问题时禁用这个功能可能会比较好)。" + +#: src\overlay\widgets\Settings.cpp:156 +msgid "Enable ImGui Assertions" +msgstr "启用ImGui断言" + +#: src\overlay\widgets\Settings.cpp:157 +msgid "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be used to check mods before shipping!)." +msgstr "启用所有的ImGui断言,断言将被记录在断言触发着的的日志文件中(在调试ImGui问题时很有用,也应该用来在Mod发布前的检查!)。" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Enable Debug Build" +msgstr "启用调试构建" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Sets internal flags to disguise as debug build (requires restart to take effect)." +msgstr "设置内部标记以伪装成调试构建(需要重启才能生效)。" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dump Game Options" +msgstr "导出游戏选项" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dumps all game options into main log file (requires restart to take effect)." +msgstr "将所有游戏选项导出到主日志文件中(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Enable Translation Log" +msgstr "启用翻译日志" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Show logs when there's a missing translation (requires restart to take effect)." +msgstr "在翻译有缺失的时候显示日志(需要重新启动才能生效)。" + +#: src\overlay\widgets\Settings.cpp:181 +msgid "Load" +msgstr "载入" + +#: src\overlay\widgets\Settings.cpp:187 +msgid "Defaults" +msgstr "恢复默认" + +#: src\overlay\widgets\Settings.cpp:334 src\overlay\widgets\Settings.cpp:342 +msgctxt "Settings" +msgid "Default" +msgstr "默认" + +#: src\overlay\widgets\Settings.cpp:369 src\overlay\widgets\Settings.cpp:378 +msgctxt "Settings" +msgid "System" +msgstr "系统" + +#: src\overlay\widgets\TweakDBEditor.cpp:134 +msgid "TweakDB is not initialized yet" +msgstr "TweakDB尚未初始化" + +#: src\overlay\widgets\TweakDBEditor.cpp:146 +msgid "Records" +msgstr "记录" + +#: src\overlay\widgets\TweakDBEditor.cpp:154 +msgid "Queries" +msgstr "查询" + +#: src\overlay\widgets\TweakDBEditor.cpp:162 +msgid "Flats" +msgstr "平面" + +#: src\overlay\widgets\TweakDBEditor.cpp:170 +msgid "Advanced" +msgstr "高级" + +#: src\overlay\widgets\TweakDBEditor.cpp:442 +#: src\overlay\widgets\TweakDBEditor.cpp:1099 +#: src\overlay\widgets\TweakDBEditor.cpp:1355 +#: src\overlay\widgets\TweakDBEditor.cpp:1481 +#: src\overlay\widgets\TweakDBEditor.cpp:1607 +msgid "Search" +msgstr "搜索" + +#: src\overlay\widgets\TweakDBEditor.cpp:544 +#, c-format +msgid "'%s' is not found in TweakDB" +msgstr "未在TweakDB中找到”%s“" + +#: src\overlay\widgets\TweakDBEditor.cpp:604 +#, c-format +msgid "unsupported type: %s" +msgstr "不支持的类型:%s" + +#: src\overlay\widgets\TweakDBEditor.cpp:637 +#, c-format +msgid "[%s] %u item" +msgid_plural "[%s] %u items" +msgstr[0] "[%s] %u个项目" + +#: src\overlay\widgets\TweakDBEditor.cpp:639 +msgid "clear" +msgstr "清除" + +#: src\overlay\widgets\TweakDBEditor.cpp:650 +msgid "edit" +msgstr "编辑" + +#: src\overlay\widgets\TweakDBEditor.cpp:662 +msgid "cancel" +msgstr "取消" + +#: src\overlay\widgets\TweakDBEditor.cpp:675 +msgid "save" +msgstr "保存" + +#: src\overlay\widgets\TweakDBEditor.cpp:739 +msgid "add new" +msgstr "新增" + +#: src\overlay\widgets\TweakDBEditor.cpp:785 +msgid "ERROR_RECORD_NOT_FOUND" +msgstr "错误,未找到记录" + +#: src\overlay\widgets\TweakDBEditor.cpp:879 +msgid "Roll " +msgstr "滚转角 " + +#: src\overlay\widgets\TweakDBEditor.cpp:884 +msgid "Pitch" +msgstr "俯仰角" + +#: src\overlay\widgets\TweakDBEditor.cpp:889 +msgid "Yaw " +msgstr "偏航角 " + +#: src\overlay\widgets\TweakDBEditor.cpp:1008 +msgid "'Color' is not supported yet" +msgstr "还不支持”Color“" + +#: src\overlay\widgets\TweakDBEditor.cpp:1044 +msgid "This is a LocalizationKey" +msgstr "这是一个LocalizationKey" + +#: src\overlay\widgets\TweakDBEditor.cpp:1202 +msgid "Game is expecting specific values." +msgstr "游戏期待特定值。" + +#: src\overlay\widgets\TweakDBEditor.cpp:1354 +#: src\overlay\widgets\TweakDBEditor.cpp:1360 +#: src\overlay\widgets\TweakDBEditor.cpp:1480 +#: src\overlay\widgets\TweakDBEditor.cpp:1486 +msgid "Regex" +msgstr "正则" + +#: src\overlay\widgets\TweakDBEditor.cpp:1425 +#: src\overlay\widgets\TweakDBEditor.cpp:1543 +msgid "ERROR_FLAT_NOT_FOUND" +msgstr "错误,未找到平面" + +#: src\overlay\widgets\TweakDBEditor.cpp:1565 +msgid "'Flats' Grouping depth" +msgstr "”平面“分组深度" + +#: src\overlay\widgets\TweakDBEditor.cpp:1571 +msgid "ComboBox dropdown height" +msgstr "组合框下拉高度" + +#: src\overlay\widgets\TweakDBEditor.cpp:1573 +msgid "Refresh all" +msgstr "刷新全部" + +#: src\overlay\widgets\TweakDBEditor.cpp:1594 +msgid "Record name" +msgstr "记录名称" + +#: src\overlay\widgets\TweakDBEditor.cpp:1596 +msgid "Delete Record" +msgstr "删除记录" + +#: src\overlay\widgets\TweakDBEditor.cpp:1604 +msgid "Record type to create" +msgstr "要创建的记录类型" + +#: src\overlay\widgets\TweakDBEditor.cpp:1634 +msgid "Create record" +msgstr "创建记录" + +#: src\overlay\widgets\TweakDBEditor.cpp:1642 +msgid "Record to clone" +msgstr "要复制的记录" + +#: src\overlay\widgets\TweakDBEditor.cpp:1644 +msgid "Clone record" +msgstr "复制记录" + diff --git a/languages/zh_TW.po b/languages/zh_TW.po new file mode 100644 index 00000000..42787452 --- /dev/null +++ b/languages/zh_TW.po @@ -0,0 +1,454 @@ +msgid "" +msgstr "" +"Project-Id-Version: cyber-engine-tweaks\n" +"Report-Msgid-Bugs-To: https://github.com/maximegmd/CyberEngineTweaks/issues\n" +"POT-Creation-Date: 2023-05-31 17:59+0800\n" +"PO-Revision-Date: 2023-05-31 11:04\n" +"Last-Translator: \n" +"Language-Team: Chinese Traditional\n" +"Language: zh_TW\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Crowdin-Project: cyber-engine-tweaks\n" +"X-Crowdin-Project-ID: 591959\n" +"X-Crowdin-Language: zh-TW\n" +"X-Crowdin-File: /i18n/languages/template.pot\n" +"X-Crowdin-File-ID: 9\n" + +#. Translators: Type in your language name in it's own language. (e.g. French -> Français) +#: src\I18n.cpp:61 +msgid "Localized Language Name" +msgstr "中文(繁體)" + +#: src\overlay\Overlay.cpp:300 +msgid "Console" +msgstr "控制台" + +#: src\overlay\Overlay.cpp:309 +msgid "Bindings" +msgstr "綁定鍵" + +#: src\overlay\Overlay.cpp:318 +msgid "Settings" +msgstr "設定" + +#: src\overlay\Overlay.cpp:327 +msgid "TweakDB Editor" +msgstr "TweakDB 編輯器" + +#: src\overlay\Overlay.cpp:336 +msgid "Game Log" +msgstr "遊戲日誌" + +#: src\overlay\Overlay.cpp:345 +msgid "ImGui Debug" +msgstr "ImGui 偵錯" + +#: src\overlay\Overlay.cpp:353 +msgid "Reload all mods" +msgstr "重新載入所有模組" + +#: src\overlay\widgets\Bindings.cpp:93 src\overlay\widgets\Settings.cpp:184 +msgid "Save" +msgstr "儲存" + +#: src\overlay\widgets\Bindings.cpp:96 +msgid "Reset changes" +msgstr "還原變更" + +#: src\overlay\widgets\Bindings.cpp:168 src\overlay\widgets\Bindings.cpp:170 +msgid "CET First Time Setup" +msgstr "CET 首次使用設定" + +#: src\overlay\widgets\Bindings.cpp:172 src\overlay\widgets\Bindings.cpp:178 +msgid "Combo can be composed from up to 4 keys." +msgstr "可以由多達4個鍵組成。" + +#: src\overlay\widgets\Bindings.cpp:173 src\overlay\widgets\Bindings.cpp:176 +msgid "Please, bind some key combination for toggling overlay!" +msgstr "請綁定一個按鍵來切換CET界面!" + +#: src\overlay\widgets\Bindings.cpp:362 src\overlay\widgets\Bindings.cpp:399 +msgid "Currently unable to draw this tooltip. Wait for a bit please..." +msgstr "目前無法繪製此工具提示,請稍等一會兒..." + +#: src\overlay\widgets\Bindings.cpp:428 +msgid "Uncheck this checkbox to unbind this binding." +msgstr "取消勾選此核取方塊以解除此綁定。" + +#: src\overlay\widgets\Bindings.cpp:474 src\overlay\widgets\Bindings.cpp:475 +msgid "Hotkeys" +msgstr "快捷鍵" + +#: src\overlay\widgets\Bindings.cpp:477 +msgid "Hotkeys react after assigned key combination has been pressed and subsequently released. You can bind up to 4 key combination to them." +msgstr "快捷鍵只能短按。您最多可以將4個按鍵的組合綁定到它們上。" + +#: src\overlay\widgets\Bindings.cpp:498 src\overlay\widgets\Bindings.cpp:499 +msgid "Inputs" +msgstr "輸入鍵" + +#: src\overlay\widgets\Bindings.cpp:501 +msgid "Inputs react when key is pressed and released. You can bind single key to them." +msgstr "輸入鍵可以進行長按。您可以將單個按鍵綁定到它們上。" + +#: src\overlay\widgets\Console.cpp:113 +msgid "Command failed to execute!" +msgstr "命令執行失敗!" + +#: src\overlay\widgets\LogWindow.cpp:20 +msgid "Clear output" +msgstr "清除輸出" + +#: src\overlay\widgets\LogWindow.cpp:28 +msgid "Auto-scroll" +msgstr "自動捲動" + +#: src\overlay\widgets\Settings.cpp:56 +msgid "Patches" +msgstr "修補" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "AMD SMT Patch" +msgstr "AMD SMT 修補" + +#: src\overlay\widgets\Settings.cpp:63 +msgid "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)." +msgstr "用於在CDPR釋放修補程式後,仍沒有獲得性能提升的AMD CPU(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Remove Pedestrians" +msgstr "移除行人" + +#: src\overlay\widgets\Settings.cpp:66 +msgid "Removes most of the pedestrians and traffic (requires restart to take effect)." +msgstr "移除大部分行人和交通(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:69 +msgid "Disable Async Compute" +msgstr "停用非同步運算" + +#: src\overlay\widgets\Settings.cpp:70 +msgid "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)." +msgstr "停用非同步運算,這可以為舊版的GPU,例如Nvidia 10XX系列,帶來加速(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Disable Anti-aliasing" +msgstr "停用抗鋸齒" + +#: src\overlay\widgets\Settings.cpp:73 +msgid "Completely disables anti-aliasing (requires restart to take effect)." +msgstr "完全停用反鋸齒(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skip Start Menu" +msgstr "跳過開始界面" + +#: src\overlay\widgets\Settings.cpp:76 +msgid "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)." +msgstr "跳過要求您按下空白鍵繼續的“正在入侵...”選單(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Suppress Intro Movies" +msgstr "停用片頭動畫" + +#: src\overlay\widgets\Settings.cpp:79 +msgid "Disables logos played at the beginning (requires restart to take effect)." +msgstr "停用開頭播放的標誌動畫(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disable Vignette" +msgstr "停用漸暗效果" + +#: src\overlay\widgets\Settings.cpp:82 +msgid "Disables vignetting along screen borders (requires restart to take effect)." +msgstr "停用螢幕邊緣的漸暗效果(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Disable Boundary Teleport" +msgstr "停用邊界傳送" + +#: src\overlay\widgets\Settings.cpp:85 +msgid "Allows players to access out-of-bounds locations (requires restart to take effect)." +msgstr "允許玩家進入超出地圖範圍的位置(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disable V-Sync (Windows 7 only)" +msgstr "停用垂直同步(僅限 Windows 7)" + +#: src\overlay\widgets\Settings.cpp:88 +msgid "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)." +msgstr "在 Windows 7 上停用垂直同步以繞過 60 FPS 限制(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix Minimap Flicker" +msgstr "修復小地圖閃爍" + +#: src\overlay\widgets\Settings.cpp:90 +msgid "Fix minimap flickering (requires restart to take effect)." +msgstr "修正小地圖閃爍(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:97 +msgid "CET Language Settings" +msgstr "CET 語言設定" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Language" +msgstr "語言" + +#: src\overlay\widgets\Settings.cpp:103 +msgid "Display language for CET." +msgstr "CET 的顯示語言。" + +#: src\overlay\widgets\Settings.cpp:108 +msgid "CET Font Settings" +msgstr "CET 字型設定" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main Font" +msgstr "主要字型" + +#: src\overlay\widgets\Settings.cpp:115 +msgid "Main display font for CET." +msgstr "CET的主要顯示字型。" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaced Font" +msgstr "等寬字型" + +#: src\overlay\widgets\Settings.cpp:117 +msgid "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET." +msgstr "CET的等寬字體,用於在控制台和遊戲日誌中顯示文本。" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Font Size" +msgstr "字型大小" + +#: src\overlay\widgets\Settings.cpp:120 +msgid "Changes the size of the font, default value is 18px." +msgstr "更改字型大小,預設值為18px。" + +#: src\overlay\widgets\Settings.cpp:125 +msgid "Advance Settings" +msgstr "進階設定" + +#: src\overlay\widgets\Settings.cpp:132 +msgid "Oversample Horizontal" +msgstr "水平過度采樣" + +#: src\overlay\widgets\Settings.cpp:133 +msgid "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "對字型進行水平過采樣,預設值為3x。(可以提高字型清晰度,但會增加記憶體使用量。)" + +#: src\overlay\widgets\Settings.cpp:136 +msgid "Oversample Vertical" +msgstr "垂直過度採樣" + +#: src\overlay\widgets\Settings.cpp:137 +msgid "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)" +msgstr "對字型進行垂直過采樣,預設值為1x。(可以提高字型清晰度,但會增加記憶體使用量。)" + +#: src\overlay\widgets\Settings.cpp:146 +msgid "CET Development Settings" +msgstr "CET 開發人員設定" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Remove Dead Bindings" +msgstr "移除失效綁定鍵" + +#: src\overlay\widgets\Settings.cpp:153 +msgid "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)." +msgstr "移除所有不再有效的綁定(當調試Mod問題時禁用此功能可能會很有用)。" + +#: src\overlay\widgets\Settings.cpp:156 +msgid "Enable ImGui Assertions" +msgstr "啟用 ImGui 斷言" + +#: src\overlay\widgets\Settings.cpp:157 +msgid "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be used to check mods before shipping!)." +msgstr "啟用ImGui斷言功能,斷言會記錄到觸發者的日誌檔案中(在調試ImGui問題時很有用,在發布Mod之前也應該使用它來檢查修改!)。" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Enable Debug Build" +msgstr "啟用偵錯構建" + +#: src\overlay\widgets\Settings.cpp:162 +msgid "Sets internal flags to disguise as debug build (requires restart to take effect)." +msgstr "設定內部旗標以偽裝為偵錯構建(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dump Game Options" +msgstr "導出游戲選項" + +#: src\overlay\widgets\Settings.cpp:165 +msgid "Dumps all game options into main log file (requires restart to take effect)." +msgstr "將所有遊戲選項轉存到主日誌檔案(需要重新啟動才能生效)。" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Enable Translation Log" +msgstr "啟用翻譯日誌" + +#: src\overlay\widgets\Settings.cpp:168 +msgid "Show logs when there's a missing translation (requires restart to take effect)." +msgstr "假如有缺少的翻譯時,顯示日誌(需要重新啟動以生效)。" + +#: src\overlay\widgets\Settings.cpp:181 +msgid "Load" +msgstr "載入" + +#: src\overlay\widgets\Settings.cpp:187 +msgid "Defaults" +msgstr "默認值" + +#: src\overlay\widgets\Settings.cpp:334 src\overlay\widgets\Settings.cpp:342 +msgctxt "Settings" +msgid "Default" +msgstr "預設" + +#: src\overlay\widgets\Settings.cpp:369 src\overlay\widgets\Settings.cpp:378 +msgctxt "Settings" +msgid "System" +msgstr "系统" + +#: src\overlay\widgets\TweakDBEditor.cpp:134 +msgid "TweakDB is not initialized yet" +msgstr "TweakDB 尚未初始化" + +#: src\overlay\widgets\TweakDBEditor.cpp:146 +msgid "Records" +msgstr "記錄" + +#: src\overlay\widgets\TweakDBEditor.cpp:154 +msgid "Queries" +msgstr "查詢" + +#: src\overlay\widgets\TweakDBEditor.cpp:162 +msgid "Flats" +msgstr "平面" + +#: src\overlay\widgets\TweakDBEditor.cpp:170 +msgid "Advanced" +msgstr "進階設定" + +#: src\overlay\widgets\TweakDBEditor.cpp:442 +#: src\overlay\widgets\TweakDBEditor.cpp:1099 +#: src\overlay\widgets\TweakDBEditor.cpp:1355 +#: src\overlay\widgets\TweakDBEditor.cpp:1481 +#: src\overlay\widgets\TweakDBEditor.cpp:1607 +msgid "Search" +msgstr "搜索" + +#: src\overlay\widgets\TweakDBEditor.cpp:544 +#, c-format +msgid "'%s' is not found in TweakDB" +msgstr "未在TweakDB中找到”%s“" + +#: src\overlay\widgets\TweakDBEditor.cpp:604 +#, c-format +msgid "unsupported type: %s" +msgstr "不支援的類型: %s" + +#: src\overlay\widgets\TweakDBEditor.cpp:637 +#, c-format +msgid "[%s] %u item" +msgid_plural "[%s] %u items" +msgstr[0] "[%s] %u 項" + +#: src\overlay\widgets\TweakDBEditor.cpp:639 +msgid "clear" +msgstr "清除" + +#: src\overlay\widgets\TweakDBEditor.cpp:650 +msgid "edit" +msgstr "編輯" + +#: src\overlay\widgets\TweakDBEditor.cpp:662 +msgid "cancel" +msgstr "取消" + +#: src\overlay\widgets\TweakDBEditor.cpp:675 +msgid "save" +msgstr "儲存" + +#: src\overlay\widgets\TweakDBEditor.cpp:739 +msgid "add new" +msgstr "新增" + +#: src\overlay\widgets\TweakDBEditor.cpp:785 +msgid "ERROR_RECORD_NOT_FOUND" +msgstr "錯誤,未找到記錄" + +#: src\overlay\widgets\TweakDBEditor.cpp:879 +msgid "Roll " +msgstr "滚转角 " + +#: src\overlay\widgets\TweakDBEditor.cpp:884 +msgid "Pitch" +msgstr "俯仰角" + +#: src\overlay\widgets\TweakDBEditor.cpp:889 +msgid "Yaw " +msgstr "偏航角 " + +#: src\overlay\widgets\TweakDBEditor.cpp:1008 +msgid "'Color' is not supported yet" +msgstr "尚未支援”Color“" + +#: src\overlay\widgets\TweakDBEditor.cpp:1044 +msgid "This is a LocalizationKey" +msgstr "這是一個LocalizationKey" + +#: src\overlay\widgets\TweakDBEditor.cpp:1202 +msgid "Game is expecting specific values." +msgstr "遊戲期待特定的值。" + +#: src\overlay\widgets\TweakDBEditor.cpp:1354 +#: src\overlay\widgets\TweakDBEditor.cpp:1360 +#: src\overlay\widgets\TweakDBEditor.cpp:1480 +#: src\overlay\widgets\TweakDBEditor.cpp:1486 +msgid "Regex" +msgstr "正則表達式" + +#: src\overlay\widgets\TweakDBEditor.cpp:1425 +#: src\overlay\widgets\TweakDBEditor.cpp:1543 +msgid "ERROR_FLAT_NOT_FOUND" +msgstr "錯誤,未找到平面" + +#: src\overlay\widgets\TweakDBEditor.cpp:1565 +msgid "'Flats' Grouping depth" +msgstr "”平面“分組深度" + +#: src\overlay\widgets\TweakDBEditor.cpp:1571 +msgid "ComboBox dropdown height" +msgstr "下拉式選單高度" + +#: src\overlay\widgets\TweakDBEditor.cpp:1573 +msgid "Refresh all" +msgstr "刷新所有" + +#: src\overlay\widgets\TweakDBEditor.cpp:1594 +msgid "Record name" +msgstr "記錄名稱" + +#: src\overlay\widgets\TweakDBEditor.cpp:1596 +msgid "Delete Record" +msgstr "刪除紀錄" + +#: src\overlay\widgets\TweakDBEditor.cpp:1604 +msgid "Record type to create" +msgstr "要創建的記錄類型" + +#: src\overlay\widgets\TweakDBEditor.cpp:1634 +msgid "Create record" +msgstr "新增紀錄" + +#: src\overlay\widgets\TweakDBEditor.cpp:1642 +msgid "Record to clone" +msgstr "需克隆的紀錄" + +#: src\overlay\widgets\TweakDBEditor.cpp:1644 +msgid "Clone record" +msgstr "克隆紀錄" + diff --git a/src/CET.cpp b/src/CET.cpp index 6021a138..5f2175bf 100644 --- a/src/CET.cpp +++ b/src/CET.cpp @@ -2,6 +2,7 @@ #include "CET.h" #include "Options.h" +#include "I18n.h" using namespace std::chrono_literals; @@ -65,6 +66,11 @@ Fonts& CET::GetFonts() noexcept return m_fonts; } +I18n& CET::GetI18n() noexcept +{ + return m_i18n; +} + bool CET::IsRunning() noexcept { return s_isRunning; @@ -77,7 +83,8 @@ CET::CET() , m_window(&m_bindings, &m_d3d12) , m_fonts(m_options, m_paths) , m_d3d12(m_window, m_paths, m_options, m_fonts) - , m_vm(m_paths, m_bindings, m_d3d12, m_fonts) + , m_vm(m_paths, m_bindings, m_d3d12, m_fonts, m_i18n) + , m_i18n(m_options, m_paths, m_fonts) , m_overlay(m_bindings, m_options, m_persistentState, m_vm) { m_vm.Initialize(); diff --git a/src/CET.h b/src/CET.h index fa6731a5..f77621c9 100644 --- a/src/CET.h +++ b/src/CET.h @@ -10,6 +10,9 @@ #include "common/CETTasks.h" #include "Fonts.h" +#define _noop(String) String // Marker for translatable strings +#define _t(...) CET::Get().GetI18n().Translate(__VA_ARGS__).c_str() // Translate + struct CET { ~CET(); @@ -26,6 +29,7 @@ struct CET Overlay& GetOverlay() noexcept; LuaVM& GetVM() noexcept; Fonts& GetFonts() noexcept; + I18n& GetI18n() noexcept; static bool IsRunning() noexcept; @@ -40,6 +44,7 @@ struct CET Fonts m_fonts; D3D12 m_d3d12; LuaVM m_vm; + I18n m_i18n; Overlay m_overlay; CETTasks m_tasks; }; diff --git a/src/Fonts.cpp b/src/Fonts.cpp index 8ef2fe04..82d93217 100644 --- a/src/Fonts.cpp +++ b/src/Fonts.cpp @@ -437,7 +437,7 @@ GlyphRangesBuilder& Fonts::GetGlyphRangesBuilder() return m_glyphRangesBuilder; } -void Fonts::PrecacheGlyphsFromMods() +void Fonts::PrecacheModFiles() { const auto modsRoot = m_paths.ModsRoot(); @@ -496,10 +496,35 @@ void Fonts::PrecacheGlyphsFromMods() Log::Info("Total mod files cached into glyph ranges builder: {}.", fileCount); } +void Fonts::PrecacheLanguageFiles() +{ + int fileCount = 0; + for (const auto& entry : std::filesystem::directory_iterator(m_paths.Languages())) + { + if (!entry.is_regular_file()) + continue; + + if (entry.path().extension() != ".po") + continue; + + bool result = m_glyphRangesBuilder.AddFile(entry.path()); + + if (!result) + { + Log::Error("Can't read file {}.", UTF16ToUTF8(entry.path().native())); + continue; + } + + fileCount++; + } + Log::Info("Total language files cached into glyph ranges builder: {}.", fileCount); +} + Fonts::Fonts(Options& aOptions, Paths& aPaths) : m_options(aOptions) , m_paths(aPaths) { EnumerateSystemFonts(); - PrecacheGlyphsFromMods(); + PrecacheModFiles(); + PrecacheLanguageFiles(); } \ No newline at end of file diff --git a/src/Fonts.h b/src/Fonts.h index ce3a9cb3..00228be9 100644 --- a/src/Fonts.h +++ b/src/Fonts.h @@ -43,7 +43,8 @@ struct Fonts std::filesystem::path GetFontPathFromOption(const std::string& acFontOption) const; GlyphRangesBuilder& GetGlyphRangesBuilder(); - void PrecacheGlyphsFromMods(); + void PrecacheModFiles(); + void PrecacheLanguageFiles(); ImFont* MainFont; ImFont* MonoFont; @@ -63,7 +64,7 @@ struct Fonts std::filesystem::path m_defaultMainFont{L"NotoSans-Regular.ttf"}; std::vector m_defaultCJKFonts{ - L"NotoSansJP-Regular.otf", L"NotoSansKR-Regular.otf", L"NotoSansSC-Regular.otf", L"NotoSansTC-Regular.otf", L"NotoSansThai-Regular.ttf"}; + L"NotoSansSC-Regular.otf", L"NotoSansJP-Regular.otf", L"NotoSansTC-Regular.otf", L"NotoSansKR-Regular.otf", L"NotoSansThai-Regular.ttf"}; std::filesystem::path m_defaultMonoFont{L"NotoSansMono-Regular.ttf"}; std::filesystem::path m_defaultIconFont{L"materialdesignicons.ttf"}; std::filesystem::path m_defaultEmojiFont{L"C:\\Windows\\Fonts\\seguiemj.ttf"}; // tried to use noto color emoji but it wont render. only this one works diff --git a/src/I18n.cpp b/src/I18n.cpp new file mode 100644 index 00000000..5082c8b7 --- /dev/null +++ b/src/I18n.cpp @@ -0,0 +1,223 @@ +#include + +#include "I18n.h" + +#include + +Language::Language(const tinygettext::Language& aLanguage, const std::string& acLocalizedName) + : m_locale(aLanguage.str()) + , m_name(aLanguage.get_name()) + , m_localizedName(acLocalizedName) +{ + FormatName(); +} +Language::Language(const std::string& acLocale, const std::string& acName, const std::string& acLocalizedName) + : m_locale(acLocale) + , m_name(acName) + , m_localizedName(acLocalizedName) +{ + FormatName(); +} +std::string Language::GetLocale() const +{ + return m_locale; +} +std::string Language::GetName() const +{ + return m_name; +} +std::string Language::GetLocalizedName() const +{ + return m_localizedName; +} +std::string Language::GetFormatedName() const +{ + return m_formatedName; +} + +void Language::FormatName() +{ + if (m_name.empty()) + m_name = m_locale; + if (m_localizedName.empty()) + m_localizedName = m_name; + if (m_localizedName == m_name) + m_formatedName = m_name; + else + m_formatedName = std::format("{}\n{}", m_name, m_localizedName); +} + +// Load all po files +void I18n::LoadLanguageFiles() +{ + m_languages.clear(); + m_languages.emplace_back(Language("System")); + m_dictManager.add_directory(UTF16ToUTF8(m_paths.Languages().native())); + auto languages = m_dictManager.get_languages(); + for (const auto& language : languages) + { + m_dictManager.set_language(language); + // Translators: Type in your language name in it's own language. (e.g. French -> Français) + auto localizedName = m_dictManager.get_dictionary().translate("Localized Language Name"); + if (localizedName.empty() || localizedName == "Localized Language Name") + localizedName = language.get_localized_name(); + m_languages.emplace_back(Language(language, localizedName)); + } +} + +// Get the list of language loaded. +std::vector I18n::GetLanguages() const +{ + return m_languages; +} + +// Get language from given locale +Language I18n::GetLanguage(const std::string& acLocale) const +{ + auto languageIterator = std::find_if(m_languages.begin(), m_languages.end(), [acLocale](const Language& language) { return language.GetLocale() == acLocale; }); + if (languageIterator == m_languages.end()) + return Language(""); + else + return *languageIterator; +} + +std::string I18n::GetSystemLocale() const +{ + return m_systemLocale; +} + +std::string I18n::GetCurrentLocale() const +{ + return m_options.Language.Locale; +} + +void I18n::Reload() +{ + m_fonts.PrecacheLanguageFiles(); + m_dictManager.remove_directory(UTF16ToUTF8(m_paths.Languages().native())); + LoadLanguageFiles(); + LoadLanguageSettings(); +} + +// Basic translate +std::string I18n::Translate(const std::string& aMsgid) const +{ + return m_dict->translate(aMsgid); +} + +// Translate with context id +std::string I18n::Translate(const std::string& aMsgctxt, const std::string aMsgid) const +{ + return m_dict->translate_ctxt(aMsgctxt, aMsgid); +} + +// Translate with plural forms +std::string I18n::Translate(const std::string& aMsgid, const std::string& aMsgidPlural, int aNum) const +{ + return m_dict->translate_plural(aMsgid, aMsgidPlural, aNum); +} + +// Translate with context id and plural forms +std::string I18n::Translate(const std::string& aMsgctxt, const std::string aMsgid, const std::string& aMsgidPlural, int aNum) const +{ + return m_dict->translate_ctxt_plural(aMsgctxt, aMsgid, aMsgidPlural, aNum); +} + +// Fetch system display locale +void I18n::FetchSystemLocale() +{ + LCID localeId = GetUserDefaultLCID(); // Get the user default locale identifier + WCHAR localeName[LOCALE_NAME_MAX_LENGTH]; + int result = GetLocaleInfoEx(LOCALE_NAME_USER_DEFAULT, LOCALE_SNAME, localeName, LOCALE_NAME_MAX_LENGTH); // Get the locale name using locale identifier + + if (result == 0) + { + Log::Error("Error when getting system display locale: {}", GetLastError()); + m_systemLocale = "en_US"; + } + auto localeUTF8 = UTF16ToUTF8(localeName); + std::replace(localeUTF8.begin(), localeUTF8.end(), '-', '_'); + m_systemLocale = localeUTF8; +} + +// Load setting from the config and set the language +void I18n::LoadLanguageSettings() +{ + const auto& locale = m_options.Language.Locale; + if (locale == "System") + SetLanguageBaseOnSystemLocale(); + else + SetLanguage(locale); +} + +// Set language base on given locale string +void I18n::SetLanguage(const std::string& acLocale) +{ + const auto& language = GetLanguage(acLocale); + if (language.GetLocale() == "") + { + SetLanguageBaseOnSystemLocale(); + m_options.Language.Locale = "System"; + m_options.Save(); + Log::Error("Translation for {} not found, using system locale instead.", acLocale, m_defaultLocale); + } + else + { + m_dictManager.set_language(tinygettext::Language::from_env(language.GetLocale())); + m_dict = &m_dictManager.get_dictionary(); + } +} + +// Set language closest to the system display locale +void I18n::SetLanguageBaseOnSystemLocale() +{ + auto systemLanguage = tinygettext::Language::from_env(m_systemLocale); + int highScore = 0; + auto closestMatch = tinygettext::Language::from_env(m_defaultLocale); + for (const auto& language : m_dictManager.get_languages()) + { + int score = tinygettext::Language::match(systemLanguage, language); + if (score > highScore) + { + closestMatch = language; + highScore = score; + } + } + Log::Info("Using system language setting. System Locale: {}, setting CET language to {}.", systemLanguage.str(), closestMatch.str()); + m_dictManager.set_language(closestMatch); + m_dict = &m_dictManager.get_dictionary(); +} + +// Info log callback function for tinygettext +void I18n::LogInfoCallback(const std::string& acString) +{ + Log::Info((!acString.empty() && acString.back() == '\n') ? acString.substr(0, acString.size() - 1) : acString); +} + +// Warning log callback function for tinygettext +void I18n::LogWarnCallback(const std::string& acString) +{ + Log::Warn((!acString.empty() && acString.back() == '\n') ? acString.substr(0, acString.size() - 1) : acString); +} + +// Error log callback function for tinygettext +void I18n::LogErrorCallback(const std::string& acString) +{ + Log::Error((!acString.empty() && acString.back() == '\n') ? acString.substr(0, acString.size() - 1) : acString); +} + +I18n::I18n(Options& aOptions, Paths& aPaths, Fonts& aFonts) + : m_options(aOptions) + , m_paths(aPaths) + , m_fonts(aFonts) +{ + if (m_options.Developer.EnableI18nLog) + tinygettext::Log::set_log_info_callback(&LogInfoCallback); + else + tinygettext::Log::set_log_info_callback(NULL); + tinygettext::Log::set_log_warning_callback(&LogWarnCallback); + tinygettext::Log::set_log_error_callback(&LogErrorCallback); + FetchSystemLocale(); + LoadLanguageFiles(); + LoadLanguageSettings(); +} \ No newline at end of file diff --git a/src/I18n.h b/src/I18n.h new file mode 100644 index 00000000..f395fc24 --- /dev/null +++ b/src/I18n.h @@ -0,0 +1,59 @@ +#pragma once + +#include "Utils.h" + +struct Language +{ + Language(const tinygettext::Language& aLanguage, const std::string& acLocalizedName); + Language(const std::string& acLocale, const std::string& acName = "", const std::string& acLocalizedName = ""); + std::string GetLocale() const; + std::string GetName() const; + std::string GetLocalizedName() const; + std::string GetFormatedName() const; + +private: + void FormatName(); + std::string m_locale{}; + std::string m_name{}; + std::string m_formatedName{}; + std::string m_localizedName{}; +}; + +struct I18n +{ + ~I18n() = default; + + void LoadLanguageSettings(); + std::vector GetLanguages() const; + Language GetLanguage(const std::string& acLocale) const; + std::string GetSystemLocale() const; + std::string GetCurrentLocale() const; + void Reload(); + + std::string Translate(const std::string& aMsgid) const; + std::string Translate(const std::string& aMsgctxt, const std::string aMsgid) const; + std::string Translate(const std::string& aMsgid, const std::string& aMsgidPlural, int aNum) const; + std::string Translate(const std::string& aMsgctxt, const std::string aMsgid, const std::string& aMsgidPlural, int aNum) const; + +private: + friend struct CET; + I18n(Options& aOptions, Paths& aPaths, Fonts& aFonts); + void FetchSystemLocale(); + void LoadLanguageFiles(); + void SetLanguage(const std::string& aLocale); + void SetLanguageBaseOnSystemLocale(); + + static void LogInfoCallback(const std::string& acString); + static void LogWarnCallback(const std::string& acString); + static void LogErrorCallback(const std::string& acString); + + Options& m_options; + Paths& m_paths; + Fonts& m_fonts; + + const std::string m_defaultLocale{"en"}; + std::string m_systemLocale{}; + std::vector m_languages; + tinygettext::DictionaryManager m_dictManager; + tinygettext::Dictionary* m_dict; +}; \ No newline at end of file diff --git a/src/Options.cpp b/src/Options.cpp index eb9131e2..052fb5fe 100644 --- a/src/Options.cpp +++ b/src/Options.cpp @@ -38,6 +38,23 @@ void PatchesSettings::ResetToDefaults() *this = {}; } +void LanguageSettings::Load(const nlohmann::json& aConfig) +{ + Locale = aConfig.value("language", Locale); +} + +nlohmann::json LanguageSettings::Save() const +{ + return { + {"language", Locale} + }; +} + +void LanguageSettings::ResetToDefaults() +{ + *this = {}; +} + void FontSettings::Load(const nlohmann::json& aConfig) { MainFont = aConfig.value("main_font", MainFont); @@ -70,6 +87,7 @@ void DeveloperSettings::Load(const nlohmann::json& aConfig) DumpGameOptions = aConfig.value("dump_game_options", DumpGameOptions); MaxLinesConsoleHistory = aConfig.value("max_lines_console_history", MaxLinesConsoleHistory); PersistentConsole = aConfig.value("persistent_console", PersistentConsole); + EnableI18nLog = aConfig.value("enable_i18n_log", EnableI18nLog); // set global "Enable ImGui Assertions" g_ImGuiAssertionsEnabled = EnableImGuiAssertions; @@ -81,7 +99,8 @@ nlohmann::json DeveloperSettings::Save() const g_ImGuiAssertionsEnabled = EnableImGuiAssertions; return {{"remove_dead_bindings", RemoveDeadBindings}, {"enable_imgui_assertions", EnableImGuiAssertions}, {"enable_debug", EnableDebug}, - {"dump_game_options", DumpGameOptions}, {"max_lines_console_history", MaxLinesConsoleHistory}, {"persistent_console", PersistentConsole}}; + {"dump_game_options", DumpGameOptions}, {"max_lines_console_history", MaxLinesConsoleHistory}, {"persistent_console", PersistentConsole}, + {"enable_i18n_log", EnableI18nLog}}; } void DeveloperSettings::ResetToDefaults() @@ -109,6 +128,11 @@ void Options::Load() if (!patchesConfig.empty()) Patches.Load(patchesConfig); + // language config + const auto& languageConfig = config["language"]; + if (!languageConfig.empty()) + Language.Load(languageConfig); + // font config const auto& fontConfig = config["font"]; if (!fontConfig.empty()) @@ -122,7 +146,7 @@ void Options::Load() void Options::Save() const { - nlohmann::json config = {{"patches", Patches.Save()}, {"font", Font.Save()}, {"developer", Developer.Save()}}; + nlohmann::json config = {{"patches", Patches.Save()}, {"language", Language.Save()}, {"font", Font.Save()}, {"developer", Developer.Save()}}; const auto path = GetAbsolutePath(m_paths.Config(), "", true); std::ofstream o(path); @@ -132,6 +156,7 @@ void Options::Save() const void Options::ResetToDefaults() { Patches.ResetToDefaults(); + Language.ResetToDefaults(); Font.ResetToDefaults(); Developer.ResetToDefaults(); diff --git a/src/Options.h b/src/Options.h index 6f4433c3..1729fce2 100644 --- a/src/Options.h +++ b/src/Options.h @@ -24,6 +24,17 @@ struct PatchesSettings bool MinimapFlicker{false}; }; +struct LanguageSettings +{ + void Load(const nlohmann::json& aConfig); + nlohmann::json Save() const; + void ResetToDefaults(); + + [[nodiscard]] auto operator<=>(const LanguageSettings&) const = default; + + std::string Locale{"System"}; +}; + struct FontSettings { void Load(const nlohmann::json& aConfig); @@ -53,6 +64,7 @@ struct DeveloperSettings bool DumpGameOptions{false}; uint64_t MaxLinesConsoleHistory{1000}; bool PersistentConsole{true}; + bool EnableI18nLog{false}; }; struct Options @@ -68,6 +80,7 @@ struct Options bool ExeValid{false}; PatchesSettings Patches{}; + LanguageSettings Language{}; FontSettings Font{}; DeveloperSettings Developer{}; diff --git a/src/Paths.cpp b/src/Paths.cpp index 0e76ef9b..09eb9694 100644 --- a/src/Paths.cpp +++ b/src/Paths.cpp @@ -50,6 +50,11 @@ const std::filesystem::path& Paths::TweakDB() const return m_tweakdb; } +const std::filesystem::path& Paths::Languages() const +{ + return m_languages; +} + Paths::Paths() { TCHAR exePathBuf[MAX_PATH] = {0}; @@ -91,4 +96,7 @@ Paths::Paths() m_fonts = m_cetRoot / L"fonts"; m_tweakdb = m_cetRoot / L"tweakdb"; + + m_languages = m_cetRoot / L"languages"; + create_directories(m_languages); } diff --git a/src/Paths.h b/src/Paths.h index f4c9b384..9071b166 100644 --- a/src/Paths.h +++ b/src/Paths.h @@ -14,6 +14,7 @@ struct Paths const std::filesystem::path& R6CacheModdedRoot() const; const std::filesystem::path& Fonts() const; const std::filesystem::path& TweakDB() const; + const std::filesystem::path& Languages() const; private: friend struct CET; @@ -30,4 +31,5 @@ struct Paths std::filesystem::path m_r6CacheModdedRoot{}; std::filesystem::path m_fonts{}; std::filesystem::path m_tweakdb{}; + std::filesystem::path m_languages{}; }; \ No newline at end of file diff --git a/src/overlay/Overlay.cpp b/src/overlay/Overlay.cpp index cade5a29..99d5392e 100644 --- a/src/overlay/Overlay.cpp +++ b/src/overlay/Overlay.cpp @@ -283,6 +283,11 @@ Overlay::~Overlay() { } +bool Overlay::ToolbarButton(const std::string& acIcon, const std::string& acLabel, const ImVec2& acSize) +{ + return ImGui::Button((acIcon + " " + acLabel).c_str(), acSize); +} + void Overlay::DrawToolbar() { // add icons to glyph builder @@ -292,7 +297,7 @@ void Overlay::DrawToolbar() auto& persistentState = m_persistentState.Overlay; ImGui::PushStyleColor(ImGuiCol_Button, persistentState.ConsoleToggled ? ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive) : ImGui::GetStyleColorVec4(ImGuiCol_Button)); - if (ImGui::Button(ICON_MD_CONSOLE " Console", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_CONSOLE, _t("Console"), ImVec2(itemWidth, 0))) m_console.Toggle(); if (!m_toggled) persistentState.ConsoleToggled = m_console.IsEnabled(); @@ -301,7 +306,7 @@ void Overlay::DrawToolbar() ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, persistentState.BindingsToggled ? ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive) : ImGui::GetStyleColorVec4(ImGuiCol_Button)); - if (ImGui::Button(ICON_MD_KEYBOARD_SETTINGS " Bindings", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_KEYBOARD_SETTINGS, _t("Bindings"), ImVec2(itemWidth, 0))) m_bindings.Toggle(); if (!m_toggled) persistentState.BindingsToggled = m_bindings.IsEnabled(); @@ -310,7 +315,7 @@ void Overlay::DrawToolbar() ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, persistentState.SettingsToggled ? ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive) : ImGui::GetStyleColorVec4(ImGuiCol_Button)); - if (ImGui::Button(ICON_MD_COG " Settings", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_COG, _t("Settings"), ImVec2(itemWidth, 0))) m_settings.Toggle(); if (!m_toggled) persistentState.SettingsToggled = m_settings.IsEnabled(); @@ -319,7 +324,7 @@ void Overlay::DrawToolbar() ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, persistentState.TweakDBEditorToggled ? ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive) : ImGui::GetStyleColorVec4(ImGuiCol_Button)); - if (ImGui::Button(ICON_MD_DATABASE_EDIT " TweakDB Editor", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_DATABASE_EDIT, _t("TweakDB Editor"), ImVec2(itemWidth, 0))) m_tweakDBEditor.Toggle(); if (!m_toggled) persistentState.TweakDBEditorToggled = m_tweakDBEditor.IsEnabled(); @@ -328,7 +333,7 @@ void Overlay::DrawToolbar() ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, persistentState.GameLogToggled ? ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive) : ImGui::GetStyleColorVec4(ImGuiCol_Button)); - if (ImGui::Button(ICON_MD_FILE_DOCUMENT " Game Log", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_FILE_DOCUMENT, _t("Game Log"), ImVec2(itemWidth, 0))) m_gameLog.Toggle(); if (!m_toggled) persistentState.GameLogToggled = m_gameLog.IsEnabled(); @@ -337,7 +342,7 @@ void Overlay::DrawToolbar() ImGui::SameLine(); ImGui::PushStyleColor(ImGuiCol_Button, persistentState.ImGuiDebugToggled ? ImGui::GetStyleColorVec4(ImGuiCol_ButtonActive) : ImGui::GetStyleColorVec4(ImGuiCol_Button)); - if (ImGui::Button(ICON_MD_BUG " ImGui Debug", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_BUG, _t("ImGui Debug"), ImVec2(itemWidth, 0))) m_imguiDebug.Toggle(); if (!m_toggled) persistentState.ImGuiDebugToggled = m_imguiDebug.IsEnabled(); @@ -345,6 +350,6 @@ void Overlay::DrawToolbar() ImGui::SameLine(); - if (ImGui::Button(ICON_MD_RESTART " Reload all mods", ImVec2(itemWidth, 0))) + if (ToolbarButton(ICON_MD_RESTART, _t("Reload all mods"), ImVec2(itemWidth, 0))) m_vm.ReloadAllMods(); } diff --git a/src/overlay/Overlay.h b/src/overlay/Overlay.h index 30ae8455..12b265c5 100644 --- a/src/overlay/Overlay.h +++ b/src/overlay/Overlay.h @@ -33,6 +33,7 @@ struct Overlay static BOOL ClipToCenter(RED4ext::CGameEngine::UnkC0* apThis); private: + bool ToolbarButton(const std::string& acIcon, const std::string& acLabel, const ImVec2& acSize); void DrawToolbar(); Console m_console; diff --git a/src/overlay/widgets/Bindings.cpp b/src/overlay/widgets/Bindings.cpp index b34f165d..9b28d4af 100644 --- a/src/overlay/widgets/Bindings.cpp +++ b/src/overlay/widgets/Bindings.cpp @@ -24,7 +24,7 @@ bool VKBindInfo::operator==(const std::string& id) const } Bindings::Bindings(VKBindings& aBindings, LuaVM& aVm) - : Widget(ICON_MD_KEYBOARD_SETTINGS " Bindings") + : Widget(ICON_MD_KEYBOARD_SETTINGS, _noop("Bindings")) , m_bindings(aBindings) , m_vm(aVm) { @@ -90,10 +90,10 @@ void Bindings::OnUpdate() ImGui::Separator(); const auto itemWidth = GetAlignedItemWidth(2); - if (ImGui::Button("Save", ImVec2(itemWidth, 0))) + if (ImGui::Button(_t("Save"), ImVec2(itemWidth, 0))) Save(); ImGui::SameLine(); - if (ImGui::Button("Reset changes", ImVec2(itemWidth, 0))) + if (ImGui::Button(_t("Reset changes"), ImVec2(itemWidth, 0))) ResetChanges(); } @@ -165,17 +165,17 @@ bool Bindings::FirstTimeSetup() m_vm.BlockDraw(true); - ImGui::OpenPopup("CET First Time Setup"); + ImGui::OpenPopup(_t("CET First Time Setup")); - if (ImGui::BeginPopupModal("CET First Time Setup", nullptr, ImGuiWindowFlags_AlwaysAutoResize)) + if (ImGui::BeginPopupModal(_t("CET First Time Setup"), nullptr, ImGuiWindowFlags_AlwaysAutoResize)) { - const auto shorterTextSz{ImGui::CalcTextSize("Combo can be composed from up to 4 keys.").x}; - const auto longerTextSz{ImGui::CalcTextSize("Please, bind some key combination for toggling overlay!").x}; + const auto shorterTextSz{ImGui::CalcTextSize(_t("Combo can be composed from up to 4 keys.")).x}; + const auto longerTextSz{ImGui::CalcTextSize(_t("Please, bind some key combination for toggling overlay!")).x}; const auto diffTextSz{longerTextSz - shorterTextSz}; - ImGui::TextUnformatted("Please, bind some key combination for toggling overlay!"); + ImGui::TextUnformatted(_t("Please, bind some key combination for toggling overlay!")); ImGui::SetCursorPosX(diffTextSz / 2); - ImGui::TextUnformatted("Combo can be composed from up to 4 keys."); + ImGui::TextUnformatted(_t("Combo can be composed from up to 4 keys.")); ImGui::Separator(); auto& [cetBinds, cetHotkeys] = m_vkBindInfos.at(s_overlayToggleModBind.ModName); @@ -359,7 +359,7 @@ void Bindings::UpdateAndDrawBinding(const VKModBind& acModBind, VKBindInfo& aVKB ImGui::EndTooltip(); } else - ImGui::SetTooltip("Currently unable to draw this tooltip. Wait for a bit please..."); + ImGui::SetTooltip(_t("Currently unable to draw this tooltip. Wait for a bit please...")); } if (bind.HasSimpleDescription()) { @@ -396,7 +396,7 @@ void Bindings::UpdateAndDrawBinding(const VKModBind& acModBind, VKBindInfo& aVKB ImGui::EndTooltip(); } else - ImGui::SetTooltip("Currently unable to draw this tooltip. Wait for a bit please..."); + ImGui::SetTooltip(_t("Currently unable to draw this tooltip. Wait for a bit please...")); } if (bind.HasSimpleDescription()) { @@ -425,7 +425,7 @@ void Bindings::UpdateAndDrawBinding(const VKModBind& acModBind, VKBindInfo& aVKB ImGui::PopID(); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) - ImGui::SetTooltip("Uncheck this checkbox to unbind this binding."); + ImGui::SetTooltip(_t("Uncheck this checkbox to unbind this binding.")); } ImGui::PopStyleColor(); @@ -471,11 +471,11 @@ void Bindings::UpdateAndDrawModBindings(const std::string& acModName, TiltedPhoq { if (!aSimplified) { - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + GetCenteredOffsetForText("Hotkeys")); - ImGui::TextUnformatted("Hotkeys"); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + GetCenteredOffsetForText(_t("Hotkeys"))); + ImGui::TextUnformatted(_t("Hotkeys")); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) - ImGui::SetTooltip("Hotkeys react after assigned key combination has been pressed and subsequently " - "released. You can bind up to 4 key combination to them."); + ImGui::SetTooltip(_t("Hotkeys react after assigned key combination has been pressed and subsequently " + "released. You can bind up to 4 key combination to them.")); ImGui::Separator(); } @@ -495,10 +495,10 @@ void Bindings::UpdateAndDrawModBindings(const std::string& acModName, TiltedPhoq { if (!aSimplified) { - ImGui::SetCursorPosX(ImGui::GetCursorPosX() + GetCenteredOffsetForText("Inputs")); - ImGui::TextUnformatted("Inputs"); + ImGui::SetCursorPosX(ImGui::GetCursorPosX() + GetCenteredOffsetForText(_t("Inputs"))); + ImGui::TextUnformatted(_t("Inputs")); if (ImGui::IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) - ImGui::SetTooltip("Inputs react when key is pressed and released. You can bind single key to them."); + ImGui::SetTooltip(_t("Inputs react when key is pressed and released. You can bind single key to them.")); ImGui::Separator(); } diff --git a/src/overlay/widgets/Console.cpp b/src/overlay/widgets/Console.cpp index 6131fe80..bd41e60f 100644 --- a/src/overlay/widgets/Console.cpp +++ b/src/overlay/widgets/Console.cpp @@ -7,7 +7,7 @@ #include Console::Console(Options& aOptions, PersistentState& aPersistentState, LuaVM& aVm) - : Widget(ICON_MD_CONSOLE " Console") + : Widget(ICON_MD_CONSOLE, _noop("Console")) , m_options(aOptions) , m_persistentState(aPersistentState) , m_vm(aVm) @@ -110,7 +110,7 @@ void Console::OnUpdate() if (!m_command.empty()) { if (!m_vm.ExecuteLua(m_command)) - consoleLogger->info("Command failed to execute!"); + consoleLogger->info(_t("Command failed to execute!")); m_command.shrink_to_fit(); diff --git a/src/overlay/widgets/GameLog.cpp b/src/overlay/widgets/GameLog.cpp index 64961059..9f02da29 100644 --- a/src/overlay/widgets/GameLog.cpp +++ b/src/overlay/widgets/GameLog.cpp @@ -2,8 +2,10 @@ #include "GameLog.h" +#include + GameLog::GameLog() - : Widget(ICON_MD_FILE_DOCUMENT " Game Log") + : Widget(ICON_MD_FILE_DOCUMENT, _noop("Game Log")) , m_logWindow("gamelog") { } diff --git a/src/overlay/widgets/ImGuiDebug.cpp b/src/overlay/widgets/ImGuiDebug.cpp index d038dea9..529a404e 100644 --- a/src/overlay/widgets/ImGuiDebug.cpp +++ b/src/overlay/widgets/ImGuiDebug.cpp @@ -2,8 +2,10 @@ #include "ImGuiDebug.h" +#include + ImGuiDebug::ImGuiDebug() - : Widget(ICON_MD_BUG " ImGui Debug", true) + : Widget(ICON_MD_BUG, _noop("ImGui Debug"), true) { } diff --git a/src/overlay/widgets/LogWindow.cpp b/src/overlay/widgets/LogWindow.cpp index f3c0cafa..b8491e9c 100644 --- a/src/overlay/widgets/LogWindow.cpp +++ b/src/overlay/widgets/LogWindow.cpp @@ -17,7 +17,7 @@ void LogWindow::Draw(const ImVec2& size) { const auto itemWidth = GetAlignedItemWidth(2); - if (ImGui::Button("Clear output", ImVec2(itemWidth, 0))) + if (ImGui::Button(_t("Clear output"), ImVec2(itemWidth, 0))) { m_normalizedWidth = -1.0f; std::lock_guard _{m_lock}; @@ -25,7 +25,7 @@ void LogWindow::Draw(const ImVec2& size) m_lines.clear(); } ImGui::SameLine(); - ImGui::Checkbox("Auto-scroll", &m_shouldScroll); + ImGui::Checkbox(_t("Auto-scroll"), &m_shouldScroll); const auto& style = ImGui::GetStyle(); diff --git a/src/overlay/widgets/Settings.cpp b/src/overlay/widgets/Settings.cpp index 6572487d..1245d977 100644 --- a/src/overlay/widgets/Settings.cpp +++ b/src/overlay/widgets/Settings.cpp @@ -7,7 +7,7 @@ #include Settings::Settings(Options& aOptions, LuaVM& aVm) - : Widget(ICON_MD_COG " Settings") + : Widget(ICON_MD_COG, _noop("Settings")) , m_options(aOptions) , m_vm(aVm) { @@ -53,74 +53,89 @@ void Settings::OnUpdate() { m_madeChanges = false; m_madeFontChanges = false; - if (ImGui::CollapsingHeader("Patches", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader(_t("Patches"), ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TreePush(); if (ImGui::BeginTable("SETTINGS", 2, ImGuiTableFlags_NoSavedSettings, ImVec2(-ImGui::GetStyle().IndentSpacing, 0))) { const auto& patchesSettings = m_options.Patches; SettingItemCheckBox( - "🚑", "AMD SMT Patch", "For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect).", m_patches.AmdSmt, + "🚑", _t("AMD SMT Patch"), _t("For AMD CPUs that did not get a performance boost after CDPR's patch (requires restart to take effect)."), m_patches.AmdSmt, patchesSettings.AmdSmt); SettingItemCheckBox( - "👻", "Remove Pedestrians", "Removes most of the pedestrians and traffic (requires restart to take effect).", m_patches.RemovePedestrians, + "👻", _t("Remove Pedestrians"), _t("Removes most of the pedestrians and traffic (requires restart to take effect)."), m_patches.RemovePedestrians, patchesSettings.RemovePedestrians); SettingItemCheckBox( - "🐌", "Disable Async Compute", - "Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect).", m_patches.AsyncCompute, - patchesSettings.AsyncCompute); + "🐌", _t("Disable Async Compute"), + _t("Disables async compute, this can give a boost on older GPUs like Nvidia 10xx series for example (requires restart to take effect)."), + m_patches.AsyncCompute, patchesSettings.AsyncCompute); SettingItemCheckBox( - "🤮", "Disable Anti-aliasing", "Completely disables anti-aliasing (requires restart to take effect).", m_patches.Antialiasing, patchesSettings.Antialiasing); + "🤮", _t("Disable Anti-aliasing"), _t("Completely disables anti-aliasing (requires restart to take effect)."), m_patches.Antialiasing, + patchesSettings.Antialiasing); SettingItemCheckBox( - "🏄", "Skip Start Menu", "Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect).", m_patches.SkipStartMenu, - patchesSettings.SkipStartMenu); + "🏄", _t("Skip Start Menu"), _t("Skips the 'Breaching...' menu asking you to press space bar to continue (requires restart to take effect)."), + m_patches.SkipStartMenu, patchesSettings.SkipStartMenu); SettingItemCheckBox( - "🎞", "Suppress Intro Movies", "Disables logos played at the beginning (requires restart to take effect).", m_patches.DisableIntroMovies, + "🎞", _t("Suppress Intro Movies"), _t("Disables logos played at the beginning (requires restart to take effect)."), m_patches.DisableIntroMovies, patchesSettings.DisableIntroMovies); SettingItemCheckBox( - "🔦", "Disable Vignette", "Disables vignetting along screen borders (requires restart to take effect).", m_patches.DisableVignette, + "🔦", _t("Disable Vignette"), _t("Disables vignetting along screen borders (requires restart to take effect)."), m_patches.DisableVignette, patchesSettings.DisableVignette); SettingItemCheckBox( - "🗺", "Disable Boundary Teleport", "Allows players to access out-of-bounds locations (requires restart to take effect).", m_patches.DisableBoundaryTeleport, - patchesSettings.DisableBoundaryTeleport); - SettingItemCheckBox("💨", "Disable V-Sync (Windows 7 only)", " (requires restart to take effect).", m_patches.DisableWin7Vsync, patchesSettings.DisableWin7Vsync); + "🗺", _t("Disable Boundary Teleport"), _t("Allows players to access out-of-bounds locations (requires restart to take effect)."), + m_patches.DisableBoundaryTeleport, patchesSettings.DisableBoundaryTeleport); SettingItemCheckBox( - "✨", "Fix Minimap Flicker", "Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect).", m_patches.MinimapFlicker, + "💨", _t("Disable V-Sync (Windows 7 only)"), _t("Disables VSync on Windows 7 to bypass the 60 FPS limit (requires restart to take effect)."), m_patches.DisableWin7Vsync, patchesSettings.DisableWin7Vsync); + SettingItemCheckBox( + "✨", _t("Fix Minimap Flicker"), _t("Fix minimap flickering (requires restart to take effect)."), m_patches.MinimapFlicker, patchesSettings.MinimapFlicker); ImGui::EndTable(); } ImGui::TreePop(); } - if (ImGui::CollapsingHeader("CET Font Settings", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader(_t("CET Language Settings"), ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::TreePush(); + if (ImGui::BeginTable("SETTINGS", 2, ImGuiTableFlags_NoSavedSettings, ImVec2(-ImGui::GetStyle().IndentSpacing, 0))) + { + const auto& languageSettings = m_options.Language; + SettingItemLanguageCombo("🌐", _t("Language"), _t("Display language for CET."), m_language.Locale, languageSettings.Locale, CET::Get().GetI18n().GetLanguages()); + ImGui::EndTable(); + } + ImGui::TreePop(); + } + if (ImGui::CollapsingHeader(_t("CET Font Settings"), ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TreePush(); if (ImGui::BeginTable("SETTINGS", 2, ImGuiTableFlags_NoSavedSettings, ImVec2(-ImGui::GetStyle().IndentSpacing, 0))) { const auto& fontSettings = m_options.Font; m_madeFontChanges |= - SettingItemFontCombo("🦄", "Main Font", "Main display font for CET.", m_font.MainFont, fontSettings.MainFont, CET::Get().GetFonts().GetSystemFonts()); + SettingItemFontCombo("🦄", _t("Main Font"), _t("Main display font for CET."), m_font.MainFont, fontSettings.MainFont, CET::Get().GetFonts().GetSystemFonts()); m_madeFontChanges |= SettingItemFontCombo( - "🪲", "Monospaced Font", "Monospaceed font, which is used for displaying texts in Console and Game Log, for CET.", m_font.MonoFont, + "🪲", _t("Monospaced Font"), _t("Monospaceed font, which is used for displaying texts in Console and Game Log, for CET."), m_font.MonoFont, fontSettings.MonoFont, CET::Get().GetFonts().GetSystemFonts()); m_madeFontChanges |= SettingItemSliderFloat( - "📏", "Font Size", "Changees the size of the font, default value is 18px.", m_font.BaseSize, fontSettings.BaseSize, 10.0f, 72.0f, "%.0fpx"); + "📏", _t("Font Size"), _t("Changes the size of the font, default value is 18px."), m_font.BaseSize, fontSettings.BaseSize, 10.0f, 72.0f, "%.0fpx"); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); static bool openFontAdvSettings = false; - ImGui::Selectable("Advance Settings", false, ImGuiSelectableFlags_SpanAllColumns); + ImGui::Selectable(_t("Advance Settings"), false, ImGuiSelectableFlags_SpanAllColumns); if (ImGui::IsItemClicked()) openFontAdvSettings = !openFontAdvSettings; if (openFontAdvSettings) { ImGui::Indent(ImGui::GetFrameHeight()); m_madeFontChanges |= SettingItemSliderInt( - "↔", "Oversample Horizontal", "Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)", + "↔", _t("Oversample Horizontal"), + _t("Oversamples font horizontally, default value is 3x. (May increase font clearity, at the cost of increasing memory usage.)"), m_font.OversampleHorizontal, fontSettings.OversampleHorizontal, 1, 10, "%dx"); m_madeFontChanges |= SettingItemSliderInt( - "↕", "Oversample Vertical", "Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)", - m_font.OversampleVertical, fontSettings.OversampleVertical, 1, 10, "%dx"); + "↕", _t("Oversample Vertical"), + _t("Oversamples font vertically, default value is 1x. (May increase font clearity, at the cost of increasing memory usage.)"), m_font.OversampleVertical, + fontSettings.OversampleVertical, 1, 10, "%dx"); ImGui::Unindent(ImGui::GetFrameHeight()); } @@ -128,26 +143,32 @@ void Settings::OnUpdate() } ImGui::TreePop(); } - if (ImGui::CollapsingHeader("CET Development Settings", ImGuiTreeNodeFlags_DefaultOpen)) + if (ImGui::CollapsingHeader(_t("CET Development Settings"), ImGuiTreeNodeFlags_DefaultOpen)) { ImGui::TreePush(); if (ImGui::BeginTable("SETTINGS", 2, ImGuiTableFlags_NoSavedSettings, ImVec2(-ImGui::GetStyle().IndentSpacing, 0))) { const auto& developerSettings = m_options.Developer; SettingItemCheckBox( - "🗑", "Remove Dead Bindings", "Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues).", + "🗑", _t("Remove Dead Bindings"), _t("Removes all bindings which are no longer valid (disabling this could be useful when debugging mod issues)."), m_developer.RemoveDeadBindings, developerSettings.RemoveDeadBindings); SettingItemCheckBox( - "💣", "Enable ImGui Assertions", - "Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also be " - "used to check mods before shipping!).", + "💣", _t("Enable ImGui Assertions"), + _t("Enables all ImGui assertions, assertions will get logged into log file of whoever triggered the assertion (useful when debugging ImGui issues, should also " + "be " + "used to check mods before shipping!)."), m_developer.EnableImGuiAssertions, developerSettings.EnableImGuiAssertions); SettingItemCheckBox( - "🔨", "Enable Debug Build", "Sets internal flags to disguise as debug build (requires restart to take effect).", m_developer.EnableDebug, + "🔨", _t("Enable Debug Build"), _t("Sets internal flags to disguise as debug build (requires restart to take effect)."), m_developer.EnableDebug, developerSettings.EnableDebug); SettingItemCheckBox( - "🖨", "Dump Game Options", "Dumps all game options into main log file (requires restart to take effect).", m_developer.DumpGameOptions, + "🖨", _t("Dump Game Options"), _t("Dumps all game options into main log file (requires restart to take effect)."), m_developer.DumpGameOptions, developerSettings.DumpGameOptions); + SettingItemCheckBox( + "🗒", _t("Enable Translation Log"), _t("Show logs when there's a missing translation (requires restart to take effect)."), m_developer.EnableI18nLog, + developerSettings.EnableI18nLog); + if (SettingItemButton("🌐", _t("Reload translation"), ICON_MD_RESTART, _t("Reload translation files."))) + CET::Get().GetI18n().Reload(); ImGui::EndTable(); } @@ -159,13 +180,13 @@ void Settings::OnUpdate() ImGui::Separator(); const auto itemWidth = GetAlignedItemWidth(3); - if (ImGui::Button("Load", ImVec2(itemWidth, 0))) + if (ImGui::Button(_t("Load"), ImVec2(itemWidth, 0))) Load(); ImGui::SameLine(); - if (ImGui::Button("Save", ImVec2(itemWidth, 0))) + if (ImGui::Button(_t("Save"), ImVec2(itemWidth, 0))) Save(); ImGui::SameLine(); - if (ImGui::Button("Defaults", ImVec2(itemWidth, 0))) + if (ImGui::Button(_t("Defaults"), ImVec2(itemWidth, 0))) ResetToDefaults(); } @@ -176,6 +197,7 @@ void Settings::Load() m_patches = m_options.Patches; m_developer = m_options.Developer; m_font = m_options.Font; + m_language = m_options.Language; } void Settings::Save() const @@ -183,8 +205,10 @@ void Settings::Save() const m_options.Patches = m_patches; m_options.Developer = m_developer; m_options.Font = m_font; + m_options.Language = m_language; if (m_madeFontChanges) CET::Get().GetFonts().RebuildFontNextFrame(); + CET::Get().GetI18n().LoadLanguageSettings(); m_options.Save(); } @@ -196,10 +220,12 @@ void Settings::ResetToDefaults() m_patches = m_options.Patches; m_developer = m_options.Developer; m_font = m_options.Font; + m_language = m_options.Language; CET::Get().GetFonts().RebuildFontNextFrame(); } -void Settings::SettingItemTemplate(const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, const bool& aValueChanged, std::function& aImGuiFunction) +void Settings::SettingItemTemplate( + const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, const bool& aValueChanged, std::function& aImGuiFunction) { ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); @@ -238,6 +264,7 @@ void Settings::SettingItemTemplate(const std::string& acIcon, const std::string& ImGui::PopStyleColor(); } +// Returns true when the value has changed bool Settings::SettingItemCheckBox(const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, bool& aCurrent, const bool& acSaved) { std::function imguiWidget = [&]() @@ -265,8 +292,10 @@ bool Settings::SettingItemCheckBox(const std::string& acIcon, const std::string& return aCurrent != acSaved; } +// Returns true when the value has changed bool Settings::SettingItemSliderFloat( - const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, float& aCurrent, const float& acSaved, float aValueMin, float aValueMax, const char* aFormat) + const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, float& aCurrent, const float& acSaved, float aValueMin, float aValueMax, + const char* aFormat) { std::function imguiWidget = [&]() { @@ -282,6 +311,7 @@ bool Settings::SettingItemSliderFloat( return aCurrent != acSaved; } +// Returns true when the value has changed bool Settings::SettingItemSliderInt( const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, int& aCurrent, const int& acSaved, int aValueMin, int aValueMax, const char* aFormat) { @@ -299,17 +329,49 @@ bool Settings::SettingItemSliderInt( return aCurrent != acSaved; } +// Returns true when the button is pressed +bool Settings::SettingItemButton(const std::string& acIcon, const std::string& acLabel, const std::string& acButtonText, const std::string& acTooltip, const float acWidth) +{ + bool clicked = false; + std::function imguiWidget = [&]() + { + // Right align + if (ImGui::BeginTable("ButtonItem", 2, ImGuiTableFlags_NoSavedSettings)) + { + ImGui::TableSetupColumn("Col1", ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupColumn("Col2", ImGuiTableColumnFlags_WidthFixed); + ImGui::TableNextRow(); + ImGui::TableSetColumnIndex(1); + + clicked = ImGui::Button(acButtonText.c_str(), ImVec2(acWidth, 0)); + + ImGui::EndTable(); + } + }; + + SettingItemTemplate(acIcon, acLabel, acTooltip, false, imguiWidget); + + return clicked; +} + +// Returns true when the value has changed bool Settings::SettingItemFontCombo( const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, std::string& aCurrent, const std::string& acSaved, const std::vector& acFonts) { std::function imguiWidget = [&]() { - if (ImGui::BeginCombo(("##" + acLabel).c_str(), aCurrent.c_str())) + auto currentItem = aCurrent; + if (currentItem == "Default") + currentItem = _t("Settings", "Default"); + if (ImGui::BeginCombo(("##" + acLabel).c_str(), currentItem.c_str())) { for (const auto& font : acFonts) { - const bool isSelected = aCurrent == font.GetName(); - if (ImGui::Selectable(font.GetName().c_str(), isSelected)) + auto fontName = font.GetName(); + const bool isSelected = aCurrent == fontName; + if (fontName == "Default") + fontName = _t("Settings", "Default"); + if (ImGui::Selectable(fontName.c_str(), isSelected)) aCurrent = font.GetName(); if (isSelected) ImGui::SetItemDefaultFocus(); @@ -324,5 +386,43 @@ bool Settings::SettingItemFontCombo( m_madeChanges |= aCurrent != acSaved; + return aCurrent != acSaved; +} + +// Returns true when the value has changed +bool Settings::SettingItemLanguageCombo( + const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, std::string& aCurrent, const std::string& acSaved, + const std::vector& acLanguages) +{ + std::function imguiWidget = [&]() + { + auto currentItem = CET::Get().GetI18n().GetLanguage(aCurrent).GetLocalizedName(); + if (currentItem == "System") + currentItem = _t("Settings", "System"); + + if (ImGui::BeginCombo(("##" + acLabel).c_str(), currentItem.c_str())) + { + for (const auto& language : acLanguages) + { + const bool isSelected = aCurrent == language.GetLocale(); + auto formatedName = language.GetFormatedName(); + if (language.GetLocale() == "System") + formatedName = _t("Settings", "System"); + + if (ImGui::Selectable(formatedName.c_str(), isSelected)) + aCurrent = language.GetLocale(); + if (isSelected) + ImGui::SetItemDefaultFocus(); + } + ImGui::EndCombo(); + } + }; + + const bool valueChanged = aCurrent != acSaved; + + SettingItemTemplate(acIcon, acLabel, acTooltip, valueChanged, imguiWidget); + + m_madeChanges |= aCurrent != acSaved; + return aCurrent != acSaved; } \ No newline at end of file diff --git a/src/overlay/widgets/Settings.h b/src/overlay/widgets/Settings.h index 3b7e93cd..37ea0a51 100644 --- a/src/overlay/widgets/Settings.h +++ b/src/overlay/widgets/Settings.h @@ -28,12 +28,16 @@ struct Settings : Widget const char* aFormat = "%.1f"); bool SettingItemSliderInt( const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, int& aCurrent, const int& acSaved, int aValueMin, int aValueMax, const char* aFormat = "%d"); + bool SettingItemButton(const std::string& acIcon, const std::string& acLabel, const std::string& acButtonText, const std::string& acTooltip, const float acWidth = 0); bool SettingItemFontCombo( const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, std::string& aCurrent, const std::string& acSaved, const std::vector& acFonts); + bool SettingItemLanguageCombo( + const std::string& acIcon, const std::string& acLabel, const std::string& acTooltip, std::string& aCurrent, const std::string& acSaved, const std::vector& acLanguages); PatchesSettings m_patches; DeveloperSettings m_developer; FontSettings m_font; + LanguageSettings m_language; Options& m_options; LuaVM& m_vm; diff --git a/src/overlay/widgets/TweakDBEditor.cpp b/src/overlay/widgets/TweakDBEditor.cpp index c0493d4e..54ebb7d6 100644 --- a/src/overlay/widgets/TweakDBEditor.cpp +++ b/src/overlay/widgets/TweakDBEditor.cpp @@ -121,7 +121,7 @@ bool StringContains(const std::string_view& acString, const std::string_view& ac } TweakDBEditor::TweakDBEditor(LuaVM& aVm) - : Widget(ICON_MD_DATABASE_EDIT " TweakDB Editor") + : Widget(ICON_MD_DATABASE_EDIT, _noop("TweakDB Editor")) , m_vm(aVm) { } @@ -131,7 +131,7 @@ void TweakDBEditor::OnUpdate() // LuaVM is initialized after TweakDB, let's wait for it if (!m_vm.IsInitialized()) { - ImGui::TextUnformatted("TweakDB is not initialized yet"); + ImGui::TextUnformatted(_t("TweakDB is not initialized yet")); return; } @@ -145,7 +145,7 @@ void TweakDBEditor::OnUpdate() if (ImGui::BeginTabBar("TweakDBEditor-Bar")) { - if (ImGui::BeginTabItem("Records")) + if (ImGui::BeginTabItem(_t("Records"))) { ImGui::BeginChild("Records"); DrawRecordsTab(); @@ -153,7 +153,7 @@ void TweakDBEditor::OnUpdate() ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Queries")) + if (ImGui::BeginTabItem(_t("Queries"))) { ImGui::BeginChild("Queries"); DrawQueriesTab(); @@ -161,7 +161,7 @@ void TweakDBEditor::OnUpdate() ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Flats")) + if (ImGui::BeginTabItem(_t("Flats"))) { ImGui::BeginChild("Flats"); DrawFlatsTab(); @@ -169,7 +169,7 @@ void TweakDBEditor::OnUpdate() ImGui::EndTabItem(); } - if (ImGui::BeginTabItem("Advanced")) + if (ImGui::BeginTabItem(_t("Advanced"))) { ImGui::BeginChild("Advanced"); DrawAdvancedTab(); @@ -469,7 +469,7 @@ bool TweakDBEditor::DrawRecordDropdown(const char* acpLabel, RED4ext::TweakDBID& { static float searchTimer = 0.0f; ImGui::SetNextItemWidth(-FLT_MIN); - if (ImGui::InputTextWithHint("##dropdownSearch", "Search", s_tweakdbidFilterBuffer, sizeof(s_tweakdbidFilterBuffer))) + if (ImGui::InputTextWithHint("##dropdownSearch", _t("Search"), s_tweakdbidFilterBuffer, sizeof(s_tweakdbidFilterBuffer))) { searchTimer = c_searchDelay; } @@ -571,7 +571,7 @@ bool TweakDBEditor::DrawFlat(RED4ext::TweakDBID aDBID) if (!data.value) { - ImGui::Text("'%s' is not found in TweakDB", GetTweakDBIDStringFlat(aDBID.value & 0xFFFFFFFFFF).c_str()); + ImGui::Text(_t("'%s' is not found in TweakDB"), GetTweakDBIDStringFlat(aDBID.value & 0xFFFFFFFFFF).c_str()); return false; } @@ -631,7 +631,7 @@ bool TweakDBEditor::DrawFlat(RED4ext::TweakDBID aDBID, RED4ext::CStackType& aSta return DrawFlatInt32(aDBID, aStackType, aReadOnly); const auto typeName = aStackType.type->GetName(); - ImGui::Text("unsupported type: %s", typeName.ToString()); + ImGui::Text(_t("unsupported type: %s"), typeName.ToString()); return false; } @@ -664,9 +664,9 @@ bool TweakDBEditor::DrawFlatArray(RED4ext::TweakDBID aDBID, RED4ext::CStackType& } uint32_t arraySize = pArrayType->GetLength(arrayInstance); - if (!aCollapsable || ImGui::TreeNode("", "[%s] %u items", arrayTypeName.ToString(), arraySize)) + if (!aCollapsable || ImGui::TreeNode("", _t("[%s] %u item", "[%s] %u items", arraySize), arrayTypeName.ToString(), arraySize)) { - if (!aReadOnly && ImGui::Button("clear")) + if (!aReadOnly && ImGui::Button(_t("clear"))) { pArrayType->Resize(arrayInstance, 0); arraySize = 0; @@ -677,7 +677,7 @@ bool TweakDBEditor::DrawFlatArray(RED4ext::TweakDBID aDBID, RED4ext::CStackType& uint64_t arrayKey = aDBID.value & 0xFFFFFFFFFF; if (!isCached) { - if (ImGui::Button("edit")) + if (ImGui::Button(_t("edit"))) { auto* allocator = pArrayType->GetAllocator(); auto result = allocator->AllocAligned(pArrayType->GetSize(), pArrayType->GetAlignment()); @@ -689,7 +689,7 @@ bool TweakDBEditor::DrawFlatArray(RED4ext::TweakDBID aDBID, RED4ext::CStackType& else { ImGui::SameLine(); - if (ImGui::Button("cancel")) + if (ImGui::Button(_t("cancel"))) { pArrayType->Destruct(arrayInstance); pArrayType->GetAllocator()->Free(arrayInstance); @@ -702,7 +702,7 @@ bool TweakDBEditor::DrawFlatArray(RED4ext::TweakDBID aDBID, RED4ext::CStackType& isCached = false; } ImGui::SameLine(); - if (ImGui::Button("save")) + if (ImGui::Button(_t("save"))) { const RED4ext::CStackType newStackType(aStackType.type, arrayInstance); isModified = TweakDB::InternalSetFlat(aDBID, newStackType); @@ -766,7 +766,7 @@ bool TweakDBEditor::DrawFlatArray(RED4ext::TweakDBID aDBID, RED4ext::CStackType& ImGui::TableNextRow(); ImGui::TableNextColumn(); - if (!aReadOnly && ImGui::Button("add new")) + if (!aReadOnly && ImGui::Button(_t("add new"))) { pArrayType->InsertAt(arrayInstance, arraySize); pArrayInnerType->Construct(pArrayType->GetElement(arrayInstance, arraySize)); @@ -812,7 +812,7 @@ bool TweakDBEditor::DrawFlatTweakDBID(RED4ext::TweakDBID aDBID, RED4ext::CStackT } else { - ImGui::SetTooltipUnformatted("ERROR_RECORD_NOT_FOUND"); + ImGui::SetTooltipUnformatted(_t("ERROR_RECORD_NOT_FOUND")); } } @@ -906,17 +906,17 @@ bool TweakDBEditor::DrawFlatEulerAngles(RED4ext::TweakDBID aDBID, RED4ext::CStac const int32_t flags = aReadOnly ? ImGuiInputTextFlags_ReadOnly : ImGuiInputTextFlags_EnterReturnsTrue; - ImGui::TextUnformatted("Roll "); + ImGui::TextUnformatted(_t("Roll ")); ImGui::SameLine(); ImGui::SetNextItemWidth(-FLT_MIN); bool valueChanged = ImGui::InputFloat("##Roll", &roll, 0.0f, 0.0f, "%f", flags); - ImGui::TextUnformatted("Pitch"); + ImGui::TextUnformatted(_t("Pitch")); ImGui::SameLine(); ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Pitch", &pitch, 0.0f, 0.0f, "%f", flags); - ImGui::TextUnformatted("Yaw "); + ImGui::TextUnformatted(_t("Yaw ")); ImGui::SameLine(); ImGui::SetNextItemWidth(-FLT_MIN); valueChanged |= ImGui::InputFloat("##Yaw", &yaw, 0.0f, 0.0f, "%f", flags); @@ -1035,7 +1035,7 @@ bool TweakDBEditor::DrawFlatColor(RED4ext::TweakDBID aDBID, RED4ext::CStackType& rgba[3] = pColor->Alpha / 255.0f; aReadOnly = true; - ImGui::TextUnformatted("'Color' is not supported yet"); + ImGui::TextUnformatted(_t("'Color' is not supported yet")); ImGui::SameLine(); const int32_t flags = aReadOnly ? ImGuiColorEditFlags_NoInputs : ImGuiColorEditFlags_None; @@ -1071,7 +1071,7 @@ bool TweakDBEditor::DrawFlatLocKeyWrapper(RED4ext::TweakDBID aDBID, RED4ext::CSt { const auto* pLocKey = static_cast(aStackType.value); - ImGui::TextUnformatted("This is a LocalizationKey"); + ImGui::TextUnformatted(_t("This is a LocalizationKey")); ImGui::TextUnformatted("Game.GetLocalizedTextByKey(...)"); uint64_t key = pLocKey->primaryKey; @@ -1126,7 +1126,7 @@ bool TweakDBEditor::DrawFlatResourceAsyncRef(RED4ext::TweakDBID aDBID, RED4ext:: static int resourcesCount = 0; static char comboSearchStr[256]{}; ImGui::SetNextItemWidth(-FLT_MIN); - if (ImGui::InputTextWithHint("##dropdownSearch", "Search", comboSearchStr, sizeof(comboSearchStr))) + if (ImGui::InputTextWithHint("##dropdownSearch", _t("Search"), comboSearchStr, sizeof(comboSearchStr))) { searchTimer = c_searchDelay; } @@ -1229,7 +1229,7 @@ bool TweakDBEditor::DrawFlatCName(RED4ext::TweakDBID aDBID, RED4ext::CStackType& { const auto* pCName = static_cast(aStackType.value); - ImGui::TextUnformatted("Game is expecting specific values."); + ImGui::TextUnformatted(_t("Game is expecting specific values.")); // Is it worth it to implement a dropdown like DrawTweakDBID? RED4ext::CName newCName; @@ -1381,13 +1381,13 @@ void TweakDBEditor::DrawRecordsTab() { static float searchTimer = 0.0f; ImGui::SetNextItemWidth( - -(ImGui::GetFrameHeight() + ImGui::CalcTextSize("Regex").x + ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x + ImGui::GetStyle().FramePadding.x)); - if (ImGui::InputTextWithHint("##search", "Search", s_recordsFilterBuffer, sizeof(s_recordsFilterBuffer))) + -(ImGui::GetFrameHeight() + ImGui::CalcTextSize(_t("Regex")).x + ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x + ImGui::GetStyle().FramePadding.x)); + if (ImGui::InputTextWithHint("##search", _t("Search"), s_recordsFilterBuffer, sizeof(s_recordsFilterBuffer))) { searchTimer = c_searchDelay; } ImGui::SameLine(); - if (ImGui::Checkbox("Regex", &s_recordsFilterIsRegex)) + if (ImGui::Checkbox(_t("Regex"), &s_recordsFilterIsRegex)) { searchTimer = -1.0f; } @@ -1452,7 +1452,7 @@ void TweakDBEditor::DrawRecordsTab() ImGui::TableNextColumn(); if (flat.m_isMissing) { - ImGui::TextUnformatted("ERROR_FLAT_NOT_FOUND"); + ImGui::TextUnformatted(_t("ERROR_FLAT_NOT_FOUND")); } else { @@ -1507,13 +1507,13 @@ void TweakDBEditor::DrawFlatsTab() { static float searchTimer = 0.0f; ImGui::SetNextItemWidth( - -(ImGui::GetFrameHeight() + ImGui::CalcTextSize("Regex").x + ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x + ImGui::GetStyle().FramePadding.x)); - if (ImGui::InputTextWithHint("##search", "Search", s_flatsFilterBuffer, sizeof(s_flatsFilterBuffer))) + -(ImGui::GetFrameHeight() + ImGui::CalcTextSize(_t("Regex")).x + ImGui::GetStyle().ItemSpacing.x + ImGui::GetStyle().ItemInnerSpacing.x + ImGui::GetStyle().FramePadding.x)); + if (ImGui::InputTextWithHint("##search", _t("Search"), s_flatsFilterBuffer, sizeof(s_flatsFilterBuffer))) { searchTimer = c_searchDelay; } ImGui::SameLine(); - if (ImGui::Checkbox("Regex", &s_flatsFilterIsRegex)) + if (ImGui::Checkbox(_t("Regex"), &s_flatsFilterIsRegex)) { searchTimer = -1.0f; } @@ -1570,7 +1570,7 @@ void TweakDBEditor::DrawFlatsTab() ImGui::TableNextColumn(); if (flat.m_isMissing) { - ImGui::TextUnformatted("ERROR_FLAT_NOT_FOUND"); + ImGui::TextUnformatted(_t("ERROR_FLAT_NOT_FOUND")); } else { @@ -1592,15 +1592,15 @@ void TweakDBEditor::DrawFlatsTab() void TweakDBEditor::DrawAdvancedTab() { - if (ImGui::InputScalar("'Flats' Grouping depth", ImGuiDataType_S8, &m_flatGroupNameDepth, nullptr, nullptr, nullptr, ImGuiInputTextFlags_EnterReturnsTrue)) + if (ImGui::InputScalar(_t("'Flats' Grouping depth"), ImGuiDataType_S8, &m_flatGroupNameDepth, nullptr, nullptr, nullptr, ImGuiInputTextFlags_EnterReturnsTrue)) { RefreshFlats(); FilterFlats(); } - ImGui::InputFloat("ComboBox dropdown height", &g_comboDropdownHeight, 0, 0); + ImGui::InputFloat(_t("ComboBox dropdown height"), &g_comboDropdownHeight, 0, 0); - if (ImGui::Button("Refresh all")) + if (ImGui::Button(_t("Refresh all"))) { // prompt widget reinitialization m_initialized = false; @@ -1621,9 +1621,9 @@ void TweakDBEditor::DrawAdvancedTab() statusTimer = 2.5f; }; - ImGui::InputText("Record name", recordName, sizeof(recordName)); + ImGui::InputText(_t("Record name"), recordName, sizeof(recordName)); - if (ImGui::Button("Delete Record")) + if (ImGui::Button(_t("Delete Record"))) { if (TweakDB::InternalDeleteRecord(RED4ext::TweakDBID(recordName), spdlog::get("scripting"))) SetStatus("Success!"); @@ -1631,10 +1631,10 @@ void TweakDBEditor::DrawAdvancedTab() SetStatus("Failed. check console!"); } - if (ImGui::BeginCombo("Record type to create", recordTypeName.ToString(), ImGuiComboFlags_HeightLargest)) + if (ImGui::BeginCombo(_t("Record type to create"), recordTypeName.ToString(), ImGuiComboFlags_HeightLargest)) { ImGui::SetNextItemWidth(-FLT_MIN); - ImGui::InputTextWithHint("##dropdownSearch", "Search", comboSearchBuffer, sizeof(comboSearchBuffer)); + ImGui::InputTextWithHint("##dropdownSearch", _t("Search"), comboSearchBuffer, sizeof(comboSearchBuffer)); if (ImGui::BeginChild("##dropdownScroll", ImVec2(0, g_comboDropdownHeight))) { for (const auto& recordGroup : m_cachedRecords) @@ -1661,7 +1661,7 @@ void TweakDBEditor::DrawAdvancedTab() ImGui::EndCombo(); } - if (ImGui::Button("Create record")) + if (ImGui::Button(_t("Create record"))) { if (TweakDB::InternalCreateRecord(recordName, recordTypeName.ToString(), spdlog::get("scripting"))) SetStatus("Success!"); @@ -1669,9 +1669,9 @@ void TweakDBEditor::DrawAdvancedTab() SetStatus("Failed. check console!"); } - DrawRecordDropdown("Record to clone", clonedRecordDBID); + DrawRecordDropdown(_t("Record to clone"), clonedRecordDBID); - if (ImGui::Button("Clone record")) + if (ImGui::Button(_t("Clone record"))) { if (TweakDB::InternalCloneRecord(recordName, clonedRecordDBID, spdlog::get("scripting"))) SetStatus("Success!"); diff --git a/src/overlay/widgets/Widget.cpp b/src/overlay/widgets/Widget.cpp index a0cacbf1..590c788b 100644 --- a/src/overlay/widgets/Widget.cpp +++ b/src/overlay/widgets/Widget.cpp @@ -4,8 +4,9 @@ #include -Widget::Widget(const std::string& acpName, bool aOwnerDraw) - : m_name(acpName) +Widget::Widget(const std::string& acIcon, const std::string& acpName, bool aOwnerDraw) + : m_icon(acIcon) + , m_name(acpName) , m_ownerDraw(aOwnerDraw) { } @@ -96,7 +97,8 @@ void Widget::Draw() ImGui::SetNextWindowPos(ImVec2(width * 0.2f, height * 0.2f), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(width * 0.6f, height * 0.6f), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSizeConstraints(ImVec2(420, 315), ImVec2(FLT_MAX, FLT_MAX)); - if (ImGui::Begin(m_name.c_str(), &newEnabled)) + const std::string title = m_icon + " " + _t(m_name) + "###" + m_name; + if (ImGui::Begin(title.c_str(), &newEnabled)) OnUpdate(); ImGui::End(); } diff --git a/src/overlay/widgets/Widget.h b/src/overlay/widgets/Widget.h index 3f5d0e65..a66ff06d 100644 --- a/src/overlay/widgets/Widget.h +++ b/src/overlay/widgets/Widget.h @@ -9,7 +9,7 @@ enum class WidgetResult struct Widget { - Widget(const std::string& acpName, bool aOwnerDraw = false); + Widget(const std::string& acIcon, const std::string& acpName, bool aOwnerDraw = false); virtual ~Widget() = default; virtual WidgetResult OnEnable(); @@ -26,6 +26,7 @@ struct Widget virtual WidgetResult OnPopup(); virtual void OnToggle(); + std::string m_icon; std::string m_name; bool m_ownerDraw{false}; bool m_enabled{false}; diff --git a/src/scripting/LuaSandbox.cpp b/src/scripting/LuaSandbox.cpp index 1da3ab53..2373f726 100644 --- a/src/scripting/LuaSandbox.cpp +++ b/src/scripting/LuaSandbox.cpp @@ -48,6 +48,8 @@ static constexpr const char* s_cGlobalObjectsWhitelist[] = { "GetDisplayResolution", "AddTextGlyphs", "ModArchiveExists", + "GetSystemLocale", + "GetCETLocale", "ImGuiListClipper", "ImGuiCond", diff --git a/src/scripting/LuaVM.h b/src/scripting/LuaVM.h index 94960069..f453c0a6 100644 --- a/src/scripting/LuaVM.h +++ b/src/scripting/LuaVM.h @@ -25,7 +25,7 @@ struct TDBIDLookupEntry struct Image; struct LuaVM { - LuaVM(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts); + LuaVM(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts, I18n& aI18n); ~LuaVM() = default; [[nodiscard]] const VKBind* GetBind(const VKModBind& acModBind) const; diff --git a/src/scripting/LuaVM_Hooks.cpp b/src/scripting/LuaVM_Hooks.cpp index 2daf950d..acf90bee 100644 --- a/src/scripting/LuaVM_Hooks.cpp +++ b/src/scripting/LuaVM_Hooks.cpp @@ -258,8 +258,8 @@ void LuaVM::HookLogChannel(RED4ext::IScriptable*, RED4ext::CStackFrame* apStack, } } -LuaVM::LuaVM(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts) - : m_scripting(aPaths, aBindings, aD3D12, aFonts) +LuaVM::LuaVM(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts, I18n& aI18n) + : m_scripting(aPaths, aBindings, aD3D12, aFonts, aI18n) , m_d3d12(aD3D12) { Hook(); diff --git a/src/scripting/Scripting.cpp b/src/scripting/Scripting.cpp index bd6662d4..2fc60cb5 100644 --- a/src/scripting/Scripting.cpp +++ b/src/scripting/Scripting.cpp @@ -32,7 +32,7 @@ static constexpr bool s_cThrowLuaErrors = true; static RTTILocator s_stringType{RED4ext::FNV1a64("String")}; static RTTILocator s_resRefType{RED4ext::FNV1a64("redResourceReferenceScriptToken")}; -Scripting::Scripting(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts) +Scripting::Scripting(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts, I18n& aI18n) : m_sandbox(this, aBindings, aFonts) , m_mapper(m_lua.AsRef(), m_sandbox) , m_store(m_sandbox, aPaths, aBindings) @@ -40,6 +40,7 @@ Scripting::Scripting(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, , m_paths(aPaths) , m_fonts(aFonts) , m_d3d12(aD3D12) + , m_i18n(aI18n) { CreateLogger(aPaths.CETRoot() / "scripting.log", "scripting"); CreateLogger(aPaths.CETRoot() / "gamelog.log", "gamelog"); @@ -163,6 +164,16 @@ void Scripting::Initialize() return false; }; + globals["GetSystemLocale"] = [this]() -> const std::string + { + return m_i18n.GetSystemLocale(); + }; + + globals["GetCETLocale"] = [this]() -> const std::string + { + return m_i18n.GetCurrentLocale(); + }; + // load mods m_store.LoadAll(); } @@ -624,7 +635,7 @@ void Scripting::UnloadAllMods() void Scripting::ReloadAllMods() { UnloadAllMods(); - CET::Get().GetFonts().PrecacheGlyphsFromMods(); // recache glyphs from mods in case of changes + CET::Get().GetFonts().PrecacheModFiles(); // recache glyphs from mods in case of changes m_store.LoadAll(); diff --git a/src/scripting/Scripting.h b/src/scripting/Scripting.h index 7853699d..100fa090 100644 --- a/src/scripting/Scripting.h +++ b/src/scripting/Scripting.h @@ -11,7 +11,7 @@ struct Scripting { using LockedState = TiltedPhoques::Locked; - Scripting(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts); + Scripting(const Paths& aPaths, VKBindings& aBindings, D3D12& aD3D12, Fonts& aFonts, I18n& aI18n); ~Scripting() = default; void Initialize(); @@ -62,4 +62,5 @@ struct Scripting const Paths& m_paths; Fonts& m_fonts; D3D12& m_d3d12; + I18n& m_i18n; }; diff --git a/src/stdafx.h b/src/stdafx.h index ce4ea787..3b2e6fce 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -36,6 +36,9 @@ #include #include +#include +#include + #include #include #include @@ -77,6 +80,7 @@ #include "reverse/Addresses.h" #include "scripting/GameHooks.h" #include "VKBindings.h" +#include "I18n.h" template <> struct std::hash { diff --git a/vendor/gettext-tools/gettext-license.txt b/vendor/gettext-tools/gettext-license.txt new file mode 100644 index 00000000..e6000869 --- /dev/null +++ b/vendor/gettext-tools/gettext-license.txt @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/vendor/gettext-tools/msginit.exe b/vendor/gettext-tools/msginit.exe new file mode 100644 index 00000000..745c3615 Binary files /dev/null and b/vendor/gettext-tools/msginit.exe differ diff --git a/vendor/gettext-tools/msgmerge.exe b/vendor/gettext-tools/msgmerge.exe new file mode 100644 index 00000000..08986362 Binary files /dev/null and b/vendor/gettext-tools/msgmerge.exe differ diff --git a/vendor/gettext-tools/xgettext.exe b/vendor/gettext-tools/xgettext.exe new file mode 100644 index 00000000..2ffc56a5 Binary files /dev/null and b/vendor/gettext-tools/xgettext.exe differ diff --git a/vendor/tinygettext b/vendor/tinygettext new file mode 160000 index 00000000..2fcecb76 --- /dev/null +++ b/vendor/tinygettext @@ -0,0 +1 @@ +Subproject commit 2fcecb76900fac852fd4006e4d49b0744b1031e1 diff --git a/xmake.lua b/xmake.lua index 26a7e95e..bcb55146 100644 --- a/xmake.lua +++ b/xmake.lua @@ -56,6 +56,7 @@ add_requires("openrestry-luajit", { configs = { gc64 = true } }) local imguiUserConfig = path.absolute("src/imgui_impl/imgui_user_config.h") add_requires("imgui v1.88-docking", { configs = { wchar32 = true, freetype = true, user_config = imguiUserConfig } }) +add_requires("libiconv 1.17") target("RED4ext.SDK") set_kind("static") @@ -65,6 +66,16 @@ target("RED4ext.SDK") add_includedirs("vendor/RED4ext.SDK/include/", { public = true }) on_install(function() end) +target("tinygettext") + add_defines("WIN32") + set_kind("static") + set_group("vendor") + add_files("vendor/tinygettext/src/**.cpp") + add_headerfiles("vendor/tinygettext/include/**.hpp", "vendor/tinygettext/include/**.h") + add_includedirs("vendor/tinygettext/include/", { public = true }) + add_packages("libiconv") + on_install(function() end) + target("cyber_engine_tweaks") add_defines("WIN32_LEAN_AND_MEAN", "NOMINMAX", "WINVER=0x0601", "SOL_ALL_SAFETIES_ON", "SOL_LUAJIT=1", "SOL_EXCEPTIONS_SAFE_PROPAGATION", "SPDLOG_WCHAR_TO_UTF8_SUPPORT", "SPDLOG_WCHAR_FILENAMES", "SPDLOG_WCHAR_SUPPORT", "IMGUI_USER_CONFIG=\""..imguiUserConfig.."\"", "SOL_IMGUI_ENABLE_FONT_MANIPULATORS") -- WINVER=0x0601 == Windows 7xmake set_pcxxheader("src/stdafx.h") @@ -74,8 +85,8 @@ target("cyber_engine_tweaks") add_headerfiles("src/**.h", "build/CETVersion.h") add_includedirs("src/", "build/") add_syslinks("User32", "Version", "d3d11", "Dwrite") - add_packages("spdlog", "nlohmann_json", "minhook", "hopscotch-map", "imgui", "mem", "sol2", "tiltedcore", "sqlite3", "openrestry-luajit", "xbyak", "stb") - add_deps("RED4ext.SDK") + add_packages("spdlog", "nlohmann_json", "minhook", "hopscotch-map", "imgui", "mem", "sol2", "tiltedcore", "sqlite3", "openrestry-luajit", "xbyak", "stb", "libiconv") + add_deps("RED4ext.SDK", "tinygettext") add_configfiles("src/CETVersion.h.in") on_package(function(target) @@ -93,6 +104,9 @@ target("cyber_engine_tweaks") os.mkdir("package/bin/x64/plugins/cyber_engine_tweaks/fonts") os.cp("fonts/*", "package/bin/x64/plugins/cyber_engine_tweaks/fonts") + os.mkdir("package/bin/x64/plugins/cyber_engine_tweaks/languages") + os.cp("languages/*.po", "package/bin/x64/plugins/cyber_engine_tweaks/languages") + os.cp("vendor/asiloader/*", "package/bin/x64/") os.cp("LICENSE", "package/bin/x64/") @@ -111,3 +125,142 @@ option("installpath") set_default("installpath") set_showmenu(true) set_description("Set the path to install cyber_engine_tweaks.asi to.", "e.g.", format("\t-xmake f --installpath=%s", [["C:\Program Files (x86)\Steam\steamapps\common\Cyberpunk 2077\bin\x64\plugins"]])) + +task("i18n-pot") + set_menu { + usage = "xmake i18n-pot", + description = "Generate update existing po file.", + options = {} + } + on_run(function() + local potPath = "./languages/template.pot" + -- get a list of cpp files under src/ + local fileList = "" + for _, filePath in ipairs(os.files("src/**.cpp")) do + fileList = fileList .. filePath .. "\n" + end + -- write the list to a tmp file + local fileListPath = "$(tmpdir)/cet_cpp_files.txt" + local file = io.open(fileListPath, "w") + if file then + file:write(fileList) + file:close() + end + + -- execute xgettext + os.execv("vendor/gettext-tools/xgettext.exe", { + vformat("--files-from=%s", fileListPath), + vformat("--output=%s", potPath), + "--c++", + "--from-code=UTF-8", + "--add-comments", + "--no-wrap", + "--keyword", + "--keyword=_t:1,1t", "--keyword=Translate:1,1t", "--keyword=translate:1,1t", + "--keyword=_t:1c,2,2t", "--keyword=Translate:1c,2,2t", "--keyword=translate_ctxt:1,1t", + "--keyword=_t:1,2,3t", "--keyword=Translate:1,2,3t", "--keyword=translate_plural:1,1t", + "--keyword=_t:1c,2,3,4t", "--keyword=Translate:1c,2,3,4t", "--keyword=translate_ctxt_plural:1,1t", + "--copyright-holder=yamashi", + "--package-name=CyberEngineTweaks", + "--package-version=", + "--msgid-bugs-address=https://github.com/maximegmd/CyberEngineTweaks/issues" + }) + -- remove the tmp file + os.rm(fileListPath) + + -- auto generate and update en.po + local enpoPath = "./languages/en.po" + os.execv("vendor/gettext-tools/msginit.exe", { + format("--input=%s", potPath), + format("--output-file=%s.tmp", enpoPath), + format("--locale=%s", "en"), + "--no-translator", + "--no-wrap", + }) + os.execv("vendor/gettext-tools/msgmerge.exe", { + "--update", + "--backup=off", + "--no-fuzzy-matching", + "--no-wrap", + enpoPath, + enpoPath..".tmp" + }) + os.rm(enpoPath..".tmp") + + end) + +task("i18n-po") + set_menu { + usage = "xmake i18n-po [options]", + description = "Generate new / update existing po file.", + options = { + {'m', "mode", "kv", "update", "Create new or update existing po file.", " - create", " - update"}, + {'l', "locale", "kv", nil, "Set locale to create. Use ll_CC or ll format (e.g. en_US, or en)."}, + } + } + on_run(function() + import("core.base.option") + local mode = option.get("mode") + local locale = option.get("locale") + + local langDir = "./languages/" + local potPath = langDir .. "template.pot" + + if mode ~= "create" and mode ~= "update" then + raise("Unkown value %s for --mode.", mode) + end + if mode == "create" and (locale == "" or locale == nil) then + raise("Locale can't be empty.") + end + if (not os.exists(potPath)) then + raise("template.pot doesn't exist.") + end + + -- create new po file + if mode == "create" then + os.execv("vendor/gettext-tools/msginit.exe", { + format("--input=%s", potPath), + format("--output-file=%s", langDir..locale..".po"), + format("--locale=%s", locale), + "--no-wrap", + }) + end + + -- update all po files + if mode == "update" then + for _, poPath in ipairs(os.files(langDir.."*.po")) do + cprint("${green bright}Updating${clear} %s", poPath) + + if path.basename(poPath) ~= "en" then + os.execv("vendor/gettext-tools/msgmerge.exe", { + "--update", + "--backup=off", + "--no-wrap", + poPath, + potPath + }) + end + end + end + end) + + task("i18n-install") + set_menu { + usage = "xmake i18n-install", + description = "Install po files to CET install path.", + options = {} + } + on_run(function() + import("core.project.config") + config.load() + local installPath = config.get("installpath") + local langPath = path.join(installPath, "cyber_engine_tweaks", "languages") + + cprint("${green bright}Installing language files ..") + assert(os.isdir(installPath), format("The path in your configuration doesn't exist or isn't a directory.\n\tUse the follow command to set install path:\n\txmake f --installpath=%s", [["C:\Program Files (x86)\Steam\steamapps\common\Cyberpunk 2077\bin\x64\plugins"]])) + + os.mkdir(langPath) + os.cp("./languages/*.po", langPath) + + cprint("po files installed at: ${underline}%s", langPath) + end) \ No newline at end of file