Compare commits

...

44 Commits

Author SHA1 Message Date
WerWolvTranslationBot 66bcdfd84e Translations update from Weblate (#488)
* Translated using Weblate (English)

Currently translated at 100.0% (134 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/en/

* Translated using Weblate (Albanian)

Currently translated at 36.5% (49 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/sq/

* Translated using Weblate (Ukrainian)

Currently translated at 85.0% (114 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/uk/

---------

Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
2023-06-19 17:44:30 +02:00
WerWolvTranslationBot 8494f2ec3e Translations update from Weblate (#487)
* Translated using Weblate (Italian)

Currently translated at 100.0% (134 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (French)

Currently translated at 71.6% (96 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 88.0% (118 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 88.0% (118 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/

* Translated using Weblate (Albanian)

Currently translated at 35.8% (48 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/sq/

* Translated using Weblate (Albanian)

Currently translated at 35.8% (48 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/sq/

* Translated using Weblate (Spanish)

Currently translated at 85.0% (114 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/es/

* Translated using Weblate (Greek)

Currently translated at 70.8% (95 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/el/

* Translated using Weblate (Greek)

Currently translated at 70.8% (95 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/el/

* Translated using Weblate (German)

Currently translated at 73.1% (98 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/de/

* Translated using Weblate (Czech)

Currently translated at 88.0% (118 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/cs/

* Translated using Weblate (Korean)

Currently translated at 88.0% (118 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/ko/

* Translated using Weblate (Portuguese (Portugal))

Currently translated at 88.0% (118 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/pt_PT/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 88.0% (118 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/pt_BR/

* Translated using Weblate (Russian)

Currently translated at 0.0% (0 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/ru/

* Translated using Weblate (Ukrainian)

Currently translated at 85.8% (115 of 134 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/uk/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

---------

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
2023-06-19 17:34:07 +02:00
WerWolvTranslationBot 52f25708ad Translations update from Weblate (#486)
* Added translation using Weblate (Czech)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Translated using Weblate (Italian)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Czech)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/cs/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/

* Added translation using Weblate (Korean)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Added translation using Weblate (Portuguese)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Added translation using Weblate (Portuguese (Brazil))

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Translated using Weblate (French)

Currently translated at 81.3% (96 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Korean)

Currently translated at 61.0% (72 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/ko/

* Translated using Weblate (Portuguese (Portugal))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/pt_PT/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/pt_BR/

* Added translation using Weblate (Russian)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Translated using Weblate (Korean)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/ko/

* Added translation using Weblate (Ukrainian)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

---------

Co-authored-by: Meiton <michal.salati@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: david082321 <david082321@yahoo.com.tw>
Co-authored-by: Sungjoon Moon <sumoon@seoulsaram.org>
Co-authored-by: Samuel Medalha <smedalha@protonmail.com>
Co-authored-by: Paulo Victor de Lima Sfair Alvares <pvsfair@gmail.com>
Co-authored-by: Libo Chen <clb729@gmail.com>
Co-authored-by: Ivan Poletsky <wiperus55@gmail.com>
Co-authored-by: Denys Dovhan <denysdovhan@gmail.com>
2023-06-19 17:25:04 +02:00
Marco Rodolfi 24b02114cb Fix weblate crap 2023-06-19 17:22:13 +02:00
Denys Dovhan 651215723d Translated using Weblate (Ukrainian)
Currently translated at 97.4% (115 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/uk/
2023-06-19 17:21:17 +02:00
Weblate ca9831be05 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Weblate f7fd7b712f Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Weblate 3859c0e483 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Weblate 2db92536fd Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Weblate a6ffc8f04d Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Weblate 4df8cb5026 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Weblate a86d473280 Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
Denys Dovhan 4d226b00fc Added translation using Weblate (Ukrainian) 2023-06-19 17:21:17 +02:00
Weblate 8b16b156ed Update translation files
Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/
2023-06-19 17:21:17 +02:00
suchmememanyskill 4029a43637 Fix uninstalling plugins (#485)
* Fix bad debug print statement in uninstall plugin

* Safely remove element from hidden plugin/plugin order list
2023-06-19 06:24:24 -07:00
Marco Rodolfi 57f4555350 [Feature] File picker improvements (#454)
* First iteration for internationalization of the loader

* First iteration for internationalization of the loader

* Cleanup node mess

* Cleanup node mess pt2

* Additional touches

* Latest decky changed merged into i18n and updated translation.

* Styling fixes

* Initial backend hosting implementation

* Added correct url path of the loopback server.

* Added correct url path of the loopback server.

* Some better namespaced text.

* Added whitelist for locales path.

* Refactor languages and fix hooks logic bugs.

* Small typo in language translation structure.

* Working backend, automatically swtich languages with steam and language fixes.

* Fix to languages

* Key fixes

* Additional language fixes.

* Additional json changes

* Final text revision and added a vscode tasks to automatically extract text from code.

* Typo in the middleware

* Remove unused imports

* Cleanup whitespaces.

* Import changes

* Revert "Import changes"

This reverts commit 8e8231950f.

* Update index.d.ts

* Clean up unused imports

* Delete pnpm-lock.yaml

* Update rollup.config.js

* Update PluginInstallModal.tsx

* Update index.tsx

* Update plugin-loader.tsx

* Update plugin-loader.tsx

* Revert "Delete pnpm-lock.yaml"

This reverts commit 3a39f36f21.

* Additional strings reworks.

* Fixes for issues coming from github merge.

* Fixes for master

* Styling fixes

* Styling pt2

* Missed a few strings in master,

* Styling fixes

* Additional master merge fixes.

* Final cleanup and adaptation to master.

* Final empty language cleanup and few string added

* Small changes to italian translation

* Disabled translation on a few components inside plugin-loader for missing react hooks.

* Fixed passing tag to translation.

* Disable debug output for reducing console spam.

* Return correct content type

* Small italian language change

* Added support for country code

* Fixed missing translation for uninstall popup.

* Fix class name shenanigans for  toast notification

* Update dependencies

* Fixed github workflow to include the new locales folder

* Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up

* Missed a file name change

* Updated dev dependencies to latest version

* Missed a few dev dependencies

* Revert "Update dependencies to latest version (unless it's React) and fixed the new small errors that cropped up"

Messed up merge with a different main branch

* Messed up deletion of rollup config.

* Fix broken pnpm lock file

* Missed a localized string during the merge

* Fixed a parameter mistake in the uninstall text parameter

* Fix pnpm random issues

* Small italian language tweaks

* Fix wrong parameter passed to the uninstall function call

* Another fix on a wrong function parameter

* Additional translation text on the store and branch selection channels

* Changed the default type passed to map to being able to index the two arrays.

* Reverted and reworked the last changes

* Distinguish events in UI for installing vs reinstalling plugins

* Additional fixes for reinstall prompt

* Revert the use of intevalPlural since the parser doesn't seem to support that.

* Missed a routing path in the backend

* Small bugfixes

* Small fixes

* Correctly adding the parameter to the request headers.

* Refactoring of the UI popup modal

* Fix pnpm shenanigans

* Final fixes for the install UI localization

* Clean up unnedeed backend code

* Small rework on text selection.

* Cleaned up parser configuration

* Removed extracttext dependency to pnpmsetup

* Merged translation and cleaned up parser

* Fixed JSON structure after manual merge.

* Added translation to the file picker

* First iteration for merging the new filepicker.

* Revert changes to PluginInstallModal

* Reworked the text modal for the final time

* Missed the proper linted text

* Missed the backend change

* Final branch cleanup

* First iteration for porting the new file picker

* Hotfix for i18n where the detector was overriding localStorage

* Please, pnpm, cooperate

* Small fix regarding the backend getting hammered when switching to not supported languages plus a small english typo

* Initial working upstream iteration for file picker

* Typo on translation variable

* File picker final improvements

* Stylistic fixes and fix on wrong bool passed to fp

* Fixup merge from main

* Other merge errors fixed

* Minor cleanups

* Fixed missing padding under text label extension

* Implement pagination backend side

* First draft for filtering backend side

* Implemented matching on file names.

* Fix for unable to order per size on folders.

* Hard checking a return value

* Added a missing import.

* Implemented show more as a frontend button

* Whoops, python typo

* Fixed python backend

* Rendering bug fix and small qol improvement

* Added missing parameter to openFilePicker call

* Fixed path on windows and unknown error on wrong path

* Small backend fixes

* Extension fix

* Simplified extension logic

* Less string conversions.

* Optimize backend code and removed additional components.

* Take correctly into account the max value

The button will now respect the actual maximum desired number of entries.

* Bugfix for ordering logic and ignore cases during sorting

* Regex call was missing an argument

* Fixed issues with filtering extensions

* Rollback testing changes

* Minor cleanup and attempt at fixing the not updating multimodal.

* Cleanup variable types.

* Mantains the same api format from the original source code.

* Removing hardcoded paths in the code

* Additional fixes for resolving the user path

* Cleanup useless modifications

* Final fixes for avoid path hardcoding

* Update lockfile and i18next version
2023-06-19 06:23:27 -07:00
WerWolvTranslationBot bd87cc852b Translations update from Weblate (#481)
* Added translation using Weblate (Czech)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Translated using Weblate (Italian)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Czech)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/cs/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/

* Added translation using Weblate (Korean)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Added translation using Weblate (Portuguese)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Added translation using Weblate (Portuguese (Brazil))

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Translated using Weblate (French)

Currently translated at 81.3% (96 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/fr/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Korean)

Currently translated at 61.0% (72 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/ko/

* Translated using Weblate (Portuguese (Portugal))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/pt_PT/

* Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/pt_BR/

* Added translation using Weblate (Russian)

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Update translation files

Updated by "Remove blank strings" hook in Weblate.

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/

* Translated using Weblate (Korean)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/ko/

---------

Co-authored-by: Meiton <michal.salati@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: david082321 <david082321@yahoo.com.tw>
Co-authored-by: Sungjoon Moon <sumoon@seoulsaram.org>
Co-authored-by: Samuel Medalha <smedalha@protonmail.com>
Co-authored-by: Paulo Victor de Lima Sfair Alvares <pvsfair@gmail.com>
Co-authored-by: Libo Chen <clb729@gmail.com>
Co-authored-by: Ivan Poletsky <wiperus55@gmail.com>
2023-06-19 09:55:02 +02:00
AAGaming 30d7c9bb81 fix: fix blank plugins
this is why i shouldn't program at night
2023-06-18 17:27:23 -04:00
AAGaming 890599c7bb chore: remove useless import 2023-06-18 17:26:42 -04:00
Marco Rodolfi b8e48d2146 WIP on main: 60353df Merge remote-tracking branch 'weblate/main' 2023-06-16 14:46:25 +02:00
Marco Rodolfi da1db5a053 index on main: 60353df Merge remote-tracking branch 'weblate/main' 2023-06-16 14:46:25 +02:00
Marco Rodolfi 60353df7ed Merge remote-tracking branch 'weblate/main' 2023-06-16 14:46:09 +02:00
Party Wumpus e8dfe5a87d When decky is uncertain of branch, set the setting to match the guess (#480)
* If branch setting is missing, set it using the 'guess' from backend

* Make the frontend default to stable branch like the backend
2023-06-15 05:53:02 -07:00
WerWolvTranslationBot d0b7d1a4a6 Translations update from Weblate (#477)
* Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/

* Translated using Weblate (German)

Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/de/

* Translated using Weblate (Italian)

Currently translated at 91.8% (102 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (111 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/es/

* Translated using Weblate (Italian)

Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

---------

Co-authored-by: david082321 <david082321@yahoo.com.tw>
Co-authored-by: Jonas Dellinger <jonas@dellinger.dev>
Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: Avery <aveeryy@protonmail.com>
2023-06-08 16:49:07 +02:00
Marco Rodolfi 13b6ed5ad9 Translated using Weblate (Italian)
Currently translated at 100.0% (118 of 118 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/
2023-06-08 14:46:26 +00:00
Weblate 89bbbf6fe4 Merge remote-tracking branch 'origin/main' 2023-06-08 14:40:08 +00:00
AAGaming 9a05c228a0 fix dumb crash when updating decky while a plugin that uses BrowserView is running 2023-06-07 18:03:41 -04:00
Party Wumpus 00d9b03322 add firefox .download clarification in readme 2023-06-07 16:56:47 +01:00
Jonas Dellinger 47bc910a84 Add functionality to hide plugins from quick access menu (#468) 2023-06-06 22:35:05 -07:00
Weblate fdc556edee Merge remote-tracking branch 'origin/main' 2023-06-04 15:09:46 +00:00
WerWolvTranslationBot 1c6270ccd6 Translations update from Weblate (#476)
* Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/

* Translated using Weblate (German)

Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/de/

* Translated using Weblate (Italian)

Currently translated at 91.8% (102 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (111 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/es/

---------

Co-authored-by: david082321 <david082321@yahoo.com.tw>
Co-authored-by: Jonas Dellinger <jonas@dellinger.dev>
Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Sean <zhangshuyan@fuji.waseda.jp>
Co-authored-by: Avery <aveeryy@protonmail.com>
2023-06-04 17:09:14 +02:00
Weblate f87e794c3f Merge remote-tracking branch 'origin/main' 2023-06-04 15:08:29 +00:00
Avery 8f17f2b0fe Translated using Weblate (Spanish)
Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/es/
2023-06-04 17:08:01 +02:00
Sean 81b601c0e7 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/
2023-06-04 17:08:01 +02:00
Marco Rodolfi 83e8c89c97 Translated using Weblate (Italian)
Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/
2023-06-04 17:08:01 +02:00
WerWolvTranslationBot ca107feb25 Translations update from Weblate (#475)
* Translated using Weblate (Chinese (Traditional))

Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/

* Translated using Weblate (German)

Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/de/

* Translated using Weblate (Italian)

Currently translated at 91.8% (102 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

* Translated using Weblate (Italian)

Currently translated at 100.0% (111 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/

---------

Co-authored-by: david082321 <david082321@yahoo.com.tw>
Co-authored-by: Jonas Dellinger <jonas@dellinger.dev>
Co-authored-by: Marco Rodolfi <marco.rodolfi@tuta.io>
Co-authored-by: Weblate <noreply@weblate.org>
2023-06-04 11:06:53 +02:00
Avery 56719df827 Translated using Weblate (Spanish)
Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/es/
2023-06-03 16:59:04 +00:00
Sean 3c11bb71f6 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hans/
2023-06-03 16:59:04 +00:00
Marco Rodolfi 413cec9244 Translated using Weblate (Italian)
Currently translated at 100.0% (114 of 114 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/
2023-06-03 16:59:04 +00:00
Weblate 935de1ad0c Merge remote-tracking branch 'origin/main' 2023-06-02 10:07:20 +00:00
Marco Rodolfi 9542708c92 Translated using Weblate (Italian)
Currently translated at 100.0% (111 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/
2023-05-31 06:53:52 +00:00
Marco Rodolfi b3c363c89f Translated using Weblate (Italian)
Currently translated at 91.8% (102 of 111 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/it/
2023-05-31 06:53:52 +00:00
Jonas Dellinger 5f5e8ad5d7 Translated using Weblate (German)
Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/de/
2023-05-31 06:53:52 +00:00
david082321 6b6de2fcd5 Translated using Weblate (Chinese (Traditional))
Currently translated at 100.0% (100 of 100 strings)

Translation: Decky/Decky
Translate-URL: https://weblate.werwolv.net/projects/decky/decky/zh_Hant/
2023-05-31 06:53:52 +00:00
43 changed files with 2880 additions and 618 deletions
+1 -1
View File
@@ -48,7 +48,7 @@ For more information about Decky Loader as well as documentation and development
1. Press the <img src="./docs/images/light/steam.svg#gh-dark-mode-only" height=16><img src="./docs/images/dark/steam.svg#gh-light-mode-only" height=16> button and open the Power menu.
1. Select "Switch to Desktop".
1. Navigate to this Github page on a browser of your choice.
1. Download the [installer file](https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/decky_installer.desktop).
1. Download the [installer file](https://github.com/SteamDeckHomebrew/decky-installer/releases/latest/download/decky_installer.desktop). (If using firefox, it will be named `decky_installer.desktop.download`. Rename it to `decky_installer.desktop` before running it)
1. Drag the file onto your desktop and double click it to run it.
1. Either type your admin password or allow Decky to temporarily set your admin password to `Decky!` (this password will be removed after the installer finishes)
1. Choose the version of Decky Loader you want to install.
+22 -5
View File
@@ -122,17 +122,14 @@ class PluginBrowser:
logger.debug("Plugin %s was stopped", name)
del self.plugins[name]
logger.debug("Plugin %s was removed from the dictionary", name)
current_plugin_order = self.settings.getSetting("pluginOrder")
current_plugin_order.remove(name)
self.settings.setSetting("pluginOrder", current_plugin_order)
logger.debug("Plugin %s was removed from the pluginOrder setting", name)
self.cleanup_plugin_settings(name)
logger.debug("removing files %s" % str(name))
rmtree(plugin_dir)
except FileNotFoundError:
logger.warning(f"Plugin {name} not installed, skipping uninstallation")
except Exception as e:
logger.error(f"Plugin {name} in {plugin_dir} was not uninstalled")
logger.error(f"Error at %s", exc_info=e)
logger.error(f"Error at {str(e)}", exc_info=e)
if self.loader.watcher:
self.loader.watcher.disabled = False
@@ -234,3 +231,23 @@ class PluginBrowser:
def cancel_plugin_install(self, request_id):
self.install_requests.pop(request_id)
def cleanup_plugin_settings(self, name):
"""Removes any settings related to a plugin. Propably called when a plugin is uninstalled.
Args:
name (string): The name of the plugin
"""
hidden_plugins = self.settings.getSetting("hiddenPlugins", [])
if name in hidden_plugins:
hidden_plugins.remove(name)
self.settings.setSetting("hiddenPlugins", hidden_plugins)
plugin_order = self.settings.getSetting("pluginOrder", [])
if name in plugin_order:
plugin_order.remove(name)
self.settings.setSetting("pluginOrder", plugin_order)
logger.debug("Removed any settings for plugin %s", name)
+1 -1
View File
@@ -159,4 +159,4 @@ async def stop_systemd_unit(unit_name: str) -> bool:
return await localplatform.service_stop(unit_name)
async def start_systemd_unit(unit_name: str) -> bool:
return await localplatform.service_start(unit_name)
return await localplatform.service_start(unit_name)
+2 -1
View File
@@ -395,6 +395,7 @@ async def get_tab_lambda(test) -> Tab:
return tab
SHARED_CTX_NAMES = ["SharedJSContext", "Steam Shared Context presented by Valve™", "Steam", "SP"]
CLOSEABLE_URLS = ["about:blank", "data:text/html,%3Cbody%3E%3C%2Fbody%3E"] # Closing anything other than these *really* likes to crash Steam
DO_NOT_CLOSE_URL = "Valve Steam Gamepad/default" # Steam Big Picture Mode tab
def tab_is_gamepadui(t: Tab) -> bool:
@@ -415,7 +416,7 @@ async def inject_to_tab(tab_name, js, run_async=False):
async def close_old_tabs():
tabs = await get_tabs()
for t in tabs:
if not t.title or (t.title not in SHARED_CTX_NAMES and DO_NOT_CLOSE_URL not in t.url):
if not t.title or (t.title not in SHARED_CTX_NAMES and any(url in t.url for url in CLOSEABLE_URLS) and DO_NOT_CLOSE_URL not in t.url):
logger.debug("Closing tab: " + getattr(t, "title", "Untitled"))
await t.close()
await sleep(0.5)
+228
View File
@@ -0,0 +1,228 @@
{
"BranchSelect": {
"update_channel": {
"label": "Aktualizační kanál",
"prerelease": "Předběžná vydání",
"stable": "Stabilní",
"testing": "Testování"
}
},
"Developer": {
"disabling": "Vypínám React DevTools",
"enabling": "Zapínám React DevTools",
"5secreload": "Znovu načtení za 5 vteřin"
},
"FilePickerIndex": {
"folder": {
"select": "Použít tuto složku"
}
},
"PluginView": {
"hidden_one": "1 plugin je v tomto seznamu skrytý",
"hidden_few": "{{count}} pluginů je v tomto seznamu skryto",
"hidden_other": "{{count}} pluginů je v tomto seznamu skryto"
},
"PluginListLabel": {
"hidden": "Skryto z nabídky rychlého přístupu"
},
"PluginCard": {
"plugin_full_access": "Tento plugin má plný přístup k vašemu Steam Decku.",
"plugin_install": "Instalovat",
"plugin_no_desc": "Nebyl uveden žádný popis.",
"plugin_version_label": "Verze pluginu"
},
"PluginInstallModal": {
"install": {
"button_idle": "Instalovat",
"button_processing": "Instalování",
"title": "Instalovat {{artifact}}",
"desc": "Jste si jisti, že chcete nainstalovat {{artifact}} {{version}}?"
},
"no_hash": "Tento plugin nemá hash, instalujete jej na vlastní nebezpečí.",
"reinstall": {
"button_idle": "Přeinstalovat",
"button_processing": "Přeinstalování",
"title": "Přeinstalovat {{artifact}}",
"desc": "Jste si jisti, že chcete přeinstalovat {{artifact}} {{version}}?"
},
"update": {
"button_idle": "Aktualizovat",
"button_processing": "Aktualizování",
"desc": "Jste si jisti, že chcete aktualizovat {{artifact}} {{version}}?",
"title": "Aktualizovat {{artifact}}"
}
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "Upravit 1 plugin",
"mixed_few": "Upravit {{count}} pluginů",
"mixed_other": "Upravit {{count}} pluginů",
"reinstall_one": "Přeinstalovat 1 plugin",
"reinstall_few": "Přeinstalovat {{count}} pluginů",
"reinstall_other": "Přeinstalovat {{count}} pluginů",
"install_one": "Instalovat 1 plugin",
"install_few": "Instalovat {{count}} pluginů",
"install_other": "Instalovat {{count}} pluginů",
"update_one": "Aktualizovat 1 plugin",
"update_few": "Aktualizovat {{count}} pluginů",
"update_other": "Aktualizovat {{count}} pluginů"
},
"ok_button": {
"idle": "Potvrdit",
"loading": "Probíhá"
},
"description": {
"install": "Instalovat {{name}} {{version}}",
"update": "Aktualizovat {{name}} na {{version}}",
"reinstall": "Přeinstalovat {{name}} {{version}}"
},
"confirm": "Jste si jisti, že chcete udělat následující úpravy?"
},
"PluginListIndex": {
"no_plugin": "Nejsou nainstalovány žádné pluginy!",
"plugin_actions": "Akce pluginu",
"reinstall": "Přeinstalovat",
"reload": "Znovu načíst",
"uninstall": "Odinstalovat",
"update_to": "Aktualizovat na {{name}}",
"show": "Rychlý přístup: Zobrazit",
"hide": "Rychlý přístup: Skrýt",
"update_all_one": "Aktualizovat 1 plugin",
"update_all_few": "Aktualizovat {{count}} pluginů",
"update_all_other": "Aktualizovat {{count}} pluginů"
},
"PluginLoader": {
"decky_title": "Decky",
"decky_update_available": "Aktualizace na {{tag_name}} dostupná!",
"error": "Chyba",
"plugin_load_error": {
"message": "Chyba při načítání pluginu {{name}}",
"toast": "Chyba při načítání {{name}}"
},
"plugin_uninstall": {
"button": "Odinstalovat",
"desc": "Opravdu chcete odinstalovat {{name}}?",
"title": "Odinstalovat {{name}}"
},
"plugin_update_one": "Je dostupná aktualizace pro 1 plugin!",
"plugin_update_few": "Jsou dostupné aktualizace pro {{count}} pluginů!",
"plugin_update_other": "Jsou dostupné aktualizace pro {{count}} pluginů!",
"plugin_error_uninstall": "Načítání {{name}} způsobilo chybu uvedenou výše. To obvykle znamená, že plugin vyžaduje aktualizaci SteamUI. Zkontrolujte, zda je aktualizace k dispozici, nebo zvažte odstranění pluginu v nastavení Decky v sekci Pluginy."
},
"SettingsDeveloperIndex": {
"cef_console": {
"button": "Otevřít konzoli",
"label": "CEF konzole",
"desc": "Otevře CEF konzoli. Užitečné pouze pro účely ladění. Věci zde jsou potenciálně nebezpečné a měly by být používány pouze v případě, že jste vývojář pluginů, nebo vás sem nějaký nasměroval."
},
"header": "Ostatní",
"react_devtools": {
"desc": "Umožňuje připojení k počítači, na kterém běží React DevTools. Změnou tohoto nastavení se znovu načte Steam. Před povolením nastavte IP adresu.",
"ip_label": "IP adresa",
"label": "Zapnout React DevTools"
},
"third_party_plugins": {
"button_install": "Instalovat",
"button_zip": "Procházet",
"header": "Pluginy třetí strany",
"label_desc": "URL",
"label_url": "Instalovat plugin z URL",
"label_zip": "Instalovat plugin ze ZIP souboru"
},
"toast_zip": {
"body": "Instalace selhala! Podporovány jsou pouze soubory ZIP.",
"title": "Decky"
},
"valve_internal": {
"desc1": "Zapíná interní vývojářské menu Valve.",
"desc2": "Nedotýkejte se ničeho v této nabídce, pokud nevíte, co děláte.",
"label": "Zapnout Valve Internal"
}
},
"RemoteDebugging": {
"remote_cef": {
"label": "Povolit vzdálené CEF ladění",
"desc": "Umožní neověřený přístup k CEF ladění komukoli ve vaší síti"
}
},
"SettingsGeneralIndex": {
"about": {
"decky_version": "Decky verze",
"header": "O Decky"
},
"beta": {
"header": "Účast v betě"
},
"developer_mode": {
"desc": "Zapíná vývojářské nastavení Decky.",
"label": "Vývojářský režim"
},
"other": {
"header": "Ostatní"
},
"updates": {
"header": "Aktualizace"
}
},
"SettingsIndex": {
"developer_title": "Vývojář",
"general_title": "Obecné",
"navbar_settings": "Nastavení Decky",
"plugins_title": "Pluginy"
},
"Store": {
"store_contrib": {
"label": "Přispívání",
"desc": "Pokud byste chtěli přispět do obchodu Decky Plugin Store, podívejte se na repozitář SteamDeckHomebrew/decky-plugin-template na GitHubu. Informace o vývoji a distribuci jsou k dispozici v README."
},
"store_filter": {
"label": "Filtr",
"label_def": "Vše"
},
"store_search": {
"label": "Hledat"
},
"store_sort": {
"label": "Seřadit",
"label_def": "Naposledy aktualizováno (Nejnovější)"
},
"store_source": {
"desc": "Veškerý zdrojový kód pluginu je dostupný v repozitáři SteamDeckHomebrew/decky-plugin-database na GitHubu.",
"label": "Zdrojový kód"
},
"store_tabs": {
"about": "O Decky Plugin Store",
"alph_asce": "Abecedně (Z do A)",
"alph_desc": "Abecedně (A do Z)",
"title": "Procházet"
},
"store_testing_cta": "Zvažte prosím testování nových pluginů, pomůžete tím týmu Decky Loader!"
},
"StoreSelect": {
"custom_store": {
"label": "Vlastní obchod",
"url_label": "URL"
},
"store_channel": {
"custom": "Vlastní",
"default": "Výchozí",
"label": "Kanál obchodu",
"testing": "Testování"
}
},
"Updater": {
"updates": {
"lat_version": "Aktuální: běží na verzi {{ver}}",
"reloading": "Znovu načítání",
"updating": "Aktualizování",
"check_button": "Zkontrolovat aktualizace",
"checking": "Kontrolování",
"cur_version": "Aktuální verze: {{ver}}",
"install_button": "Instalovat aktualizaci",
"label": "Aktualizace"
},
"decky_updates": "Aktualizace Decky",
"patch_notes_desc": "Poznámky k verzi",
"no_patch_notes_desc": "žádné poznámky pro tuto verzi"
}
}
+19 -1
View File
@@ -50,7 +50,9 @@
"reinstall": "Neu installieren",
"reload": "Neu laden",
"uninstall": "Deinstallieren",
"update_to": "Aktualisieren zu {{name}}"
"update_to": "Aktualisieren zu {{name}}",
"update_all_one": "",
"update_all_other": ""
},
"PluginLoader": {
"decky_title": "Decky",
@@ -179,5 +181,21 @@
"updating": "Aktualisiere"
},
"no_patch_notes_desc": "Für diese Version gibt es keine Patchnotizen"
},
"PluginView": {
"hidden_one": "",
"hidden_other": ""
},
"MultiplePluginsInstallModal": {
"title": {
"install_one": "",
"install_other": "",
"mixed_one": "",
"mixed_other": "",
"update_one": "",
"update_other": "",
"reinstall_one": "",
"reinstall_other": ""
}
}
}
+22 -2
View File
@@ -69,7 +69,9 @@
"reinstall": "Επανεγκατάσταση",
"reload": "Επαναφόρτωση",
"uninstall": "Απεγκατάσταση",
"update_to": "Ενημέρωση σε {{name}}"
"update_to": "Ενημέρωση σε {{name}}",
"update_all_one": "",
"update_all_other": ""
},
"PluginLoader": {
"decky_title": "Decky",
@@ -84,7 +86,9 @@
"button": "Απεγκατάσταση",
"desc": "Σίγουρα θέλετε να απεγκαταστήσετε το {{name}};",
"title": "Απεγκατάσταση {{name}}"
}
},
"plugin_update_one": "",
"plugin_update_other": ""
},
"RemoteDebugging": {
"remote_cef": {
@@ -176,5 +180,21 @@
"folder": {
"select": "Χρησιμοποιήστε αυτό το φάκελο"
}
},
"PluginView": {
"hidden_one": "",
"hidden_other": ""
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "",
"mixed_other": "",
"update_one": "",
"update_other": "",
"reinstall_one": "",
"reinstall_other": "",
"install_one": "",
"install_other": ""
}
}
}
+41 -4
View File
@@ -12,11 +12,46 @@
"disabling": "Disabling React DevTools",
"enabling": "Enabling React DevTools"
},
"FilePickerIndex": {
"folder": {
"select": "Use this folder"
"DropdownMultiselect": {
"button": {
"back": "Back"
}
},
"FilePickerError": {
"errors": {
"file_not_found": "The path specified is not valid. Please check it and reenter it correctly.",
"unknown": "An unknown error occurred. The raw error is: {{raw_error}}"
}
},
"FilePickerIndex": {
"files": {
"all_files": "All Files",
"file_type": "File Type",
"show_hidden": "Show Hidden Files"
},
"filter": {
"created_asce": "Created (Oldest)",
"created_desc": "Created (Newest)",
"modified_asce": "Modified (Oldest)",
"modified_desc": "Modified (Newest)",
"name_asce": "Z-A",
"name_desc": "A-Z",
"size_asce": "Size (Smallest)",
"size_desc": "Size (Largest)"
},
"folder": {
"label": "Folder",
"select": "Use this folder",
"show_more": "Show more files"
}
},
"PluginView": {
"hidden_one": "1 plugin is hidden from this list",
"hidden_other": "{{count}} plugins are hidden from this list"
},
"PluginListLabel": {
"hidden": "Hidden from the quick access menu"
},
"PluginCard": {
"plugin_full_access": "This plugin has full access to your Steam Deck.",
"plugin_install": "Install",
@@ -46,7 +81,7 @@
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "Modify 1 plugin",
"mixed_one": "Modify {{count}} plugin",
"mixed_other": "Modify {{count}} plugins",
"update_one": "Update 1 plugin",
"update_other": "Update {{count}} plugins",
@@ -73,6 +108,8 @@
"reload": "Reload",
"uninstall": "Uninstall",
"update_to": "Update to {{name}}",
"show": "Quick access: Show",
"hide": "Quick access: Hide",
"update_all_one": "Update 1 plugin",
"update_all_other": "Update {{count}} plugins"
},
+136 -26
View File
@@ -2,45 +2,72 @@
"SettingsDeveloperIndex": {
"third_party_plugins": {
"button_install": "Instalar",
"button_zip": "Navegar"
"button_zip": "Navegar",
"label_desc": "URL",
"label_url": "Instalar plugin desde URL",
"label_zip": "Instalar plugin desde archivo ZIP",
"header": "Plugins de terceros"
},
"valve_internal": {
"desc2": "No toque nada en este menú a menos que sepa lo que hace."
"desc2": "No toques nada en este menú a menos que sepas lo que haces.",
"label": "Activar menú interno de Valve",
"desc1": "Activa el menú interno de desarrollo de Valve."
},
"toast_zip": {
"title": "Decky"
}
"title": "Decky",
"body": "¡Ha fallado la instalación! Solo se permiten archivos ZIP."
},
"cef_console": {
"button": "Abrir consola",
"label": "Consola CEF",
"desc": "Abre la consola del CEF. Solamente es útil para propósitos de depuración. Las cosas que hagas aquí pueden ser potencialmente peligrosas y solo se debería usar si eres un desarrollador de plugins, o uno te ha dirigido aquí."
},
"react_devtools": {
"ip_label": "IP",
"label": "Activar DevTools de React",
"desc": "Permite la conexión a un ordenador ejecutando las DevTools de React. Cambiar este ajuste recargará Steam. Configura la dirección IP antes de activarlo."
},
"header": "Otros"
},
"PluginInstallModal": {
"install": {
"button_idle": "Instalar",
"button_processing": "Instalando"
"button_processing": "Instalando",
"title": "Instalar {{artifact}}",
"desc": "¿Estás seguro de que quieres instalar {{artifact}} {{version}}?"
},
"reinstall": {
"button_idle": "Reinstalar",
"button_processing": "Reinstalando"
"button_processing": "Reinstalando",
"desc": "¿Estás seguro de que quieres reinstalar {{artifact}} {{version}}?",
"title": "Reinstalar {{artifact}}"
},
"update": {
"button_processing": "Actualizando",
"button_idle": "Actualizar"
}
"button_idle": "Actualizar",
"desc": "¿Estás seguro de que quieres actualizar {{artifact}} {{version}}?",
"title": "Actualizar {{artifact}}"
},
"no_hash": "Este plugin no tiene un hash, lo estás instalando bajo tu propia responsabilidad."
},
"Developer": {
"disabling": "Desactivando",
"enabling": "Activando",
"disabling": "Desactivando DevTools de React",
"enabling": "Activando DevTools de React",
"5secreload": "Recargando en 5 segundos"
},
"BranchSelect": {
"update_channel": {
"prerelease": "Prelanzamiento",
"stable": "Estable",
"label": "Canal de actualización"
"label": "Canal de actualización",
"testing": "Pruebas"
}
},
"PluginCard": {
"plugin_full_access": "Este plugin tiene acceso completo a su Steam Deck.",
"plugin_install": "Instalar",
"plugin_version_label": "Versión de Plugin"
"plugin_version_label": "Versión de Plugin",
"plugin_no_desc": "No se proporcionó una descripción."
},
"FilePickerIndex": {
"folder": {
@@ -51,19 +78,35 @@
"uninstall": "Desinstalar",
"reinstall": "Reinstalar",
"reload": "Recargar",
"plugin_actions": "Acciónes de Plugin",
"no_plugin": "¡No hay plugins instalados!"
"plugin_actions": "Acciones de plugin",
"no_plugin": "¡No hay plugins instalados!",
"update_all_one": "Actualizar 1 plugin",
"update_all_many": "Actualizar {{count}} plugins",
"update_all_other": "Actualizar {{count}} plugins",
"update_to": "Actualizar a {{name}}"
},
"PluginLoader": {
"error": "Error",
"plugin_uninstall": {
"button": "Desinstalar"
"button": "Desinstalar",
"desc": "¿Estás seguro de que quieres desinstalar {{name}}?",
"title": "Desinstalar {{name}}"
},
"decky_title": "Decky"
"decky_title": "Decky",
"plugin_update_one": "¡Actualización disponible para 1 plugin!",
"plugin_update_many": "¡Actualizaciones disponibles para {{count}} plugins!",
"plugin_update_other": "¡Actualizaciones disponibles para {{count}} plugins!",
"decky_update_available": "¡Actualización {{tag_name}} disponible!",
"plugin_load_error": {
"message": "Se ha producido un error al cargar el plugin {{name}}",
"toast": "Se ha producido un error al cargar {{name}}"
},
"plugin_error_uninstall": "Al cargar {{name}} se ha producido una excepción como se muestra arriba. Esto suele significar que el plugin requiere una actualización para la nueva versión de SteamUI. Comprueba si hay una actualización disponible o valora eliminarlo en los ajustes de Decky, en la sección Plugins."
},
"RemoteDebugging": {
"remote_cef": {
"desc": "Permitir acceso no autenticado al CEF debugger a cualquier persona en su red"
"desc": "Permitir acceso no autenticado al CEF debugger a cualquier persona en su red",
"label": "Permitir depuración remota del CEF"
}
},
"SettingsGeneralIndex": {
@@ -71,10 +114,18 @@
"header": "Actualizaciones"
},
"about": {
"header": "Información"
"header": "Acerca de",
"decky_version": "Versión de Decky"
},
"developer_mode": {
"label": "Modo Desarrollador"
"label": "Modo desarrollador",
"desc": "Activa los ajustes de desarrollador de Decky."
},
"beta": {
"header": "Participación en la beta"
},
"other": {
"header": "Otros"
}
},
"SettingsIndex": {
@@ -88,26 +139,85 @@
"label": "Buscar"
},
"store_sort": {
"label": "Ordenar"
"label": "Ordenar",
"label_def": "Actualizado por última vez (Nuevos)"
},
"store_contrib": {
"desc": "Si desea contribuir a la Tienda de Decky Plugin, revise el repositorio SteamDeckHomebrew/decky-plugin-template en GitHub. Información acerca del desarrollo y distribución está disponible en al archivo README.",
"desc": "Si desea contribuir a la tienda de plugins de Decky, mira el repositorio SteamDeckHomebrew/decky-plugin-template en GitHub. Hay información acerca del desarrollo y distribución en el archivo README.",
"label": "Contribuyendo"
},
"store_tabs": {
"about": "Información",
"title": "Navegar"
"title": "Navegar",
"alph_asce": "Alfabéticamente (Z-A)",
"alph_desc": "Alfabéticamente (A-Z)"
},
"store_testing_cta": "¡Por favor considera probando plugins nuevos para ayudar al equipo de Decky Loader!"
"store_testing_cta": "¡Por favor considera probar plugins nuevos para ayudar al equipo de Decky Loader!",
"store_source": {
"desc": "El código fuente de los plugins está disponible en el repositiorio SteamDeckHomebrew/decky-plugin-database en GitHub.",
"label": "Código fuente"
},
"store_filter": {
"label_def": "Todos",
"label": "Filtrar"
}
},
"Updater": {
"updates": {
"reloading": "Recargando",
"updating": "Actualizando",
"checking": "Buscando",
"check_button": "Buscar Actualizaciones",
"install_button": "Instalar Actualización",
"label": "Actualizaciones"
"check_button": "Buscar actualizaciones",
"install_button": "Instalar actualización",
"label": "Actualizaciones",
"lat_version": "Actualizado: ejecutando {{ver}}",
"cur_version": "Versión actual: {{ver}}"
},
"decky_updates": "Actualizaciones de Decky",
"no_patch_notes_desc": "No hay notas de parche para esta versión",
"patch_notes_desc": "Notas de parche"
},
"MultiplePluginsInstallModal": {
"title": {
"reinstall_one": "Reinstalar 1 plugin",
"reinstall_many": "Reinstalar {{count}} plugins",
"reinstall_other": "Reinstalar {{count}} plugins",
"update_one": "Actualizar 1 plugin",
"update_many": "Actualizar {{count}} plugins",
"update_other": "Actualizar {{count}} plugins",
"mixed_one": "Modificar 1 plugin",
"mixed_many": "Modificar {{count}} plugins",
"mixed_other": "Modificar {{count}} plugins",
"install_one": "Instalar 1 plugin",
"install_many": "Instalar {{count}} plugins",
"install_other": "Instalar {{count}} plugins"
},
"ok_button": {
"idle": "Confirmar",
"loading": "Trabajando"
},
"confirm": "¿Estás seguro de que quieres hacer las siguientes modificaciones?",
"description": {
"install": "Instalar {{name}} {{version}}",
"update": "Actualizar {{name}} a {{version}}",
"reinstall": "Reinstalar {{name}} {{version}}"
}
},
"StoreSelect": {
"custom_store": {
"url_label": "URL",
"label": "Tienda personalizada"
},
"store_channel": {
"custom": "Personalizada",
"default": "Por defecto",
"label": "Canál de la tienda",
"testing": "Pruebas"
}
},
"PluginView": {
"hidden_one": "",
"hidden_many": "",
"hidden_other": ""
}
}
+26 -2
View File
@@ -101,12 +101,15 @@
"reload": "Recharger",
"uninstall": "Désinstaller",
"update_to": "Mettre à jour vers {{name}}",
"no_plugin": "Aucun plugin installé !"
"no_plugin": "Aucun plugin installé !",
"update_all_one": "",
"update_all_many": "",
"update_all_other": ""
},
"PluginLoader": {
"decky_title": "Decky",
"error": "Erreur",
"plugin_error_uninstall": "Allez sur <0></0> dans le menu de Decky si vous voulez désinstaller ce plugin.",
"plugin_error_uninstall": "Allez sur {{name}} dans le menu de Decky si vous voulez désinstaller ce plugin.",
"plugin_load_error": {
"message": "Erreur lors du chargement du plugin {{name}}",
"toast": "Erreur lors du chargement de {{name}}"
@@ -179,5 +182,26 @@
"title": "Explorer"
},
"store_testing_cta": "Pensez à tester de nouveaux plugins pour aider l'équipe Decky Loader !"
},
"PluginView": {
"hidden_one": "",
"hidden_many": "",
"hidden_other": ""
},
"MultiplePluginsInstallModal": {
"title": {
"reinstall_one": "",
"reinstall_many": "",
"reinstall_other": "",
"install_one": "",
"install_many": "",
"install_other": "",
"mixed_one": "",
"mixed_many": "",
"mixed_other": "",
"update_one": "",
"update_many": "",
"update_other": ""
}
}
}
+47 -4
View File
@@ -8,13 +8,41 @@
}
},
"Developer": {
"5secreload": "Ricarico in 5 secondi",
"5secreload": "Ricarico tra 5 secondi",
"disabling": "Disabilito i tools di React",
"enabling": "Abilito i tools di React"
},
"DropdownMultiselect": {
"button": {
"back": "Indietro"
}
},
"FilePickerError": {
"errors": {
"file_not_found": "Il percorso specificato non è valido. Controllalo e prova a reinserirlo di nuovo.",
"unknown": "È avvenuto un'errore sconosciuto. L'errore segnalato è {{raw_error}}"
}
},
"FilePickerIndex": {
"files": {
"all_files": "Tutti i file",
"file_type": "Tipo di file",
"show_hidden": "Mostra nascosti"
},
"filter": {
"created_asce": "Creazione (meno recente)",
"created_desc": "Creazione (più recente)",
"modified_asce": "Modifica (meno recente)",
"modified_desc": "Modifica (più recente)",
"name_asce": "Z-A",
"name_desc": "A-Z",
"size_asce": "Dimensione (più piccolo)",
"size_desc": "Dimensione (più grande)"
},
"folder": {
"select": "Usa questa cartella"
"label": "Cartella",
"select": "Usa questa cartella",
"show_more": "Mostra più file"
}
},
"PluginCard": {
@@ -53,7 +81,9 @@
"update_to": "Aggiorna a {{name}}",
"update_all_one": "Aggiorna un plugin",
"update_all_many": "Aggiorna {{count}} plugins",
"update_all_other": "Aggiorna {{count}} plugins"
"update_all_other": "Aggiorna {{count}} plugins",
"show": "Accesso rapido: Mostra",
"hide": "Accesso rapido: Nascondi"
},
"PluginLoader": {
"decky_title": "Decky",
@@ -82,7 +112,7 @@
"SettingsDeveloperIndex": {
"header": "Altro",
"react_devtools": {
"desc": "Abilita la connessione ad un computer che esegue i DevTools di React. Cambiando questa impostazione ricaricherà Steam. Imposta l'indirizzo IP prima di abilitarlo.",
"desc": "Abilita la connessione ad un computer che esegue i DevTools di React. Steam verrà ricaricato se lo stato cambia. Imposta il tuo indirizzo IP prima di abilitarlo.",
"ip_label": "IP",
"label": "Abilita i DevTools di React"
},
@@ -102,6 +132,11 @@
"desc1": "Abilita il menu di sviluppo interno di Valve.",
"desc2": "Non toccare nulla in questo menu se non sai quello che fa.",
"label": "Abilita Menu Sviluppatore"
},
"cef_console": {
"label": "Console CEF",
"button": "Apri la console",
"desc": "Apri la console di CEF. Utile solamente per ragioni di debug. Questa opzione deve essere usata solo se sei uno sviluppatore di plugin o se uno di questi ti ha chiesto di farlo, visto che questa feature potrebbe essere potenzialmente pericolosa."
}
},
"SettingsGeneralIndex": {
@@ -209,5 +244,13 @@
"update": "Aggiorna {{name}} alla versione {{version}}",
"reinstall": "Reinstalla {{name}} {{version}}"
}
},
"PluginView": {
"hidden_one": "Un plugin è nascosto dalla lista",
"hidden_many": "Sono nascosti {{count}} plugin dalla lista",
"hidden_other": "Sono nascosti {{count}} plugin dalla lista"
},
"PluginListLabel": {
"hidden": "Nascosti dal menu di accesso rapido"
}
}
+214
View File
@@ -0,0 +1,214 @@
{
"BranchSelect": {
"update_channel": {
"label": "업데이트 배포 채널",
"stable": "안정판",
"testing": "시험판",
"prerelease": "사전 출시판"
}
},
"Developer": {
"disabling": "React DevTools 비활성화",
"enabling": "React DevTools 활성화",
"5secreload": "5초 내로 다시 로드 됩니다"
},
"FilePickerIndex": {
"folder": {
"select": "이 폴더 사용"
}
},
"PluginView": {
"hidden_other": "플러그인 {{count}}개 숨김"
},
"PluginListLabel": {
"hidden": "빠른 액세스 메뉴에서 숨김"
},
"PluginCard": {
"plugin_install": "설치",
"plugin_no_desc": "플러그인 설명이 제공되지 않았습니다.",
"plugin_version_label": "플러그인 버전",
"plugin_full_access": "이 플러그인은 Steam Deck의 모든 접근 권한을 가집니다."
},
"PluginInstallModal": {
"install": {
"button_idle": "설치",
"button_processing": "설치 중",
"desc": "{{artifact}} {{version}}을(를) 설치하겠습니까?",
"title": "{{artifact}} 설치"
},
"reinstall": {
"button_idle": "재설치",
"button_processing": "재설치 중",
"desc": "{{artifact}} {{version}}을(를) 재설치하겠습니까?",
"title": "{{artifact}} 재설치"
},
"update": {
"button_idle": "업데이트",
"button_processing": "업데이트 중",
"title": "{{artifact}} 업데이트",
"desc": "{{artifact}} {{version}} 업데이트를 설치하겠습니까?"
},
"no_hash": "이 플러그인은 해시 확인을 하지 않습니다, 설치에 따른 위험은 사용자가 감수해야 합니다."
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_other": "플러그인 {{count}}개 수정",
"update_other": "플러그인 {{count}}개 업데이트",
"reinstall_other": "플러그인 {{count}}개 재설치",
"install_other": "플러그인 {{count}}개 설치"
},
"ok_button": {
"idle": "확인",
"loading": "작업 중"
},
"confirm": "해당 수정을 적용하겠습니까?",
"description": {
"install": "{{name}} {{version}} 플러그인 설치",
"update": "{{name}}의 {{version}} 업데이트 설치",
"reinstall": "{{name}} {{version}} 재설치"
}
},
"PluginListIndex": {
"plugin_actions": "플러그인 동작",
"reinstall": "재설치",
"reload": "다시 로드",
"uninstall": "설치 제거",
"show": "빠른 액세스 메뉴: 표시",
"hide": "빠른 액세스 메뉴: 숨김",
"update_all_other": "플러그인 {{count}}개 업데이트",
"no_plugin": "설치된 플러그인이 없습니다!",
"update_to": "{{name}}(으)로 업데이트"
},
"PluginLoader": {
"decky_title": "Decky",
"decky_update_available": "{{tag_name}} 업데이트를 설치할 수 있습니다!",
"error": "오류",
"plugin_load_error": {
"message": "{{name}} 플러그인 불러오기 오류",
"toast": "{{name}} 불러오기 오류"
},
"plugin_uninstall": {
"button": "설치 제거",
"desc": "{{name}}을(를) 설치 제거하겠습니까?",
"title": "{{name}} 설치 제거"
},
"plugin_update_other": "플러그인 {{count}}개를 업데이트 할 수 있습니다!",
"plugin_error_uninstall": "{{name}} 플러그인을 불러올 때 위와 같은 예외가 발생했습니다. 이는 보통 SteamUI 최신 버전에 맞는 플러그인 업데이트가 필요할 때 발생합니다. Decky 설정의 플러그인 항목에서 업데이트가 있는지 확인하거나 설치 제거를 시도 해 보세요."
},
"RemoteDebugging": {
"remote_cef": {
"label": "리모트 CEF 디버그 허용",
"desc": "네트워크의 모든 사용자에게 CEF 디버거에 대한 인증되지 않은 액세스 허용"
}
},
"SettingsDeveloperIndex": {
"cef_console": {
"button": "콘솔 열기",
"label": "CEF 콘솔",
"desc": "CEF 콘솔을 엽니다. 디버그 전용입니다. 이 항목들은 위험 가능성이 있으므로 플러그인 개발자이거나 개발자의 가이드를 따를 경우에만 사용해야 합니다."
},
"header": "기타",
"react_devtools": {
"ip_label": "IP",
"label": "React DevTools 활성화",
"desc": "React DevTools를 실행하고 있는 컴퓨터에 연결을 활성화합니다. 이 설정을 변경하면 Steam이 다시 로드됩니다. 활성화하기 전에 IP 주소를 설정하세요."
},
"third_party_plugins": {
"button_install": "설치",
"button_zip": "검색",
"header": "서드파티 플러그인",
"label_desc": "URL",
"label_url": "URL에서 플러그인 설치",
"label_zip": "ZIP 파일에서 플러그인 설치"
},
"toast_zip": {
"body": "설치를 실패했습니다! ZIP 파일만이 지원됩니다.",
"title": "Decky"
},
"valve_internal": {
"desc1": "Valve 내부 개발자 메뉴를 활성화합니다.",
"label": "Valve 내부 개발자 메뉴 활성화",
"desc2": "이 메뉴의 기능을 모른다면 어떤 것도 건드리지 마세요."
}
},
"SettingsGeneralIndex": {
"about": {
"decky_version": "Decky 버전",
"header": "정보"
},
"beta": {
"header": "베타 참가"
},
"developer_mode": {
"desc": "Decky의 개발자 설정을 활성화합니다.",
"label": "개발자 모드"
},
"other": {
"header": "기타"
},
"updates": {
"header": "업데이트"
}
},
"SettingsIndex": {
"developer_title": "개발자",
"general_title": "일반",
"navbar_settings": "Decky 설정",
"plugins_title": "플러그인"
},
"Store": {
"store_contrib": {
"desc": "Decky 플러그인 스토어에 기여하고 싶다면 SteamDeckHomebrew/decky-plugin-template Github 저장소를 확인하세요. 개발 및 배포에 대한 정보는 README에서 확인할 수 있습니다.",
"label": "기여하기"
},
"store_filter": {
"label": "필터",
"label_def": "모두"
},
"store_search": {
"label": "검색"
},
"store_sort": {
"label": "정렬",
"label_def": "최근 업데이트 순"
},
"store_source": {
"desc": "모든 플러그인 소스 코드는 SteamDeckHomebrew/decky-plugin-database Github 저장소에서 확인할 수 있습니다.",
"label": "소스 코드"
},
"store_tabs": {
"about": "정보",
"alph_asce": "알파벳순 (Z-A)",
"alph_desc": "알파벳순 (A-Z)",
"title": "검색"
},
"store_testing_cta": "새로운 플러그인을 테스트하여 Decky Loader 팀을 도와주세요!"
},
"StoreSelect": {
"custom_store": {
"label": "사용자 지정 스토어",
"url_label": "URL"
},
"store_channel": {
"custom": "사용자 지정",
"label": "스토어 배포 채널",
"default": "기본",
"testing": "시험"
}
},
"Updater": {
"decky_updates": "Decky 업데이트",
"no_patch_notes_desc": "이 버전에는 패치 노트가 없습니다",
"patch_notes_desc": "패치 노트",
"updates": {
"check_button": "업데이트 확인",
"checking": "확인 중",
"cur_version": "현재 버전: {{ver}}",
"install_button": "업데이트 설치",
"label": "업데이트",
"lat_version": "최신 상태: {{ver}} 실행 중",
"reloading": "다시 로드 중",
"updating": "업데이트 중"
}
}
}
+228
View File
@@ -0,0 +1,228 @@
{
"BranchSelect": {
"update_channel": {
"prerelease": "Pré-lançamento",
"stable": "Estável",
"testing": "Em Teste",
"label": "Canal de Atualização"
}
},
"Developer": {
"5secreload": "Recarregando em 5 segundos",
"enabling": "Habilitando React DevTools",
"disabling": "Desabilitando React DevTools"
},
"FilePickerIndex": {
"folder": {
"select": "Use esta pasta"
}
},
"PluginListLabel": {
"hidden": "Oculto no menu de acesso rápido"
},
"PluginCard": {
"plugin_full_access": "Este plugin tem acesso total ao seu Steam Deck.",
"plugin_install": "Instalar",
"plugin_no_desc": "Nenhuma descrição fornecida.",
"plugin_version_label": "Versão do plugin"
},
"PluginInstallModal": {
"install": {
"button_idle": "Instalar",
"button_processing": "Instalando",
"desc": "Você tem certeza que deseja instalar {{artifact}} {{version}}?",
"title": "Instalar {{artifact}}"
},
"reinstall": {
"button_idle": "Reinstalar",
"button_processing": "Reinstalando",
"desc": "Tem certeza que voce deseja reinstalar {{artifact}} {{version}}?",
"title": "Reinstalar {{artifact}}"
},
"update": {
"button_idle": "Atualizar",
"button_processing": "Atualizando",
"desc": "Tem certeza que voce deseja atualizar {{artifact}} {{version}}?",
"title": "Atualizar {{artifact}}"
},
"no_hash": "Este plugin não tem um hash, você o está instalando por sua conta em risco."
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "Modificar 1 plugin",
"mixed_many": "Modificar {{count}} plugins",
"mixed_other": "Modificar {{count}} plugins",
"update_one": "Atualizar 1 plugin",
"update_many": "Atualizar {{count}} plugins",
"update_other": "Atualizar {{count}} plugins",
"install_one": "Instalar 1 plugin",
"install_many": "Instalar {{count}} plugins",
"install_other": "Instalar {{count}} plugins",
"reinstall_one": "Reinstalar 1 plugin",
"reinstall_many": "Reinstalar {{count}} plugins",
"reinstall_other": "Reinstalar {{count}} plugins"
},
"ok_button": {
"idle": "Confirmar",
"loading": "Carregando"
},
"description": {
"install": "Instalar {{name}} {{version}}",
"update": "Atualizar {{name}} para {{version}}",
"reinstall": "Reinstalar {{name}} {{version}}"
},
"confirm": "Tem certeza que deseja fazer as seguintes modificações?"
},
"PluginListIndex": {
"no_plugin": "Nenhum plugin instalado!",
"plugin_actions": "Ações do plugin",
"reinstall": "Reinstalar",
"reload": "Recarregar",
"uninstall": "Desinstalar",
"update_to": "Atualizar para {{name}}",
"show": "Acesso Rápido: Mostrar",
"update_all_one": "Atualizar 1 plugin",
"update_all_many": "Atualizar {{count}} plugins",
"update_all_other": "Atualizar {{count}} plugins",
"hide": "Acesso Rápido: Ocultar"
},
"PluginLoader": {
"decky_title": "Decky",
"error": "Erro",
"plugin_load_error": {
"message": "Erro ao carregar o plugin {{name}}",
"toast": "Erro ao carregar {{name}}"
},
"plugin_uninstall": {
"button": "Desinstalar",
"desc": "Você tem certeza que deseja desinstalar {{name}}?",
"title": "Desinstalar {{name}}"
},
"decky_update_available": "Atualização para {{tag_name}} disponível!",
"plugin_error_uninstall": "Um erro aconteceu ao carregar {{name}}, como mostrado acima. Isso normalmente significa que o plugin precisa de uma atualização para a nova versão do SteamUI. Confira se existe uma atualização ou avalie a remoção do plugin nas configurações do Decky, na sessão de plugins.",
"plugin_update_one": "Atualizações disponível para 1 plugin!",
"plugin_update_many": "Atualizações disponíveis para {{count}} plugins!",
"plugin_update_other": "Atualizações disponíveis para {{count}} plugins!"
},
"RemoteDebugging": {
"remote_cef": {
"label": "Permitir Depuração CEF Demota",
"desc": "Permitir acesso não autenticato ao depurador CEF para qualquer um na sua rede"
}
},
"SettingsDeveloperIndex": {
"cef_console": {
"button": "Abrir o Console",
"label": "Console CEF",
"desc": "Abre o Console CEF. Somente útil para fins de depuração. O material aqui é potencialmente perigoso e só deve ser usado se você for um desenvolvedor de plugin, ou direcionado até aqui por um."
},
"header": "Outros",
"react_devtools": {
"desc": "Habilita a conexão a um computador executando React DevTools. Alterar essa configuração irá recarregar a Steam. Defina o endereço IP antes de habilitar.",
"ip_label": "IP",
"label": "Habilitar React DevTools"
},
"third_party_plugins": {
"button_install": "Instalar",
"button_zip": "Navegar",
"header": "Plugins de terceiros",
"label_url": "Instalar Plugin a partir da URL",
"label_zip": "Instalar Plugin a partir de um arquivo ZIP",
"label_desc": "URL"
},
"toast_zip": {
"title": "Decky",
"body": "Falha na instalação! Somente arquivos ZIP são suportados."
},
"valve_internal": {
"desc1": "Habilita o menu interno de desenvolvedor da Valve.",
"desc2": "Não toque em nada neste menu, a não ser que você saiba o que está fazendo.",
"label": "Habilitar Menu Interno da Valve"
}
},
"SettingsGeneralIndex": {
"about": {
"decky_version": "Versão do Decky",
"header": "Sobre"
},
"developer_mode": {
"desc": "Habilita as configurações de desenvolvedor do Decky.",
"label": "Modo Deselvolvedor"
},
"other": {
"header": "Outros"
},
"updates": {
"header": "Atualizações"
},
"beta": {
"header": "Participação no Beta"
}
},
"SettingsIndex": {
"developer_title": "Desenvolvedor",
"general_title": "Geral",
"navbar_settings": "Configurações do Decky",
"plugins_title": "Plugins"
},
"Store": {
"store_contrib": {
"label": "Contribuindo",
"desc": "Se você deseja contribuir para a Loja de Plugins para o Decky, confira o repositório SteamDeckHomebrew/decky-plugin-template no GitHub. Informações sobre o desenvolvimento e distribuição estão disponíveis no README."
},
"store_filter": {
"label": "Filtros",
"label_def": "Todos"
},
"store_search": {
"label": "Buscar"
},
"store_sort": {
"label": "Ordenar",
"label_def": "Último atualizado (Mais recente)"
},
"store_source": {
"desc": "Todos os codigo fonte dos plugins estão disponíveis no repositório SteamDeckHomebrew/decky-plugin-database no GitHub.",
"label": "Código Fonte"
},
"store_tabs": {
"about": "Sobre",
"alph_desc": "Alfabética (A - Z)",
"title": "Navegar",
"alph_asce": "Alfabética (Z - A)"
},
"store_testing_cta": "Por favor, considere testar os novos plugins para ajudar o time do Decky Loader!"
},
"StoreSelect": {
"custom_store": {
"label": "Loja Personalizada",
"url_label": "URL"
},
"store_channel": {
"custom": "Personalizada",
"default": "Padrão",
"label": "Canal da Loja",
"testing": "Em Teste"
}
},
"Updater": {
"no_patch_notes_desc": "nenhuma nota de alteração para esta versão",
"patch_notes_desc": "Notas de alteração",
"updates": {
"check_button": "Buscar Atualizações",
"checking": "Buscando",
"cur_version": "Versão atual: {{ver}}",
"install_button": "Instalar Atualização",
"label": "Atualizações",
"lat_version": "Atualizado: rodando {{ver}}",
"reloading": "Recarregando",
"updating": "Atualizando"
},
"decky_updates": "Atualizações do Decky"
},
"PluginView": {
"hidden_one": "1 plugin está oculto nesta lista",
"hidden_many": "{{count}} plugins estão ocultos nesta lista",
"hidden_other": "{{count}} plugins estão ocultos nesta lista"
}
}
+228
View File
@@ -0,0 +1,228 @@
{
"FilePickerIndex": {
"folder": {
"select": "Usar esta pasta"
}
},
"PluginView": {
"hidden_one": "1 plugin está oculto desta lista",
"hidden_many": "{{count}} plugins estão ocultos desta lista",
"hidden_other": "{{count}} plugins estão ocultos desta lista"
},
"PluginCard": {
"plugin_full_access": "Este plugin tem acesso total à tua Steam Deck.",
"plugin_install": "Instalar",
"plugin_version_label": "Versão do plugin",
"plugin_no_desc": "Não tem descrição."
},
"PluginInstallModal": {
"install": {
"button_idle": "Instalar",
"button_processing": "Instalação em curso",
"title": "Instalar {{artifact}}",
"desc": "De certeza que queres instalar {{artifact}} {{version}}?"
},
"reinstall": {
"button_idle": "Reinstalar",
"button_processing": "Reinstalação em curso",
"title": "Reinstalar {{artifact}}",
"desc": "De certeza que queres reinstalar {{artifact}} {{version}}?"
},
"update": {
"button_idle": "Actualizar",
"button_processing": "Actualização em curso",
"title": "Actualizar {{artifact}}",
"desc": "De certeza que queres actualizar {{artifact}} {{version}}?"
},
"no_hash": "Este plugin não tem um hash, estás a instalá-lo por tua conta e risco."
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "Alterar 1 plugin",
"mixed_many": "Alterar {{count}} plugins",
"mixed_other": "Alterar {{count}} plugins",
"update_one": "Actualizar 1 plugin",
"update_many": "Actualizar {{count}} plugins",
"update_other": "Actualizar {{count}} plugins",
"reinstall_one": "Reinstalar 1 plugin",
"reinstall_many": "Reinstalar {{count}} plugins",
"reinstall_other": "Reinstalar {{count}} plugins",
"install_one": "Instalar 1 plugin",
"install_many": "Instalar {{count}} plugins",
"install_other": "Instalar {{count}} plugins"
},
"ok_button": {
"idle": "Confirmar",
"loading": "Em curso"
},
"description": {
"install": "Instalar {{name}} {{version}}",
"update": "Actualizar {{name}} para {{version}}",
"reinstall": "Reinstalar {{name}} {{version}}"
},
"confirm": "De certeza que queres fazer as seguintes alterações?"
},
"PluginListIndex": {
"no_plugin": "Nenhum plugin instalado!",
"reinstall": "Reinstalar",
"uninstall": "Desinstalar",
"update_to": "Actualizar para {{name}}",
"update_all_one": "Actualizar 1 plugin",
"update_all_many": "Actualizar {{count}} plugins",
"update_all_other": "Actualizar {{count}} plugins",
"plugin_actions": "Operações de plugin",
"reload": "Recarregar",
"show": "Acesso rápido: Mostrar",
"hide": "Acesso rápido: Ocultar"
},
"BranchSelect": {
"update_channel": {
"stable": "Estável",
"testing": "Em teste",
"label": "Canal de actualização",
"prerelease": "Pré-lançamento"
}
},
"Developer": {
"5secreload": "Vai recarregar em 5 segundos",
"disabling": "Desactivando React DevTools",
"enabling": "Activando React DevTools"
},
"PluginListLabel": {
"hidden": "Oculto do menu de acesso rápido"
},
"PluginLoader": {
"decky_title": "Decky",
"error": "Erro",
"plugin_load_error": {
"message": "Erro ao carregar o plugin {{name}}",
"toast": "Erro ao carregar {{name}}"
},
"plugin_uninstall": {
"button": "Desinstalar",
"title": "Desinstalar {{name}}",
"desc": "De certeza que queres desinstalar {{name}}?"
},
"decky_update_available": "Está disponível uma nova versão de {{tag_name}} !",
"plugin_update_one": "1 plugin tem actualizações disponíveis!",
"plugin_update_many": "{{count}} plugins têm actualizações disponíveis!",
"plugin_update_other": "{{count}} plugins têm actualizações disponíveis!",
"plugin_error_uninstall": "Houve uma excepção ao carregar {{name}}, como mostrado em cima. Pode ter sido porque o plugin requere a última versão do SteamUI. Verifica se há uma actualização disponível ou desinstala o plugin nas definições do Decky."
},
"SettingsDeveloperIndex": {
"cef_console": {
"button": "Abrir consola",
"label": "Consola CEF",
"desc": "Abre a consola do CEF. Só é útil para efeitos de debugging. Pode ser perigosa e só deve ser usada se és um desenvolvedor de plugins, ou se foste aqui indicado por um desenvolvedor."
},
"header": "Outros",
"react_devtools": {
"desc": "Permite a conecção a um computador que está a correr React DevTools. Mudar esta definição vai recarregar o Steam. Define o endereço de IP antes de activar.",
"ip_label": "IP",
"label": "Activar React DevTools"
},
"third_party_plugins": {
"button_install": "Instalar",
"button_zip": "Navegar",
"header": "Plugins de terceiros",
"label_desc": "URl",
"label_url": "Instalar plugin a partir dum URL",
"label_zip": "Instalar plugin a partir dum ficheiro ZIP"
},
"toast_zip": {
"title": "Decky",
"body": "A instalação falhou! Só ficheiros ZIP são suportados."
},
"valve_internal": {
"label": "Activar menu interno da Valve",
"desc1": "Activa o menu interno de programador da Valve.",
"desc2": "Não toques em nada deste menu se não souberes a sua função."
}
},
"RemoteDebugging": {
"remote_cef": {
"desc": "Permitir acesso não autenticado ao debugger do CEF a qualquer pessoa na tua rede",
"label": "Permitir debugging remoto do CEF"
}
},
"SettingsGeneralIndex": {
"about": {
"decky_version": "Versão do Decky",
"header": "Sobre"
},
"beta": {
"header": "Participação na versão Beta"
},
"developer_mode": {
"label": "Modo de programador",
"desc": "Activa as definições de programador do Decky."
},
"other": {
"header": "Outros"
},
"updates": {
"header": "Actualizações"
}
},
"SettingsIndex": {
"developer_title": "Programador",
"general_title": "Geral",
"navbar_settings": "Definições do Decky",
"plugins_title": "Plugins"
},
"Store": {
"store_contrib": {
"label": "Contribuir",
"desc": "Se queres contribuir com um novo plugin, vai ao repositório SteamDeckHomebrew/decky-plugin-template no GitHub. No README, podes encontrar mais informação sobre desenvolvimento e distribuição."
},
"store_filter": {
"label": "Filtro",
"label_def": "Todos"
},
"store_search": {
"label": "Procurar"
},
"store_sort": {
"label": "Ordenar",
"label_def": "Última actualização (mais recente)"
},
"store_source": {
"label": "Código fonte",
"desc": "O código fonte de cada plugin está disponível no repositório SteamDeckHomebrew/decky-plugin-database no GitHub."
},
"store_tabs": {
"about": "Sobre",
"alph_asce": "Alfabeticamente (Z-A)",
"alph_desc": "Alfabeticamente (A-Z)",
"title": "Navegar"
},
"store_testing_cta": "Testa novos plugins e ajuda a equipa do Decky Loader!"
},
"StoreSelect": {
"custom_store": {
"url_label": "URL",
"label": "Loja personalizada"
},
"store_channel": {
"custom": "Personalizada",
"default": "Standard",
"testing": "Em teste",
"label": "Canal de loja"
}
},
"Updater": {
"decky_updates": "Actualizações do Decky",
"no_patch_notes_desc": "sem registo de alterações desta versão",
"patch_notes_desc": "Registo de alterações",
"updates": {
"check_button": "Procurar actualizações",
"checking": "Busca de actualizações em curso",
"cur_version": "Versão actual: {{ver}}",
"label": "Actualizações",
"lat_version": "Actualizado: a correr {{ver}}",
"updating": "Actualização em curso",
"reloading": "Recarregar",
"install_button": "Instalar actualização"
}
}
}
+33
View File
@@ -0,0 +1,33 @@
{
"MultiplePluginsInstallModal": {
"title": {
"update_one": "",
"update_few": "",
"update_many": "",
"reinstall_one": "",
"reinstall_few": "",
"reinstall_many": "",
"install_one": "",
"install_few": "",
"install_many": "",
"mixed_one": "",
"mixed_few": "",
"mixed_many": ""
}
},
"PluginListIndex": {
"update_all_one": "",
"update_all_few": "",
"update_all_many": ""
},
"PluginLoader": {
"plugin_update_one": "",
"plugin_update_few": "",
"plugin_update_many": ""
},
"PluginView": {
"hidden_one": "",
"hidden_few": "",
"hidden_many": ""
}
}
+22 -2
View File
@@ -59,11 +59,15 @@
"desc": "Je i sigurt që don ta çinstalojsh {{name}}?"
},
"error": "Gabim",
"plugin_error_uninstall": "Ju lutem shko nga <0></0> në Decky menu nëse don ta çinstalojsh këtë shtese."
"plugin_error_uninstall": "Ju lutem shko nga {{name}} në Decky menu nëse don ta çinstalojsh këtë shtese.",
"plugin_update_one": "",
"plugin_update_other": ""
},
"PluginListIndex": {
"no_plugin": "Nuk ka shtesa të instaluar!",
"uninstall": "Çinstalo"
"uninstall": "Çinstalo",
"update_all_one": "",
"update_all_other": ""
},
"SettingsGeneralIndex": {
"other": {
@@ -111,5 +115,21 @@
"updates": {
"cur_version": "Versioni e tanishëme: {{ver}}"
}
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "",
"mixed_other": "",
"update_one": "",
"update_other": "",
"reinstall_one": "",
"reinstall_other": "",
"install_one": "",
"install_other": ""
}
},
"PluginView": {
"hidden_one": "",
"hidden_other": ""
}
}
+228
View File
@@ -0,0 +1,228 @@
{
"BranchSelect": {
"update_channel": {
"prerelease": "Передреліз",
"testing": "Тестовий",
"label": "Канал оновлень",
"stable": "Стабільний"
}
},
"Developer": {
"5secreload": "Перезавантаження за 5 секунд",
"enabling": "Увімкнення React DevTools",
"disabling": "Вимкнення React DevTools"
},
"FilePickerIndex": {
"folder": {
"select": "Використовувати цю папку"
}
},
"PluginListLabel": {
"hidden": "Приховано з меню швидкого доступу"
},
"PluginCard": {
"plugin_full_access": "Цей плагін має повний доступ до вашого Steam Deck.",
"plugin_install": "Встановити",
"plugin_no_desc": "Опис не надано.",
"plugin_version_label": "Версія плагіна"
},
"PluginInstallModal": {
"install": {
"button_idle": "Встановити",
"button_processing": "Встановлення",
"title": "Встановити {{artifact}}",
"desc": "Ви впевнені, що хочете встановити {{artifact}} {{version}}?"
},
"reinstall": {
"button_idle": "Перевстановити",
"desc": "Ви впевнені, що хочете перевстановити {{artifact}} {{version}}?",
"title": "Перевстановити {{artifact}}",
"button_processing": "Перевстановлення"
},
"update": {
"button_idle": "Оновити",
"button_processing": "Оновлення",
"title": "Оновити {{artifact}}",
"desc": "Ви впевнені, що хочете оновити {{artifact}} {{version}}?"
},
"no_hash": "Цей плагін не має хешу, ви встановлюєте його на власний ризик."
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_one": "Модифікувати 1 плагін",
"mixed_few": "Модифікувати {{count}} плагінів",
"mixed_many": "",
"reinstall_one": "Перевстановити 1 плагін",
"reinstall_few": "Перевстановити {{count}} плагінів",
"reinstall_many": "Перевстановити {{count}} плагінів",
"update_one": "Оновити 1 плагін",
"update_few": "Оновити {{count}} плагінів",
"update_many": "Оновити {{count}} плагінів",
"install_one": "Встановити 1 плагін",
"install_few": "Встановити {{count}} плагінів",
"install_many": "Встановити {{count}} плагінів"
},
"ok_button": {
"idle": "Підтвердити",
"loading": "Опрацювання"
},
"description": {
"install": "Встановити {{name}} {{version}}",
"update": "Оновити {{name}} до {{version}}",
"reinstall": "Перевстановити {{name}} {{version}}"
},
"confirm": "Ви впевнені, що хочете застосувати такі модифікації?"
},
"PluginListIndex": {
"no_plugin": "Плагінів не встановлено!",
"plugin_actions": "Дії плагінів",
"reinstall": "Перевстановити",
"reload": "Перезавантажити",
"update_to": "Оновити {{name}}",
"show": "Швидкий доступ: Показати",
"hide": "Швидкий доступ: Приховати",
"uninstall": "Видалити",
"update_all_one": "Оновити 1 плагін",
"update_all_few": "Оновити {{count}} плагінів",
"update_all_many": "Оновити {{count}} плагінів"
},
"PluginLoader": {
"decky_title": "Decky",
"decky_update_available": "Доступне оновлення до {{tag_name}}!",
"error": "Помилка",
"plugin_load_error": {
"message": "Помилка завантаження плагіна {{name}}",
"toast": "Помилка завантаження {{name}}"
},
"plugin_uninstall": {
"desc": "Ви впевнені, що хочете видалити {{name}}?",
"title": "Видалити {{name}}",
"button": "Видалення"
},
"plugin_error_uninstall": "Завантаження {{name}} спровокувало помилку показану вище. Зазвичай це означає, що плагін вимагає оновлення до нової версії SteamUI. Перевірте чи таке оновлення доступне або виконайте його видалення у налаштуваннях Decky, у секції Плагіни.",
"plugin_update_one": "Доступне оновлення для 1 плагіна!",
"plugin_update_few": "Доступне оновлення для {{count}} плагінів!",
"plugin_update_many": "Доступне оновлення для {{count}} плагінів!"
},
"SettingsDeveloperIndex": {
"cef_console": {
"button": "Відкрити консоль",
"label": "CEF-консоль",
"desc": "Відкрити CEF-консоль. Корисно тільки для дебагу. Ця штука потенційно небезпечна і повинна використовувати виключно якщо ви розробник плагіна, або якщо розробник спрямував вас сюди."
},
"header": "Інше",
"react_devtools": {
"desc": "Вмикає доступ до компʼютера із запущеним React DevTools. Зміна цього налаштування перезавантажить Steam. Вкажіть IP перед увімкненням.",
"label": "Увімкнути React DevTools",
"ip_label": "IP"
},
"third_party_plugins": {
"button_install": "Встановити",
"header": "Сторонні плагіни",
"label_desc": "URL",
"label_url": "Встановити плагін з URL",
"label_zip": "Встановити плагін з ZIP-файлу",
"button_zip": "Огляд"
},
"toast_zip": {
"title": "Decky",
"body": "Помилка встановлення! Підтримуються лише ZIP-файли."
},
"valve_internal": {
"desc1": "Вмикає внутрішнє розробницьке меню Valve.",
"label": "Увімкнути Valve Internal",
"desc2": "Нічого не торкайтесь у цьому меню, якщо не розумієте, що ви робите."
}
},
"SettingsGeneralIndex": {
"about": {
"decky_version": "Версія Decky",
"header": "Про нас"
},
"beta": {
"header": "Участь у Beta"
},
"developer_mode": {
"desc": "Вмикає розробницькі налаштування Decky.",
"label": "Розробницький режим"
},
"other": {
"header": "Інше"
},
"updates": {
"header": "Оновлення"
}
},
"SettingsIndex": {
"developer_title": "Розробник",
"general_title": "Загальне",
"navbar_settings": "Налаштування Decky",
"plugins_title": "Плагіни"
},
"Store": {
"store_contrib": {
"label": "Зробити внесок",
"desc": "Якщо ви бажаєте додати щось у Decky Plugin Store, завітайте у репозиторій SteamDeckHomebrew/decky-plugin-template на GitHub. Інформація про розробку та поширення доступна у README."
},
"store_filter": {
"label": "Фільтр",
"label_def": "Усе"
},
"store_search": {
"label": "Пошук"
},
"store_sort": {
"label": "Сортування",
"label_def": "Востаннє оновлені (Найновіші)"
},
"store_source": {
"label": "Вихідний код",
"desc": "Код усіх плагінів доступний у репозиторії SteamDeckHomebrew/decky-plugin-database на GitHub."
},
"store_tabs": {
"about": "Інформація",
"alph_asce": "За алфавітом (Z до A)",
"alph_desc": "За алфавітом (A до Z)",
"title": "Огляд"
},
"store_testing_cta": "Розгляньте можливість тестування нових плагінів, щоб допомогти команді Decky Loader!"
},
"StoreSelect": {
"custom_store": {
"label": "Власний магазин",
"url_label": "URL"
},
"store_channel": {
"custom": "Власний",
"default": "За замовчуванням",
"testing": "Тестування",
"label": "Канал магазину"
}
},
"Updater": {
"decky_updates": "Оновлення Decky",
"no_patch_notes_desc": "Немає нотаток до цієї версії",
"patch_notes_desc": "Перелік змін",
"updates": {
"checking": "Перевірка",
"cur_version": "Поточна версія: {{ver}}",
"install_button": "Встановити оновлення",
"label": "Оновлення",
"reloading": "Перезавантаження",
"updating": "Оновлення",
"check_button": "Перевірити оновлення",
"lat_version": "Оновлено: використовується {{ver}}"
}
},
"PluginView": {
"hidden_one": "{{count}} плагін приховано з цього списку",
"hidden_few": "{{count}} плагінів приховано з цього списку",
"hidden_many": "{{count}} плагінів приховано з цього списку"
},
"RemoteDebugging": {
"remote_cef": {
"desc": "Дозволити доступ до CEF-дебагера без аутентифікації для будь-кого у вашій мережі",
"label": "Дозволити віддалений CEF-дебагінг"
}
}
}
+47 -14
View File
@@ -9,8 +9,8 @@
},
"Developer": {
"5secreload": "5 秒钟后重新加载",
"disabling": "正在禁用",
"enabling": "正在启用"
"disabling": "正在禁用 React DevTools",
"enabling": "正在启用 React DevTools"
},
"FilePickerIndex": {
"folder": {
@@ -21,7 +21,7 @@
"plugin_install": "安装",
"plugin_no_desc": "无描述提供。",
"plugin_version_label": "插件版本",
"plugin_full_access": "此插件可以完全访问你的 Steam Deck"
"plugin_full_access": "此插件可以完全访问你的 Steam Deck"
},
"PluginInstallModal": {
"install": {
@@ -42,7 +42,7 @@
"desc": "你确定要更新 {{artifact}} {{version}} 吗?",
"title": "更新 {{artifact}}"
},
"no_hash": "此插件没有哈希校验值,你需要自行承担安装风险"
"no_hash": "此插件没有哈希校验值,你需要自行承担安装风险"
},
"PluginListIndex": {
"no_plugin": "没有安装插件!",
@@ -50,12 +50,15 @@
"reinstall": "重新安装",
"reload": "重新加载",
"uninstall": "卸载",
"update_to": "更新 {{name}}"
"update_to": "更新 {{name}}",
"update_all_other": "更新 {{count}} 个插件",
"show": "快速访问菜单:可见",
"hide": "快速访问菜单:不可见"
},
"PluginLoader": {
"decky_title": "Decky",
"error": "错误",
"plugin_error_uninstall": "如果你想卸载插件请点击 Decky 菜单中的 <0></0> 图标",
"plugin_error_uninstall": "加载 {{name}} 时引起了上述异常。这通常意味着插件需要更新以适应 SteamUI 的新版本。请检查插件是否有更新,或在 Decky 设置中的插件部分将其移除。",
"plugin_load_error": {
"message": "加载插件 {{name}} 错误",
"toast": "加载插件 {{name}} 发生了错误"
@@ -78,7 +81,7 @@
"react_devtools": {
"ip_label": "IP",
"label": "启用 React DevTools",
"desc": "允许连接到运行着 React DevTools 的计算机,更改此设置将重新加载Steam,请在启用前设置IP地址"
"desc": "允许连接到运行着 React DevTools 的计算机,更改此设置将重新加载Steam,请在启用前设置IP地址"
},
"third_party_plugins": {
"button_install": "安装",
@@ -90,13 +93,19 @@
},
"toast_zip": {
"title": "Decky",
"body": "安装失败!只有 ZIP 格式的插件被支持"
"body": "安装失败!只有 ZIP 格式的插件被支持"
},
"valve_internal": {
"desc1": "启用 Valve 内部开发者菜单",
"desc2": "除非你知道你在干什么,否则请不要修改此菜单中的任何内容",
"desc1": "启用 Valve 内部开发者菜单",
"desc2": "除非你知道你在干什么,否则请不要修改此菜单中的任何内容",
"label": "启用 Valve 内部开发者"
}
},
"cef_console": {
"button": "打开控制台",
"label": "CEF 控制台",
"desc": "打开 CEF 控制台。仅在调试目的下使用。这列选项均有风险,请仅在您是插件开发者或是在插件开发者指导时访问使用。"
},
"header": "其他"
},
"SettingsGeneralIndex": {
"about": {
@@ -108,7 +117,7 @@
},
"developer_mode": {
"label": "开发者模式",
"desc": "启用 Decky 的开发者测试"
"desc": "启用 Decky 的开发者测试"
},
"other": {
"header": "其他"
@@ -126,7 +135,7 @@
"Store": {
"store_contrib": {
"label": "贡献",
"desc": "如果你想要提交你的插件到 Decky 插件商店,请访问 GitHub 上的 SteamDeckHomebrew/decky-plugin-template 存储库,关于开发和分发的相关信息,请查看 README 文件"
"desc": "如果你想要提交你的插件到 Decky 插件商店,请访问 GitHub 上的 SteamDeckHomebrew/decky-plugin-template 存储库,关于开发和分发的相关信息,请查看 README 文件"
},
"store_filter": {
"label": "过滤器",
@@ -141,7 +150,7 @@
},
"store_source": {
"label": "源代码",
"desc": "所有插件的源代码都可以在 GitHub 上的 SteamDeckHomebrew/decky-plugin-database 存储库中获得"
"desc": "所有插件的源代码都可以在 GitHub 上的 SteamDeckHomebrew/decky-plugin-database 存储库中获得"
},
"store_tabs": {
"about": "关于",
@@ -177,5 +186,29 @@
"reloading": "重新加载中",
"updating": "更新中"
}
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_other": "更改 {{count}} 个插件",
"update_other": "更新 {{count}} 个插件",
"reinstall_other": "重装 {{count}} 个插件",
"install_other": "安装 {{count}} 个插件"
},
"ok_button": {
"idle": "确认",
"loading": "工作中"
},
"confirm": "确定要进行以下修改吗?",
"description": {
"install": "安装 {{name}} {{version}}",
"update": "更新 {{name}} to {{version}}",
"reinstall": "重装 {{name}} {{version}}"
}
},
"PluginListLabel": {
"hidden": "快速访问菜单中不可见"
},
"PluginView": {
"hidden_other": "此列表隐藏了 {{count}} 个插件"
}
}
+36 -4
View File
@@ -9,8 +9,8 @@
},
"Developer": {
"5secreload": "5 秒後重新載入",
"disabling": "正在停用",
"enabling": "正在啟用"
"disabling": "正在停用 React DevTools",
"enabling": "正在啟用 React DevTools"
},
"FilePickerIndex": {
"folder": {
@@ -50,7 +50,10 @@
"uninstall": "解除安裝",
"update_to": "更新到 {{name}}",
"reinstall": "重新安裝",
"reload": "重新載入"
"reload": "重新載入",
"show": "快速存取:顯示",
"hide": "快速存取:隱藏",
"update_all_other": "更新 {{count}} 個外掛程式"
},
"PluginLoader": {
"decky_title": "Decky",
@@ -97,7 +100,12 @@
"ip_label": "IP",
"label": "啟用 React DevTools"
},
"header": "其他"
"header": "其他",
"cef_console": {
"button": "開啟控制台",
"label": "CEF 控制台",
"desc": "開啟 CEF 控制台。僅用於偵錯。這裡的東西有潛在的風險,只有當你是一個外掛程式開發者或者被外掛程式開發者引導到這裡時,才應該使用。"
}
},
"SettingsGeneralIndex": {
"about": {
@@ -178,5 +186,29 @@
"cur_version": "目前版本:{{ver}}",
"updating": "正在更新"
}
},
"PluginView": {
"hidden_other": "{{count}} 個外掛程式已隱藏"
},
"PluginListLabel": {
"hidden": "已從快速存取選單中移除"
},
"MultiplePluginsInstallModal": {
"title": {
"mixed_other": "修改 {{count}} 個外掛程式",
"update_other": "更新 {{count}} 個外掛程式",
"reinstall_other": "重新安裝 {{count}} 個外掛程式",
"install_other": "安裝 {{count}} 個外掛程式"
},
"ok_button": {
"idle": "確定",
"loading": "執行中"
},
"confirm": "您確定要進行以下的修改嗎?",
"description": {
"install": "安裝 {{name}} {{version}}",
"update": "更新 {{name}} 到 {{version}}",
"reinstall": "重新安裝 {{name}} {{version}}"
}
}
}
+1 -1
View File
@@ -22,7 +22,7 @@ class SettingsManager:
for file in listdir(wrong_dir):
if file.endswith(".json"):
rename(path.join(wrong_dir,file),
path.join(settings_directory, file))
path.join(settings_directory, file))
self.path = path.join(settings_directory, name + ".json")
+2
View File
@@ -67,9 +67,11 @@ class Updater:
logger.info("Current branch is not set, determining branch from version...")
if self.localVer.startswith("v") and "-pre" in self.localVer:
logger.info("Current version determined to be pre-release")
manager.setSetting('branch', 1)
return 1
else:
logger.info("Current version determined to be stable")
manager.setSetting('branch', 0)
return 0
return ver
+84 -21
View File
@@ -1,16 +1,21 @@
import uuid
import os
from json.decoder import JSONDecodeError
from os.path import splitext
import re
from traceback import format_exc
from stat import FILE_ATTRIBUTE_HIDDEN
from asyncio import sleep, start_server, gather, open_connection
from aiohttp import ClientSession, web
from logging import getLogger
from injector import inject_to_tab, get_gamepadui_tab, close_old_tabs, get_tab
from pathlib import Path
from localplatform import ON_WINDOWS
import helpers
import subprocess
from localplatform import service_stop, service_start
from localplatform import service_stop, service_start, get_home_path, get_username
class Utilities:
def __init__(self, context) -> None:
@@ -33,7 +38,8 @@ class Utilities:
"filepicker_ls": self.filepicker_ls,
"disable_rdt": self.disable_rdt,
"enable_rdt": self.enable_rdt,
"get_tab_id": self.get_tab_id
"get_tab_id": self.get_tab_id,
"get_user_info": self.get_user_info,
}
self.logger = getLogger("Utilities")
@@ -189,31 +195,82 @@ class Utilities:
await service_stop(helpers.REMOTE_DEBUGGER_UNIT)
return True
async def filepicker_ls(self, path, include_files=True):
# def sorter(file): # Modification time
# if os.path.isdir(os.path.join(path, file)) or os.path.isfile(os.path.join(path, file)):
# return os.path.getmtime(os.path.join(path, file))
# return 0
# file_names = sorted(os.listdir(path), key=sorter, reverse=True) # TODO provide more sort options
file_names = sorted(os.listdir(path)) # Alphabetical
async def filepicker_ls(self,
path : str | None = None,
include_files: bool = True,
include_folders: bool = True,
include_ext: list[str] = [],
include_hidden: bool = False,
order_by: str = "name_asc",
filter_for: str | None = None,
page: int = 1,
max: int = 1000):
if path == None:
path = get_home_path()
files = []
path = Path(path).resolve()
for file in file_names:
full_path = os.path.join(path, file)
is_dir = os.path.isdir(full_path)
files, folders = [], []
if is_dir or include_files:
files.append({
"isdir": is_dir,
"name": file,
"realpath": os.path.realpath(full_path)
})
#Resolving all files/folders in the requested directory
for file in path.iterdir():
if file.exists():
filest = file.stat()
is_hidden = file.name.startswith('.')
if ON_WINDOWS and not is_hidden:
is_hidden = bool(filest.st_file_attributes & FILE_ATTRIBUTE_HIDDEN)
if include_folders and file.is_dir():
if (is_hidden and include_hidden) or not is_hidden:
folders.append({"file": file, "filest": filest, "is_dir": True})
elif include_files:
# Handle requested extensions if present
if 'all_files' in include_ext or splitext(file.name)[1].lstrip('.') in include_ext:
if (is_hidden and include_hidden) or not is_hidden:
files.append({"file": file, "filest": filest, "is_dir": False})
# Filter logic
if filter_for is not None:
try:
if re.compile(filter_for):
files = filter(lambda file: re.search(filter_for, file.name) != None, files)
except re.error:
files = filter(lambda file: file.name.find(filter_for) != -1, files)
# Ordering logic
ord_arg = order_by.split("_")
ord = ord_arg[0]
rev = True if ord_arg[1] == "asc" else False
match ord:
case 'name':
files.sort(key=lambda x: x['file'].name.casefold(), reverse = rev)
folders.sort(key=lambda x: x['file'].name.casefold(), reverse = rev)
case 'modified':
files.sort(key=lambda x: x['filest'].st_mtime, reverse = not rev)
folders.sort(key=lambda x: x['filest'].st_mtime, reverse = not rev)
case 'created':
files.sort(key=lambda x: x['filest'].st_ctime, reverse = not rev)
folders.sort(key=lambda x: x['filest'].st_ctime, reverse = not rev)
case 'size':
files.sort(key=lambda x: x['filest'].st_size, reverse = not rev)
# Folders has no file size, order by name instead
folders.sort(key=lambda x: x['file'].name.casefold())
#Constructing the final file list, folders first
all = [{
"isdir": x['is_dir'],
"name": str(x['file'].name),
"realpath": str(x['file']),
"size": x['filest'].st_size,
"modified": x['filest'].st_mtime,
"created": x['filest'].st_ctime,
} for x in folders + files ]
return {
"realpath": os.path.realpath(path),
"files": files
"realpath": str(path),
"files": all[(page-1)*max:(page)*max],
"total": len(all),
}
# Based on https://stackoverflow.com/a/46422554/13174603
def start_rdt_proxy(self, ip, port):
@@ -289,5 +346,11 @@ class Utilities:
await tab.evaluate_js("location.reload();", False, True, False)
self.logger.info("React DevTools disabled")
async def get_user_info(self) -> dict:
return {
"username": get_username(),
"path": get_home_path()
}
async def get_tab_id(self, name):
return (await get_tab(name)).id
+2
View File
@@ -2,3 +2,5 @@ node_modules/
.yalc
yalc.lock
stats.html
+6 -4
View File
@@ -22,7 +22,7 @@
"@types/react-router": "5.1.18",
"@types/webpack": "^5.28.1",
"husky": "^8.0.3",
"i18next-parser": "^7.9.0",
"i18next-parser": "^8.0.0",
"import-sort-style-module": "^6.0.0",
"inquirer": "^8.2.5",
"prettier": "^2.8.8",
@@ -33,7 +33,8 @@
"rollup-plugin-delete": "^2.0.0",
"rollup-plugin-external-globals": "^0.6.1",
"rollup-plugin-polyfill-node": "^0.10.2",
"tslib": "^2.5.2",
"rollup-plugin-visualizer": "^5.9.2",
"tslib": "^2.5.3",
"typescript": "^4.9.5"
},
"importSort": {
@@ -44,11 +45,12 @@
},
"dependencies": {
"decky-frontend-lib": "3.21.1",
"i18next": "^22.5.0",
"filesize": "^10.0.7",
"i18next": "^23.1.0",
"i18next-http-backend": "^2.2.1",
"react-file-icon": "^1.3.0",
"react-i18next": "^12.3.1",
"react-icons": "^4.8.0",
"react-icons": "^4.9.0",
"react-markdown": "^8.0.7",
"remark-gfm": "^3.0.1"
}
+449 -337
View File
File diff suppressed because it is too large Load Diff
+4 -2
View File
@@ -7,6 +7,7 @@ import typescript from '@rollup/plugin-typescript';
import { defineConfig } from 'rollup';
import del from 'rollup-plugin-delete';
import externalGlobals from 'rollup-plugin-external-globals';
import { visualizer } from 'rollup-plugin-visualizer';
const hiddenWarnings = ['THIS_IS_UNDEFINED', 'EVAL'];
@@ -16,7 +17,7 @@ export default defineConfig({
del({ targets: '../backend/static/*', force: true }),
commonjs(),
nodeResolve({
browser: true
browser: true,
}),
externalGlobals({
react: 'SP_REACT',
@@ -33,6 +34,7 @@ export default defineConfig({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
image(),
visualizer(),
],
preserveEntrySignatures: false,
output: {
@@ -46,4 +48,4 @@ export default defineConfig({
if (hiddenWarnings.some((warning) => message.code === warning)) return;
handleWarning(message);
},
});
});
+26 -5
View File
@@ -7,21 +7,30 @@ import { VerInfo } from '../updater';
interface PublicDeckyState {
plugins: Plugin[];
pluginOrder: string[];
hiddenPlugins: string[];
activePlugin: Plugin | null;
updates: PluginUpdateMapping | null;
hasLoaderUpdate?: boolean;
isLoaderUpdating: boolean;
versionInfo: VerInfo | null;
userInfo: UserInfo | null;
}
export interface UserInfo {
username: string;
path: string;
}
export class DeckyState {
private _plugins: Plugin[] = [];
private _pluginOrder: string[] = [];
private _hiddenPlugins: string[] = [];
private _activePlugin: Plugin | null = null;
private _updates: PluginUpdateMapping | null = null;
private _hasLoaderUpdate: boolean = false;
private _isLoaderUpdating: boolean = false;
private _versionInfo: VerInfo | null = null;
private _userInfo: UserInfo | null = null;
public eventBus = new EventTarget();
@@ -29,11 +38,13 @@ export class DeckyState {
return {
plugins: this._plugins,
pluginOrder: this._pluginOrder,
hiddenPlugins: this._hiddenPlugins,
activePlugin: this._activePlugin,
updates: this._updates,
hasLoaderUpdate: this._hasLoaderUpdate,
isLoaderUpdating: this._isLoaderUpdating,
versionInfo: this._versionInfo,
userInfo: this._userInfo,
};
}
@@ -52,6 +63,11 @@ export class DeckyState {
this.notifyUpdate();
}
setHiddenPlugins(hiddenPlugins: string[]) {
this._hiddenPlugins = hiddenPlugins;
this.notifyUpdate();
}
setActivePlugin(name: string) {
this._activePlugin = this._plugins.find((plugin) => plugin.name === name) ?? null;
this.notifyUpdate();
@@ -77,6 +93,11 @@ export class DeckyState {
this.notifyUpdate();
}
setUserInfo(userInfo: UserInfo) {
this._userInfo = userInfo;
this.notifyUpdate();
}
private notifyUpdate() {
this.eventBus.dispatchEvent(new Event('update'));
}
@@ -111,11 +132,11 @@ export const DeckyStateContextProvider: FC<Props> = ({ children, deckyState }) =
return () => deckyState.eventBus.removeEventListener('update', onUpdate);
}, []);
const setIsLoaderUpdating = (hasUpdate: boolean) => deckyState.setIsLoaderUpdating(hasUpdate);
const setVersionInfo = (versionInfo: VerInfo) => deckyState.setVersionInfo(versionInfo);
const setActivePlugin = (name: string) => deckyState.setActivePlugin(name);
const closeActivePlugin = () => deckyState.closeActivePlugin();
const setPluginOrder = (pluginOrder: string[]) => deckyState.setPluginOrder(pluginOrder);
const setIsLoaderUpdating = deckyState.setIsLoaderUpdating.bind(deckyState);
const setVersionInfo = deckyState.setVersionInfo.bind(deckyState);
const setActivePlugin = deckyState.setActivePlugin.bind(deckyState);
const closeActivePlugin = deckyState.closeActivePlugin.bind(deckyState);
const setPluginOrder = deckyState.setPluginOrder.bind(deckyState);
return (
<DeckyStateContext.Provider
+11
View File
@@ -8,6 +8,8 @@ import {
staticClasses,
} from 'decky-frontend-lib';
import { VFC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FaEyeSlash } from 'react-icons/fa';
import { Plugin } from '../plugin';
import { useDeckyState } from './DeckyState';
@@ -16,8 +18,10 @@ import { useQuickAccessVisible } from './QuickAccessVisibleState';
import TitleView from './TitleView';
const PluginView: VFC = () => {
const { hiddenPlugins } = useDeckyState();
const { plugins, updates, activePlugin, pluginOrder, setActivePlugin, closeActivePlugin } = useDeckyState();
const visible = useQuickAccessVisible();
const { t } = useTranslation();
const [pluginList, setPluginList] = useState<Plugin[]>(
plugins.sort((a, b) => pluginOrder.indexOf(a.name) - pluginOrder.indexOf(b.name)),
@@ -48,6 +52,7 @@ const PluginView: VFC = () => {
<PanelSection>
{pluginList
.filter((p) => p.content)
.filter(({ name }) => !hiddenPlugins.includes(name))
.map(({ name, icon }) => (
<PanelSectionRow key={name}>
<ButtonItem layout="below" onClick={() => setActivePlugin(name)}>
@@ -59,6 +64,12 @@ const PluginView: VFC = () => {
</ButtonItem>
</PanelSectionRow>
))}
{hiddenPlugins.length > 0 && (
<div style={{ display: 'flex', alignItems: 'center', gap: '10px', fontSize: '0.8rem', marginTop: '10px' }}>
<FaEyeSlash />
<div>{t('PluginView.hidden', { count: hiddenPlugins.length })}</div>
</div>
)}
</PanelSection>
</div>
</>
@@ -1,17 +1,16 @@
import { FC, createContext, useContext, useState } from 'react';
const QuickAccessVisibleState = createContext<boolean>(true);
const QuickAccessVisibleState = createContext<boolean>(false);
export const useQuickAccessVisible = () => useContext(QuickAccessVisibleState);
export const QuickAccessVisibleStateProvider: FC<{ initial: boolean; tab: any }> = ({ children, initial, tab }) => {
export const QuickAccessVisibleStateProvider: FC<{ tab: any }> = ({ children, tab }) => {
const initial = tab.initialVisibility;
const [visible, setVisible] = useState<boolean>(initial);
const [prev, setPrev] = useState<boolean>(initial);
// HACK but i can't think of a better way to do this
tab.qAMVisibilitySetter = setVisible;
if (initial != prev) {
setPrev(initial);
setVisible(initial);
}
tab.qAMVisibilitySetter = (val: boolean) => {
if (val != visible) setVisible(val);
};
return <QuickAccessVisibleState.Provider value={visible}>{children}</QuickAccessVisibleState.Provider>;
};
@@ -0,0 +1,121 @@
import {
DialogButton,
DialogCheckbox,
DialogCheckboxProps,
Marquee,
Menu,
MenuItem,
findModuleChild,
showContextMenu,
} from 'decky-frontend-lib';
import { FC, useCallback, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { FaChevronDown } from 'react-icons/fa';
const dropDownControlButtonClass = findModuleChild((m) => {
if (typeof m !== 'object') return undefined;
for (const prop in m) {
if (m[prop]?.toString()?.includes('gamepaddropdown_DropDownControlButton')) {
return m[prop];
}
}
});
const DropdownMultiselectItem: FC<
{
value: any;
onSelect: (checked: boolean, value: any) => void;
checked: boolean;
} & DialogCheckboxProps
> = ({ value, onSelect, checked: defaultChecked, ...rest }) => {
const [checked, setChecked] = useState(defaultChecked);
useEffect(() => {
onSelect?.(checked, value);
}, [checked, onSelect, value]);
return (
<MenuItem bInteractableItem onClick={() => setChecked((x) => !x)}>
<DialogCheckbox
style={{ marginBottom: 0, padding: 0 }}
className="decky_DropdownMultiselectItem_DialogCheckbox"
bottomSeparator="none"
{...rest}
onClick={() => setChecked((x) => !x)}
onChange={(checked) => setChecked(checked)}
controlled
checked={checked}
/>
</MenuItem>
);
};
const DropdownMultiselect: FC<{
items: {
label: string;
value: string;
}[];
selected: string[];
onSelect: (selected: any[]) => void;
label: string;
}> = ({ label, items, selected, onSelect }) => {
const [itemsSelected, setItemsSelected] = useState<any>(selected);
const { t } = useTranslation();
const handleItemSelect = useCallback((checked, value) => {
setItemsSelected((x: any) =>
checked ? [...x.filter((y: any) => y !== value), value] : x.filter((y: any) => y !== value),
);
}, []);
useEffect(() => {
onSelect(itemsSelected);
}, [itemsSelected, onSelect]);
return (
<DialogButton
style={{
display: 'flex',
alignItems: 'center',
maxWidth: '100%',
}}
className={dropDownControlButtonClass}
onClick={(evt) => {
evt.preventDefault();
showContextMenu(
<Menu label={label} cancelText={t('DropdownMultiselect.button.back') as string}>
<style>
{`
/* Inherit color from ".basiccontextmenu" */
.decky_DropdownMultiselectItem_DialogCheckbox > .DialogToggle_Label {
color: inherit;
}
`}
</style>
<div style={{ marginTop: '10px' }}>{/*FIXME: Hack for missing padding under label menu*/}</div>
{items.map((x) => (
<DropdownMultiselectItem
key={x.value}
label={x.label}
value={x.value}
checked={itemsSelected.includes(x.value)}
onSelect={handleItemSelect}
/>
))}
</Menu>,
evt.currentTarget ?? window,
);
}}
>
<Marquee>
{selected.length > 0
? selected.map((x: any) => items[items.findIndex((v) => v.value === x)].label).join(', ')
: '…'}
</Marquee>
<div style={{ flexGrow: 1, minWidth: '1ch' }} />
<FaChevronDown style={{ height: '1em', flex: '0 0 1em' }} />
</DialogButton>
);
};
export default DropdownMultiselect;
@@ -0,0 +1,30 @@
import { ConfirmModal } from 'decky-frontend-lib';
import { FC } from 'react';
interface PluginUninstallModalProps {
name: string;
title: string;
buttonText: string;
description: string;
closeModal?(): void;
}
const PluginUninstallModal: FC<PluginUninstallModalProps> = ({ name, title, buttonText, description, closeModal }) => {
return (
<ConfirmModal
closeModal={closeModal}
onOK={async () => {
await window.DeckyPluginLoader.callServerMethod('uninstall_plugin', { name });
// uninstalling a plugin resets the hidden setting for it server-side
// we invalidate here so if you re-install it, you won't have an out-of-date hidden filter
await window.DeckyPluginLoader.hiddenPluginsService.invalidate();
}}
strTitle={title}
strOKButtonText={buttonText}
>
{description}
</ConfirmModal>
);
};
export default PluginUninstallModal;
@@ -0,0 +1,51 @@
import { FC, useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { IconContext } from 'react-icons';
import { FaExclamationTriangle, FaQuestionCircle } from 'react-icons/fa';
export enum FileErrorTypes {
FileNotFound,
Unknown,
None,
}
interface FilePickerErrorProps {
error: FileErrorTypes;
rawError?: string;
}
const FilePickerError: FC<FilePickerErrorProps> = ({ error, rawError = null }) => {
const [icon, setIcon] = useState<JSX.Element>(<FaQuestionCircle />);
const [text, setText] = useState<string | null>(null);
const { t } = useTranslation();
useEffect(() => {
switch (error) {
case FileErrorTypes.FileNotFound:
setText(t('FilePickerError.errors.file_not_found'));
setIcon(<FaExclamationTriangle />);
break;
case FileErrorTypes.Unknown:
setText(t('FilePickerError.errors.unknown', { raw_error: rawError }));
setIcon(<FaQuestionCircle />);
break;
case FileErrorTypes.None:
setText(null);
setIcon(<div></div>);
break;
}
}, [error]);
return (
<>
<div style={{ paddingTop: '50px', textAlign: 'center', height: '100%' }}>
<IconContext.Provider value={{ className: 'fileError', size: '128px' }}>
<div style={{ alignSelf: 'center', alignContent: 'center' }}>{icon}</div>
</IconContext.Provider>
<p style={{ height: '32px', paddingTop: '25px', alignSelf: 'flex-start', textAlign: 'center' }}>{text}</p>
</div>
</>
);
};
export default FilePickerError;
@@ -0,0 +1,46 @@
import { FC } from 'react';
import { Translation } from 'react-i18next';
export enum SortOptions {
name_desc = 'name_desc',
name_asc = 'name_asc',
modified_desc = 'modified_desc',
modified_asc = 'modified_asc',
created_desc = 'created_desc',
created_asc = 'created_asc',
size_desc = 'size_desc',
size_asc = 'size_asc',
}
interface TSortOptionsProps {
trans_part: SortOptions;
}
const TSortOptions: FC<TSortOptionsProps> = ({ trans_part }) => {
return (
<Translation>
{(t, {}) => {
switch (trans_part) {
case SortOptions.name_desc:
return t('FilePickerIndex.filter.name_desc');
case SortOptions.name_asc:
return t('FilePickerIndex.filter.name_asce');
case SortOptions.modified_desc:
return t('FilePickerIndex.filter.modified_desc');
case SortOptions.modified_asc:
return t('FilePickerIndex.filter.modified_asce');
case SortOptions.created_desc:
return t('FilePickerIndex.filter.created_desc');
case SortOptions.created_asc:
return t('FilePickerIndex.filter.created_asce');
case SortOptions.size_desc:
return t('FilePickerIndex.filter.size_desc');
case SortOptions.size_asc:
return t('FilePickerIndex.filter.size_asce');
}
}}
</Translation>
);
};
export default TSortOptions;
@@ -38,7 +38,7 @@ const imageStyle = {
color: '#d18f00',
};
const imageExtList = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tif', 'tiff'];
const imageExtList = ['png', 'jpg', 'jpeg', 'gif', 'bmp', 'tif', 'tiff', 'apng', 'tga'];
styleDef.push([imageStyle, imageExtList]);
@@ -1,11 +1,26 @@
import { DialogButton, Focusable, SteamSpinner, TextField } from 'decky-frontend-lib';
import { useEffect } from 'react';
import { FunctionComponent, useState } from 'react';
import {
ControlsList,
DialogBody,
DialogButton,
DialogControlsSection,
DialogFooter,
Dropdown,
Focusable,
Marquee,
SteamSpinner,
TextField,
ToggleField,
} from 'decky-frontend-lib';
import { filesize } from 'filesize';
import { FunctionComponent, useCallback, useEffect, useMemo, useState } from 'react';
import { FileIcon, defaultStyles } from 'react-file-icon';
import { useTranslation } from 'react-i18next';
import { FaArrowUp, FaFolder } from 'react-icons/fa';
import Logger from '../../../logger';
import DropdownMultiselect from '../DropdownMultiselect';
import FilePickerError, { FileErrorTypes } from './FilePickerError';
import TSortOption, { SortOptions } from './i18n/TSortOptions';
import { styleDefObj } from './iconCustomizations';
const logger = new Logger('FilePicker');
@@ -13,27 +28,89 @@ const logger = new Logger('FilePicker');
export interface FilePickerProps {
startPath: string;
includeFiles?: boolean;
regex?: RegExp;
includeFolders?: boolean;
filter?: RegExp | ((file: File) => boolean);
validFileExtensions?: string[];
allowAllFiles?: boolean;
defaultHidden?: boolean;
max?: number;
onSubmit: (val: { path: string; realpath: string }) => void;
closeModal?: () => void;
}
interface File {
export interface File {
isdir: boolean;
ishidden: boolean;
name: string;
realpath: string;
size: number;
modified: number;
created: number;
}
interface FileListing {
realpath: string;
files: File[];
total: number;
}
const sortOptions = [
{
data: SortOptions.name_desc,
label: <TSortOption trans_part={SortOptions.name_desc} />,
},
{
data: SortOptions.name_asc,
label: <TSortOption trans_part={SortOptions.name_asc} />,
},
{
data: SortOptions.modified_desc,
label: <TSortOption trans_part={SortOptions.modified_desc} />,
},
{
data: SortOptions.modified_asc,
label: <TSortOption trans_part={SortOptions.modified_asc} />,
},
{
data: SortOptions.created_desc,
label: <TSortOption trans_part={SortOptions.created_desc} />,
},
{
data: SortOptions.created_asc,
label: <TSortOption trans_part={SortOptions.created_asc} />,
},
{
data: SortOptions.size_desc,
label: <TSortOption trans_part={SortOptions.size_desc} />,
},
{
data: SortOptions.size_asc,
label: <TSortOption trans_part={SortOptions.size_asc} />,
},
];
function getList(
path: string,
includeFiles: boolean = true,
includeFiles: boolean,
includeFolders: boolean = true,
includeExt: string[] | null = null,
includeHidden: boolean = false,
orderBy: SortOptions = SortOptions.name_desc,
filterFor: RegExp | ((file: File) => boolean) | null = null,
pageNumber: number = 1,
max: number = 1000,
): Promise<{ result: FileListing | string; success: boolean }> {
return window.DeckyPluginLoader.callServerMethod('filepicker_ls', { path, include_files: includeFiles });
return window.DeckyPluginLoader.callServerMethod('filepicker_ls', {
path,
include_files: includeFiles,
include_folders: includeFolders,
include_ext: includeExt ? includeExt : [],
include_hidden: includeHidden,
order_by: orderBy,
filter_for: filterFor,
page: pageNumber,
max: max,
});
}
const iconStyles = {
@@ -44,126 +121,240 @@ const iconStyles = {
const FilePicker: FunctionComponent<FilePickerProps> = ({
startPath,
includeFiles = true,
regex,
filter = undefined,
includeFolders = true,
validFileExtensions = undefined,
allowAllFiles = true,
defaultHidden = false, // false by default makes sense for most users
max = 1000,
onSubmit,
closeModal,
}) => {
const { t } = useTranslation();
if (startPath.endsWith('/')) startPath = startPath.substring(0, startPath.length - 1); // remove trailing path
if (startPath !== '/' && startPath.endsWith('/')) startPath = startPath.substring(0, startPath.length - 1); // remove trailing path
const [path, setPath] = useState<string>(startPath);
const [listing, setListing] = useState<FileListing>({ files: [], realpath: path });
const [error, setError] = useState<string | null>(null);
const [listing, setListing] = useState<FileListing>({ files: [], realpath: path, total: 0 });
const [files, setFiles] = useState<File[]>([]);
const [error, setError] = useState<FileErrorTypes>(FileErrorTypes.None);
const [rawError, setRawError] = useState<string | null>(null);
const [page, setPage] = useState<number>(1);
const [loading, setLoading] = useState<boolean>(true);
const [showHidden, setShowHidden] = useState<boolean>(defaultHidden);
const [sort, setSort] = useState<SortOptions>(SortOptions.name_desc);
const [selectedExts, setSelectedExts] = useState<string[] | undefined>(validFileExtensions);
const validExtsOptions = useMemo(() => {
let validExt: { label: string; value: string }[] = [];
if (validFileExtensions) {
if (allowAllFiles) {
validExt.push({ label: t('FilePickerIndex.files.all_files'), value: 'all_files' });
}
validExt.push(...validFileExtensions.map((x) => ({ label: x, value: x })));
}
return validExt;
}, [validFileExtensions, allowAllFiles]);
function isSelectionValid(validExts: string[], selection: string[]) {
if (validExts.some((el) => selection.includes(el))) return true;
return false;
}
const handleExtsSelect = useCallback((val: any) => {
// unselect other options if "All Files" is checked
if (allowAllFiles && val.includes('all_files')) {
setSelectedExts(['all_files']);
} else if (validFileExtensions && isSelectionValid(validFileExtensions, val)) {
// If at least one extension is still selected, then assign this selection to the selected values
setSelectedExts(val);
} else {
// Else do nothing
setSelectedExts(selectedExts);
}
}, []);
useEffect(() => {
(async () => {
if (error) setError(null);
setLoading(true);
const listing = await getList(path, includeFiles);
const listing = await getList(
path,
includeFiles,
includeFolders,
selectedExts,
showHidden,
sort,
filter,
page,
max,
);
if (!listing.success) {
setListing({ files: [], realpath: path });
setListing({ files: [], realpath: path, total: 0 });
setLoading(false);
setError(listing.result as string);
logger.error(listing.result);
const theError = listing.result as string;
switch (theError) {
case theError.match(/\[Errno\s2.*/i)?.input:
case theError.match(/\[WinError\s3.*/i)?.input:
setError(FileErrorTypes.FileNotFound);
break;
default:
setRawError(theError);
setError(FileErrorTypes.Unknown);
break;
}
logger.debug(theError);
return;
} else {
setRawError(null);
setError(FileErrorTypes.None);
setFiles((listing.result as FileListing).files);
}
setLoading(false);
setListing(listing.result as FileListing);
logger.log('reloaded', path, listing);
})();
}, [path]);
}, [error, path, includeFiles, includeFolders, showHidden, sort, selectedExts, page]);
return (
<div className="deckyFilePicker">
<Focusable style={{ display: 'flex', flexDirection: 'row', paddingBottom: '10px' }}>
<DialogButton
style={{
minWidth: 'unset',
width: '40px',
flexGrow: '0',
borderRadius: 'unset',
margin: '0',
padding: '10px',
}}
onClick={() => {
const newPathArr = path.split('/');
newPathArr.pop();
let newPath = newPathArr.join('/');
if (newPath == '') newPath = '/';
setPath(newPath);
}}
>
<FaArrowUp />
</DialogButton>
<div style={{ flexGrow: '1', width: '100%' }}>
<TextField
value={path}
onChange={(e) => {
e.target.value && setPath(e.target.value);
}}
style={{ height: '100%' }}
/>
</div>
</Focusable>
<Focusable style={{ display: 'flex', flexDirection: 'column', height: '60vh', overflow: 'scroll' }}>
{loading && <SteamSpinner style={{ height: '100%' }} />}
{!loading &&
listing.files
.filter((file) => (includeFiles || file.isdir) && (!regex || regex.test(file.name)))
.map((file) => {
let extension = file.realpath.split('.').pop() as string;
return (
<DialogButton
style={{ borderRadius: 'unset', margin: '0', padding: '10px' }}
onClick={() => {
const fullPath = `${path}${path.endsWith('/') ? '' : '/'}${file.name}`;
if (file.isdir) setPath(fullPath);
else {
onSubmit({ path: fullPath, realpath: file.realpath });
closeModal?.();
}
}}
>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'flex-start' }}>
{file.isdir ? (
<FaFolder style={iconStyles} />
) : (
<div style={iconStyles}>
{file.realpath.includes('.') ? (
<FileIcon {...defaultStyles[extension]} {...styleDefObj[extension]} extension={''} />
) : (
<FileIcon />
)}
</div>
)}
<span
<>
<DialogBody className="deckyFilePicker">
<DialogControlsSection>
<Focusable flow-children="right" style={{ display: 'flex', marginBottom: '1em' }}>
<DialogButton
style={{
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
minWidth: 'unset',
width: '40px',
borderRadius: 'unset',
margin: '0',
padding: '10px',
}}
onClick={() => {
const newPathArr = path.split('/');
const lastPath = newPathArr.pop();
//If I have a single / with spaces, pop the array twice
if (lastPath?.match(/^\/\s*$/) != null) newPathArr.pop();
let newPath = newPathArr.join('/');
if (newPath == '') newPath = '/';
setPath(newPath);
}}
>
<FaArrowUp />
</DialogButton>
<div style={{ width: '100%' }}>
<TextField
value={path}
onChange={(e) => {
e.target.value && setPath(e.target.value);
}}
style={{ height: '100%' }}
/>
</div>
</Focusable>
<ControlsList alignItems="center" spacing="standard">
<ToggleField
highlightOnFocus={false}
label={t('FilePickerIndex.files.show_hidden')}
bottomSeparator="none"
checked={showHidden}
onChange={() => setShowHidden((x) => !x)}
/>
<Dropdown rgOptions={sortOptions} selectedOption={sort} onChange={(x) => setSort(x.data)} />
{validFileExtensions && (
<DropdownMultiselect
label={t('FilePickerIndex.files.file_type')}
items={validExtsOptions}
selected={selectedExts ? selectedExts : []}
onSelect={handleExtsSelect}
/>
)}
</ControlsList>
</DialogControlsSection>
<DialogControlsSection style={{ marginTop: '1em' }}>
<Focusable
style={{ display: 'flex', gap: '.25em', flexDirection: 'column', height: '60vh', overflow: 'scroll' }}
>
{loading && error === FileErrorTypes.None && <SteamSpinner style={{ height: '100%' }} />}
{!loading &&
error === FileErrorTypes.None &&
files.map((file) => {
const extension = file.realpath.split('.').pop() as string;
return (
<DialogButton
key={`${file.realpath}${file.name}`}
style={{ borderRadius: 'unset', margin: '0', padding: '10px' }}
onClick={() => {
const fullPath = `${path}${path.endsWith('/') ? '' : '/'}${file.name}`;
if (file.isdir) setPath(fullPath);
else {
onSubmit({ path: fullPath, realpath: file.realpath });
closeModal?.();
}
}}
>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'flex-start' }}>
{file.isdir ? (
<FaFolder style={iconStyles} />
) : (
<div style={iconStyles}>
{file.realpath.includes('.') ? (
<FileIcon {...defaultStyles[extension]} {...styleDefObj[extension]} extension={''} />
) : (
<FileIcon />
)}
</div>
)}
<Marquee>{file.name}</Marquee>
</div>
<div
style={{
textOverflow: 'ellipsis',
overflow: 'hidden',
display: 'flex',
opacity: 0.5,
fontSize: '.6em',
textAlign: 'left',
lineHeight: 1,
marginTop: '.5em',
}}
>
{file.name}
</span>
</div>
</DialogButton>
);
})}
{error}
</Focusable>
{file.isdir ? t('FilePickerIndex.folder.label') : filesize(file.size, { standard: 'iec' })}
<span style={{ marginLeft: 'auto' }}>{new Date(file.modified * 1000).toLocaleString()}</span>
</div>
</DialogButton>
);
})}
{error !== FileErrorTypes.None && <FilePickerError error={error} rawError={rawError ? rawError : ''} />}
</Focusable>
</DialogControlsSection>
</DialogBody>
{!loading && !error && !includeFiles && (
<DialogButton
className="Primary"
style={{ marginTop: '10px', alignSelf: 'flex-end' }}
onClick={() => {
onSubmit({ path, realpath: listing.realpath });
closeModal?.();
}}
>
{t('FilePickerIndex.folder.select')}
</DialogButton>
<DialogFooter>
<DialogButton
className="Primary"
style={{ marginTop: '10px', alignSelf: 'flex-end' }}
onClick={() => {
onSubmit({ path, realpath: listing.realpath });
closeModal?.();
}}
>
{t('FilePickerIndex.folder.select')}
</DialogButton>
</DialogFooter>
)}
</div>
{page * max < listing.total && (
<DialogFooter>
<DialogButton
className="Primary"
style={{ marginTop: '10px', alignSelf: 'flex-end' }}
onClick={() => {
setPage(page + 1);
}}
>
{t('FilePickerIndex.folder.show_more')}
</DialogButton>
</DialogFooter>
)}
</>
);
};
@@ -13,26 +13,24 @@ import { useTranslation } from 'react-i18next';
import { FaFileArchive, FaLink, FaReact, FaSteamSymbol, FaTerminal } from 'react-icons/fa';
import { setShouldConnectToReactDevTools, setShowValveInternal } from '../../../../developer';
import Logger from '../../../../logger';
import { installFromURL } from '../../../../store';
import { useSetting } from '../../../../utils/hooks/useSetting';
import { getSetting } from '../../../../utils/settings';
import RemoteDebuggingSettings from '../general/RemoteDebugging';
const installFromZip = () => {
window.DeckyPluginLoader.openFilePicker('/home/deck', true).then((val) => {
const logger = new Logger('DeveloperIndex');
const installFromZip = async () => {
const path = await getSetting<string>('user_info.user_home', '');
if (path === '') {
logger.error('The default path has not been found!');
return;
}
window.DeckyPluginLoader.openFilePicker(path, true, undefined, true, ['zip', 'rar'], false, true).then((val) => {
const url = `file://${val.path}`;
console.log(`Installing plugin locally from ${url}`);
if (url.endsWith('.zip')) {
installFromURL(url);
} else {
window.DeckyPluginLoader.toaster.toast({
//title: t('SettingsDeveloperIndex.toast_zip.title'),
title: 'Decky',
//body: t('SettingsDeveloperIndex.toast_zip.body'),
body: 'Installation failed! Only ZIP files are supported.',
onClick: installFromZip,
});
}
installFromURL(url);
});
};
@@ -21,7 +21,7 @@ const BranchSelect: FunctionComponent<{}> = () => {
t('BranchSelect.update_channel.prerelease'),
t('BranchSelect.update_channel.testing'),
];
const [selectedBranch, setSelectedBranch] = useSetting<UpdateBranch>('branch', UpdateBranch.Prerelease);
const [selectedBranch, setSelectedBranch] = useSetting<UpdateBranch>('branch', UpdateBranch.Stable);
return (
// Returns numerical values from 0 to 2 (with current branch setup as of 8/28/22)
@@ -0,0 +1,34 @@
import { FC } from 'react';
import { useTranslation } from 'react-i18next';
import { FaEyeSlash } from 'react-icons/fa';
interface PluginListLabelProps {
hidden: boolean;
name: string;
version?: string;
}
const PluginListLabel: FC<PluginListLabelProps> = ({ name, hidden, version }) => {
const { t } = useTranslation();
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
<div>{version ? `${name} - ${version}` : name}</div>
{hidden && (
<div
style={{
fontSize: '0.8rem',
color: '#dcdedf',
display: 'flex',
alignItems: 'center',
gap: '10px',
}}
>
<FaEyeSlash />
{t('PluginListLabel.hidden')}
</div>
)}
</div>
);
};
export default PluginListLabel;
@@ -22,10 +22,7 @@ import {
} from '../../../../store';
import { useSetting } from '../../../../utils/hooks/useSetting';
import { useDeckyState } from '../../../DeckyState';
function labelToName(pluginLabel: string, pluginVersion?: string): string {
return pluginVersion ? pluginLabel.substring(0, pluginLabel.indexOf(` - ${pluginVersion}`)) : pluginLabel;
}
import PluginListLabel from './PluginListLabel';
async function reinstallPlugin(pluginName: string, currentVersion?: string) {
const serverData = await getPluginList();
@@ -36,10 +33,17 @@ async function reinstallPlugin(pluginName: string, currentVersion?: string) {
}
}
function PluginInteractables(props: { entry: ReorderableEntry<PluginData> }) {
const data = props.entry.data;
type PluginTableData = PluginData & { name: string; hidden: boolean; onHide(): void; onShow(): void };
function PluginInteractables(props: { entry: ReorderableEntry<PluginTableData> }) {
const { t } = useTranslation();
let pluginName = labelToName(props.entry.label, data?.version);
// nothing to display without this data...
if (!props.entry.data) {
return null;
}
const { name, update, version, onHide, onShow, hidden } = props.entry.data;
const showCtxMenu = (e: MouseEvent | GamepadEvent) => {
showContextMenu(
@@ -47,7 +51,7 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginData> }) {
<MenuItem
onSelected={() => {
try {
fetch(`http://127.0.0.1:1337/plugins/${pluginName}/reload`, {
fetch(`http://127.0.0.1:1337/plugins/${name}/reload`, {
method: 'POST',
credentials: 'include',
headers: {
@@ -58,7 +62,7 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginData> }) {
console.error('Error Reloading Plugin Backend', err);
}
window.DeckyPluginLoader.importPlugin(pluginName, data?.version);
window.DeckyPluginLoader.importPlugin(name, version);
}}
>
{t('PluginListIndex.reload')}
@@ -66,15 +70,20 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginData> }) {
<MenuItem
onSelected={() =>
window.DeckyPluginLoader.uninstallPlugin(
pluginName,
t('PluginLoader.plugin_uninstall.title', { name: pluginName }),
name,
t('PluginLoader.plugin_uninstall.title', { name }),
t('PluginLoader.plugin_uninstall.button'),
t('PluginLoader.plugin_uninstall.desc', { name: pluginName }),
t('PluginLoader.plugin_uninstall.desc', { name }),
)
}
>
{t('PluginListIndex.uninstall')}
</MenuItem>
{hidden ? (
<MenuItem onSelected={onShow}>{t('PluginListIndex.show')}</MenuItem>
) : (
<MenuItem onSelected={onHide}>{t('PluginListIndex.hide')}</MenuItem>
)}
</Menu>,
e.currentTarget ?? window,
);
@@ -82,22 +91,22 @@ function PluginInteractables(props: { entry: ReorderableEntry<PluginData> }) {
return (
<>
{data?.update ? (
{update ? (
<DialogButton
style={{ height: '40px', minWidth: '60px', marginRight: '10px' }}
onClick={() => requestPluginInstall(pluginName, data?.update as StorePluginVersion, InstallType.UPDATE)}
onOKButton={() => requestPluginInstall(pluginName, data?.update as StorePluginVersion, InstallType.UPDATE)}
onClick={() => requestPluginInstall(name, update, InstallType.UPDATE)}
onOKButton={() => requestPluginInstall(name, update, InstallType.UPDATE)}
>
<div style={{ display: 'flex', minWidth: '180px', justifyContent: 'space-between', alignItems: 'center' }}>
{t('PluginListIndex.update_to', { name: data?.update?.name })}
{t('PluginListIndex.update_to', { name: update.name })}
<FaDownload style={{ paddingLeft: '1rem' }} />
</div>
</DialogButton>
) : (
<DialogButton
style={{ height: '40px', minWidth: '60px', marginRight: '10px' }}
onClick={() => reinstallPlugin(pluginName, data?.version)}
onOKButton={() => reinstallPlugin(pluginName, data?.version)}
onClick={() => reinstallPlugin(name, version)}
onOKButton={() => reinstallPlugin(name, version)}
>
<div style={{ display: 'flex', minWidth: '180px', justifyContent: 'space-between', alignItems: 'center' }}>
{t('PluginListIndex.reinstall')}
@@ -130,7 +139,7 @@ type PluginData = {
};
export default function PluginList() {
const { plugins, updates, pluginOrder, setPluginOrder } = useDeckyState();
const { plugins, updates, pluginOrder, setPluginOrder, hiddenPlugins } = useDeckyState();
const [_, setPluginOrderSetting] = useSetting<string[]>(
'pluginOrder',
plugins.map((plugin) => plugin.name),
@@ -141,22 +150,29 @@ export default function PluginList() {
window.DeckyPluginLoader.checkPluginUpdates();
}, []);
const [pluginEntries, setPluginEntries] = useState<ReorderableEntry<PluginData>[]>([]);
const [pluginEntries, setPluginEntries] = useState<ReorderableEntry<PluginTableData>[]>([]);
const hiddenPluginsService = window.DeckyPluginLoader.hiddenPluginsService;
useEffect(() => {
setPluginEntries(
plugins.map((plugin) => {
plugins.map(({ name, version }) => {
const hidden = hiddenPlugins.includes(name);
return {
label: plugin.version ? `${plugin.name} - ${plugin.version}` : plugin.name,
label: <PluginListLabel name={name} hidden={hidden} version={version} />,
position: pluginOrder.indexOf(name),
data: {
update: updates?.get(plugin.name),
version: plugin.version,
name,
hidden,
version,
update: updates?.get(name),
onHide: () => hiddenPluginsService.update([...hiddenPlugins, name]),
onShow: () => hiddenPluginsService.update(hiddenPlugins.filter((pluginName) => name !== pluginName)),
},
position: pluginOrder.indexOf(plugin.name),
};
}),
);
}, [plugins, updates]);
}, [plugins, updates, hiddenPlugins]);
if (plugins.length === 0) {
return (
@@ -166,8 +182,8 @@ export default function PluginList() {
);
}
function onSave(entries: ReorderableEntry<PluginData>[]) {
const newOrder = entries.map((entry) => labelToName(entry.label, entry?.data?.version));
function onSave(entries: ReorderableEntry<PluginTableData>[]) {
const newOrder = entries.map((entry) => entry.data!.name);
console.log(newOrder);
setPluginOrder(newOrder);
setPluginOrderSetting(newOrder);
@@ -200,7 +216,7 @@ export default function PluginList() {
</DialogButton>
)}
<DialogControlsSection style={{ marginTop: 0 }}>
<ReorderableList<PluginData> entries={pluginEntries} onSave={onSave} interactables={PluginInteractables} />
<ReorderableList<PluginTableData> entries={pluginEntries} onSave={onSave} interactables={PluginInteractables} />
</DialogControlsSection>
</DialogBody>
);
-1
View File
@@ -1,5 +1,4 @@
import { findModuleChild, sleep } from 'decky-frontend-lib';
import { useTranslation } from 'react-i18next';
import { FaReact } from 'react-icons/fa';
import Logger from './logger';
+34
View File
@@ -0,0 +1,34 @@
import { DeckyState } from './components/DeckyState';
import { getSetting, setSetting } from './utils/settings';
/**
* A Service class for managing the state and actions related to the hidden plugins feature
*
* It's mostly responsible for sending setting updates to the server and keeping the local state in sync.
*/
export class HiddenPluginsService {
constructor(private deckyState: DeckyState) {}
init() {
getSetting<string[]>('hiddenPlugins', []).then((hiddenPlugins) => {
this.deckyState.setHiddenPlugins(hiddenPlugins);
});
}
/**
* Sends the new hidden plugins list to the server and persists it locally in the decky state
*
* @param hiddenPlugins The new list of hidden plugins
*/
async update(hiddenPlugins: string[]) {
await setSetting('hiddenPlugins', hiddenPlugins);
this.deckyState.setHiddenPlugins(hiddenPlugins);
}
/**
* Refreshes the state of hidden plugins in the local state
*/
async invalidate() {
this.deckyState.setHiddenPlugins(await getSetting('hiddenPlugins', []));
}
}
+31 -20
View File
@@ -1,5 +1,4 @@
import {
ConfirmModal,
ModalRoot,
PanelSection,
PanelSectionRow,
@@ -13,14 +12,17 @@ import {
import { FC, lazy } from 'react';
import { FaExclamationCircle, FaPlug } from 'react-icons/fa';
import { DeckyState, DeckyStateContextProvider, useDeckyState } from './components/DeckyState';
import { DeckyState, DeckyStateContextProvider, UserInfo, useDeckyState } from './components/DeckyState';
import LegacyPlugin from './components/LegacyPlugin';
import { File } from './components/modals/filepicker';
import { deinitFilepickerPatches, initFilepickerPatches } from './components/modals/filepicker/patches';
import MultiplePluginsInstallModal from './components/modals/MultiplePluginsInstallModal';
import PluginInstallModal from './components/modals/PluginInstallModal';
import PluginUninstallModal from './components/modals/PluginUninstallModal';
import NotificationBadge from './components/NotificationBadge';
import PluginView from './components/PluginView';
import WithSuspense from './components/WithSuspense';
import { HiddenPluginsService } from './hidden-plugins-service';
import Logger from './logger';
import { InstallType, Plugin } from './plugin';
import RouterHook from './router-hook';
@@ -30,7 +32,7 @@ import TabsHook from './tabs-hook';
import OldTabsHook from './tabs-hook.old';
import Toaster from './toaster';
import { VerInfo, callUpdaterMethod } from './updater';
import { getSetting } from './utils/settings';
import { getSetting, setSetting } from './utils/settings';
import TranslationHelper, { TranslationClass } from './utils/TranslationHelper';
const StorePage = lazy(() => import('./components/store/Store'));
@@ -45,6 +47,7 @@ class PluginLoader extends Logger {
private routerHook: RouterHook = new RouterHook();
public toaster: Toaster = new Toaster();
private deckyState: DeckyState = new DeckyState();
public hiddenPluginsService = new HiddenPluginsService(this.deckyState);
private reloadLock: boolean = false;
// stores a list of plugin names which requested to be reloaded
@@ -97,9 +100,17 @@ class PluginLoader extends Logger {
initFilepickerPatches();
this.getUserInfo();
this.updateVersion();
}
public async getUserInfo() {
const userInfo = (await this.callServerMethod('get_user_info')).result as UserInfo;
setSetting('user_info.user_name', userInfo.username);
setSetting('user_info.user_home', userInfo.path);
}
public async updateVersion() {
const versionInfo = (await callUpdaterMethod('get_version')).result as VerInfo;
this.deckyState.setVersionInfo(versionInfo);
@@ -182,21 +193,8 @@ class PluginLoader extends Logger {
);
}
public uninstallPlugin(name: string, title: string, button_text: string, description: string) {
showModal(
<ConfirmModal
onOK={async () => {
await this.callServerMethod('uninstall_plugin', { name });
}}
onCancel={() => {
// do nothing
}}
strTitle={title}
strOKButtonText={button_text}
>
{description}
</ConfirmModal>,
);
public uninstallPlugin(name: string, title: string, buttonText: string, description: string) {
showModal(<PluginUninstallModal name={name} title={title} buttonText={buttonText} description={description} />);
}
public hasPlugin(name: string) {
@@ -220,6 +218,8 @@ class PluginLoader extends Logger {
console.log(pluginOrder);
this.deckyState.setPluginOrder(pluginOrder);
});
this.hiddenPluginsService.init();
}
public deinit() {
@@ -277,6 +277,7 @@ class PluginLoader extends Logger {
Authentication: window.deckyAuthToken,
},
});
if (res.ok) {
try {
let plugin_export = await eval(await res.text());
@@ -361,7 +362,12 @@ class PluginLoader extends Logger {
openFilePicker(
startPath: string,
includeFiles?: boolean,
regex?: RegExp,
filter?: RegExp | ((file: File) => boolean),
includeFolders?: boolean,
extensions?: string[],
showHiddenFiles?: boolean,
allowAllFiles?: boolean,
max?: number,
): Promise<{ path: string; realpath: string }> {
return new Promise((resolve, reject) => {
const Content = ({ closeModal }: { closeModal?: () => void }) => (
@@ -376,9 +382,14 @@ class PluginLoader extends Logger {
<FilePicker
startPath={startPath}
includeFiles={includeFiles}
regex={regex}
includeFolders={includeFolders}
filter={filter}
validFileExtensions={extensions}
allowAllFiles={allowAllFiles}
defaultHidden={showHiddenFiles}
onSubmit={resolve}
closeModal={closeModal}
max={max}
/>
</WithSuspense>
</ModalRoot>
+9 -6
View File
@@ -128,7 +128,13 @@ class TabsHook extends Logger {
let deckyTabAmount = existingTabs.reduce((prev: any, cur: any) => (cur.decky ? prev + 1 : prev), 0);
if (deckyTabAmount == this.tabs.length) {
for (let tab of existingTabs) {
if (tab?.decky && tab?.qAMVisibilitySetter) tab?.qAMVisibilitySetter(visible);
if (tab?.decky) {
if (tab?.qAMVisibilitySetter) {
tab?.qAMVisibilitySetter(visible);
} else {
tab.initialVisibility = visible;
}
}
}
return;
}
@@ -138,12 +144,9 @@ class TabsHook extends Logger {
title,
tab: icon,
decky: true,
initialVisibility: visible,
};
tab.panel = (
<QuickAccessVisibleStateProvider initial={visible} tab={tab}>
{content}
</QuickAccessVisibleStateProvider>
);
tab.panel = <QuickAccessVisibleStateProvider tab={tab}>{content}</QuickAccessVisibleStateProvider>;
existingTabs.push(tab);
}
}