Compare commits

...
12 Commits
Author SHA1 Message Date
Roman Tarasov 1cc20f44af Remove deprecated KStuff pause/autotune support 2026-06-21 01:54:55 +03:00
Roman Tarasov 2eb9164a51 Add configurable notification language 2026-06-21 01:30:20 +03:00
Drakmor 98bf401481 Merge pull request #62 from emald6969/patch-3
Update fr_fr.inc
2026-06-07 15:05:07 +03:00
Drakmor 6dc8059ada Merge pull request #65 from emald6969/patch-6
Update fr_ca.inc
2026-06-07 15:04:43 +03:00
emald6969 cf7ef3517a Update fr_ca.inc 2026-06-04 23:07:16 +01:00
emald6969 5b2e057295 Update fr_fr.inc
fixed a typo sorry
2026-06-04 20:20:38 +01:00
Drakmor 1b5d178889 Merge pull request #60 from PSBrew/l10n
l10n: Brazilian Portuguese (pt-BR) translation review
2026-06-04 09:46:42 +03:00
Renan 2622818dd5 l10n: Brazilian Portuguese (pt-BR) translation review 2026-06-03 23:22:43 -03:00
Renan 0a3c380766 l10n: Brazilian Portuguese (pt-BR) translation review 2026-06-03 23:17:05 -03:00
Drakmor c05ff8899b Merge pull request #58 from emald6969/patch-1
Update ar_sa.inc
2026-06-03 23:51:07 +03:00
emald6969 8f89369449 Update ar_sa.inc 2026-06-03 21:33:03 +01:00
Roman Tarasov 31181f2d60 Add localized notifications 2026-06-03 22:44:37 +03:00
56 changed files with 1498 additions and 2235 deletions

No files matched your search

+6 -30
View File
@@ -11,7 +11,9 @@
**ShadowMountPlus** is a fully automated, background "Auto-Mounter" payload for Jailbroken PlayStation 5 consoles. It streamlines the game mounting process by eliminating the need for manual configuration or external tools (such as DumpRunner or Itemzflow). ShadowMountPlus automatically detects, mounts, and installs game dumps from both **internal and external storage**.
**Compatibility:** Supports all Jailbroken PS5 firmwares running **[Kstuff-lite v1.07+](https://github.com/EchoStretch/kstuff-lite)**.
**Compatibility:** Supports all Jailbroken PS5 firmwares running **[Kstuff-lite](https://github.com/EchoStretch/kstuff-lite)**.
**Important:** This version no longer supports ShadowMount-managed Kstuff autopause. Use a current Kstuff-lite build; older Kstuff/autopause setups are not supported.
## 💜 Support Development
@@ -54,6 +56,7 @@ This file is optional. If it does not exist, ShadowMountPlus creates it from the
Supported keys (all optional):
- `debug=1|0` (`1` enables `log_debug` output to console + `/data/shadowmount/debug.log`; default is `1`)
- `quiet_mode=1|0` (`1` suppresses plain informational popups but keeps rich toasts; default is `0`)
- `language=auto|<locale>` (notification language; `auto` uses the console system language, e.g. `en-US`, `ru-RU`; default: `auto`)
- `mount_read_only=1|0` (default: `1`)
- `force_mount=1|0` (mounting even damaged file systems; default: `0`)
- `app_install_all=1|0` (`1` stages new titles and submits them through `sceAppInstUtilAppInstallAll`; default: `0` on FW below `12.00`, forced `1` on FW `12.00+`)
@@ -71,15 +74,7 @@ Supported keys (all optional):
- `global_fakelib_path=<absolute_path>` (global fakelib folder; default: `/data/shadowmount/fakelib`)
- `global_fakelib_priority=game|global` (overlay priority when both global and game fakelib exist; default: `game`)
- `global_fakelib_exclude=<TITLE_ID>` (repeatable; disables the global fakelib overlay for matching titles)
- `kstuff_game_auto_toggle=1|0` (`1` pauses kstuff after tracked game launches and resumes it on stop; default: `1`)
- `kstuff_crash_detection=1|0` (`1` enables crash monitoring and pause-delay autotune updates; default: `1`)
- `kstuff_pause_delay_image_seconds=<0..3600>` (delay before pausing kstuff for image-backed launches; default: `25`)
- `kstuff_pause_delay_direct_seconds=<0..3600>` (delay before pausing kstuff for direct/non-image launches; default: `15`)
- `kstuff_no_pause=<TITLE_ID>` (repeatable; keeps kstuff enabled for matching titles)
- `kstuff_delay=<TITLE_ID>:<0..3600>` (repeatable; per-title pause delay override, last matching rule wins)
- `/data/shadowmount/autotune.ini` may also provide per-title pause-delay overrides with highest priority:
- `kstuff_delay=<TITLE_ID>:<0..3600>`
- `<TITLE_ID>=<0..3600>`
- `/data/shadowmount/autotune.ini` may also provide image-sector overrides with highest priority:
- `image_sector=<image_filename>:<sector_size>`
- `scanpath=<absolute_path>` (can be repeated on multiple lines; default: built-in scan path list below)
- `lvd_exfat_sector_size=<value>` (default: `512`)
@@ -132,26 +127,6 @@ Backport overlay behavior:
- `backport_fakelib=0` disables the sandbox `fakelib` watcher, including global fakelib.
- For `backport_fakelib` to work correctly, the standalone `BackPork` payload must be disabled. Running both at the same time will conflict.
Kstuff game lifecycle behavior:
- When `kstuff_game_auto_toggle=1`, ShadowMount watches game `exec/exit` events in the background.
- Image-backed launches use `kstuff_pause_delay_image_seconds`; direct/non-image launches use `kstuff_pause_delay_direct_seconds`.
- `kstuff_crash_detection=0` disables crash monitoring and the automatic pause-delay tuning logic, while leaving normal kstuff auto-pause/auto-resume behavior intact.
- `kstuff_no_pause` skips auto-pause entirely for matching title IDs.
- `kstuff_delay` overrides the pause delay for matching title IDs, regardless of image/direct launch type.
- `/data/shadowmount/autotune.ini` overrides both `config.ini` and `autopause.txt` for matching title IDs.
- `/data/shadowmount/autotune.ini` also overrides `image_sector` rules from `config.ini` for matching image file names.
- A game source folder may optionally contain `autopause.txt`; it is read once at launch time.
- Priority order is: `autotune.ini` -> `kstuff_delay` from `config.ini` -> `autopause.txt` -> global direct/image default delay.
- If `autopause.txt` contains only a number, that value is used for direct launches and doubled for image-backed launches.
- `autopause.txt` may also use:
- `direct=<seconds>`
- `image=<seconds>`
- If both kinds of rule target the same title, `kstuff_no_pause` takes priority.
- When crash monitoring detects an app crash before kstuff was paused, ShadowMountPlus only notifies that the app crashed and kstuff is not to blame.
- When crash monitoring detects an app crash within 2 minutes after kstuff auto-pause, ShadowMountPlus doubles the applied pause delay for that title and upserts it into `/data/shadowmount/autotune.ini` (up to `3600` seconds), then prompts you to launch the game again.
- When the last tracked game stops, ShadowMount immediately enables kstuff again if it was the component that disabled it.
Validation:
- See `config.ini.example` for a ready-to-use template.
@@ -449,6 +424,7 @@ If a game is mounted but does not start:
* VoidWhisper for ShadowMount
* BestPig for BackPort
* EchoStretch for kstuff-toggle and etc
* Idlesauce
* Gezine
* earthonion
* LightningMods
+6 -27
View File
@@ -21,6 +21,12 @@
# Default: 0
# quiet_mode=0
# Notification language:
# auto -> use the console system language
# Or set a supported locale, for example: en-US, ru-RU, de-DE, fr-FR, es-ES
# Default: auto
# language=auto
# Global mount mode:
# 1/true/yes/on/ro -> read-only mounts
# 0/false/no/off/rw -> read-write mounts
@@ -90,26 +96,6 @@
## Exclude specific title IDs from the global fakelib overlay (repeatable):
## global_fakelib_exclude=PPSA12345
# Auto-manage kstuff around game launches:
# 1/true/yes/on -> pause kstuff after game launch, resume immediately on stop
# 0/false/no/off -> leave kstuff state untouched
# Default: 1
# kstuff_game_auto_toggle=1
# Detect crash-candidate state and autotune pause delay:
# 1/true/yes/on -> enable crash monitoring and autotune updates
# 0/false/no/off -> disable crash detection/autotune logic
# Default: 1
# kstuff_crash_detection=1
# Delay before pausing kstuff for image-backed titles.
# Default: 25
# kstuff_pause_delay_image_seconds=25
# Delay before pausing kstuff for direct/non-image launches.
# Default: 15
# kstuff_pause_delay_direct_seconds=15
# Backend-specific sector size overrides:
# Defaults: lvd_exfat=512, lvd_ufs=4096, lvd_pfs=32768, md_exfat=512, md_ufs=512
# lvd_exfat_sector_size=512
@@ -134,13 +120,6 @@
## image_rw=My Game Dump.exfat
## image_sector=My Game Dump.exfat:65536
## Keep kstuff enabled for specific title IDs (repeatable):
## kstuff_no_pause=PPSA12345
## Override pause delay for specific title IDs (repeatable):
## Format: TITLEID:SECONDS
## kstuff_delay=PPSA12345:30
## More custom scan root examples:
## scanpath=/data/homebrew
## scanpath=/data/etaHEN/games
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_ar_sa[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "الانتقال إلى إعدادات التصحيح",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "+شادوماونت v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "شادوماونت+: لم يعد الفحص التكراري مدعوماً، وسيتم استخدام عمق الفحص ٢.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "شادوماونت+: تم تفعيل عمق الفحص %u.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = ":\n%s\n%s\n0x%08X فشلت تهيئة اللعبة للإصدارات الأقدم",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = ":%s تمت تهيئة اللعبة للإصدارات الأقدم",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "تم رفض تحميل الصورة:\n%s\nحجم الكتلة صغير جداً (%llu < %u).\nتم حفظ قيمة حجم القطاع الجديدة: %u.\nحاول التحميل مرة أخرى.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "تم رفض تحميل الصورة:\n%s\nحجم الكتلة صغير جداً (%llu < %u).\nاستخدم حجماً أكبر للكتلة في الصورة أو حجماً أصغر للقطاع في الإعدادات.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "فشل التسجيل: %s (%s)\nمجلد تثبيت التطبيقات غير متاح",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "فشل التسجيل: %s (%s)\nالرمز=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "جارٍ التثبيت: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "تم التثبيت: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "فشل تحميل الصورة: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "حجم كتلة نظام الملفات (%llu) أصغر من حجم قطاع الجهاز (%u) لـ %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "الصورة المحمّلة غير قابلة للقراءة أو تالفة",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "الذاكرة المؤقتة للصور ممتلئة (%u مدخلاً)، وتعذر تتبع %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "الذاكرة المؤقتة للصور ممتلئة (%u مدخلاً)، جارٍ التراجع عن العملية",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "فشل التثبيت: %s (%s)\nانتهت المهلة بعد 5 دقائق",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "تمت إضافة التثبيت الجماعي إلى قائمة الانتظار (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... و %d أخرى",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "فشل التثبيت الجماعي لـ %d تطبيق.\nالرمز=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "ملف param.json مفقود أو غير صالح:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "تم العثور على %d ألعاب جديدة. جارٍ التنفيذ...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "تمت مزامنة المكتبة.\nتم العثور على %d ألعاب.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "شادوماونت+: تمت إعادة تحميل الإعدادات.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "تم تجاهل عنصر مكرر.\n%s\n%s\nالموجود مسبقاً\n%s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_cs_cz[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Přejít do nastavení ladění",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 je zastaralé, používá se scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: hloubka skenu %u povolena.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay selhal: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Backport hry použit: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Připojení obrazu odmítnuto:\n%s\nVelikost clusteru je příliš malá (%llu < %u).\nUloženo přepsání image_sector: %u.\nZkuste připojit znovu.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Připojení obrazu odmítnuto:\n%s\nVelikost clusteru je příliš malá (%llu < %u).\nPoužijte větší cluster v obrazu nebo nižší sector size v config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrace selhala: %s (%s)\nAppInstallTitleDir není dostupné",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrace selhala: %s (%s)\nkód=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Instalace: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Nainstalováno: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Připojení obrazu selhalo: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Velikost clusteru souborového systému (%llu) je menší než velikost sektoru zařízení (%u) pro %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Připojený obraz je nečitelný nebo poškozený",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache obrazů plná (%u položek), nelze sledovat mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache obrazů plná (%u položek), vracím mount zpět",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Instalace selhala: %s (%s)\nČasový limit po 5 minutách",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Dávková instalace ve frontě (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... a dalších %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Dávková instalace selhala pro %d aplikací.\nkód=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "Chybí nebo je neplatný param.json:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Nalezeno %d nových her. Spouštím...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Knihovna synchronizována.\nNalezeno %d her.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config znovu načten.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplicitní %s ignorováno:\n%s\nexistující: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_da_dk[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Gå til fejlfindingsindstillinger",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 er forældet, bruger scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: scanningsdybde %u aktiveret.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport-overlay mislykkedes: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Spil backportet: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image-mount afvist:\n%s\nKlyngestørrelsen er for lille (%llu < %u).\nimage_sector-tilsidesættelse gemt: %u.\nPrøv at mounte igen.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image-mount afvist:\n%s\nKlyngestørrelsen er for lille (%llu < %u).\nBrug større klynger i image eller lavere sector size i config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrering mislykkedes: %s (%s)\nAppInstallTitleDir ikke tilgængelig",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrering mislykkedes: %s (%s)\nkode=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Installerer: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Installeret: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image-mount mislykkedes: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Filsystemets klyngestørrelse (%llu) er mindre end enhedens sektorstørrelse (%u) for %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Mountet image er ulæseligt eller beskadiget",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Image-cache fuld (%u poster), kan ikke spore mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Image-cache fuld (%u poster), ruller mount tilbage",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Installation mislykkedes: %s (%s)\nTimeout efter 5 minutter",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Batchinstallation i kø (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... og %d mere",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Batchinstallation mislykkedes for %d app(s).\nkode=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json mangler eller er ugyldig:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Fandt %d nye spil. Kører...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Bibliotek synkroniseret.\nFandt %d spil.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config genindlæst.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Dublet %s ignoreret:\n%s\neksisterende: %s",
};
+32
View File
@@ -0,0 +1,32 @@
static const char *const g_de_de[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Zu Debug-Einstellungen",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 ist veraltet, scan_depth=2 wird verwendet.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: Scan-Tiefe %u aktiviert.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport-Overlay fehlgeschlagen: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Spiel backportiert: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image-Mount abgelehnt:\n%s\nClustergröße ist zu klein (%llu < %u).\nimage_sector-Override gespeichert: %u.\nErneut mounten.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image-Mount abgelehnt:\n%s\nClustergröße ist zu klein (%llu < %u).\nVerwende eine größere Clustergröße im Image oder eine kleinere sector size in der Config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrierung fehlgeschlagen: %s (%s)\nAppInstallTitleDir nicht verfügbar",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrierung fehlgeschlagen: %s (%s)\nCode=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Installiere: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Installiert: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image-Mount fehlgeschlagen: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */
[SM_L10N_FS_CLUSTER_SMALL] = "Dateisystem-Clustergröße (%llu) ist kleiner als Gerätesektorgröße (%u) für %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Gemountetes Image ist nicht lesbar oder beschädigt",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Image-Cache voll (%u Einträge), Mount %s kann nicht verfolgt werden",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Image-Cache voll (%u Einträge), Mount wird zurückgesetzt",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Installation fehlgeschlagen: %s (%s)\nZeitüberschreitung nach 5 Minuten",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Batch-Installation eingereiht (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... und %d weitere",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Batch-Installation für %d App(s) fehlgeschlagen.\nCode=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json fehlt oder ist ungültig:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d neue Spiele gefunden. Ausführung...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Bibliothek synchronisiert.\n%d Spiele gefunden.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: Config neu geladen.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplikat %s ignoriert:\n%s\nvorhanden: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_el_gr[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Μετάβαση στις ρυθμίσεις αποσφαλμάτωσης",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: το recursive_scan=1 είναι παρωχημένο, χρησιμοποιείται scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: ενεργό βάθος σάρωσης %u.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Αποτυχία backport overlay: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Εφαρμόστηκε backport στο παιχνίδι: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Απορρίφθηκε το mount του image:\n%s\nΤο μέγεθος cluster είναι πολύ μικρό (%llu < %u).\nΑποθηκεύτηκε override image_sector: %u.\nΔοκιμάστε ξανά.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Απορρίφθηκε το mount του image:\n%s\nΤο μέγεθος cluster είναι πολύ μικρό (%llu < %u).\nΧρησιμοποιήστε μεγαλύτερο cluster στο image ή μικρότερο sector size στο config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Αποτυχία εγγραφής: %s (%s)\nΤο AppInstallTitleDir δεν είναι διαθέσιμο",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Αποτυχία εγγραφής: %s (%s)\nκωδικός=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Εγκατάσταση: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Εγκαταστάθηκε: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Αποτυχία mount image: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Το μέγεθος cluster του συστήματος αρχείων (%llu) είναι μικρότερο από το μέγεθος sector της συσκευής (%u) για %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Το mounted image δεν διαβάζεται ή είναι κατεστραμμένο",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Η cache image είναι πλήρης (%u εγγραφές), δεν μπορεί να παρακολουθηθεί το mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Η cache image είναι πλήρης (%u εγγραφές), γίνεται rollback του mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Αποτυχία εγκατάστασης: %s (%s)\nTimeout μετά από 5 λεπτά",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Μαζική εγκατάσταση στην ουρά (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... και %d ακόμα",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Η μαζική εγκατάσταση απέτυχε για %d app(s).\nκωδικός=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "Λείπει ή είναι άκυρο το param.json:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Βρέθηκαν %d νέα παιχνίδια. Εκτέλεση...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Η βιβλιοθήκη συγχρονίστηκε.\nΒρέθηκαν %d παιχνίδια.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: το config επαναφορτώθηκε.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Το διπλότυπο %s αγνοήθηκε:\n%s\nυπάρχον: %s",
};
+43
View File
@@ -0,0 +1,43 @@
static const char *const g_en_gb[SM_L10N_COUNT] = {
[SM_L10N_ACTION_DEBUG_SETTINGS] = "Go to Debug Settings",
[SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] =
"ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2.",
[SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: scan depth %u enabled.",
[SM_L10N_BACKPORT_OVERLAY_FAILED] =
"Backport overlay failed: %s\n%s\n0x%08X",
[SM_L10N_GAME_BACKPORTED] = "Game backported: %s",
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] =
"Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\n"
"Saved image_sector override: %u.\nTry mounting again.",
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] =
"Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\n"
"Use a larger cluster size in the image or lower sector size in config.",
[SM_L10N_REGISTER_FAILED_UNAVAILABLE] =
"Register failed: %s (%s)\nAppInstallTitleDir unavailable",
[SM_L10N_REGISTER_FAILED_CODE] = "Register failed: %s (%s)\ncode=0x%08X",
[SM_L10N_INSTALLING] = "Installing: %s (%s)...",
[SM_L10N_INSTALLED] = "Installed: %s",
[SM_L10N_IMAGE_MOUNT_FAILED] = "Image mount failed: 0x%08X (%s)\n%s",
[SM_L10N_FS_CLUSTER_SMALL] =
"Filesystem cluster size (%llu) is smaller than device sector size "
"(%u) for %s",
[SM_L10N_IMAGE_UNREADABLE_DAMAGED] =
"Mounted image is unreadable or damaged",
[SM_L10N_IMAGE_CACHE_FULL_TRACK] =
"Image cache full (%u entries), cannot track mount %s",
[SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] =
"Image cache full (%u entries), rolling back mount",
[SM_L10N_INSTALL_FAILED_TIMEOUT] =
"Install failed: %s (%s)\nTimed out after 5 minutes",
[SM_L10N_BATCH_INSTALL_QUEUED] = "Batch install queued (%d):",
[SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... and %d more",
[SM_L10N_BATCH_INSTALL_FAILED] =
"Batch install failed for %d app(s).\ncode=0x%08X",
[SM_L10N_MISSING_PARAM] = "Missing/invalid param.json:\n%s",
[SM_L10N_FOUND_NEW_GAMES] = "Found %d new games. Executing...",
[SM_L10N_LIBRARY_SYNCED] = "Library Synchronised.\nFound %d games.",
[SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config reloaded.",
[SM_L10N_DUPLICATE_IGNORED] =
"Duplicate %s ignored:\n%s\nexisting: %s",
};
+43
View File
@@ -0,0 +1,43 @@
static const char *const g_en_us[SM_L10N_COUNT] = {
[SM_L10N_ACTION_DEBUG_SETTINGS] = "Go to Debug Settings",
[SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] =
"ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2.",
[SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: scan depth %u enabled.",
[SM_L10N_BACKPORT_OVERLAY_FAILED] =
"Backport overlay failed: %s\n%s\n0x%08X",
[SM_L10N_GAME_BACKPORTED] = "Game backported: %s",
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] =
"Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\n"
"Saved image_sector override: %u.\nTry mounting again.",
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] =
"Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\n"
"Use a larger cluster size in the image or lower sector size in config.",
[SM_L10N_REGISTER_FAILED_UNAVAILABLE] =
"Register failed: %s (%s)\nAppInstallTitleDir unavailable",
[SM_L10N_REGISTER_FAILED_CODE] = "Register failed: %s (%s)\ncode=0x%08X",
[SM_L10N_INSTALLING] = "Installing: %s (%s)...",
[SM_L10N_INSTALLED] = "Installed: %s",
[SM_L10N_IMAGE_MOUNT_FAILED] = "Image mount failed: 0x%08X (%s)\n%s",
[SM_L10N_FS_CLUSTER_SMALL] =
"Filesystem cluster size (%llu) is smaller than device sector size "
"(%u) for %s",
[SM_L10N_IMAGE_UNREADABLE_DAMAGED] =
"Mounted image is unreadable or damaged",
[SM_L10N_IMAGE_CACHE_FULL_TRACK] =
"Image cache full (%u entries), cannot track mount %s",
[SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] =
"Image cache full (%u entries), rolling back mount",
[SM_L10N_INSTALL_FAILED_TIMEOUT] =
"Install failed: %s (%s)\nTimed out after 5 minutes",
[SM_L10N_BATCH_INSTALL_QUEUED] = "Batch install queued (%d):",
[SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... and %d more",
[SM_L10N_BATCH_INSTALL_FAILED] =
"Batch install failed for %d app(s).\ncode=0x%08X",
[SM_L10N_MISSING_PARAM] = "Missing/invalid param.json:\n%s",
[SM_L10N_FOUND_NEW_GAMES] = "Found %d new games. Executing...",
[SM_L10N_LIBRARY_SYNCED] = "Library Synchronized.\nFound %d games.",
[SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config reloaded.",
[SM_L10N_DUPLICATE_IGNORED] =
"Duplicate %s ignored:\n%s\nexisting: %s",
};
+69
View File
@@ -0,0 +1,69 @@
static const char *const g_es_es[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */
[SM_L10N_ACTION_DEBUG_SETTINGS] = "Ir a ajustes de depuración",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */
[SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] =
"ShadowMount+: recursive_scan=1 está obsoleto, se usará scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */
[SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: profundidad de escaneo %u activada.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */
[SM_L10N_BACKPORT_OVERLAY_FAILED] =
"Error en overlay de backport: %s\n%s\n0x%08X",
/* English: Game backported: %s */
[SM_L10N_GAME_BACKPORTED] = "Juego con backport aplicado: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] =
"Montaje de imagen rechazado:\n%s\nEl tamaño de clúster es demasiado pequeño (%llu < %u).\n"
"Anulación image_sector guardada: %u.\nIntente montar de nuevo.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] =
"Montaje de imagen rechazado:\n%s\nEl tamaño de clúster es demasiado pequeño (%llu < %u).\n"
"Use un clúster mayor en la imagen o un sector size menor en la configuración.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */
[SM_L10N_REGISTER_FAILED_UNAVAILABLE] =
"Error al registrar: %s (%s)\nAppInstallTitleDir no disponible",
/* English: Register failed: %s (%s)\ncode=0x%08X */
[SM_L10N_REGISTER_FAILED_CODE] =
"Error al registrar: %s (%s)\ncódigo=0x%08X",
/* English: Installing: %s (%s)... */
[SM_L10N_INSTALLING] = "Instalando: %s (%s)...",
/* English: Installed: %s */
[SM_L10N_INSTALLED] = "Instalado: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */
[SM_L10N_IMAGE_MOUNT_FAILED] = "Error al montar imagen: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */
[SM_L10N_FS_CLUSTER_SMALL] =
"El tamaño de clúster del sistema de archivos (%llu) es menor que el tamaño de sector del dispositivo (%u) para %s",
/* English: Mounted image is unreadable or damaged */
[SM_L10N_IMAGE_UNREADABLE_DAMAGED] =
"La imagen montada es ilegible o está dañada",
/* English: Image cache full (%u entries), cannot track mount %s */
[SM_L10N_IMAGE_CACHE_FULL_TRACK] =
"Caché de imágenes llena (%u entradas), no se puede rastrear el mount %s",
/* English: Image cache full (%u entries), rolling back mount */
[SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] =
"Caché de imágenes llena (%u entradas), revirtiendo mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */
[SM_L10N_INSTALL_FAILED_TIMEOUT] =
"Error de instalación: %s (%s)\nTiempo agotado tras 5 minutos",
/* English: Batch install queued (%d): */
[SM_L10N_BATCH_INSTALL_QUEUED] = "Instalación por lotes en cola (%d):",
/* English: \n... and %d more */
[SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... y %d más",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */
[SM_L10N_BATCH_INSTALL_FAILED] =
"Error de instalación por lotes para %d aplicación(es).\ncódigo=0x%08X",
/* English: Missing/invalid param.json:\n%s */
[SM_L10N_MISSING_PARAM] = "param.json ausente o no válido:\n%s",
/* English: Found %d new games. Executing... */
[SM_L10N_FOUND_NEW_GAMES] = "Se encontraron %d juegos nuevos. Ejecutando...",
/* English: Library Synchronized.\nFound %d games. */
[SM_L10N_LIBRARY_SYNCED] = "Biblioteca sincronizada.\nSe encontraron %d juegos.",
/* English: ShadowMount+: config reloaded. */
[SM_L10N_CONFIG_RELOADED] = "ShadowMount+: configuración recargada.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */
[SM_L10N_DUPLICATE_IGNORED] =
"Duplicado %s ignorado:\n%s\nexistente: %s",
};
+69
View File
@@ -0,0 +1,69 @@
static const char *const g_es_mx[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */
[SM_L10N_ACTION_DEBUG_SETTINGS] = "Ir a configuración de depuración",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */
[SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] =
"ShadowMount+: recursive_scan=1 está obsoleto, se usará scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */
[SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: profundidad de escaneo %u activada.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */
[SM_L10N_BACKPORT_OVERLAY_FAILED] =
"Falló el overlay de backport: %s\n%s\n0x%08X",
/* English: Game backported: %s */
[SM_L10N_GAME_BACKPORTED] = "Backport aplicado al juego: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] =
"Montaje de imagen rechazado:\n%s\nEl tamaño de clúster es demasiado pequeño (%llu < %u).\n"
"Se guardó la anulación image_sector: %u.\nIntenta montar de nuevo.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] =
"Montaje de imagen rechazado:\n%s\nEl tamaño de clúster es demasiado pequeño (%llu < %u).\n"
"Usa un clúster más grande en la imagen o un sector size menor en la configuración.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */
[SM_L10N_REGISTER_FAILED_UNAVAILABLE] =
"Falló el registro: %s (%s)\nAppInstallTitleDir no disponible",
/* English: Register failed: %s (%s)\ncode=0x%08X */
[SM_L10N_REGISTER_FAILED_CODE] =
"Falló el registro: %s (%s)\ncódigo=0x%08X",
/* English: Installing: %s (%s)... */
[SM_L10N_INSTALLING] = "Instalando: %s (%s)...",
/* English: Installed: %s */
[SM_L10N_INSTALLED] = "Instalado: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */
[SM_L10N_IMAGE_MOUNT_FAILED] = "Falló el montaje de imagen: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */
[SM_L10N_FS_CLUSTER_SMALL] =
"El tamaño de clúster del sistema de archivos (%llu) es menor que el tamaño de sector del dispositivo (%u) para %s",
/* English: Mounted image is unreadable or damaged */
[SM_L10N_IMAGE_UNREADABLE_DAMAGED] =
"La imagen montada no se puede leer o está dañada",
/* English: Image cache full (%u entries), cannot track mount %s */
[SM_L10N_IMAGE_CACHE_FULL_TRACK] =
"Caché de imágenes llena (%u entradas), no se puede rastrear el mount %s",
/* English: Image cache full (%u entries), rolling back mount */
[SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] =
"Caché de imágenes llena (%u entradas), revirtiendo mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */
[SM_L10N_INSTALL_FAILED_TIMEOUT] =
"Falló la instalación: %s (%s)\nTiempo agotado después de 5 minutos",
/* English: Batch install queued (%d): */
[SM_L10N_BATCH_INSTALL_QUEUED] = "Instalación por lotes en cola (%d):",
/* English: \n... and %d more */
[SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... y %d más",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */
[SM_L10N_BATCH_INSTALL_FAILED] =
"Falló la instalación por lotes para %d app(s).\ncódigo=0x%08X",
/* English: Missing/invalid param.json:\n%s */
[SM_L10N_MISSING_PARAM] = "param.json faltante o no válido:\n%s",
/* English: Found %d new games. Executing... */
[SM_L10N_FOUND_NEW_GAMES] = "Se encontraron %d juegos nuevos. Ejecutando...",
/* English: Library Synchronized.\nFound %d games. */
[SM_L10N_LIBRARY_SYNCED] = "Biblioteca sincronizada.\nSe encontraron %d juegos.",
/* English: ShadowMount+: config reloaded. */
[SM_L10N_CONFIG_RELOADED] = "ShadowMount+: configuración recargada.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */
[SM_L10N_DUPLICATE_IGNORED] =
"Duplicado %s ignorado:\n%s\nexistente: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_fi_fi[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Siirry virheenkorjausasetuksiin",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 on vanhentunut, käytetään scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: skannaussyvyys %u käytössä.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport-overlay epäonnistui: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Peli backportattu: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Imagen liittäminen hylätty:\n%s\nKlusterikoko on liian pieni (%llu < %u).\nimage_sector-ohitus tallennettu: %u.\nYritä liittää uudelleen.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Imagen liittäminen hylätty:\n%s\nKlusterikoko on liian pieni (%llu < %u).\nKäytä imagessa suurempaa klusteria tai configissa pienempää sector size -arvoa.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Rekisteröinti epäonnistui: %s (%s)\nAppInstallTitleDir ei ole käytettävissä",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Rekisteröinti epäonnistui: %s (%s)\nkoodi=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Asennetaan: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Asennettu: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Imagen liittäminen epäonnistui: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Tiedostojärjestelmän klusterikoko (%llu) on pienempi kuin laitteen sektorikoko (%u) kohteelle %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Liitetty image ei ole luettavissa tai on vioittunut",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Image-välimuisti täynnä (%u merkintää), mountia %s ei voi seurata",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Image-välimuisti täynnä (%u merkintää), mount perutaan",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Asennus epäonnistui: %s (%s)\nAikakatkaisu 5 minuutin jälkeen",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Eräasennus jonossa (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... ja %d lisää",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Eräasennus epäonnistui %d sovellukselle.\nkoodi=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json puuttuu tai on virheellinen:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Löytyi %d uutta peliä. Suoritetaan...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Kirjasto synkronoitu.\nLöytyi %d peliä.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config ladattu uudelleen.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Kaksoiskappale %s ohitettu:\n%s\nolemassa: %s",
};
+69
View File
@@ -0,0 +1,69 @@
static const char *const g_fr_ca[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */
[SM_L10N_ACTION_DEBUG_SETTINGS] = "Allez aux paramètres de débogage",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */
[SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] =
"ShadowMount+ : recursive_scan=1 est obsolète, scan_depth=2 sera utilisé.",
/* English: ShadowMount+: scan depth %u enabled. */
[SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+ : profondeur d'analyse %u activée.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */
[SM_L10N_BACKPORT_OVERLAY_FAILED] =
"Échec de l'affichage du backport : %s\n%s\n0x%08X",
/* English: Game backported: %s */
[SM_L10N_GAME_BACKPORTED] = "Jeu backporté : %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] =
"Montage de l'image refusé :\n%s\nLa taille du regroupement d'analyse est trop petite (%llu < %u).\n"
"Remplacement image_sector enregistré : %u.\nEssayez de remonter.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] =
"Montage de l'image refusé :\n%s\nLa taille du regroupement d'analyse est trop petite (%llu < %u).\n"
"Utilisez un regroupement d'analyse plus grand dans l'image ou une taille de secteur plus petite dans la config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */
[SM_L10N_REGISTER_FAILED_UNAVAILABLE] =
"Échec de l'enregistrement : %s (%s)\nAppInstallTitleDir indisponible",
/* English: Register failed: %s (%s)\ncode=0x%08X */
[SM_L10N_REGISTER_FAILED_CODE] =
"Échec de l'enregistrement : %s (%s)\ncode=0x%08X",
/* English: Installing: %s (%s)... */
[SM_L10N_INSTALLING] = "Installation : %s (%s)...",
/* English: Installed: %s */
[SM_L10N_INSTALLED] = "Installé : %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */
[SM_L10N_IMAGE_MOUNT_FAILED] = "Échec du montage de l'image : 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */
[SM_L10N_FS_CLUSTER_SMALL] =
"La taille du regroupement d'analyse du système de fichiers (%llu) est inférieure à la taille du secteur du périphérique (%u) pour %s",
/* English: Mounted image is unreadable or damaged */
[SM_L10N_IMAGE_UNREADABLE_DAMAGED] =
"L'image montée est illisible ou endommagée",
/* English: Image cache full (%u entries), cannot track mount %s */
[SM_L10N_IMAGE_CACHE_FULL_TRACK] =
"Cache d'images plein (%u entrées), impossible de suivre le mount %s",
/* English: Image cache full (%u entries), rolling back mount */
[SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] =
"Cache d'images plein (%u entrées), annulation du montage",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */
[SM_L10N_INSTALL_FAILED_TIMEOUT] =
"Échec de l'installation : %s (%s)\nDélai expiré après 5 minutes",
/* English: Batch install queued (%d): */
[SM_L10N_BATCH_INSTALL_QUEUED] = "Installation par lot mise en file (%d) :",
/* English: \n... and %d more */
[SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... et %d de plus",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */
[SM_L10N_BATCH_INSTALL_FAILED] =
"Échec de l'installation par lot pour %d application(s).\ncode=0x%08X",
/* English: Missing/invalid param.json:\n%s */
[SM_L10N_MISSING_PARAM] = "param.json manquant ou invalide :\n%s",
/* English: Found %d new games. Executing... */
[SM_L10N_FOUND_NEW_GAMES] = "%d nouveaux jeux trouvés. Exécution...",
/* English: Library Synchronized.\nFound %d games. */
[SM_L10N_LIBRARY_SYNCED] = "Bibliothèque synchronisée.\n%d jeux trouvés.",
/* English: ShadowMount+: config reloaded. */
[SM_L10N_CONFIG_RELOADED] = "ShadowMount+ : config rechargée.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */
[SM_L10N_DUPLICATE_IGNORED] =
"Doublon %s ignoré :\n%s\nexistant : %s",
};
+69
View File
@@ -0,0 +1,69 @@
static const char *const g_fr_fr[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */
[SM_L10N_ACTION_DEBUG_SETTINGS] = "Allez aux paramètres de débogage",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */
[SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */
[SM_L10N_RECURSIVE_SCAN_DEPRECATED] =
"ShadowMount+ : recursive_scan=1 est obsolète, scan_depth=2 sera utilisé.",
/* English: ShadowMount+: scan depth %u enabled. */
[SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+ : profondeur d'analyse %u activée.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */
[SM_L10N_BACKPORT_OVERLAY_FAILED] =
"Échec de l'affichage du backport : %s\n%s\n0x%08X",
/* English: Game backported: %s */
[SM_L10N_GAME_BACKPORTED] = "Jeu backporté : %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] =
"Montage de l'image refusé :\n%s\nLa taille du regroupement d'analyse est trop petite (%llu < %u).\n"
"Remplacement image_sector enregistré : %u.\nEssayez de remonter.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */
[SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] =
"Montage de l'image refusé :\n%s\nLa taille du regroupement d'analyse est trop petite (%llu < %u).\n"
"Utilisez un regroupement d'analyse plus grand dans l'image ou une taille de secteur plus petite dans la config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */
[SM_L10N_REGISTER_FAILED_UNAVAILABLE] =
"Échec de l'enregistrement : %s (%s)\nAppInstallTitleDir indisponible",
/* English: Register failed: %s (%s)\ncode=0x%08X */
[SM_L10N_REGISTER_FAILED_CODE] =
"Échec de l'enregistrement : %s (%s)\ncode=0x%08X",
/* English: Installing: %s (%s)... */
[SM_L10N_INSTALLING] = "Installation : %s (%s)...",
/* English: Installed: %s */
[SM_L10N_INSTALLED] = "Installé : %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */
[SM_L10N_IMAGE_MOUNT_FAILED] = "Échec du montage de l'image : 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */
[SM_L10N_FS_CLUSTER_SMALL] =
"La taille du regroupement d'analyse du système de fichiers (%llu) est inférieure à la taille du secteur du périphérique (%u) pour %s",
/* English: Mounted image is unreadable or damaged */
[SM_L10N_IMAGE_UNREADABLE_DAMAGED] =
"L'image montée est illisible ou endommagée",
/* English: Image cache full (%u entries), cannot track mount %s */
[SM_L10N_IMAGE_CACHE_FULL_TRACK] =
"Cache d'images plein (%u entrées), impossible de suivre le mount %s",
/* English: Image cache full (%u entries), rolling back mount */
[SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] =
"Cache d'images plein (%u entrées), annulation du montage",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */
[SM_L10N_INSTALL_FAILED_TIMEOUT] =
"Échec de l'installation : %s (%s)\nDélai expiré après 5 minutes",
/* English: Batch install queued (%d): */
[SM_L10N_BATCH_INSTALL_QUEUED] = "Installation par lot mise en file (%d) :",
/* English: \n... and %d more */
[SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... et %d de plus",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */
[SM_L10N_BATCH_INSTALL_FAILED] =
"Échec de l'installation par lot pour %d application(s).\ncode=0x%08X",
/* English: Missing/invalid param.json:\n%s */
[SM_L10N_MISSING_PARAM] = "param.json manquant ou invalide :\n%s",
/* English: Found %d new games. Executing... */
[SM_L10N_FOUND_NEW_GAMES] = "%d nouveaux jeux trouvés. Exécution...",
/* English: Library Synchronized.\nFound %d games. */
[SM_L10N_LIBRARY_SYNCED] = "Bibliothèque synchronisée.\n%d jeux trouvés.",
/* English: ShadowMount+: config reloaded. */
[SM_L10N_CONFIG_RELOADED] = "ShadowMount+ : config rechargée.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */
[SM_L10N_DUPLICATE_IGNORED] =
"Doublon %s ignoré :\n%s\nexistant : %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_hu_hu[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Ugrás a hibakeresési beállításokhoz",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: a recursive_scan=1 elavult, scan_depth=2 lesz használva.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: %u keresési mélység engedélyezve.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay sikertelen: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Játék backportolva: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image mount elutasítva:\n%s\nA cluster mérete túl kicsi (%llu < %u).\nimage_sector felülírás mentve: %u.\nPróbáld újra mountolni.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image mount elutasítva:\n%s\nA cluster mérete túl kicsi (%llu < %u).\nHasználj nagyobb clustert az image-ben vagy kisebb sector size értéket a configban.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Regisztráció sikertelen: %s (%s)\nAppInstallTitleDir nem elérhető",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Regisztráció sikertelen: %s (%s)\nkód=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Telepítés: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Telepítve: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image mount sikertelen: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "A fájlrendszer cluster mérete (%llu) kisebb, mint az eszköz szektormérete (%u): %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "A mountolt image olvashatatlan vagy sérült",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Az image cache megtelt (%u bejegyzés), a mount nem követhető: %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Az image cache megtelt (%u bejegyzés), mount visszavonása",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Telepítés sikertelen: %s (%s)\nIdőtúllépés 5 perc után",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Kötegelt telepítés sorban (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... és még %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Kötegelt telepítés sikertelen %d appnál.\nkód=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "Hiányzó vagy érvénytelen param.json:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d új játék található. Végrehajtás...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Könyvtár szinkronizálva.\n%d játék található.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config újratöltve.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplikált %s kihagyva:\n%s\nlétező: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_id_id[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Buka pengaturan debug",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 sudah usang, memakai scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: kedalaman pemindaian %u aktif.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay gagal: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Backport game diterapkan: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Mount image ditolak:\n%s\nUkuran cluster terlalu kecil (%llu < %u).\nOverride image_sector disimpan: %u.\nCoba mount lagi.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Mount image ditolak:\n%s\nUkuran cluster terlalu kecil (%llu < %u).\nGunakan cluster lebih besar di image atau sector size lebih rendah di config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrasi gagal: %s (%s)\nAppInstallTitleDir tidak tersedia",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrasi gagal: %s (%s)\nkode=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Menginstal: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Terinstal: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Mount image gagal: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Ukuran cluster filesystem (%llu) lebih kecil dari ukuran sector perangkat (%u) untuk %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Image yang dimount tidak terbaca atau rusak",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache image penuh (%u entri), tidak dapat melacak mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache image penuh (%u entri), mengembalikan mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Instalasi gagal: %s (%s)\nWaktu habis setelah 5 menit",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Instalasi batch masuk antrean (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... dan %d lagi",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Instalasi batch gagal untuk %d app.\nkode=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json hilang atau tidak valid:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Menemukan %d game baru. Menjalankan...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Library disinkronkan.\nMenemukan %d game.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config dimuat ulang.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplikat %s diabaikan:\n%s\nyang ada: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_it_it[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Vai alle impostazioni di debug",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 è deprecato, uso scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: profondità scansione %u abilitata.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Overlay backport non riuscito: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Gioco backportato: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Montaggio immagine rifiutato:\n%s\nLa dimensione cluster è troppo piccola (%llu < %u).\nOverride image_sector salvato: %u.\nProva a montare di nuovo.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Montaggio immagine rifiutato:\n%s\nLa dimensione cluster è troppo piccola (%llu < %u).\nUsa un cluster più grande nell'immagine o una sector size più bassa nella config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrazione non riuscita: %s (%s)\nAppInstallTitleDir non disponibile",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrazione non riuscita: %s (%s)\ncodice=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Installazione: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Installato: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Montaggio immagine non riuscito: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "La dimensione cluster del filesystem (%llu) è minore della dimensione settore del dispositivo (%u) per %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "L'immagine montata è illeggibile o danneggiata",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache immagini piena (%u voci), impossibile tracciare il mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache immagini piena (%u voci), annullo il mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Installazione non riuscita: %s (%s)\nTimeout dopo 5 minuti",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Installazione batch in coda (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... e altri %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Installazione batch non riuscita per %d app.\ncodice=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json mancante o non valido:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Trovati %d nuovi giochi. Esecuzione...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Libreria sincronizzata.\nTrovati %d giochi.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config ricaricata.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplicato %s ignorato:\n%s\nesistente: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_ja_jp[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "デバッグ設定へ移動",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 は非推奨です。scan_depth=2 を使用します。",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: スキャン深度 %u が有効です。",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "backport overlay に失敗しました: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "ゲームを backport しました: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "イメージのマウントが拒否されました:\n%s\nクラスタサイズが小さすぎます (%llu < %u)。\nimage_sector override を保存しました: %u。\nもう一度マウントしてください。",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "イメージのマウントが拒否されました:\n%s\nクラスタサイズが小さすぎます (%llu < %u)。\nイメージのクラスタサイズを大きくするか、config の sector size を小さくしてください。",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "登録に失敗しました: %s (%s)\nAppInstallTitleDir が利用できません",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "登録に失敗しました: %s (%s)\nコード=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "インストール中: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "インストール済み: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "イメージのマウントに失敗しました: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "ファイルシステムのクラスタサイズ (%llu) が %s のデバイスセクタサイズ (%u) より小さいです",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "マウント済みイメージを読み取れないか破損しています",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "イメージキャッシュが満杯です (%u 件)。mount %s を追跡できません",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "イメージキャッシュが満杯です (%u 件)。mount を元に戻します",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "インストールに失敗しました: %s (%s)\n5 分後にタイムアウトしました",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "一括インストールをキューに追加しました (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... 他 %d 件",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "%d 個のアプリの一括インストールに失敗しました。\nコード=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json が見つからないか無効です:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d 本の新しいゲームを検出しました。実行中...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "ライブラリを同期しました。\n%d 本のゲームを検出しました。",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config を再読み込みしました。",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "重複 %s を無視しました:\n%s\n既存: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_ko_kr[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "디버그 설정으로 이동",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1은 더 이상 권장되지 않으며 scan_depth=2를 사용합니다.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: 스캔 깊이 %u 활성화됨.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "backport overlay 실패: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "게임 backport 적용됨: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "이미지 마운트 거부됨:\n%s\n클러스터 크기가 너무 작습니다 (%llu < %u).\nimage_sector override 저장됨: %u.\n다시 마운트해 보세요.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "이미지 마운트 거부됨:\n%s\n클러스터 크기가 너무 작습니다 (%llu < %u).\n이미지에서 더 큰 클러스터를 사용하거나 config에서 더 낮은 sector size를 사용하세요.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "등록 실패: %s (%s)\nAppInstallTitleDir 사용 불가",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "등록 실패: %s (%s)\n코드=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "설치 중: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "설치됨: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "이미지 마운트 실패: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "파일 시스템 클러스터 크기(%llu)가 %s의 장치 섹터 크기(%u)보다 작습니다",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "마운트된 이미지를 읽을 수 없거나 손상되었습니다",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "이미지 캐시가 가득 참(%u개), mount %s 추적 불가",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "이미지 캐시가 가득 참(%u개), mount 롤백 중",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "설치 실패: %s (%s)\n5분 후 시간 초과",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "일괄 설치 대기열 추가됨 (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... 외 %d개",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "%d개 앱 일괄 설치 실패.\n코드=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json 누락 또는 잘못됨:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "새 게임 %d개 발견. 실행 중...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "라이브러리 동기화됨.\n게임 %d개 발견.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config 다시 로드됨.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "중복 %s 무시됨:\n%s\n기존: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_nl_nl[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Ga naar debug-instellingen",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 is verouderd, scan_depth=2 wordt gebruikt.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: scandiepte %u ingeschakeld.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport-overlay mislukt: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Game gebackport: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image-mount geweigerd:\n%s\nClustergrootte is te klein (%llu < %u).\nimage_sector-override opgeslagen: %u.\nProbeer opnieuw te mounten.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image-mount geweigerd:\n%s\nClustergrootte is te klein (%llu < %u).\nGebruik een grotere cluster in de image of een lagere sector size in config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registreren mislukt: %s (%s)\nAppInstallTitleDir niet beschikbaar",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registreren mislukt: %s (%s)\ncode=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Installeren: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Geïnstalleerd: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image-mount mislukt: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Clustergrootte van bestandssysteem (%llu) is kleiner dan apparaatsectorgrootte (%u) voor %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Gemounte image is onleesbaar of beschadigd",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Imagecache vol (%u vermeldingen), kan mount %s niet volgen",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Imagecache vol (%u vermeldingen), mount wordt teruggedraaid",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Installatie mislukt: %s (%s)\nTime-out na 5 minuten",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Batchinstallatie in wachtrij (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... en nog %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Batchinstallatie mislukt voor %d app(s).\ncode=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json ontbreekt of is ongeldig:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d nieuwe games gevonden. Uitvoeren...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Bibliotheek gesynchroniseerd.\n%d games gevonden.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config herladen.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplicaat %s genegeerd:\n%s\nbestaand: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_no_no[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Gå til feilsøkingsinnstillinger",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 er utdatert, bruker scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: skannedybde %u aktivert.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport-overlay mislyktes: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Spill backportet: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image-mount avvist:\n%s\nKlyngestørrelsen er for liten (%llu < %u).\nimage_sector-overstyring lagret: %u.\nPrøv å mounte igjen.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image-mount avvist:\n%s\nKlyngestørrelsen er for liten (%llu < %u).\nBruk større klynge i imaget eller lavere sector size i config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrering mislyktes: %s (%s)\nAppInstallTitleDir utilgjengelig",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrering mislyktes: %s (%s)\nkode=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Installerer: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Installert: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image-mount mislyktes: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Filsystemets klyngestørrelse (%llu) er mindre enn enhetens sektorstørrelse (%u) for %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Mountet image er uleselig eller skadet",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Image-cache full (%u oppføringer), kan ikke spore mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Image-cache full (%u oppføringer), ruller mount tilbake",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Installasjon mislyktes: %s (%s)\nTidsavbrudd etter 5 minutter",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Batchinstallasjon i kø (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... og %d til",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Batchinstallasjon mislyktes for %d app(er).\nkode=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json mangler eller er ugyldig:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Fant %d nye spill. Kjører...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Bibliotek synkronisert.\nFant %d spill.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config lastet på nytt.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplikat %s ignorert:\n%s\neksisterende: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_pl_pl[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Przejdź do ustawień debugowania",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 jest przestarzałe, używam scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: głębokość skanowania %u włączona.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Overlay backportu nie powiódł się: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Backport gry zastosowany: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Odrzucono montowanie obrazu:\n%s\nRozmiar klastra jest za mały (%llu < %u).\nZapisano nadpisanie image_sector: %u.\nSpróbuj zamontować ponownie.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Odrzucono montowanie obrazu:\n%s\nRozmiar klastra jest za mały (%llu < %u).\nUżyj większego klastra w obrazie lub mniejszego sector size w config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Rejestracja nie powiodła się: %s (%s)\nAppInstallTitleDir niedostępne",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Rejestracja nie powiodła się: %s (%s)\nkod=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Instalowanie: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Zainstalowano: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Montowanie obrazu nie powiodło się: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Rozmiar klastra systemu plików (%llu) jest mniejszy niż rozmiar sektora urządzenia (%u) dla %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Zamontowany obraz jest nieczytelny lub uszkodzony",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache obrazów pełny (%u wpisów), nie można śledzić mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache obrazów pełny (%u wpisów), wycofywanie mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Instalacja nie powiodła się: %s (%s)\nLimit czasu po 5 minutach",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Instalacja zbiorcza w kolejce (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... i jeszcze %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Instalacja zbiorcza nie powiodła się dla %d aplikacji.\nkod=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "Brakujący lub nieprawidłowy param.json:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Znaleziono %d nowych gier. Wykonywanie...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Biblioteka zsynchronizowana.\nZnaleziono %d gier.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config przeładowany.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplikat %s zignorowany:\n%s\nistniejący: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_pt_br[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Ir para as Configurações de Depuração",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 está obsoleto, usando scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: profundidade de varredura %u ativada.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Falha no overlay de backport: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Backport aplicado ao jogo: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Montagem da imagem rejeitada:\n%s\nO tamanho do cluster é pequeno demais (%llu < %u).\nNovo valor para o parâmetro image_sector salvo: %u.\nTente montar novamente.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Montagem da imagem rejeitada:\n%s\nO tamanho do cluster é pequeno demais (%llu < %u).\nUse um cluster maior na imagem ou um tamanho de setor menor na configuração.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registro falhou: %s (%s)\nAppInstallTitleDir indisponível",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registro falhou: %s (%s)\ncódigo=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Instalando: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Instalado: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Falha ao montar imagem: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "O tamanho do cluster do sistema de arquivos (%llu) é menor que o tamanho do setor do dispositivo (%u) para %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "A imagem montada está ilegível ou danificada",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache de imagens cheio (%u entradas), não é possível rastrear a montagem %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache de imagens cheio (%u entradas), revertendo a montagem",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "A instalação falhou: %s (%s)\nTempo esgotado após 5 minutos",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Instalação em lote enfileirada (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... e mais %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Instalação em lote falhou para %d app(s).\ncódigo=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "Arquivo param.json ausente ou inválido:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d novos jogos encontrados. Executando...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Biblioteca sincronizada.\n%d jogos encontrados.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: configuração recarregada.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Cópia duplicada de %s ignorada:\n%s\nExistente: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_pt_pt[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Ir para Definições de depuração",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 está obsoleto, será usado scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: profundidade de pesquisa %u ativada.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Falha no overlay de backport: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Jogo com backport aplicado: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Montagem da imagem rejeitada:\n%s\nO tamanho do cluster é demasiado pequeno (%llu < %u).\nSubstituição image_sector guardada: %u.\nTente montar novamente.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Montagem da imagem rejeitada:\n%s\nO tamanho do cluster é demasiado pequeno (%llu < %u).\nUse um cluster maior na imagem ou uma sector size menor na configuração.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registo falhou: %s (%s)\nAppInstallTitleDir indisponível",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registo falhou: %s (%s)\ncódigo=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "A instalar: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Instalado: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Falha ao montar imagem: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "O tamanho do cluster do sistema de ficheiros (%llu) é menor que o tamanho do setor do dispositivo (%u) para %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "A imagem montada está ilegível ou danificada",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache de imagens cheia (%u entradas), não é possível seguir o mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache de imagens cheia (%u entradas), a reverter mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Instalação falhou: %s (%s)\nTempo esgotado após 5 minutos",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Instalação em lote na fila (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... e mais %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Instalação em lote falhou para %d aplicação(ões).\ncódigo=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json em falta ou inválido:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d novos jogos encontrados. A executar...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Biblioteca sincronizada.\n%d jogos encontrados.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: configuração recarregada.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplicado %s ignorado:\n%s\nexistente: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_ro_ro[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Mergi la setările de depanare",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 este depășit, se folosește scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: adâncime scanare %u activată.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Overlay backport eșuat: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Backport aplicat jocului: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Montarea imaginii respinsă:\n%s\nDimensiunea clusterului este prea mică (%llu < %u).\nOverride image_sector salvat: %u.\nÎncercați montarea din nou.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Montarea imaginii respinsă:\n%s\nDimensiunea clusterului este prea mică (%llu < %u).\nFolosiți un cluster mai mare în imagine sau sector size mai mic în config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Înregistrare eșuată: %s (%s)\nAppInstallTitleDir indisponibil",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Înregistrare eșuată: %s (%s)\ncod=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Se instalează: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Instalat: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Montarea imaginii a eșuat: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Dimensiunea clusterului sistemului de fișiere (%llu) este mai mică decât sectorul dispozitivului (%u) pentru %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Imaginea montată este ilizibilă sau deteriorată",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache-ul de imagini este plin (%u intrări), mount %s nu poate fi urmărit",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache-ul de imagini este plin (%u intrări), se anulează mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Instalare eșuată: %s (%s)\nTimeout după 5 minute",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Instalare în lot pusă în coadă (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... și încă %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Instalarea în lot a eșuat pentru %d aplicații.\ncod=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json lipsește sau este invalid:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "S-au găsit %d jocuri noi. Se execută...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Bibliotecă sincronizată.\nS-au găsit %d jocuri.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config reîncărcat.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Duplicatul %s ignorat:\n%s\nexistent: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_ru_ru[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Открыть меню отладки",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 устарел, используется scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: глубина сканирования %u включена.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Сбой наложения бэкпорта: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Бэкпорт применён к игре: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Монтирование образа отклонено:\n%s\nРазмер кластера слишком мал (%llu < %u).\nСохранено переопределение image_sector: %u.\nПопробуйте смонтировать снова.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Монтирование образа отклонено:\n%s\nРазмер кластера слишком мал (%llu < %u).\nИспользуйте больший размер кластера в образе или меньший sector size в конфиге.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Ошибка регистрации: %s (%s)\nAppInstallTitleDir недоступен",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Ошибка регистрации: %s (%s)\nкод=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Установка: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Установлено: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Сбой монтирования образа: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Размер кластера файловой системы (%llu) меньше размера сектора устройства (%u) для %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Смонтированный образ повреждён",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Кэш образов заполнен (%u записей), невозможно отслеживать монтирование %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Кэш образов заполнен (%u записей), монтирование будет отменёно",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Сбой установки: %s (%s)\nИстёк 5 мимнутный тайм-аут",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Добавлен в очередь пакетной установки (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... и ещё %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Сбой пакетной установки для %d приложений.\nкод=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "Отсутствует или неверный param.json:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Найдено %d новых игр.\nВыполняется обновление библиотеки.",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Библиотека обновлена.\nНайдено %d игр.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: конфиг перезагружен.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Дубликат %s пропущен:\n%s\nсуществующий: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_sv_se[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Gå till felsökningsinställningar",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 är föråldrat, använder scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: skanningsdjup %u aktiverat.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport-overlay misslyckades: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Spelet backportat: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image-montering nekades:\n%s\nKlusterstorleken är för liten (%llu < %u).\nimage_sector-åsidosättning sparad: %u.\nFörsök montera igen.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image-montering nekades:\n%s\nKlusterstorleken är för liten (%llu < %u).\nAnvänd större kluster i imagen eller lägre sector size i config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Registrering misslyckades: %s (%s)\nAppInstallTitleDir inte tillgänglig",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Registrering misslyckades: %s (%s)\nkod=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Installerar: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Installerat: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image-montering misslyckades: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Filsystemets klusterstorlek (%llu) är mindre än enhetens sektorstorlek (%u) för %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Monterad image är oläsbar eller skadad",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Image-cache full (%u poster), kan inte spåra mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Image-cache full (%u poster), återställer mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Installation misslyckades: %s (%s)\nTidsgräns efter 5 minuter",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Batchinstallation köad (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... och %d till",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Batchinstallation misslyckades för %d app(ar).\nkod=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json saknas eller är ogiltig:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Hittade %d nya spel. Kör...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Bibliotek synkroniserat.\nHittade %d spel.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config omladdad.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Dubblett %s ignorerad:\n%s\nbefintlig: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_th_th[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "ไปที่การตั้งค่าดีบัก",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 เลิกใช้แล้ว จะใช้ scan_depth=2",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: เปิดใช้ความลึกการสแกน %u",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "backport overlay ล้มเหลว: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "ใช้ backport กับเกมแล้ว: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "ปฏิเสธการ mount image:\n%s\nขนาด cluster เล็กเกินไป (%llu < %u)\nบันทึกค่า override image_sector แล้ว: %u\nลอง mount อีกครั้ง",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "ปฏิเสธการ mount image:\n%s\nขนาด cluster เล็กเกินไป (%llu < %u)\nใช้ cluster ที่ใหญ่กว่าใน image หรือ sector size ที่ต่ำกว่าใน config",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "ลงทะเบียนล้มเหลว: %s (%s)\nAppInstallTitleDir ไม่พร้อมใช้งาน",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "ลงทะเบียนล้มเหลว: %s (%s)\nรหัส=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "กำลังติดตั้ง: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "ติดตั้งแล้ว: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "mount image ล้มเหลว: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "ขนาด cluster ของ filesystem (%llu) เล็กกว่าขนาด sector ของอุปกรณ์ (%u) สำหรับ %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "image ที่ mount อ่านไม่ได้หรือเสียหาย",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "cache image เต็ม (%u รายการ), ติดตาม mount %s ไม่ได้",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "cache image เต็ม (%u รายการ), กำลังย้อนกลับ mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "ติดตั้งล้มเหลว: %s (%s)\nหมดเวลาหลัง 5 นาที",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "เพิ่มการติดตั้งแบบชุดเข้าคิวแล้ว (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... และอีก %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "การติดตั้งแบบชุดล้มเหลวสำหรับ %d แอป\nรหัส=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json หายไปหรือไม่ถูกต้อง:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "พบเกมใหม่ %d เกม กำลังดำเนินการ...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "ซิงค์ไลบรารีแล้ว\nพบ %d เกม",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: โหลด config ใหม่แล้ว",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "ข้ามรายการซ้ำ %s:\n%s\nที่มีอยู่: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_tr_tr[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Hata ayıklama ayarlarına git",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 kullanımdan kalktı, scan_depth=2 kullanılıyor.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: tarama derinliği %u etkin.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay başarısız: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Oyuna backport uygulandı: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Image mount reddedildi:\n%s\nCluster boyutu çok küçük (%llu < %u).\nimage_sector geçersiz kılması kaydedildi: %u.\nTekrar mount etmeyi deneyin.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Image mount reddedildi:\n%s\nCluster boyutu çok küçük (%llu < %u).\nImage içinde daha büyük cluster veya config içinde daha düşük sector size kullanın.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Kayıt başarısız: %s (%s)\nAppInstallTitleDir kullanılamıyor",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Kayıt başarısız: %s (%s)\nkod=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Yükleniyor: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Yüklendi: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Image mount başarısız: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Dosya sistemi cluster boyutu (%llu), %s için aygıt sektör boyutundan (%u) küçük",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Mount edilen image okunamıyor veya hasarlı",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Image önbelleği dolu (%u kayıt), mount %s izlenemiyor",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Image önbelleği dolu (%u kayıt), mount geri alınıyor",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Yükleme başarısız: %s (%s)\n5 dakika sonra zaman aşımı",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Toplu yükleme sıraya alındı (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... ve %d tane daha",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "%d uygulama için toplu yükleme başarısız.\nkod=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json eksik veya geçersiz:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "%d yeni oyun bulundu. Çalıştırılıyor...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Kütüphane senkronize edildi.\n%d oyun bulundu.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config yeniden yüklendi.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Yinelenen %s yok sayıldı:\n%s\nmevcut: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_vi_vn[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "Đi tới cài đặt gỡ lỗi",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 đã lỗi thời, dùng scan_depth=2.",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: đã bật độ sâu quét %u.",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay thất bại: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "Đã áp dụng backport cho game: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "Từ chối mount image:\n%s\nKích thước cluster quá nhỏ (%llu < %u).\nĐã lưu ghi đè image_sector: %u.\nHãy thử mount lại.",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "Từ chối mount image:\n%s\nKích thước cluster quá nhỏ (%llu < %u).\nDùng cluster lớn hơn trong image hoặc sector size thấp hơn trong config.",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "Đăng ký thất bại: %s (%s)\nAppInstallTitleDir không khả dụng",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "Đăng ký thất bại: %s (%s)\nmã=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "Đang cài đặt: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "Đã cài đặt: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "Mount image thất bại: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "Kích thước cluster của hệ thống tệp (%llu) nhỏ hơn kích thước sector thiết bị (%u) cho %s",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "Image đã mount không đọc được hoặc bị hỏng",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "Cache image đầy (%u mục), không thể theo dõi mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "Cache image đầy (%u mục), đang hoàn tác mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "Cài đặt thất bại: %s (%s)\nHết thời gian sau 5 phút",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "Cài đặt hàng loạt đã vào hàng đợi (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... và thêm %d",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "Cài đặt hàng loạt thất bại cho %d ứng dụng.\nmã=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json thiếu hoặc không hợp lệ:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "Tìm thấy %d game mới. Đang thực thi...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "Thư viện đã đồng bộ.\nTìm thấy %d game.",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: đã tải lại config.",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "Đã bỏ qua bản trùng %s:\n%s\nđã có: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_zh_cn[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "前往调试设置",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 已弃用,将使用 scan_depth=2。",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: 已启用扫描深度 %u。",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay 失败: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "游戏已应用 backport: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "镜像挂载被拒绝:\n%s\n簇大小太小 (%llu < %u)。\n已保存 image_sector 覆盖值: %u。\n请再次尝试挂载。",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "镜像挂载被拒绝:\n%s\n簇大小太小 (%llu < %u)。\n请在镜像中使用更大的簇大小,或在 config 中降低 sector size。",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "注册失败: %s (%s)\nAppInstallTitleDir 不可用",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "注册失败: %s (%s)\n代码=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "正在安装: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "已安装: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "镜像挂载失败: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "文件系统簇大小 (%llu) 小于 %s 的设备扇区大小 (%u)",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "已挂载的镜像不可读或已损坏",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "镜像缓存已满(%u 项),无法跟踪 mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "镜像缓存已满(%u 项),正在回滚 mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "安装失败: %s (%s)\n5 分钟后超时",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "批量安装已排队 (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... 以及另外 %d 个",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "%d 个应用批量安装失败。\n代码=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json 缺失或无效:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "发现 %d 个新游戏。正在执行...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "库已同步。\n发现 %d 个游戏。",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config 已重新加载。",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "已忽略重复项 %s:\n%s\n现有: %s",
};
+28
View File
@@ -0,0 +1,28 @@
static const char *const g_zh_tw[SM_L10N_COUNT] = {
/* English: Go to Debug Settings */ [SM_L10N_ACTION_DEBUG_SETTINGS] = "前往除錯設定",
/* English: ShadowMount+ v%s exFAT/UFS/PFS */ [SM_L10N_STARTUP] = "ShadowMount+ v%s exFAT/UFS/PFS",
/* English: ShadowMount+: recursive_scan=1 is deprecated, using scan_depth=2. */ [SM_L10N_RECURSIVE_SCAN_DEPRECATED] = "ShadowMount+: recursive_scan=1 已淘汰,將使用 scan_depth=2。",
/* English: ShadowMount+: scan depth %u enabled. */ [SM_L10N_SCAN_DEPTH_ENABLED] = "ShadowMount+: 已啟用掃描深度 %u。",
/* English: Backport overlay failed: %s\n%s\n0x%08X */ [SM_L10N_BACKPORT_OVERLAY_FAILED] = "Backport overlay 失敗: %s\n%s\n0x%08X",
/* English: Game backported: %s */ [SM_L10N_GAME_BACKPORTED] = "遊戲已套用 backport: %s",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nSaved image_sector override: %u.\nTry mounting again. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED] = "映像掛載被拒絕:\n%s\n叢集大小太小 (%llu < %u)。\n已儲存 image_sector 覆寫值: %u。\n請再次嘗試掛載。",
/* English: Image mount rejected:\n%s\nCluster size is too small (%llu < %u).\nUse a larger cluster size in the image or lower sector size in config. */ [SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG] = "映像掛載被拒絕:\n%s\n叢集大小太小 (%llu < %u)。\n請在映像中使用較大的叢集大小,或在 config 中降低 sector size。",
/* English: Register failed: %s (%s)\nAppInstallTitleDir unavailable */ [SM_L10N_REGISTER_FAILED_UNAVAILABLE] = "註冊失敗: %s (%s)\nAppInstallTitleDir 無法使用",
/* English: Register failed: %s (%s)\ncode=0x%08X */ [SM_L10N_REGISTER_FAILED_CODE] = "註冊失敗: %s (%s)\n代碼=0x%08X",
/* English: Installing: %s (%s)... */ [SM_L10N_INSTALLING] = "正在安裝: %s (%s)...",
/* English: Installed: %s */ [SM_L10N_INSTALLED] = "已安裝: %s",
/* English: Image mount failed: 0x%08X (%s)\n%s */ [SM_L10N_IMAGE_MOUNT_FAILED] = "映像掛載失敗: 0x%08X (%s)\n%s",
/* English: Filesystem cluster size (%llu) is smaller than device sector size (%u) for %s */ [SM_L10N_FS_CLUSTER_SMALL] = "檔案系統叢集大小 (%llu) 小於 %s 的裝置磁區大小 (%u)",
/* English: Mounted image is unreadable or damaged */ [SM_L10N_IMAGE_UNREADABLE_DAMAGED] = "已掛載的映像無法讀取或已損壞",
/* English: Image cache full (%u entries), cannot track mount %s */ [SM_L10N_IMAGE_CACHE_FULL_TRACK] = "映像快取已滿(%u 筆),無法追蹤 mount %s",
/* English: Image cache full (%u entries), rolling back mount */ [SM_L10N_IMAGE_CACHE_FULL_ROLLBACK] = "映像快取已滿(%u 筆),正在回復 mount",
/* English: Install failed: %s (%s)\nTimed out after 5 minutes */ [SM_L10N_INSTALL_FAILED_TIMEOUT] = "安裝失敗: %s (%s)\n5 分鐘後逾時",
/* English: Batch install queued (%d): */ [SM_L10N_BATCH_INSTALL_QUEUED] = "批次安裝已排入佇列 (%d):",
/* English: \n... and %d more */ [SM_L10N_BATCH_INSTALL_AND_MORE] = "\n... 以及另外 %d 個",
/* English: Batch install failed for %d app(s).\ncode=0x%08X */ [SM_L10N_BATCH_INSTALL_FAILED] = "%d 個應用程式批次安裝失敗。\n代碼=0x%08X",
/* English: Missing/invalid param.json:\n%s */ [SM_L10N_MISSING_PARAM] = "param.json 遺失或無效:\n%s",
/* English: Found %d new games. Executing... */ [SM_L10N_FOUND_NEW_GAMES] = "找到 %d 個新遊戲。正在執行...",
/* English: Library Synchronized.\nFound %d games. */ [SM_L10N_LIBRARY_SYNCED] = "資料庫已同步。\n找到 %d 個遊戲。",
/* English: ShadowMount+: config reloaded. */ [SM_L10N_CONFIG_RELOADED] = "ShadowMount+: config 已重新載入。",
/* English: Duplicate %s ignored:\n%s\nexisting: %s */ [SM_L10N_DUPLICATE_IGNORED] = "已忽略重複項 %s:\n%s\n現有: %s",
};
-12
View File
@@ -25,18 +25,6 @@ bool get_image_mode_override(const char *filename, bool *mount_read_only_out);
// Resolve a per-image sector-size override from autotune.ini or config.ini.
bool get_image_sector_size_override(const char *filename,
uint32_t *sector_size_out);
// Return true when kstuff auto-pause is disabled for the given title ID.
bool is_kstuff_pause_disabled_for_title(const char *title_id);
// Resolve a per-title kstuff pause-delay override in seconds.
bool get_kstuff_pause_delay_override_for_title(const char *title_id,
uint32_t *delay_seconds_out);
// Resolve a per-title autotuned kstuff pause-delay override in seconds.
bool get_kstuff_autotune_pause_delay_for_title(const char *title_id,
uint32_t *delay_seconds_out);
// Upsert an autotuned pause-delay override for the title.
bool upsert_kstuff_autotune_pause_delay(const char *title_id,
uint32_t current_delay_seconds,
uint32_t *delay_seconds_out);
// Upsert an autotuned per-image sector-size override.
bool upsert_image_sector_size_autotune(const char *filename,
uint32_t sector_size,
-41
View File
@@ -1,41 +0,0 @@
#ifndef SM_KSTUFF_H
#define SM_KSTUFF_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
// Resolve firmware-specific kstuff sysentvec addresses and initialize state.
void sm_kstuff_init(void);
// Shut down runtime kstuff control state.
void sm_kstuff_shutdown(void);
// Return true when firmware-specific kstuff control is available.
bool sm_kstuff_is_supported(void);
// Return true when both tracked kstuff sysentvecs are enabled.
bool sm_kstuff_is_enabled(void);
// Set both tracked kstuff sysentvecs and return the resulting enabled state.
bool sm_kstuff_set_enabled(bool enabled, bool notify_user);
// Return true when game-driven kstuff automation should run.
bool sm_kstuff_game_feature_enabled(void);
// Track a supported game launch for delayed auto-pause handling.
void sm_kstuff_game_on_exec(pid_t pid, const char *title_id, uint32_t app_id,
uint64_t exec_time_us);
// Publish an AppFocus change for processing on the lifecycle/kstuff thread.
void sm_kstuff_note_app_focus(uint32_t app_id);
// Return the next wake deadline in monotonic microseconds, or 0 when idle.
uint64_t sm_kstuff_game_next_wake_us(uint64_t now_us);
// Forget a tracked game and restore kstuff when no paused entries remain.
void sm_kstuff_game_on_exit(pid_t pid);
// Apply any delayed kstuff pause whose deadline has elapsed.
void sm_kstuff_game_poll(void);
// Clear tracked game state and restore kstuff if the watcher paused it.
void sm_kstuff_game_shutdown(void);
// Pause kstuff for runtime sleep without restoring game-driven pauses.
void sm_kstuff_sleep_enter(void);
// Restore kstuff after runtime sleep when sleep entry disabled it.
void sm_kstuff_sleep_leave(void);
// Re-apply runtime config changes to the currently tracked game, if any.
void sm_kstuff_on_config_reload(void);
#endif
+43
View File
@@ -0,0 +1,43 @@
#ifndef SM_L10N_H
#define SM_L10N_H
#include "sm_platform.h"
typedef enum {
SM_L10N_ACTION_DEBUG_SETTINGS = 0,
SM_L10N_STARTUP,
SM_L10N_RECURSIVE_SCAN_DEPRECATED,
SM_L10N_SCAN_DEPTH_ENABLED,
SM_L10N_BACKPORT_OVERLAY_FAILED,
SM_L10N_GAME_BACKPORTED,
SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED,
SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG,
SM_L10N_REGISTER_FAILED_UNAVAILABLE,
SM_L10N_REGISTER_FAILED_CODE,
SM_L10N_INSTALLING,
SM_L10N_INSTALLED,
SM_L10N_IMAGE_MOUNT_FAILED,
SM_L10N_FS_CLUSTER_SMALL,
SM_L10N_IMAGE_UNREADABLE_DAMAGED,
SM_L10N_IMAGE_CACHE_FULL_TRACK,
SM_L10N_IMAGE_CACHE_FULL_ROLLBACK,
SM_L10N_INSTALL_FAILED_TIMEOUT,
SM_L10N_BATCH_INSTALL_QUEUED,
SM_L10N_BATCH_INSTALL_AND_MORE,
SM_L10N_BATCH_INSTALL_FAILED,
SM_L10N_MISSING_PARAM,
SM_L10N_FOUND_NEW_GAMES,
SM_L10N_LIBRARY_SYNCED,
SM_L10N_CONFIG_RELOADED,
SM_L10N_DUPLICATE_IGNORED,
SM_L10N_COUNT
} sm_l10n_key_t;
void sm_l10n_init(void);
bool sm_l10n_parse_language_id(const char *value, int32_t *language_id_out);
const char *sm_l10n_language_name(int32_t language_id);
const char *sm_l10n_get(sm_l10n_key_t key);
const char *sm_l10n_lang(void);
const char *sm_l10n_locale(void);
#endif
+1 -5
View File
@@ -4,13 +4,11 @@
#define DEFAULT_SCAN_INTERVAL_US 15000000u
#define DEFAULT_SCAN_DEPTH 1u
#define DEFAULT_STABILITY_WAIT_SECONDS 10u
#define DEFAULT_KSTUFF_PAUSE_DELAY_IMAGE_SECONDS 25u
#define DEFAULT_KSTUFF_PAUSE_DELAY_DIRECT_SECONDS 15u
#define SM_LANGUAGE_AUTO (-1)
#define MAX_PENDING 512
#define MAX_IMAGE_MOUNTS 256
#define MAX_IMAGE_MODE_RULES 128
#define MAX_KSTUFF_TITLE_RULES 128
#define MAX_FAKELIB_EXCLUDE_RULES 128
#define PATH_STATE_CAPACITY MAX_PENDING
#define TITLE_STATE_CAPACITY MAX_PENDING
@@ -27,14 +25,12 @@
#define LVD_RELEASE_WAIT_POLL_US 500000u
#define GAME_LIFECYCLE_POLL_INTERVAL_US 250000u
#define GAME_APPINFO_LOOKUP_TIMEOUT_US 1000000u
#define KSTUFF_RESTORE_RETRY_US 1000000u
#define SHELLCORE_FLAG_POLL_INTERVAL_US 100000u
#define MIN_SCAN_DEPTH 1u
#define MAX_SCAN_DEPTH 2u
#define MIN_SCAN_INTERVAL_SECONDS 1u
#define MAX_SCAN_INTERVAL_SECONDS 3600u
#define MAX_STABILITY_WAIT_SECONDS 3600u
#define MAX_KSTUFF_PAUSE_DELAY_SECONDS 3600u
#define APP_DB_QUERY_BUSY_RETRIES 3
#define APP_DB_UPDATE_BUSY_RETRIES 25
+7
View File
@@ -3,6 +3,8 @@
#include <stdbool.h>
#include "sm_l10n.h"
typedef struct sm_error sm_error_t;
// Write a formatted line to the debug log.
@@ -13,17 +15,22 @@ void sm_notifications_init(void);
void sm_log_shutdown(void);
// Send a rich toast notification with packaged icon and version header.
void notify_system_rich(bool allow_in_quiet_mode, const char *fmt, ...);
void notify_system_rich_l10n(bool allow_in_quiet_mode, sm_l10n_key_t key, ...);
// Send the "game installed" rich toast for the given title ID.
void notify_game_installed_rich(const char *title_id);
// Send an informational system notification (suppressed in quiet mode).
void notify_system_info(const char *fmt, ...);
void notify_system_info_l10n(sm_l10n_key_t key, ...);
// Send a system notification with formatted text.
void notify_system(const char *fmt, ...);
void notify_system_l10n(sm_l10n_key_t key, ...);
// Clear the last recorded subsystem error.
void sm_error_clear(void);
// Store the last subsystem error with formatted details.
void sm_error_set(const char *subsystem, int code, const char *path,
const char *fmt, ...);
void sm_error_set_l10n(const char *subsystem, int code, const char *path,
sm_l10n_key_t key, ...);
// Return the last recorded subsystem error.
const sm_error_t *sm_last_error(void);
// Return whether the current error was already notified.
-26
View File
@@ -1,26 +0,0 @@
#ifndef SM_MDBG_H
#define SM_MDBG_H
#include <stdbool.h>
#include <stdint.h>
#include <sys/types.h>
// Initialize mdbg-backed crash monitoring state.
void sm_mdbg_init(void);
// Shut down mdbg-backed crash monitoring state.
void sm_mdbg_shutdown(void);
// Start monitoring the tracked game process for crash-candidate state.
void sm_mdbg_game_on_exec(pid_t pid, const char *title_id, uint32_t app_id);
// Record that kstuff auto-pause was actually applied to the tracked game.
void sm_mdbg_game_on_kstuff_pause(pid_t pid, uint64_t pause_time_us,
uint32_t pause_delay_seconds);
// Stop monitoring the tracked game process on exit.
void sm_mdbg_game_on_exit(pid_t pid);
// Clear tracked game monitoring state unconditionally.
void sm_mdbg_game_shutdown(void);
// Return the next wake deadline in monotonic microseconds, or 0 when idle.
uint64_t sm_mdbg_next_wake_us(uint64_t now_us);
// Poll the tracked process for mdbg crash-candidate state.
void sm_mdbg_poll(void);
#endif
+1
View File
@@ -47,6 +47,7 @@ int sceAppInstUtilAppInstallAll(void);
int sceAppInstUtilAppUnInstall(const char *title_id);
int sceKernelGetAppInfo(pid_t pid, app_info_t *info);
int sceKernelUsleep(unsigned int microseconds);
int32_t sceSystemServiceParamGetInt(int32_t paramId, int32_t *value);
int sceUserServiceInitialize(void *);
void sceUserServiceTerminate(void);
+1 -4
View File
@@ -113,8 +113,6 @@ typedef struct runtime_config {
bool backport_fakelib_enabled;
bool global_fakelib_enabled;
bool global_fakelib_mount_first;
bool kstuff_game_auto_toggle;
bool kstuff_crash_detection_enabled;
bool legacy_recursive_scan_forced;
char global_fakelib_path[MAX_PATH];
uint32_t global_fakelib_exclude_title_count;
@@ -122,8 +120,7 @@ typedef struct runtime_config {
uint32_t scan_depth;
uint32_t scan_interval_us;
uint32_t stability_wait_seconds;
uint32_t kstuff_pause_delay_image_seconds;
uint32_t kstuff_pause_delay_direct_seconds;
int32_t language_id;
attach_backend_t exfat_backend;
attach_backend_t ufs_backend;
uint32_t lvd_sector_exfat;
+4 -10
View File
@@ -10,7 +10,6 @@
#include "sm_shellcore_flags.h"
#include "sm_config_mount.h"
#include "sm_game_lifecycle.h"
#include "sm_kstuff.h"
#include "sm_mount_device.h"
#include "sm_filesystem.h"
#include "sm_image.h"
@@ -21,7 +20,6 @@
#include "sm_install.h"
#include "sm_appdb.h"
#include "sm_limits.h"
#include "sm_mdbg.h"
#include "sm_paths.h"
#ifndef SHADOWMOUNT_VERSION
@@ -471,8 +469,6 @@ int main(void) {
stop_conflicting_backpork();
if (!sm_shellcore_flags_start())
log_debug(" [SHELLFLAG] monitor unavailable");
sm_mdbg_init();
sm_kstuff_init();
if (!refresh_game_lifecycle_watcher())
log_debug(" [GAME] lifecycle watcher unavailable");
@@ -483,14 +479,14 @@ int main(void) {
log_debug(" [MOUNT] remount_system_ex failed: %s", strerror(errno));
}
notify_system("ShadowMount+ v%s exFAT/UFS/PFS", SHADOWMOUNT_VERSION);
notify_system_l10n(SM_L10N_STARTUP, SHADOWMOUNT_VERSION);
log_non_empty_scan_paths();
if (runtime_config()->legacy_recursive_scan_forced) {
notify_system_info("ShadowMount+: recursive_scan=1 deprecated, using scan_depth=2.");
notify_system_info_l10n(SM_L10N_RECURSIVE_SCAN_DEPRECATED);
} else if (runtime_config()->scan_depth > 1u) {
notify_system_info("ShadowMount+: scan depth %u enabled.",
runtime_config()->scan_depth);
notify_system_info_l10n(SM_L10N_SCAN_DEPTH_ENABLED,
runtime_config()->scan_depth);
}
cleanup_mount_dirs();
@@ -517,8 +513,6 @@ shutdown:
sm_shellcore_flags_stop();
stop_game_lifecycle_watcher();
sm_scanner_shutdown();
sm_kstuff_shutdown();
sm_mdbg_shutdown();
cleanup_kstuff_noautomount_files();
shutdown_title_mounts();
if (!shutdown_image_mounts()) {
+19 -423
View File
@@ -2,6 +2,7 @@
#include "sm_config_mount.h"
#include "sm_types.h"
#include "sm_limits.h"
#include "sm_l10n.h"
#include "sm_log.h"
#include "sm_mount_defs.h"
#include "sm_mount_device.h"
@@ -21,20 +22,11 @@ typedef struct {
bool valid;
} image_mode_rule_t;
typedef struct {
char title_id[MAX_TITLE_ID];
uint32_t delay_seconds;
bool valid;
} kstuff_delay_rule_t;
typedef struct {
runtime_config_t cfg;
char scan_path_storage[MAX_SCAN_PATHS][MAX_PATH];
int scan_path_count;
image_mode_rule_t image_mode_rules[MAX_IMAGE_MODE_RULES];
char kstuff_no_pause_title_ids[MAX_KSTUFF_TITLE_RULES][MAX_TITLE_ID];
int kstuff_no_pause_title_count;
kstuff_delay_rule_t kstuff_delay_rules[MAX_KSTUFF_TITLE_RULES];
} runtime_config_state_t;
typedef struct {
@@ -69,8 +61,6 @@ static bool normalize_title_id_value(const char *value,
static config_load_status_t load_runtime_config_state(runtime_config_state_t *state);
static bool parse_u32_ini(const char *value, uint32_t *out);
static bool is_valid_sector_size(uint32_t size);
static bool set_kstuff_pause_delay_override_rule(runtime_config_state_t *state,
const char *value);
static bool add_global_fakelib_exclude_rule(runtime_config_state_t *state,
const char *value);
static bool normalize_image_filename_value(const char *value,
@@ -86,18 +76,6 @@ static bool lookup_image_sector_override_in_file(const char *path,
static bool upsert_image_sector_override_in_file(const char *path,
const char *filename,
uint32_t sector_size);
static bool parse_kstuff_delay_rule_value(const char *value,
char title_id_out[MAX_TITLE_ID],
uint32_t *delay_seconds_out);
static bool parse_kstuff_delay_rule_line(const char *key, const char *value,
char title_id_out[MAX_TITLE_ID],
uint32_t *delay_seconds_out);
static bool lookup_kstuff_delay_override_in_file(const char *path,
const char *title_id,
uint32_t *delay_seconds_out);
static bool upsert_kstuff_delay_override_in_file(const char *path,
const char *title_id,
uint32_t delay_seconds);
static void apply_firmware_runtime_overrides(runtime_config_state_t *state);
static char *trim_ascii(char *s) {
@@ -236,13 +214,6 @@ static void init_runtime_scan_paths_defaults(runtime_config_state_t *state) {
add_runtime_managed_scan_paths(state);
}
static void clear_kstuff_title_rules(runtime_config_state_t *state) {
state->kstuff_no_pause_title_count = 0;
memset(state->kstuff_no_pause_title_ids, 0,
sizeof(state->kstuff_no_pause_title_ids));
memset(state->kstuff_delay_rules, 0, sizeof(state->kstuff_delay_rules));
}
static void init_runtime_config_defaults(runtime_config_state_t *state) {
memset(state, 0, sizeof(*state));
state->cfg.debug_enabled = true;
@@ -254,18 +225,13 @@ static void init_runtime_config_defaults(runtime_config_state_t *state) {
state->cfg.backport_fakelib_enabled = true;
state->cfg.global_fakelib_enabled = true;
state->cfg.global_fakelib_mount_first = true;
state->cfg.kstuff_game_auto_toggle = true;
state->cfg.kstuff_crash_detection_enabled = true;
state->cfg.legacy_recursive_scan_forced = false;
(void)strlcpy(state->cfg.global_fakelib_path, DEFAULT_GLOBAL_FAKELIB_PATH,
sizeof(state->cfg.global_fakelib_path));
state->cfg.scan_depth = DEFAULT_SCAN_DEPTH;
state->cfg.scan_interval_us = DEFAULT_SCAN_INTERVAL_US;
state->cfg.stability_wait_seconds = DEFAULT_STABILITY_WAIT_SECONDS;
state->cfg.kstuff_pause_delay_image_seconds =
DEFAULT_KSTUFF_PAUSE_DELAY_IMAGE_SECONDS;
state->cfg.kstuff_pause_delay_direct_seconds =
DEFAULT_KSTUFF_PAUSE_DELAY_DIRECT_SECONDS;
state->cfg.language_id = SM_LANGUAGE_AUTO;
state->cfg.exfat_backend = default_exfat_backend();
state->cfg.ufs_backend = default_ufs_backend();
state->cfg.lvd_sector_exfat = LVD_SECTOR_SIZE_EXFAT;
@@ -274,7 +240,6 @@ static void init_runtime_config_defaults(runtime_config_state_t *state) {
state->cfg.md_sector_exfat = MD_SECTOR_SIZE_EXFAT;
state->cfg.md_sector_ufs = MD_SECTOR_SIZE_UFS;
memset(state->image_mode_rules, 0, sizeof(state->image_mode_rules));
clear_kstuff_title_rules(state);
init_runtime_scan_paths_defaults(state);
apply_firmware_runtime_overrides(state);
}
@@ -313,11 +278,6 @@ static void apply_reloadable_runtime_fields(runtime_config_state_t *dst,
sizeof(dst->scan_path_storage));
memcpy(dst->image_mode_rules, src->image_mode_rules,
sizeof(dst->image_mode_rules));
memcpy(dst->kstuff_no_pause_title_ids, src->kstuff_no_pause_title_ids,
sizeof(dst->kstuff_no_pause_title_ids));
dst->kstuff_no_pause_title_count = src->kstuff_no_pause_title_count;
memcpy(dst->kstuff_delay_rules, src->kstuff_delay_rules,
sizeof(dst->kstuff_delay_rules));
}
static bool runtime_config_states_equal(const runtime_config_state_t *a,
@@ -421,22 +381,6 @@ bool get_image_sector_size_override(const char *filename,
return false;
}
bool is_kstuff_pause_disabled_for_title(const char *title_id) {
ensure_runtime_config_ready();
const runtime_config_state_t *state = active_runtime_state();
char normalized[MAX_TITLE_ID];
if (!normalize_title_id_value(title_id, normalized))
return false;
for (int i = 0; i < state->kstuff_no_pause_title_count; ++i) {
if (strcmp(state->kstuff_no_pause_title_ids[i], normalized) == 0)
return true;
}
return false;
}
bool is_global_fakelib_excluded_for_title(const char *title_id) {
ensure_runtime_config_ready();
@@ -453,59 +397,6 @@ bool is_global_fakelib_excluded_for_title(const char *title_id) {
return false;
}
bool get_kstuff_pause_delay_override_for_title(const char *title_id,
uint32_t *delay_seconds_out) {
ensure_runtime_config_ready();
if (!delay_seconds_out)
return false;
const runtime_config_state_t *state = active_runtime_state();
char normalized[MAX_TITLE_ID];
if (!normalize_title_id_value(title_id, normalized))
return false;
for (int i = 0; i < MAX_KSTUFF_TITLE_RULES; ++i) {
if (!state->kstuff_delay_rules[i].valid)
continue;
if (strcmp(state->kstuff_delay_rules[i].title_id, normalized) != 0)
continue;
*delay_seconds_out = state->kstuff_delay_rules[i].delay_seconds;
return true;
}
return false;
}
bool get_kstuff_autotune_pause_delay_for_title(const char *title_id,
uint32_t *delay_seconds_out) {
return lookup_kstuff_delay_override_in_file(AUTOTUNE_FILE, title_id,
delay_seconds_out);
}
bool upsert_kstuff_autotune_pause_delay(const char *title_id,
uint32_t current_delay_seconds,
uint32_t *delay_seconds_out) {
if (delay_seconds_out)
*delay_seconds_out = 0;
char normalized[MAX_TITLE_ID];
if (!normalize_title_id_value(title_id, normalized))
return false;
uint64_t tuned_delay_seconds = (uint64_t)current_delay_seconds * 2ull;
if (tuned_delay_seconds == 0)
tuned_delay_seconds = 1;
if (tuned_delay_seconds > MAX_KSTUFF_PAUSE_DELAY_SECONDS)
tuned_delay_seconds = MAX_KSTUFF_PAUSE_DELAY_SECONDS;
if (!upsert_kstuff_delay_override_in_file(AUTOTUNE_FILE, normalized,
(uint32_t)tuned_delay_seconds)) {
return false;
}
if (delay_seconds_out)
*delay_seconds_out = (uint32_t)tuned_delay_seconds;
return true;
}
bool upsert_image_sector_size_autotune(const char *filename,
uint32_t sector_size,
uint32_t *sector_size_out) {
@@ -588,33 +479,6 @@ static bool parse_bool_ini(const char *value, bool *out) {
return false;
}
static bool parse_kstuff_delay_rule_value(const char *value,
char title_id_out[MAX_TITLE_ID],
uint32_t *delay_seconds_out) {
if (!value || !title_id_out || !delay_seconds_out)
return false;
char local[128];
if (strlcpy(local, value, sizeof(local)) >= sizeof(local))
return false;
char *sep = strchr(local, ':');
if (!sep)
return false;
*sep = '\0';
char *title_id = trim_ascii(local);
char *delay_value = trim_ascii(sep + 1);
if (!normalize_title_id_value(title_id, title_id_out))
return false;
if (!parse_u32_ini(delay_value, delay_seconds_out) ||
*delay_seconds_out > MAX_KSTUFF_PAUSE_DELAY_SECONDS) {
return false;
}
return true;
}
static bool parse_image_sector_rule_value(const char *value,
char filename_out[MAX_PATH],
uint32_t *sector_size_out) {
@@ -642,64 +506,6 @@ static bool parse_image_sector_rule_value(const char *value,
return true;
}
static bool parse_kstuff_delay_rule_line(const char *key, const char *value,
char title_id_out[MAX_TITLE_ID],
uint32_t *delay_seconds_out) {
if (!key || !value || !title_id_out || !delay_seconds_out)
return false;
if (strcasecmp(key, "kstuff_delay") == 0)
return parse_kstuff_delay_rule_value(value, title_id_out, delay_seconds_out);
if (!normalize_title_id_value(key, title_id_out))
return false;
if (!parse_u32_ini(value, delay_seconds_out) ||
*delay_seconds_out > MAX_KSTUFF_PAUSE_DELAY_SECONDS) {
return false;
}
return true;
}
static bool lookup_kstuff_delay_override_in_file(const char *path,
const char *title_id,
uint32_t *delay_seconds_out) {
if (!path || !title_id || !delay_seconds_out)
return false;
char normalized_title_id[MAX_TITLE_ID];
if (!normalize_title_id_value(title_id, normalized_title_id))
return false;
FILE *f = fopen(path, "r");
if (!f)
return false;
char line[512];
while (fgets(line, sizeof(line), f)) {
char *key = NULL;
char *value = NULL;
if (!parse_ini_line(line, &key, &value))
continue;
uint32_t delay_seconds = 0;
char parsed_title_id[MAX_TITLE_ID];
if (!parse_kstuff_delay_rule_line(key, value, parsed_title_id,
&delay_seconds)) {
continue;
}
if (strcmp(parsed_title_id, normalized_title_id) != 0)
continue;
fclose(f);
*delay_seconds_out = delay_seconds;
return true;
}
fclose(f);
return false;
}
static bool lookup_image_sector_override_in_file(const char *path,
const char *filename,
uint32_t *sector_size_out) {
@@ -744,103 +550,6 @@ static bool lookup_image_sector_override_in_file(const char *path,
return true;
}
static bool upsert_kstuff_delay_override_in_file(const char *path,
const char *title_id,
uint32_t delay_seconds) {
if (!path || !title_id || delay_seconds > MAX_KSTUFF_PAUSE_DELAY_SECONDS)
return false;
char normalized_title_id[MAX_TITLE_ID];
if (!normalize_title_id_value(title_id, normalized_title_id))
return false;
char temp_path[MAX_PATH];
int written = snprintf(temp_path, sizeof(temp_path), "%s.tmp", path);
if (written <= 0 || (size_t)written >= sizeof(temp_path))
return false;
FILE *in = fopen(path, "r");
FILE *out = fopen(temp_path, "w");
if (!out) {
log_debug(" [CFG] autotune temp open failed: %s (%s)", temp_path,
strerror(errno));
if (in)
fclose(in);
return false;
}
bool found = false;
if (in) {
char line[512];
while (fgets(line, sizeof(line), in)) {
char original[sizeof(line)];
(void)strlcpy(original, line, sizeof(original));
char *key = NULL;
char *value = NULL;
if (!parse_ini_line(line, &key, &value)) {
if (fputs(original, out) == EOF)
goto write_failed;
continue;
}
uint32_t parsed_delay = 0;
char parsed_title_id[MAX_TITLE_ID];
if (!parse_kstuff_delay_rule_line(key, value, parsed_title_id,
&parsed_delay) ||
strcmp(parsed_title_id, normalized_title_id) != 0) {
if (fputs(original, out) == EOF)
goto write_failed;
continue;
}
if (!found) {
if (fprintf(out, "kstuff_delay=%s:%u\n", normalized_title_id,
(unsigned)delay_seconds) < 0) {
goto write_failed;
}
found = true;
}
}
fclose(in);
in = NULL;
}
if (!found &&
fprintf(out, "kstuff_delay=%s:%u\n", normalized_title_id,
(unsigned)delay_seconds) < 0) {
goto write_failed;
}
if (fclose(out) != 0) {
out = NULL;
log_debug(" [CFG] autotune temp close failed: %s (%s)", temp_path,
strerror(errno));
unlink(temp_path);
return false;
}
out = NULL;
if (rename(temp_path, path) != 0) {
log_debug(" [CFG] autotune replace failed: %s -> %s (%s)", temp_path, path,
strerror(errno));
unlink(temp_path);
return false;
}
return true;
write_failed:
log_debug(" [CFG] autotune temp write failed: %s (%s)", temp_path,
strerror(errno));
if (in)
fclose(in);
fclose(out);
unlink(temp_path);
return false;
}
static bool upsert_image_sector_override_in_file(const char *path,
const char *filename,
uint32_t sector_size) {
@@ -1040,27 +749,6 @@ static bool set_image_sector_rule(runtime_config_state_t *state,
return false;
}
static bool add_kstuff_no_pause_title_rule(runtime_config_state_t *state,
const char *value) {
char normalized[MAX_TITLE_ID];
if (!normalize_title_id_value(value, normalized))
return false;
for (int i = 0; i < state->kstuff_no_pause_title_count; ++i) {
if (strcmp(state->kstuff_no_pause_title_ids[i], normalized) == 0)
return true;
}
if (state->kstuff_no_pause_title_count >= MAX_KSTUFF_TITLE_RULES)
return false;
(void)strlcpy(state->kstuff_no_pause_title_ids[state->kstuff_no_pause_title_count],
normalized,
sizeof(state->kstuff_no_pause_title_ids[state->kstuff_no_pause_title_count]));
state->kstuff_no_pause_title_count++;
return true;
}
static bool add_global_fakelib_exclude_rule(runtime_config_state_t *state,
const char *value) {
char normalized[MAX_TITLE_ID];
@@ -1085,38 +773,6 @@ static bool add_global_fakelib_exclude_rule(runtime_config_state_t *state,
return true;
}
static bool set_kstuff_pause_delay_override_rule(runtime_config_state_t *state,
const char *value) {
if (!state || !value)
return false;
char normalized[MAX_TITLE_ID];
uint32_t delay_seconds = 0;
if (!parse_kstuff_delay_rule_value(value, normalized, &delay_seconds))
return false;
for (int i = 0; i < MAX_KSTUFF_TITLE_RULES; ++i) {
if (!state->kstuff_delay_rules[i].valid)
continue;
if (strcmp(state->kstuff_delay_rules[i].title_id, normalized) != 0)
continue;
state->kstuff_delay_rules[i].delay_seconds = delay_seconds;
return true;
}
for (int i = 0; i < MAX_KSTUFF_TITLE_RULES; ++i) {
if (state->kstuff_delay_rules[i].valid)
continue;
(void)strlcpy(state->kstuff_delay_rules[i].title_id, normalized,
sizeof(state->kstuff_delay_rules[i].title_id));
state->kstuff_delay_rules[i].delay_seconds = delay_seconds;
state->kstuff_delay_rules[i].valid = true;
return true;
}
return false;
}
static config_load_status_t load_runtime_config_state(runtime_config_state_t *state) {
init_runtime_config_defaults(state);
@@ -1190,6 +846,19 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
continue;
}
if (strcasecmp(key, "language") == 0 || strcasecmp(key, "lang") == 0 ||
strcasecmp(key, "locale") == 0) {
int32_t language_id = SM_LANGUAGE_AUTO;
if (!sm_l10n_parse_language_id(value, &language_id)) {
log_debug(" [CFG] invalid language at line %d: %s=%s "
"(use auto or a supported locale like en-US, ru-RU)",
line_no, key, value);
continue;
}
state->cfg.language_id = language_id;
continue;
}
if (strcasecmp(key, "app_install_all") == 0) {
if (!parse_bool_ini(value, &bval)) {
log_debug(" [CFG] invalid bool at line %d: %s=%s", line_no, key, value);
@@ -1308,42 +977,6 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
continue;
}
if (strcasecmp(key, "kstuff_game_auto_toggle") == 0) {
if (!parse_bool_ini(value, &bval)) {
log_debug(" [CFG] invalid bool at line %d: %s=%s", line_no, key, value);
continue;
}
state->cfg.kstuff_game_auto_toggle = bval;
continue;
}
if (strcasecmp(key, "kstuff_crash_detection") == 0) {
if (!parse_bool_ini(value, &bval)) {
log_debug(" [CFG] invalid bool at line %d: %s=%s", line_no, key, value);
continue;
}
state->cfg.kstuff_crash_detection_enabled = bval;
continue;
}
if (strcasecmp(key, "kstuff_no_pause") == 0) {
if (!add_kstuff_no_pause_title_rule(state, value)) {
log_debug(" [CFG] invalid kstuff no-pause title rule at line %d: "
"%s=%s", line_no, key, value);
}
continue;
}
if (strcasecmp(key, "kstuff_delay") == 0) {
if (!set_kstuff_pause_delay_override_rule(state, value)) {
log_debug(" [CFG] invalid kstuff pause override at line %d: %s=%s "
"(format: TITLEID:SECONDS, max: %u)",
line_no, key, value,
(unsigned)MAX_KSTUFF_PAUSE_DELAY_SECONDS);
}
continue;
}
if (strcasecmp(key, "scan_interval_seconds") == 0 ||
strcasecmp(key, "scan_interval_sec") == 0) {
if (!parse_u32_ini(value, &u32) || u32 < MIN_SCAN_INTERVAL_SECONDS ||
@@ -1368,30 +1001,6 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
continue;
}
if (strcasecmp(key, "kstuff_pause_delay_image_seconds") == 0 ||
strcasecmp(key, "kstuff_pause_delay_image_sec") == 0) {
if (!parse_u32_ini(value, &u32) || u32 > MAX_KSTUFF_PAUSE_DELAY_SECONDS) {
log_debug(" [CFG] invalid image kstuff pause delay at line %d: %s=%s "
"(max: %u)", line_no, key, value,
(unsigned)MAX_KSTUFF_PAUSE_DELAY_SECONDS);
continue;
}
state->cfg.kstuff_pause_delay_image_seconds = u32;
continue;
}
if (strcasecmp(key, "kstuff_pause_delay_direct_seconds") == 0 ||
strcasecmp(key, "kstuff_pause_delay_direct_sec") == 0) {
if (!parse_u32_ini(value, &u32) || u32 > MAX_KSTUFF_PAUSE_DELAY_SECONDS) {
log_debug(" [CFG] invalid direct kstuff pause delay at line %d: %s=%s "
"(max: %u)", line_no, key, value,
(unsigned)MAX_KSTUFF_PAUSE_DELAY_SECONDS);
continue;
}
state->cfg.kstuff_pause_delay_direct_seconds = u32;
continue;
}
if (strcasecmp(key, "exfat_backend") == 0) {
if (!parse_backend_ini(value, &backend)) {
log_debug(" [CFG] invalid backend at line %d: %s=%s", line_no, key,
@@ -1477,26 +1086,18 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
image_rule_count++;
}
int kstuff_delay_rule_count = 0;
for (int k = 0; k < MAX_KSTUFF_TITLE_RULES; k++) {
if (state->kstuff_delay_rules[k].valid)
kstuff_delay_rule_count++;
}
log_debug(" [CFG] loaded: debug=%d quiet=%d ro=%d force=%d "
"app_install_all=%d app_install_all_forced=%d scan_depth=%u "
"language=%s app_install_all=%d app_install_all_forced=%d scan_depth=%u "
"legacy_recursive_scan_forced=%d backport_fakelib=%d "
"global_fakelib=%d global_fakelib_priority=%s "
"global_fakelib_path=%s global_fakelib_exclude=%u "
"kstuff_game_auto_toggle=%d kstuff_crash_detection=%d "
"kstuff_pause_delay_image_s=%u kstuff_pause_delay_direct_s=%u "
"exfat_backend=%s ufs_backend=%s "
"lvd_sec(exfat=%u ufs=%u pfs=%u) md_sec(exfat=%u ufs=%u) "
"scan_interval_s=%u stability_wait_s=%u scan_paths=%d image_rules=%d "
"kstuff_no_pause=%d kstuff_delay_rules=%d",
"scan_interval_s=%u stability_wait_s=%u scan_paths=%d image_rules=%d",
state->cfg.debug_enabled ? 1 : 0, state->cfg.quiet_mode ? 1 : 0,
state->cfg.mount_read_only ? 1 : 0,
state->cfg.force_mount ? 1 : 0,
sm_l10n_language_name(state->cfg.language_id),
state->cfg.app_install_all_enabled ? 1 : 0,
state->cfg.app_install_all_forced ? 1 : 0, state->cfg.scan_depth,
state->cfg.legacy_recursive_scan_forced ? 1 : 0,
@@ -1505,18 +1106,13 @@ static config_load_status_t load_runtime_config_state(runtime_config_state_t *st
state->cfg.global_fakelib_mount_first ? "game" : "global",
state->cfg.global_fakelib_path,
state->cfg.global_fakelib_exclude_title_count,
state->cfg.kstuff_game_auto_toggle ? 1 : 0,
state->cfg.kstuff_crash_detection_enabled ? 1 : 0,
state->cfg.kstuff_pause_delay_image_seconds,
state->cfg.kstuff_pause_delay_direct_seconds,
attach_backend_name(state->cfg.exfat_backend),
attach_backend_name(state->cfg.ufs_backend),
state->cfg.lvd_sector_exfat, state->cfg.lvd_sector_ufs,
state->cfg.lvd_sector_pfs, state->cfg.md_sector_exfat,
state->cfg.md_sector_ufs, state->cfg.scan_interval_us / 1000000u,
state->cfg.stability_wait_seconds, state->scan_path_count,
image_rule_count, state->kstuff_no_pause_title_count,
kstuff_delay_rule_count);
image_rule_count);
return CONFIG_LOAD_OK;
}
+1 -1
View File
@@ -281,7 +281,7 @@ void sm_fakelib_game_on_exec(pid_t pid, const char *title_id) {
}
if (has_game)
notify_system_info("Game backported: %s", title_id);
notify_system_info_l10n(SM_L10N_GAME_BACKPORTED, title_id);
pthread_mutex_unlock(&g_fakelib_mutex);
}
+3 -3
View File
@@ -576,8 +576,8 @@ bool mount_backport_overlay(const char *mount_point,
int overlay_err = errno;
log_debug(" [IMG] backport overlay failed: %s -> %s (%s)", backport_path,
mount_point, strerror(overlay_err));
notify_system("Backport overlay failed: %s\n%s\n0x%08X", title_id,
backport_path, (uint32_t)overlay_err);
notify_system_l10n(SM_L10N_BACKPORT_OVERLAY_FAILED, title_id, backport_path,
(uint32_t)overlay_err);
return false;
}
@@ -901,7 +901,7 @@ bool mount_title_nullfs(const char *title_id, const char *src_path) {
log_debug(" [LINK] mount directory exists but stat failed for %s: %s",
dst, strerror(stat_errno));
if (!recover_mount_directory_after_stat_failure(dst, &dst_st))
return false;
return false;
}
if (!S_ISDIR(dst_st.st_mode)) {
log_debug(" [LINK] mount target is not a directory: %s mode=0%o", dst,
+5 -18
View File
@@ -9,10 +9,8 @@
#include "sm_appdb.h"
#include "sm_fakelib.h"
#include "sm_game_lifecycle.h"
#include "sm_kstuff.h"
#include "sm_limits.h"
#include "sm_log.h"
#include "sm_mdbg.h"
#include "sm_runtime.h"
#include "sm_scanner.h"
#include "sm_time.h"
@@ -164,8 +162,8 @@ static bool is_process_alive(pid_t pid) {
return errno != ESRCH;
}
static bool dispatch_game_launch(int kq, pid_t pid, uint64_t exec_time_us,
const char *title_id, uint32_t app_id) {
static bool dispatch_game_launch(int kq, pid_t pid, const char *title_id,
uint32_t app_id) {
if (!register_game_exit_watch(kq, pid)) {
log_debug(" [GAME] skipping launch tracking for %s pid=%ld without exit watch",
title_id, (long)pid);
@@ -175,7 +173,6 @@ static bool dispatch_game_launch(int kq, pid_t pid, uint64_t exec_time_us,
log_debug(" [GAME] started: %s pid=%ld app_id=0x%08X", title_id,
(long)pid, app_id);
publish_active_game(pid, title_id);
sm_kstuff_game_on_exec(pid, title_id, app_id, exec_time_us);
sm_fakelib_game_on_exec(pid, title_id);
return true;
}
@@ -330,8 +327,6 @@ static const struct timespec *compute_game_wait_timeout(
uint64_t next_wake_us = 0;
next_wake_us = min_nonzero_u64(next_wake_us, next_pending_game_wake_us(now_us));
next_wake_us = min_nonzero_u64(next_wake_us, sm_kstuff_game_next_wake_us(now_us));
next_wake_us = min_nonzero_u64(next_wake_us, sm_mdbg_next_wake_us(now_us));
if (next_wake_us == 0)
return NULL;
@@ -359,7 +354,7 @@ static void poll_game_modules(int kq) {
pid_t pid = entry->pid;
uint64_t exec_time_us = entry->exec_time_us;
if (is_supported_title_id(title_id)) {
if (dispatch_game_launch(kq, pid, exec_time_us, title_id, app_id)) {
if (dispatch_game_launch(kq, pid, title_id, app_id)) {
clear_pending_game_launch(entry);
clear_all_pending_game_launches();
break;
@@ -380,9 +375,6 @@ static void poll_game_modules(int kq) {
clear_pending_game_launch(entry);
}
}
sm_kstuff_game_poll();
sm_mdbg_poll();
}
static bool register_game_exit_watch(int kq, pid_t pid) {
@@ -406,7 +398,7 @@ static void handle_game_exec(int kq, pid_t pid) {
uint32_t app_id = 0;
if (resolve_game_title_id(pid, title_id, &app_id)) {
if (is_supported_title_id(title_id)) {
if (dispatch_game_launch(kq, pid, now_us, title_id, app_id))
if (dispatch_game_launch(kq, pid, title_id, app_id))
clear_all_pending_game_launches();
else
defer_confirmed_game_launch_retry(pid, now_us, now_us, title_id);
@@ -429,7 +421,6 @@ static void handle_game_exit(pid_t pid) {
if (atomic_load(&g_active_game_pid) == pid)
publish_active_game_pid(0);
sm_fakelib_game_on_exit(pid);
sm_kstuff_game_on_exit(pid);
if (had_active_title) {
int snd0_updates = normalize_snd0info_for_title(title_id);
if (snd0_updates >= 0)
@@ -449,10 +440,9 @@ static void restore_suspended_game_if_alive(int kq, pid_t pid) {
if (!is_supported_title_id(title_id))
return;
uint64_t now_us = monotonic_time_us();
log_debug(" [GAME] resumed: %s pid=%ld app_id=0x%08X", title_id,
(long)pid, app_id);
(void)dispatch_game_launch(kq, pid, now_us, title_id, app_id);
(void)dispatch_game_launch(kq, pid, title_id, app_id);
}
static void *game_lifecycle_watcher_main(void *arg) {
@@ -503,7 +493,6 @@ static void *game_lifecycle_watcher_main(void *arg) {
suspended_game_pid = atomic_load(&g_active_game_pid);
clear_all_pending_game_launches();
sm_fakelib_game_shutdown();
sm_kstuff_sleep_enter();
publish_active_game(0, NULL);
sleep_cleanup_done = true;
}
@@ -527,7 +516,6 @@ static void *game_lifecycle_watcher_main(void *arg) {
break;
sleep_cleanup_done = false;
restore_suspended_game_if_alive(kq, suspended_game_pid);
sm_kstuff_sleep_leave();
suspended_game_pid = 0;
}
@@ -564,7 +552,6 @@ static void *game_lifecycle_watcher_main(void *arg) {
clear_all_pending_game_launches();
sm_fakelib_game_shutdown();
sm_kstuff_game_shutdown();
publish_active_game(0, NULL);
close(kq);
log_debug(" [GAME] lifecycle watcher stopped");
+16 -21
View File
@@ -563,7 +563,8 @@ static bool reject_mounted_image_io(const char *file_path,
const char *devname,
const char *mount_point, int io_err,
const char *stage) {
sm_error_set("IMG", io_err, file_path, "Mounted image is unreadable or damaged");
sm_error_set_l10n("IMG", io_err, file_path,
SM_L10N_IMAGE_UNREADABLE_DAMAGED);
log_debug(" [IMG][%s] unreadable or damaged mount (%s -> %s, %s): %s",
attach_backend_name(attach_backend), devname, mount_point, stage,
strerror(io_err));
@@ -626,9 +627,9 @@ static bool reuse_existing_image_mount(const char *file_path,
}
if (!cache_image_mount(file_path, mount_point, existing_unit,
existing_backend)) {
sm_error_set("IMG", ENOSPC, file_path,
"Image cache full (%u entries), cannot track mount %s",
(unsigned)MAX_IMAGE_MOUNTS, mount_point);
sm_error_set_l10n("IMG", ENOSPC, file_path,
SM_L10N_IMAGE_CACHE_FULL_TRACK,
(unsigned)MAX_IMAGE_MOUNTS, mount_point);
log_debug(" [IMG] image cache full, refusing unmanaged mount reuse: %s",
mount_point);
errno = ENOSPC;
@@ -892,26 +893,20 @@ static bool validate_mounted_image(const char *file_path, image_fs_type_t fs_typ
upsert_image_sector_size_autotune(get_filename_component(file_path),
(uint32_t)fs_block_size,
&tuned_sector_size);
sm_error_set("IMG", EINVAL, file_path,
"Filesystem cluster size (%llu) is smaller than device "
"sector size (%u) for %s",
(unsigned long long)fs_block_size, min_device_sector, devname);
sm_error_set_l10n("IMG", EINVAL, file_path, SM_L10N_FS_CLUSTER_SMALL,
(unsigned long long)fs_block_size, min_device_sector,
devname);
log_debug(" [IMG][%s] %s", attach_backend_name(attach_backend),
sm_last_error()->message);
if (autotuned) {
log_debug(" [CFG] image sector autotuned: %s=%u",
get_filename_component(file_path), tuned_sector_size);
notify_system("Image mount rejected:\n%s\nCluster size is too small "
"(%llu < %u).\nSaved image_sector override: %u.\nTry "
"mounting again.",
file_path, (unsigned long long)fs_block_size,
min_device_sector, tuned_sector_size);
notify_system_l10n(SM_L10N_IMAGE_REJECTED_CLUSTER_AUTOTUNED, file_path,
(unsigned long long)fs_block_size, min_device_sector,
tuned_sector_size);
} else {
notify_system("Image mount rejected:\n%s\nCluster size is too small "
"(%llu < %u).\nUse a larger cluster size in the image or "
"lower sector size in config.",
file_path, (unsigned long long)fs_block_size,
min_device_sector);
notify_system_l10n(SM_L10N_IMAGE_REJECTED_CLUSTER_CONFIG, file_path,
(unsigned long long)fs_block_size, min_device_sector);
}
sm_error_mark_notified();
(void)unmount_image(file_path, unit_id, attach_backend);
@@ -1025,9 +1020,9 @@ bool mount_image(const char *file_path, image_fs_type_t fs_type) {
log_fs_stats("IMG", mount_point, image_fs_name(fs_type));
if (!cache_image_mount(file_path, mount_point, unit_id, attach_backend)) {
sm_error_set("IMG", ENOSPC, file_path,
"Image cache full (%u entries), rolling back mount",
(unsigned)MAX_IMAGE_MOUNTS);
sm_error_set_l10n("IMG", ENOSPC, file_path,
SM_L10N_IMAGE_CACHE_FULL_ROLLBACK,
(unsigned)MAX_IMAGE_MOUNTS);
log_debug(" [IMG] image cache full, rolling back mount: %s -> %s",
file_path, mount_point);
(void)unmount_image(file_path, unit_id, attach_backend);
+6 -6
View File
@@ -346,8 +346,8 @@ static bool mount_and_install(const char *src_path, const char *title_id,
resolve_app_install_title_dir();
if (!app_install_title_dir_fn) {
log_debug(" [REG] sceAppInstUtilAppInstallTitleDir unavailable");
notify_system("Register failed: %s (%s)\nAppInstallTitleDir unavailable",
title_name, title_id);
notify_system_l10n(SM_L10N_REGISTER_FAILED_UNAVAILABLE, title_name,
title_id);
return false;
}
@@ -377,8 +377,8 @@ static bool mount_and_install(const char *src_path, const char *title_id,
// Silent on restore/remount to avoid spam
} else {
log_debug(" [REG] FAIL: 0x%x", res);
notify_system("Register failed: %s (%s)\ncode=0x%08X", title_name, title_id,
(uint32_t)res);
notify_system_l10n(SM_L10N_REGISTER_FAILED_CODE, title_name, title_id,
(uint32_t)res);
return false;
}
@@ -406,8 +406,8 @@ void process_scan_candidates(const scan_candidate_t *candidates,
} else {
log_debug(" [ACTION] Installing: %s (%s)", c->title_name, c->title_id);
if (!use_app_install_all) {
notify_system_info("Installing: %s (%s)...", c->title_name,
c->title_id);
notify_system_info_l10n(SM_L10N_INSTALLING, c->title_name,
c->title_id);
}
}
+8 -6
View File
@@ -239,8 +239,8 @@ static void finalize_pending_install_timeout(pending_install_entry_t *entry) {
log_debug(" [REG] Install timeout after 5 minutes: %s (%s)",
entry->title_name, entry->title_id);
notify_system("Install failed: %s (%s)\nTimed out after 5 minutes",
entry->title_name, entry->title_id);
notify_system_l10n(SM_L10N_INSTALL_FAILED_TIMEOUT, entry->title_name,
entry->title_id);
(void)note_pending_install_failure(entry);
clear_pending_install_entry(entry);
}
@@ -365,7 +365,8 @@ static void notify_queued_install_batch(void) {
char message[3075];
int shown_count = 0;
snprintf(message, sizeof(message), "Batch install queued (%d):", queued_count);
snprintf(message, sizeof(message), sm_l10n_get(SM_L10N_BATCH_INSTALL_QUEUED),
queued_count);
for (int i = 0; i < MAX_PENDING; i++) {
const pending_install_entry_t *entry = &g_pending_installs[i];
@@ -378,7 +379,8 @@ static void notify_queued_install_batch(void) {
if (shown_count < queued_count) {
size_t used = strlen(message);
if (used < sizeof(message)) {
(void)snprintf(message + used, sizeof(message) - used, "\n... and %d more",
(void)snprintf(message + used, sizeof(message) - used,
sm_l10n_get(SM_L10N_BATCH_INSTALL_AND_MORE),
queued_count - shown_count);
}
}
@@ -429,8 +431,8 @@ bool sm_install_submit_queued(void) {
if (res != 0) {
log_debug(" [REG] Batch install request failed: 0x%x", res);
if (!g_queued_install_submit_failure_notified) {
notify_system("Batch install failed for %d app(s).\ncode=0x%08X",
queued_count, (uint32_t)res);
notify_system_l10n(SM_L10N_BATCH_INSTALL_FAILED, queued_count,
(uint32_t)res);
g_queued_install_submit_failure_notified = true;
}
schedule_queued_install_submit_retry(now_us);
-920
View File
@@ -1,920 +0,0 @@
#include "sm_platform.h"
#include "sm_config_mount.h"
#include "sm_filesystem.h"
#include "sm_kstuff.h"
#include "sm_limits.h"
#include "sm_log.h"
#include "sm_mdbg.h"
#include "sm_path_utils.h"
#include "sm_runtime.h"
#include "sm_time.h"
#include "sm_types.h"
#include <stdatomic.h>
#define KSTUFF_SYSENTVEC_TOGGLE_OFFSET 14
#define KSTUFF_SYSENTVEC_ENABLED 0xdeb7u
#define KSTUFF_SYSENTVEC_DISABLED 0xffffu
typedef struct {
bool active;
bool image_backed;
bool autopause_delay_valid;
bool pause_applied;
bool focus_override_active;
pid_t pid;
uint32_t app_id;
uint32_t autopause_delay_seconds;
uint64_t launch_time_us;
uint64_t pause_deadline_us;
char title_id[MAX_TITLE_ID];
} kstuff_game_entry_t;
typedef struct {
intptr_t sysentvec_ps5;
intptr_t sysentvec_ps4;
bool probe_available;
bool supported;
bool restore_on_empty;
bool sleep_pause_restore;
bool current_app_focus_valid;
uint32_t current_app_focus_id;
uint64_t restore_retry_us;
kstuff_game_entry_t game;
} kstuff_state_t;
static kstuff_state_t g_kstuff;
static _Atomic uint32_t g_pending_app_focus_id;
static _Atomic bool g_pending_app_focus_valid;
static _Atomic bool g_pending_config_reload;
static uint32_t get_effective_pause_delay_seconds(const kstuff_game_entry_t *entry);
static bool refresh_kstuff_support_state(void);
static uint32_t get_pause_delay_seconds_for_title(const char *title_id,
bool *image_backed_out,
uint32_t *autopause_delay_out,
bool *autopause_delay_valid_out);
static void restore_kstuff_if_needed(const char *reason);
static char *trim_ascii_inplace(char *s) {
while (*s == ' ' || *s == '\t' || *s == '\r' || *s == '\n')
s++;
size_t len = strlen(s);
while (len > 0) {
char ch = s[len - 1u];
if (ch != ' ' && ch != '\t' && ch != '\r' && ch != '\n')
break;
s[len - 1u] = '\0';
len--;
}
return s;
}
static char *strip_inline_comment(char *s) {
char *comment = strpbrk(s, "#;");
if (comment)
*comment = '\0';
return trim_ascii_inplace(s);
}
static bool parse_pause_delay_seconds(const char *value,
uint32_t *delay_seconds_out) {
if (!value || !delay_seconds_out)
return false;
errno = 0;
char *end = NULL;
unsigned long parsed = strtoul(value, &end, 10);
if (errno != 0 || end == value || *end != '\0' ||
parsed > MAX_KSTUFF_PAUSE_DELAY_SECONDS) {
return false;
}
*delay_seconds_out = (uint32_t)parsed;
return true;
}
static bool get_autopause_delay_for_source(const char *source_path,
bool image_backed,
uint32_t *delay_seconds_out) {
if (!source_path || source_path[0] == '\0' || !delay_seconds_out)
return false;
char autopause_path[MAX_PATH];
int written = snprintf(autopause_path, sizeof(autopause_path), "%s/%s",
source_path, "autopause.txt");
if (written <= 0 || (size_t)written >= sizeof(autopause_path))
return false;
FILE *f = fopen(autopause_path, "r");
if (!f)
return false;
char line[128];
bool have_scalar = false;
bool have_direct = false;
bool have_image = false;
uint32_t scalar_delay = 0;
uint32_t direct_delay = 0;
uint32_t image_delay = 0;
while (fgets(line, sizeof(line), f)) {
char *value = strip_inline_comment(line);
if (value[0] == '\0')
continue;
char *eq = strchr(value, '=');
if (!eq) {
if (!have_scalar && parse_pause_delay_seconds(value, &scalar_delay))
have_scalar = true;
continue;
}
*eq = '\0';
char *key = trim_ascii_inplace(value);
char *arg = trim_ascii_inplace(eq + 1);
uint32_t parsed_delay = 0;
if (!parse_pause_delay_seconds(arg, &parsed_delay))
continue;
if (strcasecmp(key, "direct") == 0) {
direct_delay = parsed_delay;
have_direct = true;
} else if (strcasecmp(key, "image") == 0) {
image_delay = parsed_delay;
have_image = true;
}
}
fclose(f);
if (image_backed && have_image) {
*delay_seconds_out = image_delay;
return true;
}
if (!image_backed && have_direct) {
*delay_seconds_out = direct_delay;
return true;
}
if (have_scalar) {
uint64_t delay_seconds = scalar_delay;
if (image_backed)
delay_seconds *= 2u;
if (delay_seconds > MAX_KSTUFF_PAUSE_DELAY_SECONDS)
delay_seconds = MAX_KSTUFF_PAUSE_DELAY_SECONDS;
*delay_seconds_out = (uint32_t)delay_seconds;
return true;
}
return false;
}
static bool resolve_title_pause_source(const char *title_id,
char source_path[MAX_PATH],
bool *image_backed_out) {
source_path[0] = '\0';
*image_backed_out = false;
if (!title_id)
return false;
if (!read_mount_link(title_id, source_path, MAX_PATH))
return false;
*image_backed_out = is_under_image_mount_base(source_path);
return true;
}
static uint32_t get_configured_pause_delay_seconds(const char *title_id,
bool image_backed,
bool *override_applied_out) {
const runtime_config_t *cfg = runtime_config();
uint32_t delay_seconds =
image_backed ? cfg->kstuff_pause_delay_image_seconds
: cfg->kstuff_pause_delay_direct_seconds;
uint32_t override_delay_seconds = 0;
if (get_kstuff_pause_delay_override_for_title(title_id,
&override_delay_seconds)) {
*override_applied_out = true;
return override_delay_seconds;
}
*override_applied_out = false;
return delay_seconds;
}
static bool resolve_kstuff_sysentvec_addrs(intptr_t *ps5_out, intptr_t *ps4_out) {
if (!ps5_out || !ps4_out)
return false;
*ps5_out = 0;
*ps4_out = 0;
switch (kernel_get_fw_version() & 0xffff0000u) {
case 0x1000000:
case 0x1010000:
case 0x1020000:
case 0x1050000:
case 0x1100000:
case 0x1110000:
case 0x1120000:
case 0x1130000:
case 0x1140000:
case 0x2000000:
case 0x2200000:
case 0x2250000:
case 0x2260000:
case 0x2300000:
case 0x2500000:
case 0x2700000:
// Older jailbreak chains usually rely on Byepervisor instead of kstuff.
return false;
case 0x3000000:
case 0x3100000:
case 0x3200000:
case 0x3210000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xca0cd8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xca0e50;
return true;
case 0x4000000:
case 0x4020000:
case 0x4030000:
case 0x4500000:
case 0x4510000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xd11bb8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xd11d30;
return true;
case 0x5000000:
case 0x5020000:
case 0x5100000:
case 0x5500000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xe00be8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xe00d60;
return true;
case 0x6000000:
case 0x6020000:
case 0x6500000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xe210a8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xe21220;
return true;
case 0x7000000:
case 0x7010000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xe21ab8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xe21c30;
return true;
case 0x7200000:
case 0x7400000:
case 0x7600000:
case 0x7610000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xe21b78;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xe21cf0;
return true;
case 0x8000000:
case 0x8200000:
case 0x8400000:
case 0x8600000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xe21ca8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xe21e20;
return true;
case 0x9000000:
case 0x9050000:
case 0x9200000:
case 0x9400000:
case 0x9600000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xdba648;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xdba7c0;
return true;
case 0x10000000:
case 0x10010000:
case 0x10200000:
case 0x10400000:
case 0x10600000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xdba6d8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xdba850;
return true;
case 0x11000000:
case 0x11200000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xdcbc78;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xdcbdf0;
return true;
case 0x11400000:
case 0x11600000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xdcbc98;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xdcbe10;
return true;
case 0x12000000:
case 0x12020000:
case 0x12200000:
case 0x12400000:
case 0x12600000:
case 0x12700000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xdcc978;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xdccaf0;
return true;
case 0x13000000:
case 0x13200000:
*ps5_out = KERNEL_ADDRESS_DATA_BASE + 0xddd8a8;
*ps4_out = KERNEL_ADDRESS_DATA_BASE + 0xddda20;
return true;
default:
return false;
}
}
static bool kstuff_sysentvec_is_enabled(intptr_t sysentvec_addr) {
return kernel_getshort(sysentvec_addr + KSTUFF_SYSENTVEC_TOGGLE_OFFSET) !=
KSTUFF_SYSENTVEC_DISABLED;
}
static uint16_t read_kstuff_sysentvec_toggle(intptr_t sysentvec_addr) {
return (uint16_t)kernel_getshort(sysentvec_addr +
KSTUFF_SYSENTVEC_TOGGLE_OFFSET);
}
static bool kstuff_sysentvec_toggle_is_known(uint16_t value) {
return value == KSTUFF_SYSENTVEC_ENABLED ||
value == KSTUFF_SYSENTVEC_DISABLED;
}
static void set_kstuff_sysentvec_enabled(intptr_t sysentvec_addr, bool enabled) {
(void)kernel_setshort(sysentvec_addr + KSTUFF_SYSENTVEC_TOGGLE_OFFSET,
enabled ? KSTUFF_SYSENTVEC_ENABLED
: KSTUFF_SYSENTVEC_DISABLED);
}
static bool read_kstuff_enabled_state(bool *ps5_out, bool *ps4_out) {
if (!refresh_kstuff_support_state())
return false;
bool ps5_enabled = kstuff_sysentvec_is_enabled(g_kstuff.sysentvec_ps5);
bool ps4_enabled = kstuff_sysentvec_is_enabled(g_kstuff.sysentvec_ps4);
if (ps5_out)
*ps5_out = ps5_enabled;
if (ps4_out)
*ps4_out = ps4_enabled;
return ps5_enabled && ps4_enabled;
}
static bool refresh_kstuff_support_state(void) {
if (!g_kstuff.probe_available) {
g_kstuff.supported = false;
return false;
}
uint16_t ps5_toggle = read_kstuff_sysentvec_toggle(g_kstuff.sysentvec_ps5);
uint16_t ps4_toggle = read_kstuff_sysentvec_toggle(g_kstuff.sysentvec_ps4);
g_kstuff.supported = kstuff_sysentvec_toggle_is_known(ps5_toggle) &&
kstuff_sysentvec_toggle_is_known(ps4_toggle);
return g_kstuff.supported;
}
static bool kstuff_state_matches(bool enabled, bool ps5_enabled,
bool ps4_enabled) {
return ps5_enabled == enabled && ps4_enabled == enabled;
}
static bool apply_kstuff_enabled_state(bool enabled, bool notify_user,
bool *fully_applied_out);
static void mark_restore_needed(void) {
g_kstuff.restore_on_empty = true;
g_kstuff.restore_retry_us = 0;
}
static bool tracked_game_requires_restore(void) {
return g_kstuff.restore_on_empty;
}
static void finish_tracked_game_clear(const char *reason) {
if (!g_kstuff.restore_on_empty)
return;
mark_restore_needed();
restore_kstuff_if_needed(reason);
}
static void apply_kstuff_config_reload(void) {
if (!runtime_config()->kstuff_crash_detection_enabled)
sm_mdbg_game_shutdown();
if (!runtime_config()->kstuff_game_auto_toggle) {
sm_kstuff_game_shutdown();
return;
}
if (!g_kstuff.game.active)
return;
if (is_kstuff_pause_disabled_for_title(g_kstuff.game.title_id)) {
bool restore_needed = tracked_game_requires_restore();
log_debug(" [KSTUFF] cleared tracked game by config reload: %s",
g_kstuff.game.title_id);
sm_mdbg_game_shutdown();
memset(&g_kstuff.game, 0, sizeof(g_kstuff.game));
if (restore_needed)
finish_tracked_game_clear("config reload");
return;
}
if (g_kstuff.game.pause_applied)
return;
bool image_backed = g_kstuff.game.image_backed;
bool autopause_delay_valid = false;
uint32_t autopause_delay_seconds = 0;
uint32_t delay_seconds = get_pause_delay_seconds_for_title(
g_kstuff.game.title_id, &image_backed, &autopause_delay_seconds,
&autopause_delay_valid);
g_kstuff.game.image_backed = image_backed;
g_kstuff.game.autopause_delay_valid = autopause_delay_valid;
g_kstuff.game.autopause_delay_seconds = autopause_delay_seconds;
g_kstuff.game.pause_deadline_us =
g_kstuff.game.launch_time_us == 0
? 0
: g_kstuff.game.launch_time_us + (uint64_t)delay_seconds * 1000000ull;
log_debug(" [KSTUFF] updated tracked game config: %s source=%s pause_delay=%us",
g_kstuff.game.title_id,
g_kstuff.game.image_backed ? "image" : "direct",
delay_seconds);
}
static uint32_t get_pause_delay_seconds_for_title(const char *title_id,
bool *image_backed_out,
uint32_t *autopause_delay_out,
bool *autopause_delay_valid_out) {
char source_path[MAX_PATH];
bool image_backed = false;
(void)resolve_title_pause_source(title_id, source_path, &image_backed);
*image_backed_out = image_backed;
*autopause_delay_out = 0;
*autopause_delay_valid_out = false;
uint32_t autotuned_delay_seconds = 0;
if (get_kstuff_autotune_pause_delay_for_title(title_id,
&autotuned_delay_seconds)) {
return autotuned_delay_seconds;
}
bool override_applied = false;
uint32_t delay_seconds =
get_configured_pause_delay_seconds(title_id, image_backed,
&override_applied);
uint32_t autopause_delay_seconds = 0;
if (get_autopause_delay_for_source(source_path, image_backed,
&autopause_delay_seconds)) {
*autopause_delay_out = autopause_delay_seconds;
*autopause_delay_valid_out = true;
if (!override_applied)
return autopause_delay_seconds;
}
return delay_seconds;
}
static void restore_kstuff_if_needed(const char *reason) {
if (g_kstuff.game.active && g_kstuff.game.pause_applied)
return;
if (!g_kstuff.restore_on_empty)
return;
uint64_t now_us = monotonic_time_us();
if (now_us != 0 && g_kstuff.restore_retry_us != 0 &&
now_us < g_kstuff.restore_retry_us) {
return;
}
if (g_kstuff.game.active && !g_kstuff.game.pause_applied) {
if (g_kstuff.game.pause_deadline_us == 0 ||
(now_us != 0 && now_us >= g_kstuff.game.pause_deadline_us)) {
return;
}
}
if (!sm_kstuff_is_supported()) {
g_kstuff.restore_retry_us =
now_us == 0 ? 1 : now_us + GAME_LIFECYCLE_POLL_INTERVAL_US;
return;
}
bool enabled = sm_kstuff_is_enabled();
if (!enabled)
enabled = sm_kstuff_set_enabled(true, true);
if (enabled) {
log_debug(" [KSTUFF] auto-resumed (%s)%s",
reason ? reason : "no reason",
g_kstuff.game.active ? ", pending delay for another tracked game"
: "");
} else {
log_debug(" [KSTUFF] failed to auto-resume (%s)",
reason ? reason : "no reason");
g_kstuff.restore_retry_us =
now_us == 0 ? 0 : now_us + KSTUFF_RESTORE_RETRY_US;
return;
}
g_kstuff.restore_on_empty = false;
g_kstuff.restore_retry_us = 0;
}
static void maybe_apply_kstuff_pause_for_slot(kstuff_game_entry_t *entry) {
if (!entry->active || entry->pause_applied)
return;
uint64_t now_us = monotonic_time_us();
if (now_us != 0 && now_us < entry->pause_deadline_us)
return;
if (g_kstuff.current_app_focus_valid && entry->app_id != 0 &&
g_kstuff.current_app_focus_id != entry->app_id) {
return;
}
if (!sm_kstuff_is_supported()) {
log_debug(" [KSTUFF] skipping auto-pause for %s pid=%ld: kstuff not "
"available",
entry->title_id, (long)entry->pid);
sm_mdbg_game_shutdown();
memset(entry, 0, sizeof(*entry));
return;
}
bool was_enabled = sm_kstuff_is_enabled();
bool fully_disabled = false;
(void)apply_kstuff_enabled_state(false, was_enabled, &fully_disabled);
if (!fully_disabled) {
log_debug(" [KSTUFF] failed to auto-pause for %s pid=%ld",
entry->title_id, (long)entry->pid);
return;
}
if (was_enabled) {
mark_restore_needed();
sm_mdbg_game_on_kstuff_pause(entry->pid, now_us,
get_effective_pause_delay_seconds(entry));
log_debug(" [KSTUFF] auto-paused for %s pid=%ld (%s launch)",
entry->title_id, (long)entry->pid,
entry->image_backed ? "image" : "direct");
} else {
log_debug(" [KSTUFF] pause deadline reached for %s pid=%ld but kstuff "
"was already disabled", entry->title_id, (long)entry->pid);
}
entry->pause_applied = true;
}
static void handle_kstuff_app_focus_change(uint32_t focused_app_id) {
g_kstuff.current_app_focus_valid = true;
g_kstuff.current_app_focus_id = focused_app_id;
if (!g_kstuff.game.active || g_kstuff.game.app_id == 0)
return;
if (focused_app_id != g_kstuff.game.app_id) {
if (!g_kstuff.game.pause_applied)
return;
if (!g_kstuff.restore_on_empty)
return;
if (g_kstuff.game.focus_override_active)
return;
bool enabled = sm_kstuff_is_enabled();
if (!enabled)
enabled = sm_kstuff_set_enabled(true, false);
if (!enabled) {
log_debug(" [KSTUFF] failed to enable on app focus leave "
"(tracked=0x%08X current=0x%08X)",
g_kstuff.game.app_id, focused_app_id);
return;
}
g_kstuff.game.focus_override_active = true;
log_debug(" [KSTUFF] temporarily enabled on app focus leave "
"(tracked=0x%08X current=0x%08X)",
g_kstuff.game.app_id, focused_app_id);
return;
}
if (!g_kstuff.game.focus_override_active)
return;
bool fully_disabled = false;
(void)apply_kstuff_enabled_state(false, false, &fully_disabled);
if (!fully_disabled) {
log_debug(" [KSTUFF] failed to restore disabled state on app focus return "
"(app_id=0x%08X)",
focused_app_id);
return;
}
g_kstuff.game.focus_override_active = false;
log_debug(" [KSTUFF] restored disabled state on app focus return "
"(app_id=0x%08X)",
focused_app_id);
}
uint64_t sm_kstuff_game_next_wake_us(uint64_t now_us) {
if (!sm_kstuff_game_feature_enabled())
return 0;
uint64_t next_wake_us = 0;
if (g_kstuff.game.active && !g_kstuff.game.pause_applied) {
if (g_kstuff.current_app_focus_valid && g_kstuff.game.app_id != 0 &&
g_kstuff.current_app_focus_id != g_kstuff.game.app_id) {
next_wake_us = 0;
} else if (g_kstuff.game.pause_deadline_us != 0) {
next_wake_us = g_kstuff.game.pause_deadline_us;
} else if (now_us == 0) {
next_wake_us = 1;
} else {
next_wake_us = now_us + GAME_LIFECYCLE_POLL_INTERVAL_US;
}
}
if (g_kstuff.restore_on_empty) {
uint64_t restore_wake_us = g_kstuff.restore_retry_us;
if (restore_wake_us == 0) {
if (g_kstuff.game.active && !g_kstuff.game.pause_applied) {
if (g_kstuff.game.pause_deadline_us != 0) {
restore_wake_us = g_kstuff.game.pause_deadline_us;
} else if (now_us == 0) {
restore_wake_us = 1;
} else {
restore_wake_us = now_us + GAME_LIFECYCLE_POLL_INTERVAL_US;
}
} else {
restore_wake_us = now_us == 0 ? 1 : now_us;
}
}
if (next_wake_us == 0 || restore_wake_us < next_wake_us)
next_wake_us = restore_wake_us;
}
return next_wake_us;
}
bool sm_kstuff_is_supported(void) {
return refresh_kstuff_support_state();
}
bool sm_kstuff_is_enabled(void) {
return read_kstuff_enabled_state(NULL, NULL);
}
static bool apply_kstuff_enabled_state(bool enabled, bool notify_user,
bool *fully_applied_out) {
bool ps5_enabled = false;
bool ps4_enabled = false;
bool is_enabled = read_kstuff_enabled_state(&ps5_enabled, &ps4_enabled);
if (!g_kstuff.supported)
return false;
bool fully_applied = kstuff_state_matches(enabled, ps5_enabled, ps4_enabled);
if (fully_applied) {
if (fully_applied_out)
*fully_applied_out = true;
return is_enabled;
}
if (ps5_enabled != enabled)
set_kstuff_sysentvec_enabled(g_kstuff.sysentvec_ps5, enabled);
if (ps4_enabled != enabled)
set_kstuff_sysentvec_enabled(g_kstuff.sysentvec_ps4, enabled);
is_enabled = read_kstuff_enabled_state(&ps5_enabled, &ps4_enabled);
fully_applied = kstuff_state_matches(enabled, ps5_enabled, ps4_enabled);
if (fully_applied_out)
*fully_applied_out = fully_applied;
if (fully_applied) {
log_debug(" [KSTUFF] %s both sysentvecs", enabled ? "enabled" : "disabled");
if (notify_user) {
notify_system_info(enabled ? "KStuff active again"
: "KStuff paused while the game is running");
}
} else {
log_debug(" [KSTUFF] %s request incomplete (ps5=%s ps4=%s)",
enabled ? "enable" : "disable", ps5_enabled ? "on" : "off",
ps4_enabled ? "on" : "off");
}
return is_enabled;
}
bool sm_kstuff_set_enabled(bool enabled, bool notify_user) {
return apply_kstuff_enabled_state(enabled, notify_user, NULL);
}
bool sm_kstuff_game_feature_enabled(void) {
return runtime_config()->kstuff_game_auto_toggle && g_kstuff.probe_available;
}
void sm_kstuff_game_on_exec(pid_t pid, const char *title_id, uint32_t app_id,
uint64_t exec_time_us) {
if (!sm_kstuff_game_feature_enabled())
return;
if (g_kstuff.game.active) {
if (g_kstuff.game.pid == pid) {
log_debug(" [KSTUFF] already tracking pid=%ld for %s", (long)pid,
title_id);
return;
}
bool restore_needed = tracked_game_requires_restore();
log_debug(" [KSTUFF] handoff tracked game pid=%ld (%s) -> pid=%ld (%s)",
(long)g_kstuff.game.pid, g_kstuff.game.title_id, (long)pid,
title_id);
sm_mdbg_game_shutdown();
memset(&g_kstuff.game, 0, sizeof(g_kstuff.game));
if (restore_needed)
finish_tracked_game_clear("tracked game handoff");
}
if (is_kstuff_pause_disabled_for_title(title_id)) {
log_debug(" [KSTUFF] auto-pause disabled by config for %s pid=%ld "
"app_id=0x%08X", title_id, (long)pid, app_id);
return;
}
bool image_backed = false;
bool autopause_delay_valid = false;
uint32_t autopause_delay_seconds = 0;
uint32_t delay_seconds = get_pause_delay_seconds_for_title(
title_id, &image_backed, &autopause_delay_seconds,
&autopause_delay_valid);
uint64_t now_us = monotonic_time_us();
uint64_t base_time_us = exec_time_us != 0 ? exec_time_us : now_us;
g_kstuff.game.active = true;
g_kstuff.game.image_backed = image_backed;
g_kstuff.game.autopause_delay_valid = autopause_delay_valid;
g_kstuff.game.pause_applied = false;
g_kstuff.game.focus_override_active = false;
g_kstuff.game.pid = pid;
g_kstuff.game.app_id = app_id;
g_kstuff.game.autopause_delay_seconds = autopause_delay_seconds;
g_kstuff.game.launch_time_us = base_time_us;
g_kstuff.game.pause_deadline_us =
base_time_us == 0 ? 0 : base_time_us + (uint64_t)delay_seconds * 1000000ull;
(void)strlcpy(g_kstuff.game.title_id, title_id, sizeof(g_kstuff.game.title_id));
sm_mdbg_game_on_exec(pid, title_id, app_id);
log_debug(" [KSTUFF] tracking game launch: %s pid=%ld app_id=0x%08X source=%s "
"pause_delay=%us", title_id, (long)pid, app_id,
image_backed ? "image" : "direct", delay_seconds);
}
void sm_kstuff_note_app_focus(uint32_t app_id) {
atomic_store(&g_pending_app_focus_id, app_id);
atomic_store(&g_pending_app_focus_valid, true);
}
void sm_kstuff_game_on_exit(pid_t pid) {
if (!g_kstuff.game.active || g_kstuff.game.pid != pid)
return;
bool restore_needed = tracked_game_requires_restore();
sm_mdbg_game_on_exit(pid);
log_debug(" [KSTUFF] game stopped: %s pid=%ld",
g_kstuff.game.title_id, (long)pid);
memset(&g_kstuff.game, 0, sizeof(g_kstuff.game));
if (restore_needed)
finish_tracked_game_clear("tracked game exit");
}
void sm_kstuff_game_poll(void) {
if (atomic_exchange(&g_pending_config_reload, false))
apply_kstuff_config_reload();
if (!sm_kstuff_game_feature_enabled())
return;
if (atomic_exchange(&g_pending_app_focus_valid, false)) {
handle_kstuff_app_focus_change(atomic_load(&g_pending_app_focus_id));
}
restore_kstuff_if_needed("pending auto-resume");
maybe_apply_kstuff_pause_for_slot(&g_kstuff.game);
}
void sm_kstuff_game_shutdown(void) {
bool restore_needed = tracked_game_requires_restore();
if (restore_needed && !g_kstuff.sleep_pause_restore &&
runtime_sleep_mode_active() && should_stop_requested()) {
restore_needed = false;
g_kstuff.restore_on_empty = false;
g_kstuff.restore_retry_us = 0;
} else if (g_kstuff.sleep_pause_restore) {
restore_needed = true;
g_kstuff.sleep_pause_restore = false;
}
sm_mdbg_game_shutdown();
memset(&g_kstuff.game, 0, sizeof(g_kstuff.game));
if (restore_needed) {
mark_restore_needed();
restore_kstuff_if_needed("watcher shutdown");
}
}
void sm_kstuff_sleep_enter(void) {
bool was_enabled = false;
bool fully_disabled = false;
sm_mdbg_game_shutdown();
memset(&g_kstuff.game, 0, sizeof(g_kstuff.game));
g_kstuff.sleep_pause_restore = false;
if (!sm_kstuff_is_supported())
return;
was_enabled = sm_kstuff_is_enabled();
(void)apply_kstuff_enabled_state(false, false, &fully_disabled);
if (!fully_disabled) {
log_debug(" [KSTUFF] failed to pause for system sleep");
return;
}
g_kstuff.sleep_pause_restore = was_enabled;
if (was_enabled)
log_debug(" [KSTUFF] paused for system sleep");
}
void sm_kstuff_sleep_leave(void) {
if (!g_kstuff.sleep_pause_restore)
return;
g_kstuff.sleep_pause_restore = false;
mark_restore_needed();
restore_kstuff_if_needed("system sleep");
}
void sm_kstuff_on_config_reload(void) {
atomic_store(&g_pending_config_reload, true);
}
void sm_kstuff_init(void) {
memset(&g_kstuff, 0, sizeof(g_kstuff));
atomic_store(&g_pending_app_focus_id, 0);
atomic_store(&g_pending_app_focus_valid, false);
atomic_store(&g_pending_config_reload, false);
if (!resolve_kstuff_sysentvec_addrs(&g_kstuff.sysentvec_ps5,
&g_kstuff.sysentvec_ps4)) {
log_debug(" [KSTUFF] runtime control unavailable on firmware 0x%08X",
kernel_get_fw_version());
return;
}
g_kstuff.probe_available = true;
if (!refresh_kstuff_support_state()) {
log_debug(" [KSTUFF] runtime control probe ready; kstuff not present at "
"startup");
return;
}
log_debug(" [KSTUFF] runtime control ready (image_delay=%u "
"direct_delay=%u)",
runtime_config()->kstuff_pause_delay_image_seconds,
runtime_config()->kstuff_pause_delay_direct_seconds);
}
void sm_kstuff_shutdown(void) {
sm_kstuff_game_shutdown();
atomic_store(&g_pending_app_focus_id, 0);
atomic_store(&g_pending_app_focus_valid, false);
atomic_store(&g_pending_config_reload, false);
memset(&g_kstuff, 0, sizeof(g_kstuff));
}
static uint32_t get_effective_pause_delay_seconds(const kstuff_game_entry_t *entry) {
if (!entry || entry->launch_time_us == 0 || entry->pause_deadline_us == 0 ||
entry->pause_deadline_us <= entry->launch_time_us) {
return 0;
}
uint64_t delay_us = entry->pause_deadline_us - entry->launch_time_us;
uint64_t delay_seconds = delay_us / 1000000ull;
if (delay_seconds > UINT32_MAX)
delay_seconds = UINT32_MAX;
return (uint32_t)delay_seconds;
}
+242
View File
@@ -0,0 +1,242 @@
#include "sm_l10n.h"
#include "sm_config_mount.h"
#include "sm_log.h"
#include "sm_types.h"
#define SCE_SYSTEM_SERVICE_PARAM_ID_LANG 1
typedef struct {
const char *country;
const char *lang;
const char *locale;
} sm_region_t;
static const sm_region_t g_regions[] = {
{"jp", "ja", "ja-JP"}, {"us", "en", "en-US"},
{"fr", "fr", "fr-FR"}, {"es", "es", "es-ES"},
{"de", "de", "de-DE"}, {"it", "it", "it-IT"},
{"nl", "nl", "nl-NL"}, {"pt", "pt", "pt-PT"},
{"ru", "ru", "ru-RU"}, {"kr", "ko", "ko-KR"},
{"tw", "zh", "zh-TW"}, {"cn", "zh", "zh-CN"},
{"fi", "fi", "fi-FI"}, {"se", "sv", "sv-SE"},
{"dk", "da", "da-DK"}, {"no", "no", "no-NO"},
{"pl", "pl", "pl-PL"}, {"br", "pt", "pt-BR"},
{"gb", "en", "en-GB"}, {"tr", "tr", "tr-TR"},
{"mx", "es", "es-MX"}, {"sa", "ar", "ar-SA"},
{"ca", "fr", "fr-CA"}, {"cz", "cs", "cs-CZ"},
{"hu", "hu", "hu-HU"}, {"gr", "el", "el-GR"},
{"ro", "ro", "ro-RO"}, {"th", "th", "th-TH"},
{"vn", "vi", "vi-VN"}, {"id", "id", "id-ID"},
};
#include "lang/ar_sa.inc"
#include "lang/cs_cz.inc"
#include "lang/da_dk.inc"
#include "lang/de_de.inc"
#include "lang/el_gr.inc"
#include "lang/en_gb.inc"
#include "lang/en_us.inc"
#include "lang/es_es.inc"
#include "lang/es_mx.inc"
#include "lang/fi_fi.inc"
#include "lang/fr_ca.inc"
#include "lang/fr_fr.inc"
#include "lang/hu_hu.inc"
#include "lang/id_id.inc"
#include "lang/it_it.inc"
#include "lang/ja_jp.inc"
#include "lang/ko_kr.inc"
#include "lang/nl_nl.inc"
#include "lang/no_no.inc"
#include "lang/pl_pl.inc"
#include "lang/pt_br.inc"
#include "lang/pt_pt.inc"
#include "lang/ro_ro.inc"
#include "lang/ru_ru.inc"
#include "lang/sv_se.inc"
#include "lang/th_th.inc"
#include "lang/tr_tr.inc"
#include "lang/vi_vn.inc"
#include "lang/zh_cn.inc"
#include "lang/zh_tw.inc"
static int g_active_lang = 1;
static bool g_l10n_initialized = false;
static size_t region_count(void) {
return sizeof(g_regions) / sizeof(g_regions[0]);
}
static bool is_valid_language_id(int32_t language_id) {
return language_id >= 0 && language_id < (int32_t)region_count();
}
static bool language_code_matches(const char *value, const char *code) {
char normalized[16];
size_t len = strlen(code);
if (len >= sizeof(normalized))
return false;
for (size_t i = 0; i < len; ++i) {
char ch = code[i];
normalized[i] = (ch == '-') ? '_' : ch;
}
normalized[len] = '\0';
return strcasecmp(value, code) == 0 || strcasecmp(value, normalized) == 0;
}
static const char *const *active_catalog(void) {
switch (g_active_lang) {
case 0:
return g_ja_jp;
case 2:
return g_fr_fr;
case 3:
return g_es_es;
case 4:
return g_de_de;
case 5:
return g_it_it;
case 6:
return g_nl_nl;
case 7:
return g_pt_pt;
case 8:
return g_ru_ru;
case 9:
return g_ko_kr;
case 10:
return g_zh_tw;
case 11:
return g_zh_cn;
case 12:
return g_fi_fi;
case 13:
return g_sv_se;
case 14:
return g_da_dk;
case 15:
return g_no_no;
case 16:
return g_pl_pl;
case 17:
return g_pt_br;
case 18:
return g_en_gb;
case 19:
return g_tr_tr;
case 20:
return g_es_mx;
case 21:
return g_ar_sa;
case 22:
return g_fr_ca;
case 23:
return g_cs_cz;
case 24:
return g_hu_hu;
case 25:
return g_el_gr;
case 26:
return g_ro_ro;
case 27:
return g_th_th;
case 28:
return g_vi_vn;
case 29:
return g_id_id;
default:
return g_en_us;
}
}
bool sm_l10n_parse_language_id(const char *value, int32_t *language_id_out) {
if (!value || !language_id_out)
return false;
if (strcasecmp(value, "auto") == 0 || strcasecmp(value, "system") == 0 ||
strcasecmp(value, "default") == 0) {
*language_id_out = SM_LANGUAGE_AUTO;
return true;
}
for (size_t i = 0; i < region_count(); ++i) {
const sm_region_t *region = &g_regions[i];
if (language_code_matches(value, region->locale) ||
strcasecmp(value, region->country) == 0 ||
strcasecmp(value, region->lang) == 0) {
*language_id_out = (int32_t)i;
return true;
}
}
return false;
}
const char *sm_l10n_language_name(int32_t language_id) {
if (language_id == SM_LANGUAGE_AUTO)
return "auto";
if (!is_valid_language_id(language_id))
return "invalid";
return g_regions[language_id].locale;
}
void sm_l10n_init(void) {
int32_t sys_lang = -1;
const runtime_config_t *cfg = runtime_config();
int32_t active_lang = cfg->language_id;
bool auto_language = (active_lang == SM_LANGUAGE_AUTO);
if (auto_language &&
sceSystemServiceParamGetInt(SCE_SYSTEM_SERVICE_PARAM_ID_LANG,
&sys_lang) == 0 &&
is_valid_language_id(sys_lang)) {
active_lang = sys_lang;
} else if (auto_language) {
active_lang = 1;
}
if (!is_valid_language_id(active_lang))
active_lang = 1;
bool changed = !g_l10n_initialized || g_active_lang != active_lang;
g_active_lang = active_lang;
if (changed || cfg->debug_enabled) {
const sm_region_t *region = &g_regions[g_active_lang];
if (auto_language) {
log_debug(" [L10N] language=auto active=%d country=%s lang=%s locale=%s",
g_active_lang, region->country, region->lang, region->locale);
} else {
log_debug(" [L10N] language=config active=%d country=%s lang=%s locale=%s",
g_active_lang, region->country, region->lang, region->locale);
}
}
g_l10n_initialized = true;
}
const char *sm_l10n_get(sm_l10n_key_t key) {
if (!g_l10n_initialized)
sm_l10n_init();
if (key < 0 || key >= SM_L10N_COUNT)
return "";
const char *const *catalog = active_catalog();
if (catalog[key])
return catalog[key];
return g_en_us[key] ? g_en_us[key] : "";
}
const char *sm_l10n_lang(void) {
if (!g_l10n_initialized)
sm_l10n_init();
return g_regions[g_active_lang].lang;
}
const char *sm_l10n_locale(void) {
if (!g_l10n_initialized)
sm_l10n_init();
return g_regions[g_active_lang].locale;
}
+70 -6
View File
@@ -65,6 +65,7 @@ static bool ensure_notification_icon_present(void) {
}
void sm_notifications_init(void) {
sm_l10n_init();
pthread_mutex_lock(&g_notifications_mutex);
if (!g_notifications_initialized)
g_notifications_initialized = ensure_notification_icon_present();
@@ -154,6 +155,10 @@ static bool send_rich_notification(const char *message) {
append_json_escaped(escaped_message, sizeof(escaped_message), message);
append_json_escaped(escaped_version, sizeof(escaped_version),
SHADOWMOUNT_VERSION);
char escaped_action[256];
escaped_action[0] = '\0';
append_json_escaped(escaped_action, sizeof(escaped_action),
sm_l10n_get(SM_L10N_ACTION_DEBUG_SETTINGS));
if (!build_notification_metadata(created_at, notification_id,
sizeof(notification_id))) {
return false;
@@ -186,7 +191,7 @@ static bool send_rich_notification(const char *message) {
" },\n"
" \"actions\": [\n"
" {\n"
" \"actionName\": \"Go to Debug Settings\",\n"
" \"actionName\": \"%s\",\n"
" \"actionType\": \"DeepLink\",\n"
" \"defaultFocus\": true,\n"
" \"parameters\": {\n"
@@ -214,7 +219,7 @@ static bool send_rich_notification(const char *message) {
" \"createdDateTime\": \"%s\",\n"
" \"localNotificationId\": \"%s\"\n"
"}",
escaped_message, escaped_version, escaped_message, created_at,
escaped_message, escaped_version, escaped_action, escaped_message, created_at,
notification_id);
if (len < 0 || (size_t)len >= sizeof(payload))
return false;
@@ -248,6 +253,10 @@ static void notify_system_plain_v(const char *fmt, va_list args) {
notify_system_plain_message(message);
}
static void notify_system_plain_l10n_v(sm_l10n_key_t key, va_list args) {
notify_system_plain_v(sm_l10n_get(key), args);
}
static FILE *ensure_log_file_open_locked(void) {
if (g_log_file)
return g_log_file;
@@ -330,10 +339,30 @@ void notify_system_rich(bool allow_in_quiet_mode, const char *fmt, ...) {
log_debug("NOTIFY: %s", message);
}
void notify_system_rich_l10n(bool allow_in_quiet_mode, sm_l10n_key_t key, ...) {
char message[3075];
va_list args;
if (runtime_config()->quiet_mode && !allow_in_quiet_mode)
return;
va_start(args, key);
vsnprintf(message, sizeof(message), sm_l10n_get(key), args);
va_end(args);
if (!send_rich_notification(message)) {
notify_system_plain_message(message);
return;
}
log_debug("NOTIFY: %s", message);
}
void notify_game_installed_rich(const char *title_id) {
if (!send_game_installed_rich_notification(title_id)) {
notify_system_info("Installed: %s",
(title_id && title_id[0] != '\0') ? title_id : "Unknown");
notify_system_info_l10n(SM_L10N_INSTALLED,
(title_id && title_id[0] != '\0') ? title_id
: "Unknown");
return;
}
@@ -350,6 +379,16 @@ void notify_system_info(const char *fmt, ...) {
va_end(args);
}
void notify_system_info_l10n(sm_l10n_key_t key, ...) {
if (runtime_config()->quiet_mode)
return;
va_list args;
va_start(args, key);
notify_system_plain_l10n_v(key, args);
va_end(args);
}
void sm_error_clear(void) {
memset(&g_last_error, 0, sizeof(g_last_error));
}
@@ -372,6 +411,24 @@ void sm_error_set(const char *subsystem, int code, const char *path,
}
}
void sm_error_set_l10n(const char *subsystem, int code, const char *path,
sm_l10n_key_t key, ...) {
memset(&g_last_error, 0, sizeof(g_last_error));
g_last_error.valid = true;
g_last_error.code = code;
if (subsystem && subsystem[0] != '\0')
(void)strlcpy(g_last_error.subsystem, subsystem,
sizeof(g_last_error.subsystem));
if (path && path[0] != '\0')
(void)strlcpy(g_last_error.path, path, sizeof(g_last_error.path));
va_list args;
va_start(args, key);
vsnprintf(g_last_error.message, sizeof(g_last_error.message),
sm_l10n_get(key), args);
va_end(args);
}
const sm_error_t *sm_last_error(void) {
return &g_last_error;
}
@@ -391,6 +448,13 @@ void notify_system(const char *fmt, ...) {
va_end(args);
}
void notify_system_l10n(sm_l10n_key_t key, ...) {
va_list args;
va_start(args, key);
notify_system_plain_l10n_v(key, args);
va_end(args);
}
void notify_image_mount_failed(const char *path, int mount_err) {
if (g_last_error.valid && g_last_error.message[0] != '\0') {
const char *error_path =
@@ -400,6 +464,6 @@ void notify_image_mount_failed(const char *path, int mount_err) {
return;
}
notify_system("Image mount failed: 0x%08X (%s)\n%s", (uint32_t)mount_err,
strerror(mount_err), path);
notify_system_l10n(SM_L10N_IMAGE_MOUNT_FAILED, (uint32_t)mount_err,
strerror(mount_err), path);
}
-664
View File
@@ -1,664 +0,0 @@
#include "sm_platform.h"
#include <inttypes.h>
#include <stdlib.h>
#include "sm_config_mount.h"
#include "sm_limits.h"
#include "sm_log.h"
#include "sm_mdbg.h"
#include "sm_time.h"
#include "sm_types.h"
int sceKernelDebugGetPrivateLogText(void *buffer, size_t buffer_size,
char **text, uint64_t *text_size);
int sceKernelDebugGetSdkLogText(void *buffer, size_t buffer_size,
char **text, uint64_t *text_size);
uint64_t sceKernelDebugGetLogBufferSize(void) __asm__("C49jelxiaVE");
int mdbg_call(void *cmd, void *req, void *res);
#define MDBG_CMD_TYPE_SERVICE 1ull
#define MDBG_CMD_PROCESS_STATE 30ull
#define MDBG_SUBCMD_FLAGS 2ull
#define MDBG_FLAG_EXCEPTION_STOP 0x00080000ull
#define MDBG_AUTOTUNE_WINDOW_US (300ull * 1000000ull)
#define MDBG_LOG_LINE_BUFFER_SIZE 512u
#define MDBG_RTLD_ERROR_PREFIX_SIZE 32u
#ifndef MDBG_USE_PRIVATE_LOG_TEXT
#define MDBG_USE_PRIVATE_LOG_TEXT 0
#endif
#ifndef MDBG_SKIP_PRIVILEGE_ELEVATION
#define MDBG_SKIP_PRIVILEGE_ELEVATION 0
#endif
#if MDBG_USE_PRIVATE_LOG_TEXT
#define MDBG_FETCH_LOG_TEXT sceKernelDebugGetPrivateLogText
#else
#define MDBG_FETCH_LOG_TEXT sceKernelDebugGetSdkLogText
#endif
typedef struct {
uint64_t type;
uint64_t cmd;
} mdbg_cmd_t;
typedef struct {
int64_t pid;
int64_t subcmd;
uint64_t arg;
uint64_t reserved[5];
} mdbg_req_t;
typedef struct {
int64_t status;
uint64_t value;
uint64_t reserved[2];
} mdbg_res_t;
typedef struct {
bool active;
bool log_monitoring_active;
bool pause_seen;
pid_t pid;
uint32_t pause_delay_seconds;
uint64_t monitor_deadline_us;
uint64_t pause_time_us;
uint64_t next_poll_us;
char title_id[MAX_TITLE_ID];
char rtld_error_prefix[MDBG_RTLD_ERROR_PREFIX_SIZE];
} mdbg_game_state_t;
typedef struct {
bool privilege_probe_done;
bool privilege_ready;
size_t log_buffer_size;
size_t log_snapshot_length;
size_t log_line_length;
char *log_snapshot;
char *log_storage;
char log_line[MDBG_LOG_LINE_BUFFER_SIZE];
mdbg_game_state_t game;
} sm_mdbg_state_t;
static sm_mdbg_state_t g_mdbg;
static bool sm_mdbg_enabled(void);
#if !MDBG_SKIP_PRIVILEGE_ELEVATION
static int elevate_to_coredump(void);
#endif
static bool ensure_mdbg_privileges(void);
static int mdbg_call_raw(int64_t pid, uint64_t subcmd, uint64_t arg,
int64_t *status_out, uint64_t *value_out);
static int query_mdbg_flags(pid_t pid, uint64_t *flags_out);
static bool is_mdbg_process_gone_error(int ret);
static void reset_log_line_buffer(void);
static void reset_log_snapshot(void);
static void free_log_buffers(void);
static bool ensure_log_buffers(void);
static int fetch_log_text(const char **text_out, size_t *text_len_out);
static size_t find_log_overlap(const char *current, size_t current_len);
static void update_log_snapshot(const char *text, size_t text_len);
static void clear_tracked_game(void);
static bool matches_tracked_rtld_error(const char *text);
static void summarize_failure_reason(const char *reason, char *summary_out,
size_t summary_out_size,
bool is_rtld_error);
static void handle_pre_pause_failure(const char *reason);
static void handle_post_pause_failure(const char *reason, uint64_t now_us);
static void process_log_line(const char *line, uint64_t now_us);
static void append_log_char(char ch, uint64_t now_us);
static void poll_log_monitor(uint64_t now_us);
static void start_log_monitoring(void);
static void handle_crash_candidate(uint64_t flags, uint64_t now_us);
static bool sm_mdbg_enabled(void) {
return runtime_config()->kstuff_crash_detection_enabled &&
runtime_config()->kstuff_game_auto_toggle;
}
#if !MDBG_SKIP_PRIVILEGE_ELEVATION
#define SCE_AUTHID_COREDUMP 0x4800000000000006ull
static int elevate_to_coredump(void) {
static const uint8_t k_priv_caps[16] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
pid_t pid = getpid();
if (kernel_set_ucred_authid(pid, SCE_AUTHID_COREDUMP) < 0)
return -1;
if (kernel_set_ucred_caps(pid, k_priv_caps) < 0)
return -1;
return 0;
}
#endif
static bool ensure_mdbg_privileges(void) {
if (g_mdbg.privilege_probe_done)
return g_mdbg.privilege_ready;
g_mdbg.privilege_probe_done = true;
#if MDBG_SKIP_PRIVILEGE_ELEVATION
g_mdbg.privilege_ready = true;
log_debug(" [MDBG] coredump privilege probe skipped");
#else
g_mdbg.privilege_ready = elevate_to_coredump() == 0;
if (g_mdbg.privilege_ready) {
log_debug(" [MDBG] coredump privileges enabled");
} else {
log_debug(" [MDBG] failed to enable coredump privileges; mdbg polling "
"disabled, log monitoring disabled");
}
#endif
return g_mdbg.privilege_ready;
}
static int mdbg_call_raw(int64_t pid, uint64_t subcmd, uint64_t arg,
int64_t *status_out, uint64_t *value_out) {
mdbg_cmd_t cmd = {MDBG_CMD_TYPE_SERVICE, MDBG_CMD_PROCESS_STATE};
mdbg_req_t req = {
.pid = pid,
.subcmd = (int64_t)subcmd,
.arg = arg,
};
mdbg_res_t res = {0};
int ret = mdbg_call(&cmd, &req, &res);
if (ret != 0)
return ret;
if (status_out)
*status_out = res.status;
if (value_out)
*value_out = res.value;
return 0;
}
static int query_mdbg_flags(pid_t pid, uint64_t *flags_out) {
int64_t status;
uint64_t value;
int ret = mdbg_call_raw(pid, MDBG_SUBCMD_FLAGS, 0, &status, &value);
if (ret < 0)
return ret;
if (status != 0)
return (int)status;
if (flags_out)
*flags_out = value;
return 0;
}
static bool is_mdbg_process_gone_error(int ret) {
return ret == -ESRCH || ret == -ENOENT || ret == ESRCH || ret == ENOENT;
}
static void reset_log_line_buffer(void) {
g_mdbg.log_line_length = 0;
g_mdbg.log_line[0] = '\0';
}
static void reset_log_snapshot(void) {
g_mdbg.log_snapshot_length = 0;
reset_log_line_buffer();
}
static void free_log_buffers(void) {
free(g_mdbg.log_snapshot);
free(g_mdbg.log_storage);
g_mdbg.log_snapshot = NULL;
g_mdbg.log_storage = NULL;
g_mdbg.log_buffer_size = 0;
reset_log_snapshot();
}
static bool ensure_log_buffers(void) {
if (g_mdbg.log_storage && g_mdbg.log_snapshot && g_mdbg.log_buffer_size != 0)
return true;
free_log_buffers();
const char *title_id =
g_mdbg.game.title_id[0] != '\0' ? g_mdbg.game.title_id : "?";
uint64_t raw_size = sceKernelDebugGetLogBufferSize();
if (raw_size == 0) {
log_debug(" [MDBG] invalid log buffer size for %s: 0x%016" PRIx64,
title_id,
raw_size);
return false;
}
size_t buffer_size = (size_t)raw_size;
char *storage = malloc(buffer_size);
char *snapshot = malloc(buffer_size);
if (!storage || !snapshot) {
free(storage);
free(snapshot);
log_debug(" [MDBG] failed to allocate log buffers for %s: size=0x%zx",
title_id,
buffer_size);
return false;
}
g_mdbg.log_storage = storage;
g_mdbg.log_snapshot = snapshot;
g_mdbg.log_buffer_size = buffer_size;
reset_log_snapshot();
log_debug(" [MDBG] log monitor ready: %s buffer_size=0x%zx", title_id,
buffer_size);
return true;
}
static int fetch_log_text(const char **text_out, size_t *text_len_out) {
char *raw_text = NULL;
uint64_t raw_len = 0;
*text_out = NULL;
*text_len_out = 0;
int ret =
MDBG_FETCH_LOG_TEXT(g_mdbg.log_storage, g_mdbg.log_buffer_size, &raw_text,
&raw_len);
if (ret < 0)
return ret;
if (!raw_text || raw_len == 0) {
return 0;
}
if (raw_len > g_mdbg.log_buffer_size)
return -EOVERFLOW;
*text_out = raw_text;
*text_len_out = (size_t)raw_len;
return 0;
}
static size_t find_log_overlap(const char *current, size_t current_len) {
if (!g_mdbg.log_snapshot || g_mdbg.log_snapshot_length == 0 || !current ||
current_len == 0) {
return 0;
}
size_t max_overlap = g_mdbg.log_snapshot_length < current_len
? g_mdbg.log_snapshot_length
: current_len;
const char *search = g_mdbg.log_snapshot + g_mdbg.log_snapshot_length -
max_overlap;
const char *end = g_mdbg.log_snapshot + g_mdbg.log_snapshot_length;
while (search < end) {
const char *candidate =
memchr(search, current[0], (size_t)(end - search));
if (!candidate)
break;
size_t overlap = (size_t)(end - candidate);
if (!memcmp(candidate, current, overlap))
return overlap;
search = candidate + 1;
}
return 0;
}
static void update_log_snapshot(const char *text, size_t text_len) {
if (!g_mdbg.log_snapshot || g_mdbg.log_buffer_size == 0)
return;
if (!text || text_len == 0) {
g_mdbg.log_snapshot_length = 0;
return;
}
if (text_len > g_mdbg.log_buffer_size)
text_len = g_mdbg.log_buffer_size;
memcpy(g_mdbg.log_snapshot, text, text_len);
g_mdbg.log_snapshot_length = text_len;
}
static void clear_tracked_game(void) {
memset(&g_mdbg.game, 0, sizeof(g_mdbg.game));
free_log_buffers();
}
static bool matches_tracked_rtld_error(const char *text) {
return text &&
g_mdbg.game.rtld_error_prefix[0] != '\0' &&
strstr(text, g_mdbg.game.rtld_error_prefix) != NULL;
}
static void summarize_failure_reason(const char *reason, char *summary_out,
size_t summary_out_size,
bool is_rtld_error) {
if (!summary_out || summary_out_size == 0)
return;
summary_out[0] = '\0';
if (!reason || reason[0] == '\0')
return;
if (is_rtld_error) {
const char *open_paren = strrchr(reason, '(');
const char *close_paren =
open_paren ? strchr(open_paren + 1, ')') : NULL;
if (open_paren && close_paren && close_paren > open_paren + 1) {
int written = snprintf(summary_out, summary_out_size,
"can't load module %.*s after KStuff pause",
(int)(close_paren - open_paren - 1),
open_paren + 1);
if (written > 0 && (size_t)written < summary_out_size)
return;
}
(void)strlcpy(summary_out, "can't load module after KStuff pause",
summary_out_size);
return;
}
(void)strlcpy(summary_out, reason, summary_out_size);
}
static void handle_pre_pause_failure(const char *reason) {
log_debug(" [MDBG] %s crashed before kstuff auto-pause%s%s",
g_mdbg.game.title_id, reason ? ": " : "", reason ? reason : "");
notify_system_info("App crashed before KStuff pause: %s. KStuff is not to "
"blame.",
g_mdbg.game.title_id);
clear_tracked_game();
}
static void handle_post_pause_failure(const char *reason, uint64_t now_us) {
if (!g_mdbg.game.pause_seen || g_mdbg.game.pause_time_us == 0 ||
now_us < g_mdbg.game.pause_time_us) {
handle_pre_pause_failure(reason);
return;
}
uint64_t post_pause_us = now_us - g_mdbg.game.pause_time_us;
if (post_pause_us > MDBG_AUTOTUNE_WINDOW_US) {
log_debug(" [MDBG] %s crashed %us after kstuff pause; autotune skipped%s%s",
g_mdbg.game.title_id, (unsigned)(post_pause_us / 1000000ull),
reason ? ": " : "", reason ? reason : "");
notify_system_info("App crashed after KStuff pause: %s. Autotune skipped.",
g_mdbg.game.title_id);
clear_tracked_game();
return;
}
char reason_summary[128];
bool is_rtld_error = matches_tracked_rtld_error(reason);
summarize_failure_reason(reason, reason_summary, sizeof(reason_summary),
is_rtld_error);
uint32_t tuned_delay_seconds = 0;
if (upsert_kstuff_autotune_pause_delay(g_mdbg.game.title_id,
g_mdbg.game.pause_delay_seconds,
&tuned_delay_seconds)) {
log_debug(" [MDBG] autotune pause delay updated: %s=%us",
g_mdbg.game.title_id, tuned_delay_seconds);
if (reason_summary[0] != '\0')
log_debug(" [MDBG] autotune trigger: %s", reason_summary);
if (is_rtld_error) {
notify_system_info("%s: %s. Delay increased to %us.\nLaunch the game again.",
g_mdbg.game.title_id,
reason_summary[0] != '\0' ? reason_summary
: "Can't load module after "
"KStuff pause",
tuned_delay_seconds);
} else {
notify_system_info("Crash detected after KStuff pause: pause delay for %s "
"increased to %us. Launch the game again.",
g_mdbg.game.title_id, tuned_delay_seconds);
}
clear_tracked_game();
return;
}
log_debug(" [MDBG] failed to persist autotune pause delay for %s%s%s",
g_mdbg.game.title_id, reason ? ": " : "", reason ? reason : "");
notify_system_info("Crash detected after KStuff pause: %s. Failed to update "
"autotune delay.",
g_mdbg.game.title_id);
clear_tracked_game();
}
static void process_log_line(const char *line, uint64_t now_us) {
if (!matches_tracked_rtld_error(line))
return;
log_debug(" [MDBG] log load error for %s: %s", g_mdbg.game.title_id, line);
handle_post_pause_failure(line, now_us);
}
static void append_log_char(char ch, uint64_t now_us) {
if (!g_mdbg.game.active)
return;
if (ch == '\r' || ch == '\n') {
if (g_mdbg.log_line_length == 0)
return;
g_mdbg.log_line[g_mdbg.log_line_length] = '\0';
process_log_line(g_mdbg.log_line, now_us);
reset_log_line_buffer();
return;
}
if (g_mdbg.log_line_length + 1u >= sizeof(g_mdbg.log_line)) {
g_mdbg.log_line[g_mdbg.log_line_length] = '\0';
process_log_line(g_mdbg.log_line, now_us);
reset_log_line_buffer();
}
g_mdbg.log_line[g_mdbg.log_line_length++] = ch;
}
static void poll_log_monitor(uint64_t now_us) {
if (!g_mdbg.game.active || !g_mdbg.game.log_monitoring_active) {
return;
}
if (!ensure_log_buffers()) {
g_mdbg.game.log_monitoring_active = false;
return;
}
const char *text = NULL;
size_t text_len = 0;
int ret = fetch_log_text(&text, &text_len);
if (ret < 0) {
log_debug(" [MDBG] log snapshot failed for %s: 0x%08x",
g_mdbg.game.title_id, ret);
g_mdbg.game.log_monitoring_active = false;
reset_log_snapshot();
return;
}
size_t skip = 0;
if (g_mdbg.log_snapshot_length != 0 && text_len >= g_mdbg.log_snapshot_length &&
!memcmp(g_mdbg.log_snapshot, text, g_mdbg.log_snapshot_length)) {
skip = g_mdbg.log_snapshot_length;
} else {
skip = find_log_overlap(text, text_len);
if (skip == 0 && g_mdbg.log_snapshot_length != 0) {
log_debug(" [MDBG] log stream reset or truncated for %s",
g_mdbg.game.title_id);
reset_log_line_buffer();
}
}
for (size_t i = skip; i < text_len; ++i) {
append_log_char(text[i], now_us);
if (!g_mdbg.game.active)
return;
}
update_log_snapshot(text, text_len);
}
static void start_log_monitoring(void) {
if (!g_mdbg.game.active)
return;
if (!ensure_mdbg_privileges()) {
g_mdbg.game.log_monitoring_active = false;
return;
}
if (!ensure_log_buffers()) {
g_mdbg.game.log_monitoring_active = false;
return;
}
g_mdbg.game.log_monitoring_active = true;
const char *text = NULL;
size_t text_len = 0;
int ret = fetch_log_text(&text, &text_len);
if (ret < 0) {
log_debug(" [MDBG] initial log snapshot failed for %s: 0x%08x",
g_mdbg.game.title_id, ret);
g_mdbg.game.log_monitoring_active = false;
reset_log_snapshot();
return;
}
update_log_snapshot(text, text_len);
reset_log_line_buffer();
}
static void handle_crash_candidate(uint64_t flags, uint64_t now_us) {
if (!g_mdbg.game.active)
return;
log_debug(" [MDBG] crash-candidate: %s pid=%ld flags=0x%08" PRIx64,
g_mdbg.game.title_id, (long)g_mdbg.game.pid, flags);
handle_post_pause_failure("crash-candidate", now_us);
}
void sm_mdbg_init(void) {
memset(&g_mdbg, 0, sizeof(g_mdbg));
}
void sm_mdbg_shutdown(void) {
free_log_buffers();
memset(&g_mdbg, 0, sizeof(g_mdbg));
}
void sm_mdbg_game_on_exec(pid_t pid, const char *title_id, uint32_t app_id) {
if (pid <= 0 || !title_id || title_id[0] == '\0')
return;
if (!sm_mdbg_enabled()) {
clear_tracked_game();
return;
}
if (g_mdbg.game.active && g_mdbg.game.pid != pid) {
log_debug(" [MDBG] replacing tracked game pid=%ld (%s) with pid=%ld (%s)",
(long)g_mdbg.game.pid, g_mdbg.game.title_id, (long)pid, title_id);
}
clear_tracked_game();
uint64_t now_us = monotonic_time_us();
g_mdbg.game.active = true;
g_mdbg.game.pid = pid;
g_mdbg.game.next_poll_us = now_us;
(void)strlcpy(g_mdbg.game.title_id, title_id, sizeof(g_mdbg.game.title_id));
int rtld_prefix_len =
snprintf(g_mdbg.game.rtld_error_prefix,
sizeof(g_mdbg.game.rtld_error_prefix),
"[rtld] <%ld> ERROR", (long)pid);
if (rtld_prefix_len <= 0 ||
(size_t)rtld_prefix_len >= sizeof(g_mdbg.game.rtld_error_prefix)) {
g_mdbg.game.rtld_error_prefix[0] = '\0';
}
log_debug(" [MDBG] tracking crash-candidate state: %s pid=%ld app_id=0x%08X",
g_mdbg.game.title_id, (long)pid, app_id);
}
void sm_mdbg_game_on_kstuff_pause(pid_t pid, uint64_t pause_time_us,
uint32_t pause_delay_seconds) {
if (!g_mdbg.game.active || g_mdbg.game.pid != pid)
return;
g_mdbg.game.pause_seen = true;
g_mdbg.game.pause_time_us = pause_time_us;
g_mdbg.game.monitor_deadline_us =
g_mdbg.game.pause_time_us + MDBG_AUTOTUNE_WINDOW_US;
g_mdbg.game.pause_delay_seconds = pause_delay_seconds;
g_mdbg.game.next_poll_us = pause_time_us;
start_log_monitoring();
}
void sm_mdbg_game_on_exit(pid_t pid) {
if (!g_mdbg.game.active || g_mdbg.game.pid != pid)
return;
clear_tracked_game();
}
void sm_mdbg_game_shutdown(void) {
clear_tracked_game();
}
uint64_t sm_mdbg_next_wake_us(uint64_t now_us) {
(void)now_us;
if (!sm_mdbg_enabled())
return 0;
if (!g_mdbg.game.active)
return 0;
uint64_t next_wake_us = g_mdbg.game.next_poll_us;
if (g_mdbg.game.monitor_deadline_us != 0 &&
(next_wake_us == 0 || g_mdbg.game.monitor_deadline_us < next_wake_us)) {
next_wake_us = g_mdbg.game.monitor_deadline_us;
}
return next_wake_us;
}
void sm_mdbg_poll(void) {
if (!sm_mdbg_enabled())
return;
if (!g_mdbg.game.active)
return;
uint64_t now_us = monotonic_time_us();
if (now_us < g_mdbg.game.next_poll_us) {
return;
}
if (g_mdbg.game.pause_seen && g_mdbg.game.monitor_deadline_us != 0 &&
now_us >= g_mdbg.game.monitor_deadline_us) {
log_debug(" [MDBG] crash monitoring window expired for %s pid=%ld",
g_mdbg.game.title_id, (long)g_mdbg.game.pid);
clear_tracked_game();
return;
}
if (!ensure_mdbg_privileges()) {
g_mdbg.game.next_poll_us = 0;
return;
}
poll_log_monitor(now_us);
if (!g_mdbg.game.active)
return;
g_mdbg.game.next_poll_us = now_us + GAME_LIFECYCLE_POLL_INTERVAL_US;
uint64_t flags = 0;
int ret = query_mdbg_flags(g_mdbg.game.pid, &flags);
if (is_mdbg_process_gone_error(ret)) {
clear_tracked_game();
return;
}
if (ret != 0)
return;
if ((flags & MDBG_FLAG_EXCEPTION_STOP) == 0)
return;
handle_crash_candidate(flags, now_us);
}
+1 -1
View File
@@ -214,7 +214,7 @@ void record_missing_param_failure(const char *path) {
log_debug(" [SCAN] missing/invalid param.json: %s", path);
if (entry->missing_param_attempts == 1)
notify_system("Missing/invalid param.json:\n%s", path);
notify_system_l10n(SM_L10N_MISSING_PARAM, path);
if (entry->missing_param_attempts >= MAX_MISSING_PARAM_SCAN_ATTEMPTS &&
!entry->missing_param_limit_logged) {
log_debug(" [SCAN] attempt limit reached (%u), skipping path: %s",
+5 -7
View File
@@ -14,8 +14,8 @@
#include "sm_image.h"
#include "sm_install.h"
#include "sm_install_queue.h"
#include "sm_kstuff.h"
#include "sm_limits.h"
#include "sm_l10n.h"
#include "sm_log.h"
#include "sm_path_utils.h"
#include "sm_paths.h"
@@ -926,8 +926,6 @@ static bool apply_runtime_config_reload_effects(int kq,
fakelib_runtime_config_changed(old_cfg, new_cfg))
sm_fakelib_game_shutdown();
sm_kstuff_on_config_reload();
if (scan_topology_changed) {
clear_scanner_watch_entries();
reset_scanner_root_states();
@@ -978,7 +976,7 @@ static bool run_full_scan_cycle(bool startup_sync, const char *reason,
new_games++;
}
if (new_games > 0)
notify_system_info("Found %d new games. Executing...", new_games);
notify_system_info_l10n(SM_L10N_FOUND_NEW_GAMES, new_games);
}
process_scan_candidates(candidates, candidate_count);
@@ -993,8 +991,7 @@ static bool run_full_scan_cycle(bool startup_sync, const char *reason,
*unstable_found_out = unstable_found;
if (startup_sync && !should_abort_scan_cycle()) {
notify_system_rich(true, "Library Synchronized.\nFound %d games.",
total_found_games);
notify_system_rich_l10n(true, SM_L10N_LIBRARY_SYNCED, total_found_games);
}
return !should_abort_scan_cycle();
@@ -1493,7 +1490,8 @@ void sm_scanner_run_loop(void) {
request_scanner_shutdown("scanner stale event drain after config reload failed");
return;
}
notify_system("ShadowMount+: config reloaded.");
sm_l10n_init();
notify_system_l10n(SM_L10N_CONFIG_RELOADED);
log_debug(" [CFG] runtime config reloaded");
now_us = monotonic_time_us();
next_full_resync_us =
+14 -2
View File
@@ -2,8 +2,6 @@
#include <pthread.h>
#include "sm_game_lifecycle.h"
#include "sm_kstuff.h"
#include "sm_limits.h"
#include "sm_log.h"
#include "sm_runtime.h"
@@ -43,7 +41,9 @@ static const shellcore_flag_bit_desc_t g_lnc_util_system_status_bits[] = {
};
static shellcore_flag_monitor_t g_shellcore_flags[] = {
#if 0
{.name = "SceShellCoreUtilAppFocus", .handle = -1, .required = true},
#endif
{.name = "SceSystemStateMgrInfo", .handle = -1, .required = true},
{.name = "SceLncUtilSystemStatus", .handle = -1, .required = false},
{.name = "SceSystemStateMgrStatus", .handle = -1},
@@ -344,9 +344,11 @@ static void format_shellcore_flag_known_masks(const shellcore_flag_monitor_t *fl
append_shellcore_flag_token(dst, dst_size, token);
}
#if 0
if (strcmp(flag->name, "SceShellCoreUtilAppFocus") == 0) {
append_shellcore_flag_token(dst, dst_size, "APP_ID");
}
#endif
}
static bool format_shellcore_flag_special_value(const shellcore_flag_monitor_t *flag,
@@ -422,6 +424,7 @@ static bool format_shellcore_flag_special_value(const shellcore_flag_monitor_t *
return true;
}
#if 0
if (strcmp(flag->name, "SceShellCoreUtilAppFocus") == 0) {
unsigned low32 = (unsigned)(pattern & 0xFFFFFFFFu);
unsigned high32 = (unsigned)(pattern >> 32);
@@ -439,6 +442,7 @@ static bool format_shellcore_flag_special_value(const shellcore_flag_monitor_t *
(void)snprintf(dst, dst_size, "0");
return true;
}
#endif
#if 0
if (strcmp(flag->name, "SceShellCoreUtilUIStatus") == 0) {
@@ -482,12 +486,14 @@ static void format_shellcore_flag_set_bits(const shellcore_flag_monitor_t *flag,
append_shellcore_flag_token(dst, dst_size, token);
}
#if 0
if (strcmp(flag->name, "SceShellCoreUtilAppFocus") == 0 &&
(pattern >> 32) == 0 && pattern != 0) {
char token[64];
(void)snprintf(token, sizeof(token), "APP_ID=0x%08X", (unsigned)pattern);
append_shellcore_flag_token(dst, dst_size, token);
}
#endif
if ((pattern & ~known_mask) != 0) {
char token[64];
@@ -620,7 +626,9 @@ static bool open_shellcore_flags(size_t *opened_count_out) {
static void poll_shellcore_flag(shellcore_flag_monitor_t *flag) {
uint64_t result_pattern = 0;
int rc;
#if 0
bool changed = false;
#endif
bool entered_shutdown_on_going = false;
bool entered_main_on_standby = false;
bool entered_suspend_on_going = false;
@@ -648,7 +656,9 @@ static void poll_shellcore_flag(shellcore_flag_monitor_t *flag) {
if (!flag->has_last_rc || flag->last_rc != 0 || !flag->has_last_pattern ||
flag->last_pattern != result_pattern) {
log_shellcore_flag_pattern(flag, result_pattern);
#if 0
changed = flag->has_last_pattern && flag->last_pattern != result_pattern;
#endif
}
is_system_state_mgr_info = strcmp(flag->name, "SceSystemStateMgrInfo") == 0;
@@ -687,10 +697,12 @@ static void poll_shellcore_flag(shellcore_flag_monitor_t *flag) {
flag->last_rc = 0;
flag->has_last_rc = true;
#if 0
if (changed && strcmp(flag->name, "SceShellCoreUtilAppFocus") == 0) {
sm_kstuff_note_app_focus((uint32_t)result_pattern);
wake_game_lifecycle_watcher();
}
#endif
if (entered_shutdown_on_going) {
request_shutdown_stop("SceSystemStateMgrInfo=SHUTDOWN_ON_GOING");
}
+1 -2
View File
@@ -135,8 +135,7 @@ void notify_duplicate_title_once(const char *title_id, const char *path_a,
if (entry->duplicate_notified_once)
return;
entry->duplicate_notified_once = true;
notify_system("Duplicate %s ignored:\n%s\nexisting: %s", title_id, path_a,
path_b);
notify_system_l10n(SM_L10N_DUPLICATE_IGNORED, title_id, path_a, path_b);
}
void clear_duplicate_title_notification(const char *title_id) {