diff --git a/App/PyUI/lang/English.json b/App/PyUI/lang/English.json index 3d1b76e58..e784d800c 100644 --- a/App/PyUI/lang/English.json +++ b/App/PyUI/lang/English.json @@ -1,436 +1,475 @@ { - "fontPurposeSizes": { - "TOP_BAR_TEXT": "Top Bar Text Size", - "BATTERY_PERCENT": "Battery Percent Size", - "LIST": "List Size", - "MESSAGE": "Message Size", - "DESCRIPTIVE_LIST_TITLE": "Descriptive List Title Size", - "DESCRIPTIVE_LIST_DESCRIPTION": "Descriptive List Description Size", - "GRID_ONE_ROW": "Grid One Row Size", - "GRID_MULTI_ROW": "Grid Multi Row Size", - "LIST_INDEX": "List Index Size", - "LIST_TOTAL": "List Total Size", - "SHADOWED": "Shadowed Size", - "SHADOWED_BACKDROP": "Shadowed Backdrop Size", - "SHADOWED_SMALL": "Shadowed Small Size", - "SHADOWED_BACKDROP_SMALL": "Shadowed Backdrop Small Size" - }, - "Games": "Games", - "Recents": "Recents", - "Apps": "Apps", + "fontPurposeSizes": { + "TOP_BAR_TEXT": "Top Bar Text Size", + "BATTERY_PERCENT": "Battery Percent Size", + "LIST": "List Size", + "MESSAGE": "Message Size", + "DESCRIPTIVE_LIST_TITLE": "Descriptive List Title Size", + "DESCRIPTIVE_LIST_DESCRIPTION": "Descriptive List Description Size", + "GRID_ONE_ROW": "Grid One Row Size", + "GRID_MULTI_ROW": "Grid Multi Row Size", + "LIST_INDEX": "List Index Size", + "LIST_TOTAL": "List Total Size", + "SHADOWED": "Shadowed Size", + "SHADOWED_BACKDROP": "Shadowed Backdrop Size", + "SHADOWED_SMALL": "Shadowed Small Size", + "SHADOWED_BACKDROP_SMALL": "Shadowed Backdrop Small Size" + }, + "Games": "Games", + "Recents": "Recents", + "Apps": "Apps", + "Collections": "Collections", + "Favorites": "Favorites", + "Settings": "Settings", + "noEntriesFound": "No Entries Found", + "systemGameSearch": "$system Game Search", + "allSystemGameSearch": "All System Game Search", + "systemMenuSubOptions": "$system Menu Sub Options", + "gameSearch": "Game Search:", + "exitPyUi": "Reload UI", + "setPyuiAsStartup": "Set PyUI as Startup", + "romSearch": "Rom Search", + "showApp": "Show App", + "hideHiddenApps": "Hide Hidden Apps", + "sortFavorites": "Sort Favorites", + "toggleSettingsAsGameSpecificOverride": "Toggle Settings as Game Specific Override", + "removeFavorite": "Remove Favorite", + "addFavorite": "Add Favorite", + "addRemoveCollection": "Add/Remove Collection", + "launchRandomGame": "Launch Random Game", + "exitGame": "Exit Game", + "saveState": "Save State", + "loadState": "Load State", + "toggleFastForward": "Toggle Fast Forward", + "raMenu": "RA Menu", + "createNewCollection": "Create New Collection", + "addTo": "Add to", + "addToCollection": "Add to Collection", + "removeFrom": "Remove from", + "powerOff": "Power Off", + "Backlight": "Backlight", + "Volume": "Volume", + "WiFi": "WiFi", + "Bluetooth": "Bluetooth", + "Theme": "Theme", + "themeSettings": "Theme Settings", + "soundSettings": "Sound Settings", + "additionalSettings": "Additional Settings", + "Status": "Status", + "calibrateAnalogSticks": "Calibrate Analog Sticks", + "remapButtons": "Remap Buttons", + "Brightness": "Brightness", + "Contrast": "Contrast", + "Saturation": "Saturation", + "Hue": "Hue", + "Red": "Red", + "Blue": "Blue", + "Green": "Green", + "displaySettings": "Display Settings", + "timeSettings": "Time Settings", + "gameSystemSelectSettings": "Game System Select Settings", + "gameSelectSettings": "Game Select Settings", + "gameSwitcherSettings": "Game Switcher Settings", + "gameArtDisplaySettings": "Game Art Display Settings", + "downloadBoxart": "Download BoxArt", + "controllerSettings": "Controller Settings", + "languageSettings": "Language Settings", + "stockOsMenu": "Stock OS Menu", + "optimizeBoxart": "Optimize Boxart", + "lockedDownModes": "Locked Down Modes", + "l2R2SkipByLetterForDaijishoThemes": "L2/R2 Skip By Letter for Daijisho Themes", + "holdMenuForGameswitcher": "Hold Menu for GameSwitcher", + "preferSavestateScreenshots": "Prefer SaveState Screenshots", + "gameCount": "Game Count", + "viewType": "View Type", + "fullScreenResizeType": "Full Screen Resize Type", + "trueFullScreen": "True Full Screen", + "topbarGamename": "TopBar = GameName", + "useRecentsForGameswitcher": "Use Recents for GameSwitcher", + "showAllSystems": "Show All Systems", + "gameSystemSorting": "Game System Sorting", + "systemTypePriority": "System Type Priority", + "systemBrandPriority": "System Brand Priority", + "systemYearPriority": "System Year Priority", + "systemNamePriority": "System Name Priority", + "enterGameSelectionOnlyMode": "Enter Game Selection Only Mode", + "enterSimpleMode": "Enter Simple Mode", + "Year": "Year", + "Month": "Month", + "Day": "Day", + "hour24": "Hour 24", + "Minute": "Minute", + "playButtonPressSound": "Play Button Press Sound", + "playBgm": "Play BGM", + "bgmVolume": "BGM Volume", + "setTimeDate": "Set Time & Date", + "setTimezone": "Set Timezone", + "Clock": "Clock", + "24HourClock": "24 Hour Clock", + "showAmPm": "Show AM/PM", + "gameSelMenu": "Game Sel Menu", + "imgMode": "Img Mode", + "Rows": "Rows", + "Cols": "Cols", + "imgWidth": "Img Width", + "imgHeight": "Img Height", + "primImgWidth": "Prim Img Width %", + "shrinkFurtherAway": "Shrink Further Away", + "boxartResizeType": "BoxArt Resize Type", + "selBgResizePadWidth": "Sel BG Resize Pad Width", + "selBgResizePadHeight": "Sel BG Resize Pad Height", + "skipMainMenu": "Skip Main Menu", + "mainMenu": "Main Menu", + "mainMenuColumns": "Main Menu Columns", + "showText": "Show Text", + "showRecents": "Show Recents", + "showCollections": "Show Collections", + "showFavorites": "Show Favorites", + "showApps": "Show Apps", + "showSettings": "Show Settings", + "mainMenuThemeOptions": "Main Menu Theme Options", + "systemSelectThemeOptions": "System Select Theme Options", + "gameSelectMenuThemeOptions": "Game Select Menu Theme Options", + "Fonts": "Fonts", + "gridViewThemeOptions": "Grid View Theme Options", + "topBarOptions": "Top Bar Options", + "leftSideInitialXOffset": "Left Side Initial X Offset", + "showSelBg": "Show Sel BG", + "wrapAround": "Wrap-Around", + "resizeType": "Resize Type", + "percentageMode": "Percentage Mode", + "verticalCarousel": "Vertical Carousel", + "sidesHangOff": "Sides Hang Off", + "height": "Height", + "width": "Width", + "selectedHeight": "Selected Height", + "selectedWidth": "Selected Width", + "imageResizeType": "Image Resize Type", + "internalPadding": "Internal Padding", + "yOffset": "Y-Offset", + "selectedIconPositionOffset": "Selected Icon Position Offset", + "useSelectedImageInAnimation": "Use Selected Image In Animation", + "xOffset": "X-Offset", + "setTopBarText": "Set Top Bar Text", + "setBottomBarText": "Set Bottom Bar Text", + "showBatteryPercent": "Show Battery Percent", + "showBatteryIcon": "Show Battery Icon", + "showVolumeNumbers": "Show Volume Numbers", + "showBottomBarButtons": "Show Bottom Bar Buttons", + "showClock": "Show Clock", + "mainMenuTitle": "Main Menu Title", + "setGridBgOffsetToImageOffset": "Set Grid BG Offset To Image Offset", + "wifiConfiguration": "WiFi Configuration", + "wifiPassword": "WiFi Password", + "scanningForNetworks": "Scanning for networks...", + "bluetoothConfiguration": "Bluetooth Configuration", + "scanning": "Scanning", + "buttonRemapper": "Button Remapper", + "mainMenuSubOptions": "Main Menu Sub Options", + "collectionName": "Collection Name:", + "gameSystemSortModeTitle": "Game System Sort Mode", + "downloadBoxartDesc": "Scan entire library for missing boxart", + "optimizeBoxartDesc": "Resize boxart and convert to QOI for faster loading", + "lockedDownModesDesc": "Simpler modes for new users or kids", + "gameOnlyModeTitle": "Game Selection Only Mode", + "gameOnlyModePrompt1": "Would you like to enter game selection only mode?", + "gameOnlyModePrompt2": "Boot straight into the game selection screen", + "gameOnlyModePrompt3": "To exit enter the Konami Code", + "simpleModeTitle": "Simple Mode", + "simpleModePrompt1": "Would you like to enter simple mode?", + "simpleModePrompt2": "It has restricted access to settings", + "simpleModePrompt3": "To exit enter the Konami Code", + "deleteBoxart": "Delete Box Art", + "deleteRom": "Delete ROM", + "deleteRomPrompt1": "Would you like to permanently delete", + "deleteBoxartPrompt1": "Would you like to permanently delete the boxart for", + "deleteRomDeleted": "{path} deleted.", + "deleteBoxartDeleted": "Boxart for {name} deleted.", + "gameTracking": "Game Tracking", + "systemTracking": "System Tracking", + "activityTracker": "Activity Tracker", + "systemActivityTracker": "System Activity Tracker", + "today": "Today", + "thisWeek": "This Week", + "thisMonth": "This Month", + "thisYear": "This Year", + "allTime": "All Time", + "screenshot": "Screenshot", + "boxart": "Boxart", + "yes": "Yes", + "no": "No", + "recentDesc": "Recent", + "collectionDesc": "Collection", + "favoriteDesc": "Favorite", + "yourGamesDesc": "Your games", + "yourAppsDesc": "Your Apps", + "yourSettingsDesc": "Your settings", + "launchRecents": "Launch Recents", + "launchFavorites": "Launch Favorites", + "launchCollections": "Launch Collections", + "launchApplications": "Launch Applications", + "launchSettings": "Launch Settings", + "applications": "Applications", + "scrapeBoxartDesc": "Scrape game boxart", + "trackAppUsageDesc": "Track app usage", + "size": "Size", + "viewTypes": { + "ICON_AND_DESC": "Icon and Description", + "FULLSCREEN_GRID": "Fullscreen Grid", + "GRID": "Grid", + "TEXT_AND_IMAGE": "Text and Image", + "TEXT_ONLY": "Text Only", + "POPUP": "Popup", + "CAROUSEL": "Carousel" + }, + "resizeTypes": { + "FIT": "Fit", + "ZOOM": "Zoom", + "NONE": "None" + }, + "booleans": { + "true": "Enabled", + "false": "Disabled" + }, + "onOff": { + "on": "On", + "off": "Off" + }, + "gameSystemSortModes": { + "Alphabetical": "Alphabetical", + "SortOrderKey": "Sort Order Key", + "Custom": "Custom" + }, + "screenTypes": { "Collections": "Collections", "Favorites": "Favorites", - "Settings": "Settings", - "noEntriesFound": "No Entries Found", - "systemGameSearch": "$system Game Search", - "allSystemGameSearch": "All System Game Search", - "systemMenuSubOptions": "$system Menu Sub Options", - "gameSearch": "Game Search:", - "exitPyUi": "Reload UI", - "setPyuiAsStartup": "Set PyUI as Startup", - "romSearch": "Rom Search", - "showApp": "Show App", - "hideHiddenApps": "Hide Hidden Apps", - "sortFavorites": "Sort Favorites", - "toggleSettingsAsGameSpecificOverride": "Toggle Settings as Game Specific Override", - "removeFavorite": "Remove Favorite", - "addFavorite": "Add Favorite", - "addRemoveCollection": "Add/Remove Collection", - "launchRandomGame": "Launch Random Game", - "exitGame": "Exit Game", - "saveState": "Save State", - "loadState": "Load State", - "toggleFastForward": "Toggle Fast Forward", - "raMenu": "RA Menu", - "createNewCollection": "Create New Collection", - "addTo": "Add to", - "addToCollection": "Add to Collection", - "removeFrom": "Remove from", - "powerOff": "Power Off", - "Backlight": "Backlight", - "Volume": "Volume", - "WiFi": "WiFi", - "Bluetooth": "Bluetooth", - "Theme": "Theme", - "themeSettings": "Theme Settings", - "soundSettings": "Sound Settings", - "additionalSettings": "Additional Settings", - "Status": "Status", - "calibrateAnalogSticks": "Calibrate Analog Sticks", - "remapButtons": "Remap Buttons", - "Brightness": "Brightness", - "Contrast": "Contrast", - "Saturation": "Saturation", - "Hue": "Hue", - "Red": "Red", - "Blue": "Blue", - "Green": "Green", - "displaySettings": "Display Settings", - "timeSettings": "Time Settings", - "gameSystemSelectSettings": "Game System Select Settings", - "gameSelectSettings": "Game Select Settings", - "gameSwitcherSettings": "Game Switcher Settings", - "gameArtDisplaySettings": "Game Art Display Settings", - "downloadBoxart": "Download BoxArt", - "controllerSettings": "Controller Settings", - "languageSettings": "Language Settings", - "stockOsMenu": "Stock OS Menu", - "optimizeBoxart": "Optimize Boxart", - "lockedDownModes": "Locked Down Modes", - "l2R2SkipByLetterForDaijishoThemes": "L2/R2 Skip By Letter for Daijisho Themes", - "holdMenuForGameswitcher": "Hold Menu for GameSwitcher", - "preferSavestateScreenshots": "Prefer SaveState Screenshots", - "gameCount": "Game Count", - "viewType": "View Type", - "fullScreenResizeType": "Full Screen Resize Type", - "trueFullScreen": "True Full Screen", - "topbarGamename": "TopBar = GameName", - "useRecentsForGameswitcher": "Use Recents for GameSwitcher", - "showAllSystems": "Show All Systems", - "gameSystemSorting": "Game System Sorting", - "systemTypePriority": "System Type Priority", - "systemBrandPriority": "System Brand Priority", - "systemYearPriority": "System Year Priority", - "systemNamePriority": "System Name Priority", - "enterGameSelectionOnlyMode": "Enter Game Selection Only Mode", - "enterSimpleMode": "Enter Simple Mode", - "Year": "Year", - "Month": "Month", - "Day": "Day", - "hour24": "Hour 24", - "Minute": "Minute", - "playButtonPressSound": "Play Button Press Sound", - "playBgm": "Play BGM", - "bgmVolume": "BGM Volume", - "setTimeDate": "Set Time & Date", - "setTimezone": "Set Timezone", - "Clock": "Clock", - "24HourClock": "24 Hour Clock", - "showAmPm": "Show AM/PM", - "gameSelMenu": "Game Sel Menu", - "imgMode": "Img Mode", - "Rows": "Rows", - "Cols": "Cols", - "imgWidth": "Img Width", - "imgHeight": "Img Height", - "primImgWidth": "Prim Img Width %", - "shrinkFurtherAway": "Shrink Further Away", - "boxartResizeType": "BoxArt Resize Type", - "selBgResizePadWidth": "Sel BG Resize Pad Width", - "selBgResizePadHeight": "Sel BG Resize Pad Height", - "skipMainMenu": "Skip Main Menu", - "mainMenu": "Main Menu", - "mainMenuColumns": "Main Menu Columns", - "showText": "Show Text", - "showRecents": "Show Recents", - "showCollections": "Show Collections", - "showFavorites": "Show Favorites", - "showApps": "Show Apps", - "showSettings": "Show Settings", - "mainMenuThemeOptions": "Main Menu Theme Options", - "systemSelectThemeOptions": "System Select Theme Options", - "gameSelectMenuThemeOptions": "Game Select Menu Theme Options", - "Fonts": "Fonts", - "gridViewThemeOptions": "Grid View Theme Options", - "topBarOptions": "Top Bar Options", - "leftSideInitialXOffset": "Left Side Initial X Offset", - "showSelBg": "Show Sel BG", - "wrapAround": "Wrap-Around", - "resizeType": "Resize Type", - "percentageMode": "Percentage Mode", - "verticalCarousel": "Vertical Carousel", - "sidesHangOff": "Sides Hang Off", - "height": "Height", - "width": "Width", - "selectedHeight": "Selected Height", - "selectedWidth": "Selected Width", - "imageResizeType": "Image Resize Type", - "internalPadding": "Internal Padding", - "yOffset": "Y-Offset", - "selectedIconPositionOffset": "Selected Icon Position Offset", - "useSelectedImageInAnimation": "Use Selected Image In Animation", - "xOffset": "X-Offset", - "setTopBarText": "Set Top Bar Text", - "setBottomBarText": "Set Bottom Bar Text", - "showBatteryPercent": "Show Battery Percent", - "showBatteryIcon": "Show Battery Icon", - "showVolumeNumbers": "Show Volume Numbers", - "showBottomBarButtons": "Show Bottom Bar Buttons", - "showClock": "Show Clock", - "mainMenuTitle": "Main Menu Title", - "setGridBgOffsetToImageOffset": "Set Grid BG Offset To Image Offset", - "wifiConfiguration": "WiFi Configuration", - "wifiPassword": "WiFi Password", - "scanningForNetworks": "Scanning for networks...", - "bluetoothConfiguration": "Bluetooth Configuration", - "scanning": "Scanning", - "buttonRemapper": "Button Remapper", - "mainMenuSubOptions": "Main Menu Sub Options", - "collectionName": "Collection Name:", - "gameSystemSortModeTitle": "Game System Sort Mode", - "downloadBoxartDesc": "Scan entire library for missing boxart", - "optimizeBoxartDesc": "Resize boxart and convert to QOI for faster loading", - "lockedDownModesDesc": "Simpler modes for new users or kids", - "gameOnlyModeTitle": "Game Selection Only Mode", - "gameOnlyModePrompt1": "Would you like to enter game selection only mode?", - "gameOnlyModePrompt2": "Boot straight into the game selection screen", - "gameOnlyModePrompt3": "To exit enter the Konami Code", - "simpleModeTitle": "Simple Mode", - "simpleModePrompt1": "Would you like to enter simple mode?", - "simpleModePrompt2": "It has restricted access to settings", - "simpleModePrompt3": "To exit enter the Konami Code", - "deleteBoxart": "Delete Box Art", - "deleteRom": "Delete ROM", - "deleteRomPrompt1": "Would you like to permanently delete", - "deleteBoxartPrompt1": "Would you like to permanently delete the boxart for", - "deleteRomDeleted": "{path} deleted.", - "deleteBoxartDeleted": "Boxart for {name} deleted.", - "gameTracking": "Game Tracking", - "systemTracking": "System Tracking", - "activityTracker": "Activity Tracker", - "systemActivityTracker": "System Activity Tracker", - "today": "Today", - "thisWeek": "This Week", - "thisMonth": "This Month", - "thisYear": "This Year", - "allTime": "All Time", - "screenshot": "Screenshot", - "boxart": "Boxart", - "yes": "Yes", - "no": "No", - "recentDesc": "Recent", - "collectionDesc": "Collection", - "favoriteDesc": "Favorite", - "yourGamesDesc": "Your games", - "yourAppsDesc": "Your Apps", - "yourSettingsDesc": "Your settings", - "launchRecents": "Launch Recents", - "launchFavorites": "Launch Favorites", - "launchCollections": "Launch Collections", - "launchApplications": "Launch Applications", - "launchSettings": "Launch Settings", - "applications": "Applications", - "scrapeBoxartDesc": "Scrape game boxart", - "trackAppUsageDesc": "Track app usage", - "size": "Size", - "viewTypes": { - "ICON_AND_DESC": "Icon and Description", - "FULLSCREEN_GRID": "Fullscreen Grid", - "GRID": "Grid", - "TEXT_AND_IMAGE": "Text and Image", - "TEXT_ONLY": "Text Only", - "POPUP": "Popup", - "CAROUSEL": "Carousel" - }, - "resizeTypes": { - "FIT": "Fit", - "ZOOM": "Zoom", - "NONE": "None" - }, - "booleans": { - "true": "Enabled", - "false": "Disabled" - }, - "onOff": { - "on": "On", - "off": "Off" - }, - "gameSystemSortModes": { - "Alphabetical": "Alphabetical", - "SortOrderKey": "Sort Order Key", - "Custom": "Custom" - }, - "screenTypes": { - "Collections": "Collections", - "Favorites": "Favorites", - "GameSelect": "Game Select", - "Recents": "Recents", - "GameSwitcher": "Game Switcher" - }, - "controllerInputs": { - "A": "A", - "B": "B", - "X": "X", - "Y": "Y", - "MENU": "Menu", - "DPAD_UP": "D-Pad Up", - "DPAD_DOWN": "D-Pad Down", - "DPAD_LEFT": "D-Pad Left", - "DPAD_RIGHT": "D-Pad Right", - "L1": "L1", - "L2": "L2", - "L3": "L3", - "R1": "R1", - "R2": "R2", - "R3": "R3", - "START": "Start", - "SELECT": "Select", - "LEFT_STICK_UP": "Left Stick Up", - "LEFT_STICK_DOWN": "Left Stick Down", - "LEFT_STICK_LEFT": "Left Stick Left", - "LEFT_STICK_RIGHT": "Left Stick Right", - "RIGHT_STICK_UP": "Right Stick Up", - "RIGHT_STICK_DOWN": "Right Stick Down", - "RIGHT_STICK_LEFT": "Right Stick Left", - "RIGHT_STICK_RIGHT": "Right Stick Right", - "VOLUME_DOWN": "Volume Down", - "VOLUME_UP": "Volume Up", - "POWER_BUTTON": "Power Button", - "UNKNOWN": "Unknown" - }, - "removeGameSwitcherGame": "Remove from GameSwitcher", - "addGameSwitcherGame": "Add to GameSwitcher", - "removeRecents": "Remove Recents", - "selectBoxart": "Select BoxArt Download", - "animationSettings": "Animation Settings", - "animationsEnabled": "Animations Enabled", - "animationSpeed": "Animation Speed", - "inputRateLimitMs": "Input Rate Limiting (ms)", - "ignoreArticlesWhenSorting": "Ignore articles when sorting", - "powerDownPrompt": "Would you like to power down?", - "powerDownOptionsWithReboot": "A = Power Down, X = Reboot, B = Cancel", - "powerDownOptions": "A = Power Down, B = Cancel", - "turningOnWifiPower": "Turning on WiFi Power", - "startingWifiProcess": "Starting WiFi process", - "startingIpAssignment": "Starting ip address assignment process", - "sdcardReadOnlyWarning": "Warning: /mnt/SDCARD is read-only. Please check your SD card.", - "wifiStatusOff": "Off", - "wifiStatusConnecting": "Connecting", - "wifiStatusError": "Error", - "aboutIpAddress": "IP Address", - "aboutMacAddress": "Mac Address", - "aboutFwVersion": "FW Version", - "aboutUnknown": "Unknown", - "noValidRomsToLaunch": "No valid ROMs available to launch.", - "loadingBoxartList": "Loading boxart list...", - "downloadingBoxartTo": "Downloading {boxart} to {path}", - "toggleView": "Toggle View", - "selectBoxArtTitle": "Select Box Art", - "optimizeBoxartPrompt1": "Would you like to optimize boxart?", - "optimizeBoxartPrompt2": "Originals will be converted, be sure to backup!", - "optimizeBoxartPrompt3": "A = Yes, B = No, X/Y = Never Prompt", - "optimizeBoxartPrompt4": "You can manually do this in:", - "optimizeBoxartPrompt5": "Settings -> Extra Settings -> Optimize BoxArt", - "selectAnOption": "Select a {name}", - "gameConfigurationTitle": "{system} Configuration", - "bluetoothConnectFailed": "Bluetooth device {name} failed to connect at step: {step}. {output}", - "bluetoothConnectSuccess": "Bluetooth device {name} connected successfully", - "stoppingBluetoothScanner": "Stopping Bluetooth scanner...", - "stoppingWifiScanner": "Stopping WiFi scanner...", - "invalidWifiPasswordLength": "Invalid WiFi password length! Must be between 8 and 63", - "updatingWifiConfig": "Updating config file for {ssid} with password {password}", - "confirmText": "Okay", - "backText": "Back", - "cloudflareOfflineAborting": "Cloudflare ping failed; device is offline. Aborting.", - "scrapingBoxartPatient": "Scraping box art. Please be patient, especially with large libraries!", - "scrapingComplete": "Scraping complete!", - "wifiMustBeConnected": "Wifi must be connected", - "libretroUnavailable": "Libretro thumbnail service unavailable; trying fallback.", - "libretroGithubUnavailable": "Libretro thumbnail GitHub repo is also currently unavailable. Please try again later.", - "imageListNotFound": "Image list file not found for {system}.", - "noMissingBoxartForSystem": "No roms are missing boxart for {system}.", - "remoteSystemNotFound": "Remote system name not found - unable to download box art for {system}.", - "scrapingBoxartProgress": "Scraping box art... ({count}/{total})", - "scrapingBoxartProgressFound": "Scraping box art... ({count}/{total}). Found {found} so far.", - "gameCountSingular": "{count} game", - "gameCountPlural": "{count} games", - "systemIndexDescription": "{name} - {count} - System {index} of {total}", - "activityTimeHoursMinutes": "{hours}h {minutes}m", - "activityTimeMinutesOnly": "{minutes}m", - "menuOptionDisplays": { - "CPU Mode": "CPU Mode", - "Retroarch Core": "Retroarch Core", - "Emulator": "Emulator", - "Emulator64": "Emulator64", - "Emulator32": "Emulator32", - "Emulator_32": "Emulator (32-bit)", - "Emulator_64": "Emulator (64-bit)", - "Emulator_Pixel2": "Emulator", - "RA Build": "RA Build", - "RA: C-button Mode": "RA: C-button Mode", - "Stretch to Full Screen": "Stretch to Full Screen", - "Control Profile": "Control Profile", - "Steward Mode (overrides control profile)": "Steward Mode (overrides control profile)", - "Controller Mode": "Controller Mode", - "Menu Hold Time": "Menu Hold Time", - "Vibrate on Menu Hold": "Vibrate on Menu Hold", - "Power indicator LED mode": "Power indicator LED mode", - "Low power warning percent": "Low power warning percent", - "Shutdown after sleeping": "Shutdown after sleeping", - "Shutdown after sleeping if unplugged": "Shutdown after sleeping if unplugged", - "Shutdown while idle in menu": "Shutdown while idle in menu", - "Shutdown while idle in game": "Shutdown while idle in game", - "Turn screen off when charging in menu": "Turn screen off when charging in menu", - "Turn screen off when charging in game": "Turn screen off when charging in game", - "Disable network services in game": "Disable network services in game", - "Disable wifi in game": "Disable wifi in game", - "Check for spruce updates on startup": "Check for spruce updates on startup", - "Launch application on startup": "Launch application on startup", - "Rumble intensity": "Rumble intensity", - "Extended brightness controls": "Extended brightness controls", - "Disable joystick": "Disable joystick", - "Enable Lid Sensor": "Enable Lid Sensor", - "Use ZRAM": "Use ZRAM", - "SD card swapfile": "SD card swapfile", - "Global sceenshot shortcut": "Global sceenshot shortcut", - "Overclock Speed": "Overclock Speed", - "Run TrimUI OSD": "Run TrimUI OSD", - "Thermal Control": "Thermal Control", - "Tap home key action": "Tap home key action", - "Hold home key action": "Hold home key action", - "RA: use in-game menu": "RA: use in-game menu", - "Transfer saves between cores": "Transfer saves between cores", - "RA: hotkey enable button": "RA: hotkey enable button", - "RA: auto save state on close": "RA: auto save state on close", - "RA: auto load state on launch": "RA: auto load state on launch", - "GB[C/A]: use Perfect Overlays": "GB[C/A]: use Perfect Overlays", - "Verbose emulator logging": "Verbose emulator logging", - "Genesis Plus GX: enable widescreen": "Genesis Plus GX: enable widescreen", - "Enable Samba": "Enable Samba", - "Enable SSH": "Enable SSH", - "Enable Syncthing": "Enable Syncthing", - "Enable WiFi File Transfer": "Enable WiFi File Transfer", - "OTA: skip version check": "OTA: skip version check", - "Enable Network Proxy": "Enable Network Proxy", - "Proxy Address": "Proxy Address", - "Proxy Port": "Proxy Port", - "Proxy Protocol": "Proxy Protocol", - "Disable RGB LEDs in all contexts": "Disable RGB LEDs in all contexts", - "RGB LED brightness": "RGB LED brightness", - "Default LED color": "Default LED color", - "Default LED behavior": "Default LED behavior", - "Default LED cycle duration (ms)": "Default LED cycle duration (ms)", - "In-game LED behavior": "In-game LED behavior", - "In-game LED color": "In-game LED color", - "In-game LED cycle duration (ms)": "In-game LED cycle duration (ms)", - "Use separate LED control during emulation": "Use separate LED control during emulation", - "Headphone Audio Multiplier": "Headphone Audio Multiplier", - "Retroachivements mode": "Retroachivements mode", - "Password": "Password", - "Username": "Username" - }, - "governorOptions": { - "Smart": "Smart", - "Performance": "Performance", - "Overclock": "Overclock", - "Powersave": "Powersave" - }, - "launchOptions": { - "Generate M3U playlists for multi-disc games": "Generate M3U playlists for multi-disc games", - "Open ScummVM Menu": "Open ScummVM Menu", - "Scan ScummVM Games": "Scan ScummVM Games", - "Generate namelist": "Generate namelist", - "Import carts from Splore": "Import carts from Splore" - }, - "powerDownChoicesReboot": "A = Power Down, X = Reboot, B = Cancel", - "powerDownChoices": "A = Power Down, B = Cancel", - "poweringOff": "Powering off...", - "rebooting": "Rebooting...", - "wifiPowerOn": "Turning on WiFi Power", - "wifiProcessStart": "Starting WiFi process", - "wifiDhcpStart": "Starting ip address assignment process", - "noValidRoms": "No valid ROMs available to launch.", - "selectOptionPrompt": "Select a {name}", - "patchingThemeAssets": "Patching theme to faster assets", - "noCoreFound": "No core found" + "GameSelect": "Game Select", + "Recents": "Recents", + "GameSwitcher": "Game Switcher" + }, + "controllerInputs": { + "A": "A", + "B": "B", + "X": "X", + "Y": "Y", + "MENU": "Menu", + "DPAD_UP": "D-Pad Up", + "DPAD_DOWN": "D-Pad Down", + "DPAD_LEFT": "D-Pad Left", + "DPAD_RIGHT": "D-Pad Right", + "L1": "L1", + "L2": "L2", + "L3": "L3", + "R1": "R1", + "R2": "R2", + "R3": "R3", + "START": "Start", + "SELECT": "Select", + "LEFT_STICK_UP": "Left Stick Up", + "LEFT_STICK_DOWN": "Left Stick Down", + "LEFT_STICK_LEFT": "Left Stick Left", + "LEFT_STICK_RIGHT": "Left Stick Right", + "RIGHT_STICK_UP": "Right Stick Up", + "RIGHT_STICK_DOWN": "Right Stick Down", + "RIGHT_STICK_LEFT": "Right Stick Left", + "RIGHT_STICK_RIGHT": "Right Stick Right", + "VOLUME_DOWN": "Volume Down", + "VOLUME_UP": "Volume Up", + "POWER_BUTTON": "Power Button", + "UNKNOWN": "Unknown" + }, + "removeGameSwitcherGame": "Remove from GameSwitcher", + "addGameSwitcherGame": "Add to GameSwitcher", + "removeRecents": "Remove Recents", + "selectBoxart": "Select BoxArt Download", + "animationSettings": "Animation Settings", + "animationsEnabled": "Animations Enabled", + "animationSpeed": "Animation Speed", + "inputRateLimitMs": "Input Rate Limiting (ms)", + "ignoreArticlesWhenSorting": "Ignore articles when sorting", + "powerDownPrompt": "Would you like to power down?", + "powerDownOptionsWithReboot": "A = Power Down, X = Reboot, B = Cancel", + "powerDownOptions": "A = Power Down, B = Cancel", + "turningOnWifiPower": "Turning on WiFi Power", + "startingWifiProcess": "Starting WiFi process", + "startingIpAssignment": "Starting ip address assignment process", + "sdcardReadOnlyWarning": "Warning: /mnt/SDCARD is read-only. Please check your SD card.", + "wifiStatusOff": "Off", + "wifiStatusConnecting": "Connecting", + "wifiStatusError": "Error", + "aboutIpAddress": "IP Address", + "aboutMacAddress": "Mac Address", + "aboutFwVersion": "FW Version", + "aboutUnknown": "Unknown", + "noValidRomsToLaunch": "No valid ROMs available to launch.", + "loadingBoxartList": "Loading boxart list...", + "downloadingBoxartTo": "Downloading {boxart} to {path}", + "toggleView": "Toggle View", + "selectBoxArtTitle": "Select Box Art", + "optimizeBoxartPrompt1": "Would you like to optimize boxart?", + "optimizeBoxartPrompt2": "Originals will be converted, be sure to backup!", + "optimizeBoxartPrompt3": "A = Yes, B = No, X/Y = Never Prompt", + "optimizeBoxartPrompt4": "You can manually do this in:", + "optimizeBoxartPrompt5": "Settings -> Extra Settings -> Optimize BoxArt", + "selectAnOption": "Select a {name}", + "gameConfigurationTitle": "{system} Configuration", + "bluetoothConnectFailed": "Bluetooth device {name} failed to connect at step: {step}. {output}", + "bluetoothConnectSuccess": "Bluetooth device {name} connected successfully", + "stoppingBluetoothScanner": "Stopping Bluetooth scanner...", + "stoppingWifiScanner": "Stopping WiFi scanner...", + "invalidWifiPasswordLength": "Invalid WiFi password length! Must be between 8 and 63", + "updatingWifiConfig": "Updating config file for {ssid} with password {password}", + "confirmText": "Okay", + "backText": "Back", + "cloudflareOfflineAborting": "Cloudflare ping failed; device is offline. Aborting.", + "scrapingBoxartPatient": "Scraping box art. Please be patient, especially with large libraries!", + "scrapingComplete": "Scraping complete!", + "wifiMustBeConnected": "Wifi must be connected", + "libretroUnavailable": "Libretro thumbnail service unavailable; trying fallback.", + "libretroGithubUnavailable": "Libretro thumbnail GitHub repo is also currently unavailable. Please try again later.", + "imageListNotFound": "Image list file not found for {system}.", + "noMissingBoxartForSystem": "No roms are missing boxart for {system}.", + "remoteSystemNotFound": "Remote system name not found - unable to download box art for {system}.", + "scrapingBoxartProgress": "Scraping box art... ({count}/{total})", + "scrapingBoxartProgressFound": "Scraping box art... ({count}/{total}). Found {found} so far.", + "gameCountSingular": "{count} game", + "gameCountPlural": "{count} games", + "systemIndexDescription": "{name} - {count} - System {index} of {total}", + "activityTimeHoursMinutes": "{hours}h {minutes}m", + "activityTimeMinutesOnly": "{minutes}m", + "menuOptionDisplays": { + "CPU Mode": "CPU Mode", + "Retroarch Core": "Retroarch Core", + "Emulator": "Emulator", + "Emulator64": "Emulator64", + "Emulator32": "Emulator32", + "Emulator_32": "Emulator (32-bit)", + "Emulator_64": "Emulator (64-bit)", + "Emulator_Pixel2": "Emulator", + "RA Build": "RA Build", + "RA: C-button Mode": "RA: C-button Mode", + "Stretch to Full Screen": "Stretch to Full Screen", + "Control Profile": "Control Profile", + "Steward Mode (overrides control profile)": "Steward Mode (overrides control profile)", + "Controller Mode": "Controller Mode", + "Menu Hold Time": "Menu Hold Time", + "Vibrate on Menu Hold": "Vibrate on Menu Hold", + "Power indicator LED mode": "Power indicator LED mode", + "Low power warning percent": "Low power warning percent", + "Shutdown after sleeping": "Shutdown after sleeping", + "Shutdown after sleeping if unplugged": "Shutdown after sleeping if unplugged", + "Shutdown while idle in menu": "Shutdown while idle in menu", + "Shutdown while idle in game": "Shutdown while idle in game", + "Turn screen off when charging in menu": "Turn screen off when charging in menu", + "Turn screen off when charging in game": "Turn screen off when charging in game", + "Disable network services in game": "Disable network services in game", + "Disable wifi in game": "Disable wifi in game", + "Check for spruce updates on startup": "Check for spruce updates on startup", + "Launch application on startup": "Launch application on startup", + "Rumble intensity": "Rumble intensity", + "Extended brightness controls": "Extended brightness controls", + "Disable joystick": "Disable joystick", + "Enable Lid Sensor": "Enable Lid Sensor", + "Use ZRAM": "Use ZRAM", + "SD card swapfile": "SD card swapfile", + "Global sceenshot shortcut": "Global sceenshot shortcut", + "Overclock Speed": "Overclock Speed", + "Run TrimUI OSD": "Run TrimUI OSD", + "Thermal Control": "Thermal Control", + "Tap home key action": "Tap home key action", + "Hold home key action": "Hold home key action", + "RA: use in-game menu": "RA: use in-game menu", + "Transfer saves between cores": "Transfer saves between cores", + "RA: hotkey enable button": "RA: hotkey enable button", + "RA: auto save state on close": "RA: auto save state on close", + "RA: auto load state on launch": "RA: auto load state on launch", + "GB[C/A]: use Perfect Overlays": "GB[C/A]: use Perfect Overlays", + "Verbose emulator logging": "Verbose emulator logging", + "Genesis Plus GX: enable widescreen": "Genesis Plus GX: enable widescreen", + "Enable Samba": "Enable Samba", + "Enable SSH": "Enable SSH", + "Enable Syncthing": "Enable Syncthing", + "Enable WiFi File Transfer": "Enable WiFi File Transfer", + "OTA: skip version check": "OTA: skip version check", + "Enable Network Proxy": "Enable Network Proxy", + "Proxy Address": "Proxy Address", + "Proxy Port": "Proxy Port", + "Proxy Protocol": "Proxy Protocol", + "Disable RGB LEDs in all contexts": "Disable RGB LEDs in all contexts", + "RGB LED brightness": "RGB LED brightness", + "Default LED color": "Default LED color", + "Default LED behavior": "Default LED behavior", + "Default LED cycle duration (ms)": "Default LED cycle duration (ms)", + "In-game LED behavior": "In-game LED behavior", + "In-game LED color": "In-game LED color", + "In-game LED cycle duration (ms)": "In-game LED cycle duration (ms)", + "Use separate LED control during emulation": "Use separate LED control during emulation", + "Headphone Audio Multiplier": "Headphone Audio Multiplier", + "Retroachivements mode": "Retroachivements mode", + "Password": "Password", + "Username": "Username" + }, + "governorOptions": { + "Smart": "Smart", + "Performance": "Performance", + "Overclock": "Overclock", + "Powersave": "Powersave" + }, + "launchOptions": { + "Generate M3U playlists for multi-disc games": "Generate M3U playlists for multi-disc games", + "Open ScummVM Menu": "Open ScummVM Menu", + "Scan ScummVM Games": "Scan ScummVM Games", + "Generate namelist": "Generate namelist", + "Import carts from Splore": "Import carts from Splore" + }, + "powerDownChoicesReboot": "A = Power Down, X = Reboot, B = Cancel", + "powerDownChoices": "A = Power Down, B = Cancel", + "poweringOff": "Powering off...", + "rebooting": "Rebooting...", + "wifiPowerOn": "Turning on WiFi Power", + "wifiProcessStart": "Starting WiFi process", + "wifiDhcpStart": "Starting ip address assignment process", + "noValidRoms": "No valid ROMs available to launch.", + "selectOptionPrompt": "Select a {name}", + "patchingThemeAssets": "Patching theme to faster assets", + "noCoreFound": "No core found", + "videoPlayer": "Video Player", + "playVideosFromMedia": "Play videos from Roms/MEDIA", + "browseVideos": "Browse videos", + "openMediaFolder": "Open Roms/MEDIA", + "searchVideos": "Search videos", + "findVideosByName": "Find videos by name", + "videoSearch": "Video Search:", + "videoSearchTitle": "Video Search", + "noMatchingVideos": "No matching videos.", + "noVideosHere": "No videos here.\nPut files in Roms/MEDIA/", + "videos": "Videos", + "parentFolder": "Parent folder", + "folder": "Folder", + "playVideo": "Play video", + "mediaLauncherMissing": "Media launcher missing.", + "refresh": "Refresh", + "reloadVideoFolder": "Reload video folder", + "back": "Back", + "returnToVideoMenu": "Return to Video Player menu", + "videoControls": "Controls", + "videoControlsDesc": "Playback button guide", + "videoControlsHelp": "Playback controls:\nB: Pause/Resume\nLeft/Right: Seek\nUp/Down: Prev/Next\nMENU: Exit player\n\nBrowser:\nX: Refresh\nB: Back", + "refreshVideoIndex": "Refresh video index", + "refreshVideoIndexDesc": "Rebuild cached video search list", + "videoIndexUpdated": "Video index updated", + "fnKeySettings": "Fn Key Settings", + "fnKeySettingsDesc": "Fn key and DIP switch actions", + "functionKeyActions": "Function key actions", + "functionKeyActionsDesc": "Stock TrimUI actions for the hardware switch", + "leftFnKey": "Left Fn key", + "leftFnKeyDesc": "Action for left Fn key", + "rightFnKey": "Right Fn key", + "rightFnKeyDesc": "Action for right Fn key", + "dipSwitchActions": "DIP switch actions", + "dipSwitchActionsDesc": "Parallel scripts run by stock scene.sh", + "joystickMode": "Joystick mode", + "joystickModeDesc": "D-pad as left stick", + "fnDiagnostics": "Diagnostics", + "fnDiagnosticsDesc": "Fn switch, CPU, fan, and scene status" } diff --git a/App/PyUI/lang/Vietnamese.json b/App/PyUI/lang/Vietnamese.json index cfea7e57e..ee8635138 100644 --- a/App/PyUI/lang/Vietnamese.json +++ b/App/PyUI/lang/Vietnamese.json @@ -1,616 +1,655 @@ { - "displayName": "Tiếng Việt", - "fonts": { - "list": "BeVietnamPro-Regular.ttf", - "grid": "BeVietnamPro-Regular.ttf", - "shadowed": "BeVietnamPro-SemiBold.ttf", - "default": "BeVietnamPro-Regular.ttf" - }, - "fontPurposeSizes": { - "TOP_BAR_TEXT": "Cỡ chữ thanh trên", - "BATTERY_PERCENT": "Cỡ chữ % pin", - "LIST": "Cỡ chữ danh sách", - "MESSAGE": "Cỡ chữ thông báo", - "DESCRIPTIVE_LIST_TITLE": "Cỡ chữ tiêu đề", - "DESCRIPTIVE_LIST_DESCRIPTION": "Cỡ chữ mô tả", - "GRID_ONE_ROW": "Cỡ chữ lưới (1 hàng)", - "GRID_MULTI_ROW": "Cỡ chữ lưới (nhiều hàng)", - "LIST_INDEX": "Cỡ chữ số thứ tự", - "LIST_TOTAL": "Cỡ chữ tổng số", - "SHADOWED": "Cỡ chữ đổ bóng", - "SHADOWED_BACKDROP": "Cỡ chữ nền đổ bóng", - "SHADOWED_SMALL": "Cỡ chữ đổ bóng nhỏ", - "SHADOWED_BACKDROP_SMALL": "Cỡ chữ nền đổ bóng nhỏ" - }, - "Games": "Trò chơi", - "Recents": "Gần đây", - "Apps": "Ứng dụng", + "displayName": "Tiếng Việt", + "fonts": { + "list": "BeVietnamPro-Regular.ttf", + "grid": "BeVietnamPro-Regular.ttf", + "shadowed": "BeVietnamPro-SemiBold.ttf", + "default": "BeVietnamPro-Regular.ttf" + }, + "fontPurposeSizes": { + "TOP_BAR_TEXT": "Cỡ chữ thanh trên", + "BATTERY_PERCENT": "Cỡ chữ % pin", + "LIST": "Cỡ chữ danh sách", + "MESSAGE": "Cỡ chữ thông báo", + "DESCRIPTIVE_LIST_TITLE": "Cỡ chữ tiêu đề", + "DESCRIPTIVE_LIST_DESCRIPTION": "Cỡ chữ mô tả", + "GRID_ONE_ROW": "Cỡ chữ lưới (1 hàng)", + "GRID_MULTI_ROW": "Cỡ chữ lưới (nhiều hàng)", + "LIST_INDEX": "Cỡ chữ số thứ tự", + "LIST_TOTAL": "Cỡ chữ tổng số", + "SHADOWED": "Cỡ chữ đổ bóng", + "SHADOWED_BACKDROP": "Cỡ chữ nền đổ bóng", + "SHADOWED_SMALL": "Cỡ chữ đổ bóng nhỏ", + "SHADOWED_BACKDROP_SMALL": "Cỡ chữ nền đổ bóng nhỏ" + }, + "Games": "Trò chơi", + "Recents": "Gần đây", + "Apps": "Ứng dụng", + "Collections": "Bộ sưu tập", + "Favorites": "Yêu thích", + "Settings": "Cài đặt", + "noEntriesFound": "Không tìm thấy mục nào", + "systemGameSearch": "Tìm trò chơi $system", + "allSystemGameSearch": "Tìm trò chơi tất cả hệ máy", + "systemMenuSubOptions": "Tùy chọn menu $system", + "gameSearch": "Tìm trò chơi:", + "exitPyUi": "Tải lại giao diện", + "setPyuiAsStartup": "Đặt PyUI làm màn hình khởi động", + "romSearch": "Tìm ROM", + "showApp": "Hiện ứng dụng", + "hideHiddenApps": "Ẩn ứng dụng đã ẩn", + "sortFavorites": "Sắp xếp yêu thích", + "toggleSettingsAsGameSpecificOverride": "Bật/tắt cài đặt riêng cho từng game", + "removeFavorite": "Bỏ yêu thích", + "addFavorite": "Thêm yêu thích", + "removeGameSwitcherGame": "Xóa khỏi Game Switcher", + "addGameSwitcherGame": "Thêm vào Game Switcher", + "addRemoveCollection": "Thêm/Xóa bộ sưu tập", + "removeRecents": "Xóa mục gần đây", + "launchRandomGame": "Chơi game ngẫu nhiên", + "exitGame": "Thoát game", + "saveState": "Lưu trạng thái", + "loadState": "Tải trạng thái", + "toggleFastForward": "Bật/tắt tua nhanh", + "raMenu": "Menu RetroArch", + "createNewCollection": "Tạo bộ sưu tập mới", + "addTo": "Thêm vào", + "addToCollection": "Thêm vào bộ sưu tập", + "removeFrom": "Xóa khỏi", + "powerOff": "Tắt nguồn", + "Backlight": "Đèn nền", + "Volume": "Âm lượng", + "WiFi": "Wi-Fi", + "Bluetooth": "Bluetooth", + "Theme": "Giao diện", + "themeSettings": "Cài đặt giao diện", + "soundSettings": "Cài đặt âm thanh", + "additionalSettings": "Cài đặt bổ sung", + "tasks": "Tác vụ", + "Status": "Trạng thái", + "calibrateAnalogSticks": "Hiệu chỉnh cần analog", + "remapButtons": "Gán lại nút", + "Brightness": "Độ sáng", + "Contrast": "Độ tương phản", + "Saturation": "Độ bão hòa", + "Hue": "Sắc độ", + "Red": "Đỏ", + "Blue": "Xanh dương", + "Green": "Xanh lá", + "displaySettings": "Cài đặt màn hình", + "timeSettings": "Cài đặt thời gian", + "gameSystemSelectSettings": "Cài đặt chọn hệ máy", + "gameSelectSettings": "Cài đặt chọn game", + "gameSwitcherSettings": "Cài đặt Game Switcher", + "gameArtDisplaySettings": "Cài đặt ảnh bìa game", + "downloadBoxart": "Tải ảnh bìa", + "selectBoxart": "Chọn ảnh bìa để tải", + "deleteBoxart": "Xóa ảnh bìa", + "deleteRom": "Xóa ROM", + "deleteRomPrompt1": "Bạn có muốn xóa vĩnh viễn", + "deleteBoxartPrompt1": "Bạn có muốn xóa vĩnh viễn ảnh bìa của", + "deleteRomDeleted": "Đã xóa {path}.", + "deleteBoxartDeleted": "Đã xóa ảnh bìa của {name}.", + "controllerSettings": "Cài đặt tay cầm", + "languageSettings": "Cài đặt ngôn ngữ", + "animationSettings": "Cài đặt hiệu ứng", + "animationsEnabled": "Bật hiệu ứng chuyển động", + "animationSpeed": "Tốc độ hiệu ứng", + "inputRateLimitMs": "Giới hạn tốc độ nhập (ms)", + "stockOsMenu": "Menu hệ điều hành gốc", + "optimizeBoxart": "Tối ưu ảnh bìa", + "lockedDownModes": "Chế độ giới hạn", + "l2R2SkipByLetterForDaijishoThemes": "L2/R2 nhảy theo chữ (theme Daijisho)", + "ignoreArticlesWhenSorting": "Bỏ qua mạo từ khi sắp xếp", + "holdMenuForGameswitcher": "Giữ Menu để mở Game Switcher", + "preferSavestateScreenshots": "Ưu tiên ảnh save state", + "gameCount": "Số lượng game", + "viewType": "Kiểu hiển thị", + "fullScreenResizeType": "Kiểu co giãn toàn màn hình", + "trueFullScreen": "Toàn màn hình thật", + "topbarGamename": "Thanh trên = tên game", + "useRecentsForGameswitcher": "Dùng Gần đây cho Game Switcher", + "showAllSystems": "Hiện tất cả hệ máy", + "gameSystemSorting": "Sắp xếp hệ máy", + "systemTypePriority": "Ưu tiên loại hệ máy", + "systemBrandPriority": "Ưu tiên hãng", + "systemYearPriority": "Ưu tiên năm phát hành", + "systemNamePriority": "Ưu tiên tên hệ máy", + "enterGameSelectionOnlyMode": "Vào chế độ chỉ chọn game", + "enterSimpleMode": "Vào chế độ đơn giản", + "Year": "Năm", + "Month": "Tháng", + "Day": "Ngày", + "hour24": "Giờ 24h", + "Minute": "Phút", + "playButtonPressSound": "Phát âm thanh khi bấm nút", + "playBgm": "Phát nhạc nền", + "bgmVolume": "Âm lượng nhạc nền", + "setTimeDate": "Đặt giờ và ngày", + "setTimezone": "Đặt múi giờ", + "Clock": "Đồng hồ", + "24HourClock": "Đồng hồ 24 giờ", + "showAmPm": "Hiện AM/PM", + "gameSelMenu": "Menu chọn game", + "imgMode": "Chế độ ảnh", + "Rows": "Hàng", + "Cols": "Cột", + "imgWidth": "Chiều rộng ảnh", + "imgHeight": "Chiều cao ảnh", + "primImgWidth": "Chiều rộng ảnh chính %", + "shrinkFurtherAway": "Thu nhỏ khi xa hơn", + "boxartResizeType": "Kiểu co giãn ảnh bìa", + "selBgResizePadWidth": "Đệm nền chọn (rộng)", + "selBgResizePadHeight": "Đệm nền chọn (cao)", + "skipMainMenu": "Bỏ qua menu chính", + "mainMenu": "Menu chính", + "mainMenuColumns": "Số cột menu chính", + "showText": "Hiện chữ", + "showRecents": "Hiện Gần đây", + "showCollections": "Hiện Bộ sưu tập", + "showFavorites": "Hiện Yêu thích", + "showApps": "Hiện Ứng dụng", + "showSettings": "Hiện Cài đặt", + "mainMenuThemeOptions": "Tùy chọn giao diện menu chính", + "systemSelectThemeOptions": "Tùy chọn giao diện chọn hệ máy", + "gameSelectMenuThemeOptions": "Tùy chọn giao diện chọn game", + "Fonts": "Phông chữ", + "gridViewThemeOptions": "Tùy chọn giao diện dạng lưới", + "topBarOptions": "Tùy chọn thanh trên", + "leftSideInitialXOffset": "Lệch X ban đầu bên trái", + "showSelBg": "Hiện nền mục chọn", + "wrapAround": "Cuộn vòng", + "resizeType": "Kiểu co giãn", + "percentageMode": "Chế độ phần trăm", + "verticalCarousel": "Carousel dọc", + "sidesHangOff": "Tràn ra hai bên", + "height": "Chiều cao", + "width": "Chiều rộng", + "selectedHeight": "Chiều cao mục chọn", + "selectedWidth": "Chiều rộng mục chọn", + "imageResizeType": "Kiểu co giãn ảnh", + "internalPadding": "Đệm trong", + "yOffset": "Lệch Y", + "selectedIconPositionOffset": "Lệch vị trí icon được chọn", + "useSelectedImageInAnimation": "Dùng ảnh chọn trong hiệu ứng", + "xOffset": "Lệch X", + "setTopBarText": "Đặt chữ thanh trên", + "setBottomBarText": "Đặt chữ thanh dưới", + "showBatteryPercent": "Hiện % pin", + "showBatteryIcon": "Hiện icon pin", + "showVolumeNumbers": "Hiện số âm lượng", + "showBottomBarButtons": "Hiện nút thanh dưới", + "showClock": "Hiện đồng hồ", + "mainMenuTitle": "Tiêu đề menu chính", + "setGridBgOffsetToImageOffset": "Căn nền lưới theo lệch ảnh", + "wifiConfiguration": "Cấu hình Wi-Fi", + "wifiPassword": "Mật khẩu Wi-Fi", + "scanningForNetworks": "Đang quét mạng...", + "bluetoothConfiguration": "Cấu hình Bluetooth", + "scanning": "Đang quét", + "buttonRemapper": "Gán lại nút", + "mainMenuSubOptions": "Tùy chọn phụ menu chính", + "collectionName": "Tên bộ sưu tập:", + "gameSystemSortModeTitle": "Chế độ sắp xếp hệ máy", + "downloadBoxartDesc": "Quét thư viện để tìm ảnh bìa còn thiếu", + "optimizeBoxartDesc": "Co giãn ảnh bìa và chuyển sang QOI để tải nhanh hơn", + "lockedDownModesDesc": "Chế độ đơn giản cho người mới hoặc trẻ em", + "gameOnlyModeTitle": "Chế độ chỉ chọn game", + "gameOnlyModePrompt1": "Bạn có muốn vào chế độ chỉ chọn game không?", + "gameOnlyModePrompt2": "Khởi động thẳng vào màn hình chọn game", + "gameOnlyModePrompt3": "Để thoát, nhập mã Konami", + "simpleModeTitle": "Chế độ đơn giản", + "simpleModePrompt1": "Bạn có muốn vào chế độ đơn giản không?", + "simpleModePrompt2": "Giới hạn quyền truy cập cài đặt", + "simpleModePrompt3": "Để thoát, nhập mã Konami", + "gameTracking": "Theo dõi game", + "systemTracking": "Theo dõi hệ máy", + "activityTracker": "Theo dõi hoạt động", + "systemActivityTracker": "Theo dõi hoạt động hệ máy", + "today": "Hôm nay", + "thisWeek": "Tuần này", + "thisMonth": "Tháng này", + "thisYear": "Năm nay", + "allTime": "Toàn thời gian", + "screenshot": "Ảnh chụp màn hình", + "boxart": "Ảnh bìa", + "yes": "Có", + "no": "Không", + "recentDesc": "Gần đây", + "collectionDesc": "Bộ sưu tập", + "favoriteDesc": "Yêu thích", + "yourGamesDesc": "Game của bạn", + "yourAppsDesc": "Ứng dụng của bạn", + "yourSettingsDesc": "Cài đặt của bạn", + "launchRecents": "Mở Gần đây", + "launchFavorites": "Mở Yêu thích", + "launchCollections": "Mở Bộ sưu tập", + "launchApplications": "Mở Ứng dụng", + "launchSettings": "Mở Cài đặt", + "applications": "Ứng dụng", + "scrapeBoxartDesc": "Tải ảnh bìa game", + "trackAppUsageDesc": "Theo dõi thời gian dùng app", + "size": "Cỡ chữ", + "viewTypes": { + "ICON_AND_DESC": "Icon và mô tả", + "FULLSCREEN_GRID": "Lưới toàn màn hình", + "GRID": "Lưới", + "TEXT_AND_IMAGE": "Chữ và ảnh", + "TEXT_ONLY": "Chỉ chữ", + "POPUP": "Popup", + "CAROUSEL": "Carousel" + }, + "resizeTypes": { + "FIT": "Vừa khung", + "ZOOM": "Phóng to", + "NONE": "Không co giãn" + }, + "booleans": { + "true": "Bật", + "false": "Tắt" + }, + "onOff": { + "on": "Bật", + "off": "Tắt" + }, + "gameSystemSortModes": { + "Alphabetical": "Theo bảng chữ cái", + "SortOrderKey": "Theo thứ tự tùy chỉnh", + "Custom": "Tùy chỉnh" + }, + "screenTypes": { "Collections": "Bộ sưu tập", "Favorites": "Yêu thích", - "Settings": "Cài đặt", - "noEntriesFound": "Không tìm thấy mục nào", - "systemGameSearch": "Tìm trò chơi $system", - "allSystemGameSearch": "Tìm trò chơi tất cả hệ máy", - "systemMenuSubOptions": "Tùy chọn menu $system", - "gameSearch": "Tìm trò chơi:", - "exitPyUi": "Tải lại giao diện", - "setPyuiAsStartup": "Đặt PyUI làm màn hình khởi động", - "romSearch": "Tìm ROM", - "showApp": "Hiện ứng dụng", - "hideHiddenApps": "Ẩn ứng dụng đã ẩn", - "sortFavorites": "Sắp xếp yêu thích", - "toggleSettingsAsGameSpecificOverride": "Bật/tắt cài đặt riêng cho từng game", - "removeFavorite": "Bỏ yêu thích", - "addFavorite": "Thêm yêu thích", - "removeGameSwitcherGame": "Xóa khỏi Game Switcher", - "addGameSwitcherGame": "Thêm vào Game Switcher", - "addRemoveCollection": "Thêm/Xóa bộ sưu tập", - "removeRecents": "Xóa mục gần đây", - "launchRandomGame": "Chơi game ngẫu nhiên", - "exitGame": "Thoát game", - "saveState": "Lưu trạng thái", - "loadState": "Tải trạng thái", - "toggleFastForward": "Bật/tắt tua nhanh", - "raMenu": "Menu RetroArch", - "createNewCollection": "Tạo bộ sưu tập mới", - "addTo": "Thêm vào", - "addToCollection": "Thêm vào bộ sưu tập", - "removeFrom": "Xóa khỏi", - "powerOff": "Tắt nguồn", - "Backlight": "Đèn nền", - "Volume": "Âm lượng", - "WiFi": "Wi-Fi", - "Bluetooth": "Bluetooth", - "Theme": "Giao diện", - "themeSettings": "Cài đặt giao diện", - "soundSettings": "Cài đặt âm thanh", - "additionalSettings": "Cài đặt bổ sung", - "tasks": "Tác vụ", - "Status": "Trạng thái", - "calibrateAnalogSticks": "Hiệu chỉnh cần analog", - "remapButtons": "Gán lại nút", - "Brightness": "Độ sáng", - "Contrast": "Độ tương phản", - "Saturation": "Độ bão hòa", - "Hue": "Sắc độ", - "Red": "Đỏ", - "Blue": "Xanh dương", - "Green": "Xanh lá", - "displaySettings": "Cài đặt màn hình", - "timeSettings": "Cài đặt thời gian", - "gameSystemSelectSettings": "Cài đặt chọn hệ máy", - "gameSelectSettings": "Cài đặt chọn game", - "gameSwitcherSettings": "Cài đặt Game Switcher", - "gameArtDisplaySettings": "Cài đặt ảnh bìa game", - "downloadBoxart": "Tải ảnh bìa", - "selectBoxart": "Chọn ảnh bìa để tải", - "deleteBoxart": "Xóa ảnh bìa", - "deleteRom": "Xóa ROM", - "deleteRomPrompt1": "Bạn có muốn xóa vĩnh viễn", - "deleteBoxartPrompt1": "Bạn có muốn xóa vĩnh viễn ảnh bìa của", - "deleteRomDeleted": "Đã xóa {path}.", - "deleteBoxartDeleted": "Đã xóa ảnh bìa của {name}.", - "controllerSettings": "Cài đặt tay cầm", - "languageSettings": "Cài đặt ngôn ngữ", - "animationSettings": "Cài đặt hiệu ứng", - "animationsEnabled": "Bật hiệu ứng chuyển động", - "animationSpeed": "Tốc độ hiệu ứng", - "inputRateLimitMs": "Giới hạn tốc độ nhập (ms)", - "stockOsMenu": "Menu hệ điều hành gốc", - "optimizeBoxart": "Tối ưu ảnh bìa", - "lockedDownModes": "Chế độ giới hạn", - "l2R2SkipByLetterForDaijishoThemes": "L2/R2 nhảy theo chữ (theme Daijisho)", - "ignoreArticlesWhenSorting": "Bỏ qua mạo từ khi sắp xếp", - "holdMenuForGameswitcher": "Giữ Menu để mở Game Switcher", - "preferSavestateScreenshots": "Ưu tiên ảnh save state", - "gameCount": "Số lượng game", - "viewType": "Kiểu hiển thị", - "fullScreenResizeType": "Kiểu co giãn toàn màn hình", - "trueFullScreen": "Toàn màn hình thật", - "topbarGamename": "Thanh trên = tên game", - "useRecentsForGameswitcher": "Dùng Gần đây cho Game Switcher", - "showAllSystems": "Hiện tất cả hệ máy", - "gameSystemSorting": "Sắp xếp hệ máy", - "systemTypePriority": "Ưu tiên loại hệ máy", - "systemBrandPriority": "Ưu tiên hãng", - "systemYearPriority": "Ưu tiên năm phát hành", - "systemNamePriority": "Ưu tiên tên hệ máy", - "enterGameSelectionOnlyMode": "Vào chế độ chỉ chọn game", - "enterSimpleMode": "Vào chế độ đơn giản", - "Year": "Năm", - "Month": "Tháng", - "Day": "Ngày", - "hour24": "Giờ 24h", - "Minute": "Phút", - "playButtonPressSound": "Phát âm thanh khi bấm nút", - "playBgm": "Phát nhạc nền", - "bgmVolume": "Âm lượng nhạc nền", - "setTimeDate": "Đặt giờ và ngày", - "setTimezone": "Đặt múi giờ", - "Clock": "Đồng hồ", - "24HourClock": "Đồng hồ 24 giờ", - "showAmPm": "Hiện AM/PM", - "gameSelMenu": "Menu chọn game", - "imgMode": "Chế độ ảnh", - "Rows": "Hàng", - "Cols": "Cột", - "imgWidth": "Chiều rộng ảnh", - "imgHeight": "Chiều cao ảnh", - "primImgWidth": "Chiều rộng ảnh chính %", - "shrinkFurtherAway": "Thu nhỏ khi xa hơn", - "boxartResizeType": "Kiểu co giãn ảnh bìa", - "selBgResizePadWidth": "Đệm nền chọn (rộng)", - "selBgResizePadHeight": "Đệm nền chọn (cao)", - "skipMainMenu": "Bỏ qua menu chính", - "mainMenu": "Menu chính", - "mainMenuColumns": "Số cột menu chính", - "showText": "Hiện chữ", - "showRecents": "Hiện Gần đây", - "showCollections": "Hiện Bộ sưu tập", - "showFavorites": "Hiện Yêu thích", - "showApps": "Hiện Ứng dụng", - "showSettings": "Hiện Cài đặt", - "mainMenuThemeOptions": "Tùy chọn giao diện menu chính", - "systemSelectThemeOptions": "Tùy chọn giao diện chọn hệ máy", - "gameSelectMenuThemeOptions": "Tùy chọn giao diện chọn game", - "Fonts": "Phông chữ", - "gridViewThemeOptions": "Tùy chọn giao diện dạng lưới", - "topBarOptions": "Tùy chọn thanh trên", - "leftSideInitialXOffset": "Lệch X ban đầu bên trái", - "showSelBg": "Hiện nền mục chọn", - "wrapAround": "Cuộn vòng", - "resizeType": "Kiểu co giãn", - "percentageMode": "Chế độ phần trăm", - "verticalCarousel": "Carousel dọc", - "sidesHangOff": "Tràn ra hai bên", - "height": "Chiều cao", - "width": "Chiều rộng", - "selectedHeight": "Chiều cao mục chọn", - "selectedWidth": "Chiều rộng mục chọn", - "imageResizeType": "Kiểu co giãn ảnh", - "internalPadding": "Đệm trong", - "yOffset": "Lệch Y", - "selectedIconPositionOffset": "Lệch vị trí icon được chọn", - "useSelectedImageInAnimation": "Dùng ảnh chọn trong hiệu ứng", - "xOffset": "Lệch X", - "setTopBarText": "Đặt chữ thanh trên", - "setBottomBarText": "Đặt chữ thanh dưới", - "showBatteryPercent": "Hiện % pin", - "showBatteryIcon": "Hiện icon pin", - "showVolumeNumbers": "Hiện số âm lượng", - "showBottomBarButtons": "Hiện nút thanh dưới", - "showClock": "Hiện đồng hồ", - "mainMenuTitle": "Tiêu đề menu chính", - "setGridBgOffsetToImageOffset": "Căn nền lưới theo lệch ảnh", - "wifiConfiguration": "Cấu hình Wi-Fi", - "wifiPassword": "Mật khẩu Wi-Fi", - "scanningForNetworks": "Đang quét mạng...", - "bluetoothConfiguration": "Cấu hình Bluetooth", - "scanning": "Đang quét", - "buttonRemapper": "Gán lại nút", - "mainMenuSubOptions": "Tùy chọn phụ menu chính", - "collectionName": "Tên bộ sưu tập:", - "gameSystemSortModeTitle": "Chế độ sắp xếp hệ máy", - "downloadBoxartDesc": "Quét thư viện để tìm ảnh bìa còn thiếu", - "optimizeBoxartDesc": "Co giãn ảnh bìa và chuyển sang QOI để tải nhanh hơn", - "lockedDownModesDesc": "Chế độ đơn giản cho người mới hoặc trẻ em", - "gameOnlyModeTitle": "Chế độ chỉ chọn game", - "gameOnlyModePrompt1": "Bạn có muốn vào chế độ chỉ chọn game không?", - "gameOnlyModePrompt2": "Khởi động thẳng vào màn hình chọn game", - "gameOnlyModePrompt3": "Để thoát, nhập mã Konami", - "simpleModeTitle": "Chế độ đơn giản", - "simpleModePrompt1": "Bạn có muốn vào chế độ đơn giản không?", - "simpleModePrompt2": "Giới hạn quyền truy cập cài đặt", - "simpleModePrompt3": "Để thoát, nhập mã Konami", - "gameTracking": "Theo dõi game", - "systemTracking": "Theo dõi hệ máy", - "activityTracker": "Theo dõi hoạt động", - "systemActivityTracker": "Theo dõi hoạt động hệ máy", - "today": "Hôm nay", - "thisWeek": "Tuần này", - "thisMonth": "Tháng này", - "thisYear": "Năm nay", - "allTime": "Toàn thời gian", - "screenshot": "Ảnh chụp màn hình", - "boxart": "Ảnh bìa", - "yes": "Có", - "no": "Không", - "recentDesc": "Gần đây", - "collectionDesc": "Bộ sưu tập", - "favoriteDesc": "Yêu thích", - "yourGamesDesc": "Game của bạn", - "yourAppsDesc": "Ứng dụng của bạn", - "yourSettingsDesc": "Cài đặt của bạn", - "launchRecents": "Mở Gần đây", - "launchFavorites": "Mở Yêu thích", - "launchCollections": "Mở Bộ sưu tập", - "launchApplications": "Mở Ứng dụng", - "launchSettings": "Mở Cài đặt", - "applications": "Ứng dụng", - "scrapeBoxartDesc": "Tải ảnh bìa game", - "trackAppUsageDesc": "Theo dõi thời gian dùng app", - "size": "Cỡ chữ", - "viewTypes": { - "ICON_AND_DESC": "Icon và mô tả", - "FULLSCREEN_GRID": "Lưới toàn màn hình", - "GRID": "Lưới", - "TEXT_AND_IMAGE": "Chữ và ảnh", - "TEXT_ONLY": "Chỉ chữ", - "POPUP": "Popup", - "CAROUSEL": "Carousel" - }, - "resizeTypes": { - "FIT": "Vừa khung", - "ZOOM": "Phóng to", - "NONE": "Không co giãn" - }, - "booleans": { - "true": "Bật", - "false": "Tắt" - }, - "onOff": { - "on": "Bật", - "off": "Tắt" - }, - "gameSystemSortModes": { - "Alphabetical": "Theo bảng chữ cái", - "SortOrderKey": "Theo thứ tự tùy chỉnh", - "Custom": "Tùy chỉnh" - }, - "screenTypes": { - "Collections": "Bộ sưu tập", - "Favorites": "Yêu thích", - "GameSelect": "Chọn game", - "Recents": "Gần đây", - "GameSwitcher": "Game Switcher" - }, - "controllerInputs": { - "A": "A", - "B": "B", - "X": "X", - "Y": "Y", - "MENU": "Menu", - "DPAD_UP": "Lên", - "DPAD_DOWN": "Xuống", - "DPAD_LEFT": "Trái", - "DPAD_RIGHT": "Phải", - "L1": "L1", - "L2": "L2", - "L3": "L3", - "R1": "R1", - "R2": "R2", - "R3": "R3", - "START": "Start", - "SELECT": "Select", - "LEFT_STICK_UP": "Cần trái lên", - "LEFT_STICK_DOWN": "Cần trái xuống", - "LEFT_STICK_LEFT": "Cần trái trái", - "LEFT_STICK_RIGHT": "Cần trái phải", - "RIGHT_STICK_UP": "Cần phải lên", - "RIGHT_STICK_DOWN": "Cần phải xuống", - "RIGHT_STICK_LEFT": "Cần phải trái", - "RIGHT_STICK_RIGHT": "Cần phải phải", - "VOLUME_DOWN": "Giảm âm lượng", - "VOLUME_UP": "Tăng âm lượng", - "POWER_BUTTON": "Nút nguồn", - "UNKNOWN": "Không xác định" - }, - "gameSystems": { - "-CUSTOM-SYSTEM-": "Hệ tùy chỉnh", - "A30PORTS": "Cổng A30", - "AMIGA": "Amiga", - "ARCADE": "Arcade", - "ARDUBOY": "Arduboy", - "ATARI": "Atari 2600", - "ATARIST": "Atari ST", - "ATOMISWAVE": "Atomiswave", - "CHAI": "ChaiLove", - "COLECO": "ColecoVis", - "COMMODORE": "Commodore 64", - "CPC": "Amst CPC", - "CPS1": "CPS1", - "CPS2": "CPS2", - "CPS3": "CPS3", - "DC": "Dreamcast", - "DOOM": "DOOM", - "DOS": "MS-DOS", - "EASYRPG": "EasyRPG", - "EIGHTHUNDRED": "Atari 800", - "FAIRCHILD": "ChannelF", - "FAKE08": "Fake08", - "FBNEO": "FBNEO", - "FC": "NES / Famicom", - "FDS": "Famicom Disk", - "FIFTYTWOHUNDRED": "Atari 5200", - "GAMETANK": "Game Tank", - "GB": "GB", - "GBA": "GBA", - "GBC": "GBC", - "GG": "Game Gear", - "GW": "G&W", - "INTELLIVISION": "Intellivis.", - "LYNX": "Atari Lynx", - "MAME2003PLUS": "MAME 03+", - "MD": "Mega Drive / Genesis", - "MEDIA": "Đa phương tiện", - "MEGADUCK": "Mega Duck", - "MKXP-Z": "MKXP", - "MS": "Sega MS", - "MSU1": "MSU1", - "MSUMD": "MSUMD", - "MSX": "MSX", - "N64": "Nintendo 64", - "NAOMI": "Naomi", - "NDS": "Nintendo DS", - "NEOCD": "Neo CD", - "NEOGEO": "NeoGeo", - "NGP": "NGP", - "NGPC": "NGPC", - "ODYSSEY": "Odyssey2", - "OPENBOR": "OpenBOR", - "PC98": "PC 98", - "PCE": "TG-16", - "PCECD": "TG-CD", - "PICO8": "PICO-8", - "POKE": "Pokemini", - "PORTS": "Cổng (Ports)", - "PS": "PlayStation", - "PSP": "PSP", - "QUAKE": "Quake", - "SATELLAVIEW": "Satella", - "SATURN": "Sega Saturn", - "SCUMMVM": "ScummVM", - "SEGACD": "Sega CD", - "SEGASGONE": "SG-1000", - "SEVENTYEIGHTHUNDRED": "Atari 7800", - "SFC": "SNES / Super Famicom", - "SGB": "SGB", - "SGFX": "SuperGfx", - "SUFAMI": "Sufami", - "SUPERVISION": "Supervision", - "THIRTYTWOX": "Sega 32X", - "TIC": "TIC-80", - "VB": "VirtualBoy", - "VECTREX": "Vectrex", - "VIC20": "VIC-20", - "VIDEOPAC": "VideoPac", - "WOLF": "Wolf3D", - "WS": "WndrSwan", - "WSC": "WndrSwnC", - "X68000": "X68000", - "ZXS": "ZXS" - }, - "menuOptionDisplays": { - "CPU Mode": "Chế độ CPU", - "Retroarch Core": "Core RetroArch", - "Emulator": "Trình giả lập", - "Emulator64": "Trình giả lập (64-bit)", - "Emulator32": "Trình giả lập (32-bit)", - "RA Build": "Bản dựng RetroArch", - "RA: C-button Mode": "RetroArch: chế độ nút C", - "Stretch to Full Screen": "Kéo giãn toàn màn hình", - "Control Profile": "Cấu hình điều khiển", - "Steward Mode (overrides control profile)": "Chế độ Steward (ghi đè cấu hình điều khiển)", - "Controller Mode": "Chế độ tay cầm", - "Menu Hold Time": "Thời gian giữ Menu", - "Vibrate on Menu Hold": "Rung khi giữ Menu", - "Power indicator LED mode": "Chế độ LED báo pin", - "Low power warning percent": "Ngưỡng cảnh báo pin yếu (%)", - "Shutdown after sleeping": "Tắt máy sau khi ngủ", - "Shutdown after sleeping if unplugged": "Tắt máy sau khi ngủ nếu rút sạc", - "Shutdown while idle in menu": "Tắt máy khi idle trong menu", - "Shutdown while idle in game": "Tắt máy khi idle trong game", - "Turn screen off when charging in menu": "Tắt màn hình khi sạc trong menu", - "Turn screen off when charging in game": "Tắt màn hình khi sạc trong game", - "Disable network services in game": "Tắt dịch vụ mạng khi chơi game", - "Disable wifi in game": "Tắt WiFi khi chơi game", - "Check for spruce updates on startup": "Kiểm tra cập nhật spruce khi khởi động", - "Launch application on startup": "Chạy ứng dụng khi khởi động", - "Rumble intensity": "Cường độ rung", - "Extended brightness controls": "Điều khiển độ sáng mở rộng", - "Disable joystick": "Tắt joystick", - "Enable Lid Sensor": "Bật cảm biến nắp", - "Use ZRAM": "Dùng ZRAM", - "SD card swapfile": "Swapfile trên thẻ SD", - "Global sceenshot shortcut": "Phím tắt chụp màn hình toàn cục", - "Overclock Speed": "Tốc độ ép xung", - "Run TrimUI OSD": "Chạy TrimUI OSD", - "Thermal Control": "Điều khiển nhiệt", - "Tap home key action": "Hành động khi nhấn phím Home", - "Hold home key action": "Hành động khi giữ phím Home", - "RA: use in-game menu": "RA: dùng menu trong game", - "Transfer saves between cores": "Chuyển save giữa các core", - "RA: hotkey enable button": "RA: nút bật phím tắt", - "RA: auto save state on close": "RA: tự lưu save state khi thoát", - "RA: auto load state on launch": "RA: tự tải save state khi chạy", - "GB[C/A]: use Perfect Overlays": "GB[C/A]: dùng Perfect Overlays", - "Verbose emulator logging": "Ghi log trình giả lập chi tiết", - "Genesis Plus GX: enable widescreen": "Genesis Plus GX: bật widescreen", - "Enable Samba": "Bật Samba", - "Enable SSH": "Bật SSH", - "Enable Syncthing": "Bật Syncthing", - "Enable WiFi File Transfer": "Bật chuyển file qua WiFi", - "OTA: skip version check": "OTA: bỏ qua kiểm tra phiên bản", - "Enable Network Proxy": "Bật proxy mạng", - "Proxy Address": "Địa chỉ proxy", - "Proxy Port": "Cổng proxy", - "Proxy Protocol": "Giao thức proxy", - "Disable RGB LEDs in all contexts": "Tắt LED RGB trong mọi trường hợp", - "RGB LED brightness": "Độ sáng LED RGB", - "Default LED color": "Màu LED mặc định", - "Default LED behavior": "Hành vi LED mặc định", - "Default LED cycle duration (ms)": "Thời gian chu kỳ LED mặc định (ms)", - "In-game LED behavior": "Hành vi LED trong game", - "In-game LED color": "Màu LED trong game", - "In-game LED cycle duration (ms)": "Thời gian chu kỳ LED trong game (ms)", - "Use separate LED control during emulation": "Điều khiển LED riêng khi giả lập", - "Headphone Audio Multiplier": "Hệ số âm lượng tai nghe", - "Retroachivements mode": "Chế độ RetroAchievements", - "Password": "Mật khẩu", - "Username": "Tên người dùng", - "Emulator_64": "Trình giả lập (64-bit)", - "Emulator_32": "Trình giả lập (32-bit)", - "Emulator_Pixel2": "Trình giả lập" - }, - "governorOptions": { - "Smart": "Thông minh", - "Performance": "Hiệu năng", - "Overclock": "Ép xung", - "Powersave": "Tiết kiệm pin" - }, - "launchOptions": { - "Generate M3U playlists for multi-disc games": "Tạo playlist M3U cho game nhiều đĩa", - "Open ScummVM Menu": "Mở menu ScummVM", - "Scan ScummVM Games": "Quét game ScummVM", - "Generate namelist": "Tạo danh sách tên", - "Import carts from Splore": "Nhập cart từ Splore" - }, - "powerDownPrompt": "Bạn có muốn tắt máy?", - "powerDownOptionsWithReboot": "A = Tắt nguồn, X = Khởi động lại, B = Hủy", - "powerDownOptions": "A = Tắt nguồn, B = Hủy", - "turningOnWifiPower": "Đang bật nguồn Wi-Fi", - "startingWifiProcess": "Đang khởi động tiến trình Wi-Fi", - "startingIpAssignment": "Đang khởi động gán địa chỉ IP", - "sdcardReadOnlyWarning": "Cảnh báo: /mnt/SDCARD ở chế độ chỉ đọc. Hãy kiểm tra thẻ SD.", - "wifiStatusOff": "Tắt", - "wifiStatusConnecting": "Đang kết nối", - "wifiStatusError": "Lỗi", - "aboutIpAddress": "Địa chỉ IP", - "aboutMacAddress": "Địa chỉ MAC", - "aboutFwVersion": "Phiên bản FW", - "aboutUnknown": "Không xác định", - "noValidRomsToLaunch": "Không có ROM hợp lệ để khởi chạy.", - "loadingBoxartList": "Đang tải danh sách ảnh bìa...", - "downloadingBoxartTo": "Đang tải {boxart} vào {path}", - "toggleView": "Chuyển kiểu hiển thị", - "selectBoxArtTitle": "Chọn ảnh bìa", - "optimizeBoxartPrompt1": "Bạn có muốn tối ưu ảnh bìa không?", - "optimizeBoxartPrompt2": "Ảnh gốc sẽ được chuyển đổi, hãy sao lưu trước!", - "optimizeBoxartPrompt3": "A = Có, B = Không, X/Y = Không hỏi lại", - "optimizeBoxartPrompt4": "Bạn có thể làm thủ công tại:", - "optimizeBoxartPrompt5": "Cài đặt -> Cài đặt bổ sung -> Tối ưu ảnh bìa", - "selectAnOption": "Chọn {name}", - "gameConfigurationTitle": "Cấu hình {system}", - "bluetoothConnectFailed": "Thiết bị Bluetooth {name} kết nối thất bại ở bước: {step}. {output}", - "bluetoothConnectSuccess": "Thiết bị Bluetooth {name} đã kết nối thành công", - "stoppingBluetoothScanner": "Đang dừng quét Bluetooth...", - "stoppingWifiScanner": "Đang dừng quét WiFi...", - "invalidWifiPasswordLength": "Mật khẩu WiFi không hợp lệ! Phải từ 8 đến 63 ký tự", - "updatingWifiConfig": "Đang cập nhật cấu hình cho {ssid} với mật khẩu {password}", - "confirmText": "Xác nhận", - "backText": "Quay lại", - "cloudflareOfflineAborting": "Không ping được Cloudflare; thiết bị đang ngoại tuyến. Đã hủy.", - "scrapingBoxartPatient": "Đang tải ảnh bìa. Vui lòng kiên nhẫn, đặc biệt với thư viện lớn!", - "scrapingComplete": "Tải ảnh bìa hoàn tất!", - "wifiMustBeConnected": "Cần kết nối WiFi", - "libretroUnavailable": "Dịch vụ thumbnail Libretro không khả dụng; đang thử phương án dự phòng.", - "libretroGithubUnavailable": "Kho GitHub thumbnail Libretro cũng không khả dụng. Vui lòng thử lại sau.", - "imageListNotFound": "Không tìm thấy file danh sách ảnh cho {system}.", - "noMissingBoxartForSystem": "Không có ROM nào thiếu ảnh bìa cho {system}.", - "remoteSystemNotFound": "Không tìm thấy tên hệ từ xa - không thể tải ảnh bìa cho {system}.", - "scrapingBoxartProgress": "Đang tải ảnh bìa... ({count}/{total})", - "scrapingBoxartProgressFound": "Đang tải ảnh bìa... ({count}/{total}). Đã tìm thấy {found}.", - "gameCountSingular": "{count} trò chơi", - "gameCountPlural": "{count} trò chơi", - "systemIndexDescription": "{name} - {count} - Hệ {index}/{total}", - "activityTimeHoursMinutes": "{hours}g {minutes}p", - "activityTimeMinutesOnly": "{minutes}p", - "powerDownChoicesReboot": "A = Tắt máy, X = Khởi động lại, B = Hủy", - "powerDownChoices": "A = Tắt máy, B = Hủy", - "poweringOff": "Đang tắt máy...", - "rebooting": "Đang khởi động lại...", - "wifiPowerOn": "Đang bật WiFi", - "wifiProcessStart": "Đang khởi động WiFi", - "wifiDhcpStart": "Đang cấp địa chỉ IP", - "noValidRoms": "Không có ROM hợp lệ để chạy.", - "selectOptionPrompt": "Chọn {name}", - "patchingThemeAssets": "Đang tối ưu theme sang asset nhanh hơn", - "noCoreFound": "Không tìm thấy core", - "settingsCategories": { - "Game Switcher Settings": "Cài đặt Game Switcher", - "Battery Settings": "Cài đặt pin", - "System Settings": "Cài đặt hệ thống", - "Emulator Settings": "Cài đặt trình giả lập", - "Network Settings": "Cài đặt mạng", - "Proxy Settings": "Cài đặt proxy", - "RGB LED Settings": "Cài đặt LED RGB", - "RetroAchievements Settings": "Cài đặt RetroAchievements", - "Audio Settings": "Cài đặt âm thanh" - }, - "menuOptionDescriptions": { - "Clockspeed to use for overclocking": "Tốc độ xung nhịp khi ép xung", - "Customize fan profiles": "Tùy chỉnh cấu hình quạt", - "Early Alpha": "Alpha sớm", - "Headphone Audio Multiplier": "Hệ số âm lượng tai nghe", - "Route HTTP(S) requests to proxy server": "Định tuyến HTTP(S) qua máy chủ proxy", - "Start + L/R change contrast at minimum brightness": "START + L/R đổi độ tương phản ở độ sáng tối thiểu", - "allows reinstall of same spruce version": "cho phép cài lại cùng phiên bản spruce", - "can help with stick delete mod bugs": "có thể khắc phục lỗi mod nút xóa", - "caution: high values may freeze device": "cẩn thận: giá trị cao có thể treo máy", - "custom allows to set in RA itself": "tùy chỉnh: đặt trong RetroArch", - "during emulation": "trong lúc giả lập", - "flash LED below threshold": "nhấp nháy LED dưới ngưỡng", - "follows defaults if set to False": "dùng mặc định nếu đặt False", - "for non-red status LED": "cho LED trạng thái không phải màu đỏ", - "for system notifications": "cho thông báo hệ thống", - "http://{ip_addr}:8080": "http://{ip_addr}:8080", - "http://{ip_addr}:8384": "http://{ip_addr}:8384", - "if connected to Wi-Fi": "nếu đã kết nối Wi-Fi", - "if enabled; non-linear": "nếu bật; phi tuyến", - "if not autoresuming last game": "nếu không tự tiếp tục game cuối", - "ignore shutdown timeout if charging": "bỏ qua hẹn tắt máy khi đang sạc", - "in RA, PPSSPP, or DraStic (reboot to apply)": "trong RA, PPSSPP hoặc DraStic (khởi động lại để áp dụng)", - "in menu, etc.": "trong menu, v.v.", - "including samba, ssh, etc.": "bao gồm samba, ssh, v.v.", - "log output to SD card for debugging": "ghi log ra thẻ SD để gỡ lỗi", - "off sleeps indefinitely": "Off = ngủ vô thời hạn", - "only applies in main UI (reboot to apply)": "chỉ áp dụng trong UI chính (khởi động lại để áp dụng)", - "provided by 1PlayerInsertCoin and Mugwomp93": "cung cấp bởi 1PlayerInsertCoin và Mugwomp93", - "reboot to apply": "khởi động lại để áp dụng", - "reduces battery consumption": "giảm tiêu thụ pin", - "reload UI to apply": "tải lại UI để áp dụng", - "seconds before GS launch from menu": "giây trước khi mở GS từ menu", - "shut device to enter sleep": "gập máy để vào chế độ ngủ", - "smb://{ip_addr}/SDCARD (user/pass=spruce/happygaming)": "smb://{ip_addr}/SDCARD (user/pass=spruce/happygaming)", - "ssh spruce@{ip_addr} (password=happygaming)": "ssh spruce@{ip_addr} (password=happygaming)", - "use widescreen hacked core when available": "dùng core widescreen hack nếu có", - "when launching GS from menu": "khi mở GS từ menu" - }, - "menuOptionValues": { - "True": "Bật", - "False": "Tắt", - "Off": "Tắt", - "On": "Bật", - "Always off": "Luôn tắt", - "Always on": "Luôn bật", - "On in menu only": "Chỉ trong menu", - "Only when unplugged": "Chỉ khi rút sạc", - "Emulator menu": "Menu trình giả lập", - "Game Switcher": "Game Switcher", - "Exit game": "Thoát game", - "Nothing": "Không làm gì", - "Prompt": "Hỏi", - "Always": "Luôn", - "Never": "Không bao giờ", - "Select": "Select", - "Start": "Start", - "Custom": "Tùy chỉnh", - "Smart": "Thông minh", - "Performance": "Hiệu năng", - "Overclock": "Ép xung", - "Powersave": "Tiết kiệm pin", - "Quiet": "Im lặng", - "Adaptive": "Thích ứng", - "Conservative": "Tiết kiệm", - "Sport": "Thể thao", - "http": "http", - "socks5": "socks5", - "Alphabetical": "Theo bảng chữ cái", - "SortOrderKey": "Theo thứ tự hệ thống", - "X360": "X360", - "Nintendo": "Nintendo", - "L2+R2+Y": "L2+R2+Y", - "L2+R2+X": "L2+R2+X", - "L2+R2+DOWN": "L2+R2+DOWN" - } + "GameSelect": "Chọn game", + "Recents": "Gần đây", + "GameSwitcher": "Game Switcher" + }, + "controllerInputs": { + "A": "A", + "B": "B", + "X": "X", + "Y": "Y", + "MENU": "Menu", + "DPAD_UP": "Lên", + "DPAD_DOWN": "Xuống", + "DPAD_LEFT": "Trái", + "DPAD_RIGHT": "Phải", + "L1": "L1", + "L2": "L2", + "L3": "L3", + "R1": "R1", + "R2": "R2", + "R3": "R3", + "START": "Start", + "SELECT": "Select", + "LEFT_STICK_UP": "Cần trái lên", + "LEFT_STICK_DOWN": "Cần trái xuống", + "LEFT_STICK_LEFT": "Cần trái trái", + "LEFT_STICK_RIGHT": "Cần trái phải", + "RIGHT_STICK_UP": "Cần phải lên", + "RIGHT_STICK_DOWN": "Cần phải xuống", + "RIGHT_STICK_LEFT": "Cần phải trái", + "RIGHT_STICK_RIGHT": "Cần phải phải", + "VOLUME_DOWN": "Giảm âm lượng", + "VOLUME_UP": "Tăng âm lượng", + "POWER_BUTTON": "Nút nguồn", + "UNKNOWN": "Không xác định" + }, + "gameSystems": { + "-CUSTOM-SYSTEM-": "Hệ tùy chỉnh", + "A30PORTS": "Cổng A30", + "AMIGA": "Amiga", + "ARCADE": "Arcade", + "ARDUBOY": "Arduboy", + "ATARI": "Atari 2600", + "ATARIST": "Atari ST", + "ATOMISWAVE": "Atomiswave", + "CHAI": "ChaiLove", + "COLECO": "ColecoVis", + "COMMODORE": "Commodore 64", + "CPC": "Amst CPC", + "CPS1": "CPS1", + "CPS2": "CPS2", + "CPS3": "CPS3", + "DC": "Dreamcast", + "DOOM": "DOOM", + "DOS": "MS-DOS", + "EASYRPG": "EasyRPG", + "EIGHTHUNDRED": "Atari 800", + "FAIRCHILD": "ChannelF", + "FAKE08": "Fake08", + "FBNEO": "FBNEO", + "FC": "NES / Famicom", + "FDS": "Famicom Disk", + "FIFTYTWOHUNDRED": "Atari 5200", + "GAMETANK": "Game Tank", + "GB": "GB", + "GBA": "GBA", + "GBC": "GBC", + "GG": "Game Gear", + "GW": "G&W", + "INTELLIVISION": "Intellivis.", + "LYNX": "Atari Lynx", + "MAME2003PLUS": "MAME 03+", + "MD": "Mega Drive / Genesis", + "MEDIA": "Đa phương tiện", + "MEGADUCK": "Mega Duck", + "MKXP-Z": "MKXP", + "MS": "Sega MS", + "MSU1": "MSU1", + "MSUMD": "MSUMD", + "MSX": "MSX", + "N64": "Nintendo 64", + "NAOMI": "Naomi", + "NDS": "Nintendo DS", + "NEOCD": "Neo CD", + "NEOGEO": "NeoGeo", + "NGP": "NGP", + "NGPC": "NGPC", + "ODYSSEY": "Odyssey2", + "OPENBOR": "OpenBOR", + "PC98": "PC 98", + "PCE": "TG-16", + "PCECD": "TG-CD", + "PICO8": "PICO-8", + "POKE": "Pokemini", + "PORTS": "Cổng (Ports)", + "PS": "PlayStation", + "PSP": "PSP", + "QUAKE": "Quake", + "SATELLAVIEW": "Satella", + "SATURN": "Sega Saturn", + "SCUMMVM": "ScummVM", + "SEGACD": "Sega CD", + "SEGASGONE": "SG-1000", + "SEVENTYEIGHTHUNDRED": "Atari 7800", + "SFC": "SNES / Super Famicom", + "SGB": "SGB", + "SGFX": "SuperGfx", + "SUFAMI": "Sufami", + "SUPERVISION": "Supervision", + "THIRTYTWOX": "Sega 32X", + "TIC": "TIC-80", + "VB": "VirtualBoy", + "VECTREX": "Vectrex", + "VIC20": "VIC-20", + "VIDEOPAC": "VideoPac", + "WOLF": "Wolf3D", + "WS": "WndrSwan", + "WSC": "WndrSwnC", + "X68000": "X68000", + "ZXS": "ZXS" + }, + "menuOptionDisplays": { + "CPU Mode": "Chế độ CPU", + "Retroarch Core": "Core RetroArch", + "Emulator": "Trình giả lập", + "Emulator64": "Trình giả lập (64-bit)", + "Emulator32": "Trình giả lập (32-bit)", + "RA Build": "Bản dựng RetroArch", + "RA: C-button Mode": "RetroArch: chế độ nút C", + "Stretch to Full Screen": "Kéo giãn toàn màn hình", + "Control Profile": "Cấu hình điều khiển", + "Steward Mode (overrides control profile)": "Chế độ Steward (ghi đè cấu hình điều khiển)", + "Controller Mode": "Chế độ tay cầm", + "Menu Hold Time": "Thời gian giữ Menu", + "Vibrate on Menu Hold": "Rung khi giữ Menu", + "Power indicator LED mode": "Chế độ LED báo pin", + "Low power warning percent": "Ngưỡng cảnh báo pin yếu (%)", + "Shutdown after sleeping": "Tắt máy sau khi ngủ", + "Shutdown after sleeping if unplugged": "Tắt máy sau khi ngủ nếu rút sạc", + "Shutdown while idle in menu": "Tắt máy khi idle trong menu", + "Shutdown while idle in game": "Tắt máy khi idle trong game", + "Turn screen off when charging in menu": "Tắt màn hình khi sạc trong menu", + "Turn screen off when charging in game": "Tắt màn hình khi sạc trong game", + "Disable network services in game": "Tắt dịch vụ mạng khi chơi game", + "Disable wifi in game": "Tắt WiFi khi chơi game", + "Check for spruce updates on startup": "Kiểm tra cập nhật spruce khi khởi động", + "Launch application on startup": "Chạy ứng dụng khi khởi động", + "Rumble intensity": "Cường độ rung", + "Extended brightness controls": "Điều khiển độ sáng mở rộng", + "Disable joystick": "Tắt joystick", + "Enable Lid Sensor": "Bật cảm biến nắp", + "Use ZRAM": "Dùng ZRAM", + "SD card swapfile": "Swapfile trên thẻ SD", + "Global sceenshot shortcut": "Phím tắt chụp màn hình toàn cục", + "Overclock Speed": "Tốc độ ép xung", + "Run TrimUI OSD": "Chạy TrimUI OSD", + "Thermal Control": "Điều khiển nhiệt", + "Tap home key action": "Hành động khi nhấn phím Home", + "Hold home key action": "Hành động khi giữ phím Home", + "RA: use in-game menu": "RA: dùng menu trong game", + "Transfer saves between cores": "Chuyển save giữa các core", + "RA: hotkey enable button": "RA: nút bật phím tắt", + "RA: auto save state on close": "RA: tự lưu save state khi thoát", + "RA: auto load state on launch": "RA: tự tải save state khi chạy", + "GB[C/A]: use Perfect Overlays": "GB[C/A]: dùng Perfect Overlays", + "Verbose emulator logging": "Ghi log trình giả lập chi tiết", + "Genesis Plus GX: enable widescreen": "Genesis Plus GX: bật widescreen", + "Enable Samba": "Bật Samba", + "Enable SSH": "Bật SSH", + "Enable Syncthing": "Bật Syncthing", + "Enable WiFi File Transfer": "Bật chuyển file qua WiFi", + "OTA: skip version check": "OTA: bỏ qua kiểm tra phiên bản", + "Enable Network Proxy": "Bật proxy mạng", + "Proxy Address": "Địa chỉ proxy", + "Proxy Port": "Cổng proxy", + "Proxy Protocol": "Giao thức proxy", + "Disable RGB LEDs in all contexts": "Tắt LED RGB trong mọi trường hợp", + "RGB LED brightness": "Độ sáng LED RGB", + "Default LED color": "Màu LED mặc định", + "Default LED behavior": "Hành vi LED mặc định", + "Default LED cycle duration (ms)": "Thời gian chu kỳ LED mặc định (ms)", + "In-game LED behavior": "Hành vi LED trong game", + "In-game LED color": "Màu LED trong game", + "In-game LED cycle duration (ms)": "Thời gian chu kỳ LED trong game (ms)", + "Use separate LED control during emulation": "Điều khiển LED riêng khi giả lập", + "Headphone Audio Multiplier": "Hệ số âm lượng tai nghe", + "Retroachivements mode": "Chế độ RetroAchievements", + "Password": "Mật khẩu", + "Username": "Tên người dùng", + "Emulator_64": "Trình giả lập (64-bit)", + "Emulator_32": "Trình giả lập (32-bit)", + "Emulator_Pixel2": "Trình giả lập" + }, + "governorOptions": { + "Smart": "Thông minh", + "Performance": "Hiệu năng", + "Overclock": "Ép xung", + "Powersave": "Tiết kiệm pin" + }, + "launchOptions": { + "Generate M3U playlists for multi-disc games": "Tạo playlist M3U cho game nhiều đĩa", + "Open ScummVM Menu": "Mở menu ScummVM", + "Scan ScummVM Games": "Quét game ScummVM", + "Generate namelist": "Tạo danh sách tên", + "Import carts from Splore": "Nhập cart từ Splore" + }, + "powerDownPrompt": "Bạn có muốn tắt máy?", + "powerDownOptionsWithReboot": "A = Tắt nguồn, X = Khởi động lại, B = Hủy", + "powerDownOptions": "A = Tắt nguồn, B = Hủy", + "turningOnWifiPower": "Đang bật nguồn Wi-Fi", + "startingWifiProcess": "Đang khởi động tiến trình Wi-Fi", + "startingIpAssignment": "Đang khởi động gán địa chỉ IP", + "sdcardReadOnlyWarning": "Cảnh báo: /mnt/SDCARD ở chế độ chỉ đọc. Hãy kiểm tra thẻ SD.", + "wifiStatusOff": "Tắt", + "wifiStatusConnecting": "Đang kết nối", + "wifiStatusError": "Lỗi", + "aboutIpAddress": "Địa chỉ IP", + "aboutMacAddress": "Địa chỉ MAC", + "aboutFwVersion": "Phiên bản FW", + "aboutUnknown": "Không xác định", + "noValidRomsToLaunch": "Không có ROM hợp lệ để khởi chạy.", + "loadingBoxartList": "Đang tải danh sách ảnh bìa...", + "downloadingBoxartTo": "Đang tải {boxart} vào {path}", + "toggleView": "Chuyển kiểu hiển thị", + "selectBoxArtTitle": "Chọn ảnh bìa", + "optimizeBoxartPrompt1": "Bạn có muốn tối ưu ảnh bìa không?", + "optimizeBoxartPrompt2": "Ảnh gốc sẽ được chuyển đổi, hãy sao lưu trước!", + "optimizeBoxartPrompt3": "A = Có, B = Không, X/Y = Không hỏi lại", + "optimizeBoxartPrompt4": "Bạn có thể làm thủ công tại:", + "optimizeBoxartPrompt5": "Cài đặt -> Cài đặt bổ sung -> Tối ưu ảnh bìa", + "selectAnOption": "Chọn {name}", + "gameConfigurationTitle": "Cấu hình {system}", + "bluetoothConnectFailed": "Thiết bị Bluetooth {name} kết nối thất bại ở bước: {step}. {output}", + "bluetoothConnectSuccess": "Thiết bị Bluetooth {name} đã kết nối thành công", + "stoppingBluetoothScanner": "Đang dừng quét Bluetooth...", + "stoppingWifiScanner": "Đang dừng quét WiFi...", + "invalidWifiPasswordLength": "Mật khẩu WiFi không hợp lệ! Phải từ 8 đến 63 ký tự", + "updatingWifiConfig": "Đang cập nhật cấu hình cho {ssid} với mật khẩu {password}", + "confirmText": "Xác nhận", + "backText": "Quay lại", + "cloudflareOfflineAborting": "Không ping được Cloudflare; thiết bị đang ngoại tuyến. Đã hủy.", + "scrapingBoxartPatient": "Đang tải ảnh bìa. Vui lòng kiên nhẫn, đặc biệt với thư viện lớn!", + "scrapingComplete": "Tải ảnh bìa hoàn tất!", + "wifiMustBeConnected": "Cần kết nối WiFi", + "libretroUnavailable": "Dịch vụ thumbnail Libretro không khả dụng; đang thử phương án dự phòng.", + "libretroGithubUnavailable": "Kho GitHub thumbnail Libretro cũng không khả dụng. Vui lòng thử lại sau.", + "imageListNotFound": "Không tìm thấy file danh sách ảnh cho {system}.", + "noMissingBoxartForSystem": "Không có ROM nào thiếu ảnh bìa cho {system}.", + "remoteSystemNotFound": "Không tìm thấy tên hệ từ xa - không thể tải ảnh bìa cho {system}.", + "scrapingBoxartProgress": "Đang tải ảnh bìa... ({count}/{total})", + "scrapingBoxartProgressFound": "Đang tải ảnh bìa... ({count}/{total}). Đã tìm thấy {found}.", + "gameCountSingular": "{count} trò chơi", + "gameCountPlural": "{count} trò chơi", + "systemIndexDescription": "{name} - {count} - Hệ {index}/{total}", + "activityTimeHoursMinutes": "{hours}g {minutes}p", + "activityTimeMinutesOnly": "{minutes}p", + "powerDownChoicesReboot": "A = Tắt máy, X = Khởi động lại, B = Hủy", + "powerDownChoices": "A = Tắt máy, B = Hủy", + "poweringOff": "Đang tắt máy...", + "rebooting": "Đang khởi động lại...", + "wifiPowerOn": "Đang bật WiFi", + "wifiProcessStart": "Đang khởi động WiFi", + "wifiDhcpStart": "Đang cấp địa chỉ IP", + "noValidRoms": "Không có ROM hợp lệ để chạy.", + "selectOptionPrompt": "Chọn {name}", + "patchingThemeAssets": "Đang tối ưu theme sang asset nhanh hơn", + "noCoreFound": "Không tìm thấy core", + "settingsCategories": { + "Game Switcher Settings": "Cài đặt Game Switcher", + "Battery Settings": "Cài đặt pin", + "System Settings": "Cài đặt hệ thống", + "Emulator Settings": "Cài đặt trình giả lập", + "Network Settings": "Cài đặt mạng", + "Proxy Settings": "Cài đặt proxy", + "RGB LED Settings": "Cài đặt LED RGB", + "RetroAchievements Settings": "Cài đặt RetroAchievements", + "Audio Settings": "Cài đặt âm thanh" + }, + "menuOptionDescriptions": { + "Clockspeed to use for overclocking": "Tốc độ xung nhịp khi ép xung", + "Customize fan profiles": "Tùy chỉnh cấu hình quạt", + "Early Alpha": "Alpha sớm", + "Headphone Audio Multiplier": "Hệ số âm lượng tai nghe", + "Route HTTP(S) requests to proxy server": "Định tuyến HTTP(S) qua máy chủ proxy", + "Start + L/R change contrast at minimum brightness": "START + L/R đổi độ tương phản ở độ sáng tối thiểu", + "allows reinstall of same spruce version": "cho phép cài lại cùng phiên bản spruce", + "can help with stick delete mod bugs": "có thể khắc phục lỗi mod nút xóa", + "caution: high values may freeze device": "cẩn thận: giá trị cao có thể treo máy", + "custom allows to set in RA itself": "tùy chỉnh: đặt trong RetroArch", + "during emulation": "trong lúc giả lập", + "flash LED below threshold": "nhấp nháy LED dưới ngưỡng", + "follows defaults if set to False": "dùng mặc định nếu đặt False", + "for non-red status LED": "cho LED trạng thái không phải màu đỏ", + "for system notifications": "cho thông báo hệ thống", + "http://{ip_addr}:8080": "http://{ip_addr}:8080", + "http://{ip_addr}:8384": "http://{ip_addr}:8384", + "if connected to Wi-Fi": "nếu đã kết nối Wi-Fi", + "if enabled; non-linear": "nếu bật; phi tuyến", + "if not autoresuming last game": "nếu không tự tiếp tục game cuối", + "ignore shutdown timeout if charging": "bỏ qua hẹn tắt máy khi đang sạc", + "in RA, PPSSPP, or DraStic (reboot to apply)": "trong RA, PPSSPP hoặc DraStic (khởi động lại để áp dụng)", + "in menu, etc.": "trong menu, v.v.", + "including samba, ssh, etc.": "bao gồm samba, ssh, v.v.", + "log output to SD card for debugging": "ghi log ra thẻ SD để gỡ lỗi", + "off sleeps indefinitely": "Off = ngủ vô thời hạn", + "only applies in main UI (reboot to apply)": "chỉ áp dụng trong UI chính (khởi động lại để áp dụng)", + "provided by 1PlayerInsertCoin and Mugwomp93": "cung cấp bởi 1PlayerInsertCoin và Mugwomp93", + "reboot to apply": "khởi động lại để áp dụng", + "reduces battery consumption": "giảm tiêu thụ pin", + "reload UI to apply": "tải lại UI để áp dụng", + "seconds before GS launch from menu": "giây trước khi mở GS từ menu", + "shut device to enter sleep": "gập máy để vào chế độ ngủ", + "smb://{ip_addr}/SDCARD (user/pass=spruce/happygaming)": "smb://{ip_addr}/SDCARD (user/pass=spruce/happygaming)", + "ssh spruce@{ip_addr} (password=happygaming)": "ssh spruce@{ip_addr} (password=happygaming)", + "use widescreen hacked core when available": "dùng core widescreen hack nếu có", + "when launching GS from menu": "khi mở GS từ menu" + }, + "menuOptionValues": { + "True": "Bật", + "False": "Tắt", + "Off": "Tắt", + "On": "Bật", + "Always off": "Luôn tắt", + "Always on": "Luôn bật", + "On in menu only": "Chỉ trong menu", + "Only when unplugged": "Chỉ khi rút sạc", + "Emulator menu": "Menu trình giả lập", + "Game Switcher": "Game Switcher", + "Exit game": "Thoát game", + "Nothing": "Không làm gì", + "Prompt": "Hỏi", + "Always": "Luôn", + "Never": "Không bao giờ", + "Select": "Select", + "Start": "Start", + "Custom": "Tùy chỉnh", + "Smart": "Thông minh", + "Performance": "Hiệu năng", + "Overclock": "Ép xung", + "Powersave": "Tiết kiệm pin", + "Quiet": "Im lặng", + "Adaptive": "Thích ứng", + "Conservative": "Tiết kiệm", + "Sport": "Thể thao", + "http": "http", + "socks5": "socks5", + "Alphabetical": "Theo bảng chữ cái", + "SortOrderKey": "Theo thứ tự hệ thống", + "X360": "X360", + "Nintendo": "Nintendo", + "L2+R2+Y": "L2+R2+Y", + "L2+R2+X": "L2+R2+X", + "L2+R2+DOWN": "L2+R2+DOWN" + }, + "videoPlayer": "Trình phát video", + "playVideosFromMedia": "Phát video từ Roms/MEDIA", + "browseVideos": "Duyệt video", + "openMediaFolder": "Mở Roms/MEDIA", + "searchVideos": "Tìm video", + "findVideosByName": "Tìm video theo tên", + "videoSearch": "Tìm video:", + "videoSearchTitle": "Tìm video", + "noMatchingVideos": "Không tìm thấy video phù hợp.", + "noVideosHere": "Không có video ở đây.\nChép file vào Roms/MEDIA/", + "videos": "Video", + "parentFolder": "Thư mục cha", + "folder": "Thư mục", + "playVideo": "Phát video", + "mediaLauncherMissing": "Thiếu launcher media.", + "refresh": "Làm mới", + "reloadVideoFolder": "Tải lại thư mục video", + "back": "Quay lại", + "returnToVideoMenu": "Quay lại menu Trình phát video", + "videoControls": "Điều khiển", + "videoControlsDesc": "Hướng dẫn nút phát video", + "videoControlsHelp": "Điều khiển khi phát:\nB: Tạm dừng/Tiếp tục\nTrái/Phải: Tua\nLên/Xuống: Video trước/tiếp\nMENU: Thoát trình phát\n\nTrình duyệt:\nX: Làm mới\nB: Quay lại", + "refreshVideoIndex": "Làm mới chỉ mục video", + "refreshVideoIndexDesc": "Tạo lại danh sách tìm kiếm video đã lưu", + "videoIndexUpdated": "Đã cập nhật chỉ mục video", + "fnKeySettings": "Cài đặt phím Fn", + "fnKeySettingsDesc": "Hành động phím Fn và công tắc DIP", + "functionKeyActions": "Hành động phím chức năng", + "functionKeyActionsDesc": "Các hành động TrimUI gốc cho công tắc phần cứng", + "leftFnKey": "Phím Fn trái", + "leftFnKeyDesc": "Hành động cho phím Fn trái", + "rightFnKey": "Phím Fn phải", + "rightFnKeyDesc": "Hành động cho phím Fn phải", + "dipSwitchActions": "Hành động công tắc DIP", + "dipSwitchActionsDesc": "Các script chạy song song bằng scene.sh gốc", + "joystickMode": "Chế độ joystick", + "joystickModeDesc": "D-pad làm cần analog trái", + "fnDiagnostics": "Chẩn đoán", + "fnDiagnosticsDesc": "Trạng thái công tắc Fn, CPU, quạt và scene" } diff --git a/App/PyUI/main-ui/menus/app/app_menu.py b/App/PyUI/main-ui/menus/app/app_menu.py index f8da518bb..d2e745b3f 100644 --- a/App/PyUI/main-ui/menus/app/app_menu.py +++ b/App/PyUI/main-ui/menus/app/app_menu.py @@ -21,10 +21,38 @@ from views.view_creator import ViewCreator -class AppMenu: - def __init__(self): - self.appFinder = Device.get_device().get_app_finder() - self.show_all_apps = False +class AppMenu: + def __init__(self): + self.appFinder = Device.get_device().get_app_finder() + self.show_all_apps = False + + @staticmethod + def _resolve_builtin_icon(app_folder, theme_icon_name): + icon = None + if app_folder: + icon = AppUtils.get_first_existing_path([os.path.join(app_folder, "icon.png")]) + if not icon: + icon = AppUtils.get_icon(app_folder, "icon.png") + if not icon: + icon = AppUtils.get_icon(None, theme_icon_name) + if not icon: + icon = Theme._icon(theme_icon_name) + return icon + + @staticmethod + def _append_builtin_app(app_list, label, description, icon, extra_data, handler, hidden=False): + suffix = "(Hidden)" if hidden else "" + app_list.append( + GridOrListEntry( + primary_text=label + suffix, + image_path=icon, + image_path_selected=icon, + description=description, + icon=icon, + extra_data=extra_data, + value=handler, + ) + ) def save_app_selection(self, selected): if(selected.get_selection() is not None): @@ -38,9 +66,12 @@ def handle_app_selection(self, app): Controller.clear_input_queue() Display.reinitialize() - def append_pyui_apps(self, app_list): - system_config = Device.get_device().get_system_config() - if(not system_config.simple_mode_enabled()): + def append_pyui_apps(self, app_list): + from menus.apps.trimui_fn_settings_app import TrimuiFnSettingsApp + from menus.apps.video_player_app import VideoPlayerApp + + system_config = Device.get_device().get_system_config() + if(not system_config.simple_mode_enabled()): boxart_scraper_config = PyUiAppConfig("Boxart Scraper") hidden = AppsManager.is_hidden(boxart_scraper_config) and not self.show_all_apps if(not hidden): @@ -71,9 +102,46 @@ def append_pyui_apps(self, app_list): extra_data=activity_tracker_config, value=ActivityTracker().run_activity_tracking_app ) - ) - - + ) + + if Device.get_device().get_device_name() in ( + "TRIMUI_SMART_PRO_S", + "TRIMUI_SMART_PRO", + "TRIMUI_BRICK", + ): + video_player_config = PyUiAppConfig(Language.get("videoPlayer", "Video Player")) + hidden = AppsManager.is_hidden(video_player_config) and not self.show_all_apps + if not hidden: + icon = self._resolve_builtin_icon("/mnt/SDCARD/App/VideoPlayer", "ffplay.png") + self._append_builtin_app( + app_list, + video_player_config.get_label(), + Language.get("playVideosFromMedia", "Play videos from Roms/MEDIA"), + icon, + video_player_config, + VideoPlayerApp().run, + hidden=AppsManager.is_hidden(video_player_config), + ) + + if Device.get_device().get_device_name() in ( + "TRIMUI_SMART_PRO_S", + "TRIMUI_SMART_PRO", + ): + fn_settings_config = PyUiAppConfig(Language.get("fnKeySettings", "Fn Key Settings")) + hidden = AppsManager.is_hidden(fn_settings_config) and not self.show_all_apps + if not hidden: + icon = self._resolve_builtin_icon("/mnt/SDCARD/App/fn_editor", "fnkey.png") + self._append_builtin_app( + app_list, + fn_settings_config.get_label(), + Language.get("fnKeySettingsDesc", "Fn key and DIP switch actions"), + icon, + fn_settings_config, + TrimuiFnSettingsApp().run, + hidden=AppsManager.is_hidden(fn_settings_config), + ) + + def run_app_selection(self) : running = True diff --git a/App/PyUI/main-ui/menus/apps/trimui_fn_settings_app.py b/App/PyUI/main-ui/menus/apps/trimui_fn_settings_app.py new file mode 100644 index 000000000..616c742fe --- /dev/null +++ b/App/PyUI/main-ui/menus/apps/trimui_fn_settings_app.py @@ -0,0 +1,275 @@ +import json +import os +import shutil +import subprocess +import time + +from controller.controller import Controller +from controller.controller_inputs import ControllerInput +from display.display import Display +from menus.language.language import Language +from menus.apps.trimui_input_helpers import TrimuiInputHelpers +from utils.logger import PyUiLogger +from views.grid_or_list_entry import GridOrListEntry +from views.selection import Selection +from views.view_creator import ViewCreator +from views.view_type import ViewType + +FN_EDITOR_DIR = "/mnt/SDCARD/App/fn_editor" +STOCK_FN_EDITOR_DIR = "/usr/trimui/apps/fn_editor" +SCENE_DIR = "/usr/trimui/scene" +GPIO363_VALUE = "/sys/class/gpio/gpio363/value" +THERMAL_PROFILE = "/mnt/SDCARD/spruce/smartpros/etc/thermal-watchdog/active_profile" +CPU4_DIR = "/sys/devices/system/cpu/cpu4/cpufreq" +FAN_STATE = "/sys/class/thermal/cooling_device0/cur_state" + + +class TrimuiFnSettingsApp: + """PyUI menu for the stock TrimUI function-key scene settings.""" + + def run(self, _input=None): + while True: + selected = Selection(None, None, 0) + options = self._build_options() + view = ViewCreator.create_view( + view_type=ViewType.ICON_AND_DESC, + top_bar_text=Language.get("fnKeySettings", "Fn Key Settings"), + options=options, + selected_index=selected.get_index(), + ) + while selected is not None: + picked = view.get_selection( + [ + ControllerInput.A, + ControllerInput.B, + ControllerInput.DPAD_LEFT, + ControllerInput.DPAD_RIGHT, + ControllerInput.L1, + ControllerInput.R1, + ] + ) + if picked.get_input() == ControllerInput.B: + return + if picked.get_input() in ( + ControllerInput.A, + ControllerInput.DPAD_LEFT, + ControllerInput.DPAD_RIGHT, + ControllerInput.L1, + ControllerInput.R1, + ): + picked.get_selection().get_value()(picked.get_input()) + options = self._build_options() + view.set_options(options) + + def _build_options(self): + return [ + GridOrListEntry( + primary_text=Language.get("functionKeyActions", "Function key actions"), + value_text=None, + image_path=None, + image_path_selected=None, + description=Language.get("functionKeyActionsDesc", "Stock TrimUI actions for the hardware switch"), + icon=None, + value=self._switch_actions_menu, + ), + GridOrListEntry( + primary_text=Language.get("joystickMode", "Joystick mode"), + value_text="< " + ("On" if TrimuiInputHelpers.is_joystick_mode() else "Off") + " >", + image_path=None, + image_path_selected=None, + description=Language.get("joystickModeDesc", "D-pad as left stick"), + icon=None, + value=self._toggle_joystick, + ), + GridOrListEntry( + primary_text=Language.get("fnDiagnostics", "Diagnostics"), + value_text=self._dip_state_label(), + image_path=None, + image_path_selected=None, + description=Language.get("fnDiagnosticsDesc", "Fn switch, CPU, fan, and scene status"), + icon=None, + value=self._show_diagnostics, + ), + ] + + def _switch_actions_menu(self, _input): + scripts = self._load_scripts("scripts.json") + if not scripts: + return + selected = Selection(None, None, 0) + options = self._build_switch_options(scripts) + view = ViewCreator.create_view( + view_type=ViewType.ICON_AND_DESC, + top_bar_text=Language.get("dipSwitchActions", "DIP switch actions"), + options=options, + selected_index=selected.get_index(), + ) + while True: + picked = view.get_selection([ControllerInput.A, ControllerInput.B]) + if picked.get_input() == ControllerInput.B: + return + if picked.get_input() == ControllerInput.A: + picked.get_selection().get_value()(picked.get_input()) + Controller.clear_input_queue() + time.sleep(0.25) + options = self._build_switch_options(scripts) + view.set_options(options) + + def _build_switch_options(self, scripts): + options = [] + for entry in scripts: + active = self._is_scene_script_enabled(entry) + options.append( + GridOrListEntry( + primary_text=entry.get("name", entry.get("launch", "?")), + value_text="On" if active else "Off", + image_path=None, + image_path_selected=None, + description=entry.get("launch"), + icon=None, + value=lambda _input, script=entry: self._toggle_scene_script(script), + ) + ) + return options + + def _toggle_joystick(self, input_value): + if input_value in (ControllerInput.DPAD_LEFT, ControllerInput.L1): + TrimuiInputHelpers.set_joystick_mode(False) + elif input_value in (ControllerInput.DPAD_RIGHT, ControllerInput.R1, ControllerInput.A): + TrimuiInputHelpers.set_joystick_mode(True) + + def _show_diagnostics(self, _input): + lines = [ + Language.get("fnDiagnostics", "Diagnostics"), + f"DIP: {self._read_file(GPIO363_VALUE, '?')}", + f"Thermal: {self._read_file(THERMAL_PROFILE, '?')}", + f"Fan: {self._read_file(FAN_STATE, '?')}", + f"CPU4: {self._cpu4_summary()}", + f"Scenes: {self._scene_summary()}", + f"CPU scene: {self._process_count('com.trimui.cpuperformance.sh')}", + ] + Display.display_message("\n".join(lines), duration_ms=7000) + + def _dip_state_label(self): + state = self._read_file(GPIO363_VALUE, "?") + if state == "1": + return "On" + if state == "0": + return "Off" + return state + + def _read_file(self, path, default=""): + try: + with open(path, "r", encoding="utf-8") as f: + return f.read().strip() or default + except Exception: + return default + + def _cpu4_summary(self): + governor = self._read_file(os.path.join(CPU4_DIR, "scaling_governor"), "?") + min_freq = self._read_file(os.path.join(CPU4_DIR, "scaling_min_freq"), "?") + max_freq = self._read_file(os.path.join(CPU4_DIR, "scaling_max_freq"), "?") + cur_freq = self._read_file(os.path.join(CPU4_DIR, "scaling_cur_freq"), "?") + return f"{governor} {min_freq}-{max_freq} ({cur_freq})" + + def _scene_summary(self): + try: + names = sorted(name for name in os.listdir(SCENE_DIR) if name.endswith(".sh")) + except Exception: + return "?" + if not names: + return "None" + return ", ".join(names[:3]) + ("..." if len(names) > 3 else "") + + def _process_count(self, pattern): + try: + output = subprocess.check_output(["pgrep", "-f", pattern], stderr=subprocess.DEVNULL, text=True) + count = len([line for line in output.splitlines() if line.strip()]) + except Exception: + count = 0 + return str(count) + + def _load_scripts(self, filename): + path = os.path.join(FN_EDITOR_DIR, filename) + if not os.path.isfile(path): + path = os.path.join(STOCK_FN_EDITOR_DIR, filename) + try: + with open(path, "r", encoding="utf-8") as f: + data = json.load(f) + if isinstance(data, list): + return data + except Exception as e: + PyUiLogger.get_logger().error(f"Cannot read {path}: {e}") + return [] + + def _scene_script_path(self, entry): + launch = entry.get("launch") + if not launch: + return None + return os.path.join(SCENE_DIR, os.path.basename(launch)) + + def _is_scene_script_enabled(self, entry): + script = self._scene_script_path(entry) + return script is not None and os.path.exists(script) + + def _toggle_scene_script(self, entry): + target = self._scene_script_path(entry) + launch = entry.get("launch") + if not target or not launch: + return + source = os.path.join(FN_EDITOR_DIR, launch) + if not os.path.isfile(source): + source = os.path.join(STOCK_FN_EDITOR_DIR, launch) + os.makedirs(SCENE_DIR, exist_ok=True) + if os.path.exists(target): + self._run_switch_script(target, "0") + time.sleep(0.5) + subprocess.run(f"pkill -f {launch}", shell=True) + try: + os.remove(target) + except Exception as e: + PyUiLogger.get_logger().error(f"Failed to remove target: {e}") + self._restart_trimui_service("trimui_scened") + return + if not os.path.isfile(source): + PyUiLogger.get_logger().error(f"Fn switch script missing: {source}") + return + subprocess.run(f"pkill -f {launch}", shell=True) + shutil.copy(source, target) + os.chmod(target, 0o755) + self._run_switch_script(target, "1") + self._restart_trimui_service("trimui_scened") + + def _run_switch_script(self, script, state): + try: + subprocess.Popen( + ["sh", script, state], + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except Exception as e: + PyUiLogger.get_logger().error(f"Failed to run switch script {script}: {e}") + + def _restart_trimui_service(self, service): + try: + subprocess.Popen( + f"killall -9 {service} 2>/dev/null; cd /usr/trimui/bin; LD_LIBRARY_PATH=/usr/trimui/lib ./{service} &", + shell=True, + stdout=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + ) + except Exception as e: + PyUiLogger.get_logger().error(f"Failed to restart {service}: {e}") + + def _run_fn_script(self, launch, extra_arg): + script = os.path.join(FN_EDITOR_DIR, launch) + if not os.path.isfile(script): + PyUiLogger.get_logger().error(f"Fn script missing: {script}") + return + try: + cmd = ["sh", script] + if extra_arg is not None: + cmd.append(extra_arg) + subprocess.run(cmd, cwd=FN_EDITOR_DIR, check=False, timeout=10) + except Exception as e: + PyUiLogger.get_logger().error(f"Fn script failed {script}: {e}") diff --git a/App/PyUI/main-ui/menus/apps/trimui_input_helpers.py b/App/PyUI/main-ui/menus/apps/trimui_input_helpers.py new file mode 100644 index 000000000..b43166bfe --- /dev/null +++ b/App/PyUI/main-ui/menus/apps/trimui_input_helpers.py @@ -0,0 +1,87 @@ +import os + + +class TrimuiInputHelpers: + INPUT_DIR = "/tmp/trimui_inputd" + NO_DPAD = f"{INPUT_DIR}/input_no_dpad" + DPAD_TO_JOYSTICK = f"{INPUT_DIR}/input_dpad_to_joystick" + MUTED_FLAG = "/tmp/system/muted" + LED_ENABLE = "/tmp/system/enable_led" + + @classmethod + def ensure_input_dir(cls): + os.makedirs(cls.INPUT_DIR, exist_ok=True) + + @classmethod + def is_joystick_mode(cls) -> bool: + return os.path.exists(cls.NO_DPAD) and os.path.exists(cls.DPAD_TO_JOYSTICK) + + @classmethod + def set_joystick_mode(cls, enabled: bool): + cls.ensure_input_dir() + if enabled: + open(cls.NO_DPAD, "a").close() + open(cls.DPAD_TO_JOYSTICK, "a").close() + else: + for path in (cls.NO_DPAD, cls.DPAD_TO_JOYSTICK): + if os.path.exists(path): + os.remove(path) + + @classmethod + def is_silent_mode(cls) -> bool: + return os.path.exists(cls.MUTED_FLAG) + + @classmethod + def set_silent_mode(cls, enabled: bool): + os.makedirs(os.path.dirname(cls.MUTED_FLAG), exist_ok=True) + try: + with open("/sys/class/speaker/mute", "w") as f: + f.write("1" if enabled else "0") + except OSError: + pass + if enabled: + open(cls.MUTED_FLAG, "a").close() + elif os.path.exists(cls.MUTED_FLAG): + os.remove(cls.MUTED_FLAG) + + @classmethod + def is_quiet_mode(cls) -> bool: + import subprocess + try: + result = subprocess.run( + ["tinymix", "get", "9"], + capture_output=True, + text=True, + timeout=2, + ) + return ">> 4" in result.stdout or ": 4" in result.stdout + except Exception: + return False + + @classmethod + def set_quiet_mode(cls, enabled: bool): + import subprocess + try: + subprocess.run( + ["tinymix", "set", "9", "4" if enabled else "1"], + check=False, + timeout=2, + ) + except Exception: + pass + + @classmethod + def is_led_enabled(cls) -> bool: + if not os.path.exists(cls.LED_ENABLE): + return True + try: + with open(cls.LED_ENABLE, "r", encoding="utf-8") as f: + return f.read().strip() != "0" + except OSError: + return True + + @classmethod + def set_led_enabled(cls, enabled: bool): + os.makedirs(os.path.dirname(cls.LED_ENABLE), exist_ok=True) + with open(cls.LED_ENABLE, "w", encoding="utf-8") as f: + f.write("1" if enabled else "0") diff --git a/App/PyUI/main-ui/menus/apps/video_player_app.py b/App/PyUI/main-ui/menus/apps/video_player_app.py new file mode 100644 index 000000000..86260b057 --- /dev/null +++ b/App/PyUI/main-ui/menus/apps/video_player_app.py @@ -0,0 +1,301 @@ +import json +import os +import re +import time + +from controller.controller import Controller +from controller.controller_inputs import ControllerInput +from devices.device import Device +from display.on_screen_keyboard import OnScreenKeyboard +from display.display import Display +from menus.language.language import Language +from utils.logger import PyUiLogger +from utils.py_ui_config import PyUiConfig +from views.grid_or_list_entry import GridOrListEntry +from views.selection import Selection +from views.view_creator import ViewCreator +from views.view_type import ViewType + +VIDEO_EXTENSIONS = { + ".mp4", ".mkv", ".avi", ".mov", ".flv", ".ts", ".webm", + ".m4v", ".wmv", ".mpeg", ".mpg", ".3gp", +} +MEDIA_LAUNCH = "/mnt/SDCARD/Emu/MEDIA/../../spruce/scripts/emu/standard_launch.sh" +VIDEO_CACHE = "/mnt/SDCARD/Saves/spruce/video-index.json" + + +class VideoPlayerApp: + def _video_root(self): + return PyUiConfig.get_video_root_path() + + def run(self, _input=None): + video_root = self._video_root() + os.makedirs(video_root, exist_ok=True) + Controller.clear_input_queue() + time.sleep(0.2) + options = [ + GridOrListEntry( + primary_text=Language.get("browseVideos", "Browse videos"), + description=Language.get("openMediaFolder", "Open Roms/MEDIA"), + value=self._browse_root, + ), + GridOrListEntry( + primary_text=Language.get("searchVideos", "Search videos"), + description=Language.get("findVideosByName", "Find videos by name"), + value=self._search_videos, + ), + GridOrListEntry( + primary_text=Language.get("refreshVideoIndex", "Refresh video index"), + description=Language.get("refreshVideoIndexDesc", "Rebuild cached video search list"), + value=self._refresh_index, + ), + GridOrListEntry( + primary_text=Language.get("videoControls", "Controls"), + description=Language.get("videoControlsDesc", "Playback button guide"), + value=self._show_controls, + ), + ] + selected = Selection(None, None, 0) + view = ViewCreator.create_view( + view_type=ViewType.ICON_AND_DESC, + top_bar_text=Language.get("videoPlayer", "Video Player"), + options=options, + selected_index=selected.get_index(), + ) + while True: + picked = view.get_selection([ControllerInput.A, ControllerInput.B]) + if picked.get_input() == ControllerInput.B: + return + if picked.get_input() == ControllerInput.A: + picked.get_selection().get_value()() + Controller.clear_input_queue() + time.sleep(0.2) + + def _browse_root(self): + video_root = self._video_root() + self._browse(video_root, video_root) + + def _show_controls(self): + Display.display_message( + Language.get( + "videoControlsHelp", + "Playback controls:\nB: Pause/Resume\nLeft/Right: Seek\nUp/Down: Prev/Next\nMENU: Exit player\n\nBrowser:\nX: Refresh\nB: Back", + ), + duration_ms=5000, + ) + + def _search_videos(self): + query = OnScreenKeyboard().get_input(Language.get("videoSearch", "Video Search:")) + if not query: + return + matches = self._search_entries(query) + if not matches: + Display.display_message(Language.get("noMatchingVideos", "No matching videos.")) + return + selected = Selection(None, None, 0) + view = ViewCreator.create_view( + view_type=ViewType.ICON_AND_DESC, + top_bar_text=Language.get("videoSearchTitle", "Video Search"), + options=self._entries_to_options(matches), + selected_index=selected.get_index(), + ) + while selected is not None: + picked = view.get_selection([ControllerInput.A, ControllerInput.B]) + if picked.get_input() == ControllerInput.B: + return + if picked.get_input() == ControllerInput.A: + self._play_video(picked.get_selection().get_extra_data()["path"]) + return + + def _refresh_index(self): + entries = self._build_video_index() + self._write_video_index(entries) + Display.display_message( + Language.get("videoIndexUpdated", "Video index updated") + f"\n{len(entries)} files", + duration_ms=2500, + ) + + def _browse(self, current_dir, root_dir): + selected = Selection(None, None, 0) + while selected is not None: + entries = self._list_entries(current_dir, root_dir) + options = self._entries_to_options(entries) + + view = ViewCreator.create_view( + view_type=ViewType.ICON_AND_DESC, + top_bar_text=os.path.basename(current_dir.rstrip("/")) or Language.get("videos", "Videos"), + options=options, + selected_index=selected.get_index(), + ) + picked = view.get_selection([ControllerInput.A, ControllerInput.B, ControllerInput.X]) + if picked.get_input() == ControllerInput.X: + self._refresh_index() + selected = Selection(None, None, picked.get_index()) + continue + if picked.get_input() == ControllerInput.B: + if current_dir == root_dir: + return + current_dir = os.path.dirname(current_dir.rstrip("/")) or root_dir + selected = Selection(None, None, 0) + continue + if picked.get_input() == ControllerInput.A: + entry = picked.get_selection().get_extra_data() + kind = entry.get("kind") + if kind == "up": + current_dir = os.path.dirname(current_dir.rstrip("/")) or root_dir + selected = Selection(None, None, 0) + elif kind == "dir": + self._browse(entry["path"], root_dir) + selected = Selection(None, None, picked.get_index()) + elif kind == "file": + self._play_video(entry["path"]) + return + + def _list_entries(self, current_dir, root_dir): + entries = [] + if current_dir != root_dir: + entries.append( + { + "label": "..", + "description": Language.get("parentFolder", "Parent folder"), + "kind": "up", + } + ) + + try: + names = sorted(os.listdir(current_dir), key=str.lower) + except OSError as e: + PyUiLogger.get_logger().error(f"Cannot list {current_dir}: {e}") + return entries + + for name in names: + if name.startswith("."): + continue + path = os.path.join(current_dir, name) + if os.path.isdir(path): + entries.append( + { + "label": f"[{name}]", + "description": Language.get("folder", "Folder"), + "kind": "dir", + "path": path, + } + ) + elif self._is_video_file(name): + entries.append( + { + "label": name, + "description": Language.get("playVideo", "Play video"), + "kind": "file", + "path": path, + } + ) + return entries + + def _entries_to_options(self, entries): + options = [] + for entry in entries: + options.append( + GridOrListEntry( + primary_text=entry["label"], + value_text=None, + image_path=None, + image_path_selected=None, + description=entry.get("description"), + icon=None, + extra_data=entry, + value=0, + ) + ) + return options + + def _search_entries(self, query): + matches = [] + query = query.lower() + for item in self._load_or_build_video_index(): + name = item.get("name", "") + path = item.get("path", "") + if query not in name.lower() or not os.path.isfile(path): + continue + rel_dir = item.get("folder", ".") + matches.append( + { + "label": name, + "description": Language.get("playVideo", "Play video") if rel_dir == "." else rel_dir, + "kind": "file", + "path": path, + } + ) + return matches + + def _load_or_build_video_index(self): + entries = self._read_video_index() + if entries is None: + entries = self._build_video_index() + self._write_video_index(entries) + return entries + + def _read_video_index(self): + try: + if not os.path.isfile(VIDEO_CACHE): + return None + cache_mtime = os.path.getmtime(VIDEO_CACHE) + root_mtime = os.path.getmtime(self._video_root()) + if root_mtime > cache_mtime: + return None + with open(VIDEO_CACHE, "r", encoding="utf-8") as f: + data = json.load(f) + entries = data.get("entries") + return entries if isinstance(entries, list) else None + except Exception as e: + PyUiLogger.get_logger().error(f"Cannot read video index: {e}") + return None + + def _write_video_index(self, entries): + try: + os.makedirs(os.path.dirname(VIDEO_CACHE), exist_ok=True) + with open(VIDEO_CACHE, "w", encoding="utf-8") as f: + json.dump({"created": int(time.time()), "entries": entries}, f) + except Exception as e: + PyUiLogger.get_logger().error(f"Cannot write video index: {e}") + + def _build_video_index(self): + entries = [] + video_root = self._video_root() + for dirpath, dirnames, filenames in os.walk(video_root): + dirnames[:] = [name for name in dirnames if not name.startswith(".")] + for name in sorted(filenames, key=str.lower): + if name.startswith(".") or not self._is_video_file(name): + continue + path = os.path.join(dirpath, name) + try: + stat = os.stat(path) + except OSError: + continue + entries.append( + { + "name": name, + "path": path, + "folder": os.path.relpath(dirpath, video_root), + "mtime": int(stat.st_mtime), + "size": stat.st_size, + } + ) + return entries + + def _is_video_file(self, name): + _, ext = os.path.splitext(name.lower()) + return ext in VIDEO_EXTENSIONS + + def _play_video(self, path): + from devices.miyoo_trim_common import MiyooTrimCommon + + if not os.path.isfile(MEDIA_LAUNCH): + Display.display_message(Language.get("mediaLauncherMissing", "Media launcher missing.")) + return + + escaped = re.sub(r'([$`"\\])', r"\\\1", path) + cmd = f'chmod a+x "{MEDIA_LAUNCH}"; "{MEDIA_LAUNCH}" "{escaped}"' + Display.deinit_display() + MiyooTrimCommon.write_cmd_to_run(cmd) + Device.get_device().exit_pyui() diff --git a/App/PyUI/main-ui/utils/py_ui_config.py b/App/PyUI/main-ui/utils/py_ui_config.py index 918fb03f7..8afe302bd 100644 --- a/App/PyUI/main-ui/utils/py_ui_config.py +++ b/App/PyUI/main-ui/utils/py_ui_config.py @@ -201,6 +201,10 @@ def get_wpa_supplicant_conf_file_location(cls, default_path): @classmethod def get_activity_log_path(cls): return cls.get("activityLogPath",None) + + @classmethod + def get_video_root_path(cls): + return cls.get("videoRootPath", "/mnt/SDCARD/Roms/MEDIA") @classmethod def get_about_entries(cls): diff --git a/App/PyUI/py-ui-config.json b/App/PyUI/py-ui-config.json index 758f461e9..7f3aeb967 100644 --- a/App/PyUI/py-ui-config.json +++ b/App/PyUI/py-ui-config.json @@ -13,6 +13,7 @@ "cfwTasks": "/mnt/SDCARD/App/PyUI/spruce-tasks.json", "wpaSupplicantConfigFileLocation": "/mnt/SDCARD/Saves/spruce/wpa_supplicant.conf", "activityLogPath":"/mnt/SDCARD/Saves/spruce/activity.jsonl", + "videoRootPath":"/mnt/SDCARD/Roms/MEDIA", "screensaverTimeoutSec": 120, "poweroffCmd":"/mnt/SDCARD/spruce/scripts/save_poweroff.sh", "rebootCmd":"/mnt/SDCARD/App/PyUI/reboot-spruce.sh", @@ -22,16 +23,16 @@ "cmd":"cat /mnt/SDCARD/spruce/spruce" }, { - "display":"RetroArch version", - "cmd":"/mnt/SDCARD/App/PyUI/get-ra-version.sh" + "display":"RetroArch version", + "cmd":"/mnt/SDCARD/App/PyUI/get-ra-version.sh" }, { - "display":"PPSSPP version", - "cmd":"/mnt/SDCARD/App/PyUI/get-psp-version.sh" + "display":"PPSSPP version", + "cmd":"/mnt/SDCARD/App/PyUI/get-psp-version.sh" }, { - "display":"SD Card usage", - "cmd":"/mnt/SDCARD/App/PyUI/get-sdcard-usage.sh" + "display":"SD Card usage", + "cmd":"/mnt/SDCARD/App/PyUI/get-sdcard-usage.sh" } ] } diff --git a/App/VideoPlayer/config.json b/App/VideoPlayer/config.json new file mode 100644 index 000000000..fc1ceff85 --- /dev/null +++ b/App/VideoPlayer/config.json @@ -0,0 +1,9 @@ +{ + "label": "Video Player", + "icon": "icon.png", + "launch": "launch.sh", + "description": "Deprecated: use PyUI Video Player in Apps menu", + "hide": true, + "devices": ["TRIMUI_BRICK", "TRIMUI_SMART_PRO", "TRIMUI_SMART_PRO_S"], + "hideInSimpleMode": false +} diff --git a/App/VideoPlayer/icon.png b/App/VideoPlayer/icon.png new file mode 100644 index 000000000..ad70fed11 Binary files /dev/null and b/App/VideoPlayer/icon.png differ diff --git a/App/VideoPlayer/launch.sh b/App/VideoPlayer/launch.sh new file mode 100644 index 000000000..83772c0d8 --- /dev/null +++ b/App/VideoPlayer/launch.sh @@ -0,0 +1,15 @@ +#!/bin/sh + +. /mnt/SDCARD/spruce/scripts/helperFunctions.sh + +PLAYER="/usr/trimui/apps/player/launch.sh" + +if [ ! -f "$PLAYER" ]; then + log_message "TrimUI Video Player not found at $PLAYER" + exit 1 +fi + +export LD_LIBRARY_PATH="/usr/trimui/lib:${LD_LIBRARY_PATH}" +chmod +x "$PLAYER" +cd "$(dirname "$PLAYER")" || exit 1 +exec "$PLAYER" diff --git a/App/fn_editor/com.trimui.cpuperformance.sh b/App/fn_editor/com.trimui.cpuperformance.sh new file mode 100644 index 000000000..29253e99e --- /dev/null +++ b/App/fn_editor/com.trimui.cpuperformance.sh @@ -0,0 +1,49 @@ +#!/bin/sh +echo "============= scene CPU Performance ============" + +THERMAL_PROFILE_PATH="/mnt/SDCARD/spruce/smartpros/etc/thermal-watchdog/active_profile" + +unlock_governor() { + for file in scaling_governor scaling_min_freq scaling_max_freq; do + chmod a+w "/sys/devices/system/cpu/cpu0/cpufreq/$file" 2>/dev/null + chmod a+w "/sys/devices/system/cpu/cpu4/cpufreq/$file" 2>/dev/null + done +} + +lock_governor() { + for file in scaling_governor scaling_min_freq scaling_max_freq; do + chmod a-w "/sys/devices/system/cpu/cpu0/cpufreq/$file" 2>/dev/null + chmod a-w "/sys/devices/system/cpu/cpu4/cpufreq/$file" 2>/dev/null + done +} + +set_cpu4() { + [ -d /sys/devices/system/cpu/cpu4/cpufreq ] || return + echo "$1" > /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor + echo -n "$2" > /sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq + echo -n "$3" > /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq +} + +set_thermal_profile() { + [ -f "$THERMAL_PROFILE_PATH" ] || return + echo "$1" > "$THERMAL_PROFILE_PATH" +} + +case "$1" in +1 ) + echo "cpu performance" + set_thermal_profile sport + unlock_governor + set_cpu4 performance 1992000 1992000 + lock_governor + ;; +0 ) + echo "cpu normal" + set_thermal_profile smart + unlock_governor + set_cpu4 ondemand 1008000 1992000 + lock_governor + ;; +*) + ;; +esac diff --git a/App/fn_editor/com.trimui.cpusave.sh b/App/fn_editor/com.trimui.cpusave.sh new file mode 100644 index 000000000..b6cc8f444 --- /dev/null +++ b/App/fn_editor/com.trimui.cpusave.sh @@ -0,0 +1,49 @@ +#!/bin/sh +echo "============= scene CPUFREQ ============" + +THERMAL_PROFILE_PATH="/mnt/SDCARD/spruce/smartpros/etc/thermal-watchdog/active_profile" + +unlock_governor() { + for file in scaling_governor scaling_min_freq scaling_max_freq; do + chmod a+w "/sys/devices/system/cpu/cpu0/cpufreq/$file" 2>/dev/null + chmod a+w "/sys/devices/system/cpu/cpu4/cpufreq/$file" 2>/dev/null + done +} + +lock_governor() { + for file in scaling_governor scaling_min_freq scaling_max_freq; do + chmod a-w "/sys/devices/system/cpu/cpu0/cpufreq/$file" 2>/dev/null + chmod a-w "/sys/devices/system/cpu/cpu4/cpufreq/$file" 2>/dev/null + done +} + +set_cpu4() { + [ -d /sys/devices/system/cpu/cpu4/cpufreq ] || return + echo "$1" > /sys/devices/system/cpu/cpu4/cpufreq/scaling_governor + echo -n "$2" > /sys/devices/system/cpu/cpu4/cpufreq/scaling_min_freq + echo -n "$3" > /sys/devices/system/cpu/cpu4/cpufreq/scaling_max_freq +} + +set_thermal_profile() { + [ -f "$THERMAL_PROFILE_PATH" ] || return + echo "$1" > "$THERMAL_PROFILE_PATH" +} + +case "$1" in +1 ) + echo "cpu save" + set_thermal_profile conservative + unlock_governor + set_cpu4 ondemand 1008000 1200000 + lock_governor + ;; +0 ) + echo "cpu normal" + set_thermal_profile smart + unlock_governor + set_cpu4 ondemand 1008000 1992000 + lock_governor + ;; +*) + ;; +esac diff --git a/App/fn_editor/icon.png b/App/fn_editor/icon.png new file mode 100644 index 000000000..eeca368d8 Binary files /dev/null and b/App/fn_editor/icon.png differ diff --git a/spruce/scripts/buttons_watchdog.sh b/spruce/scripts/buttons_watchdog.sh index c70aff8c5..49ed689ec 100644 --- a/spruce/scripts/buttons_watchdog.sh +++ b/spruce/scripts/buttons_watchdog.sh @@ -39,7 +39,7 @@ nearest_system_brightness() { done } -# Map the System Value to MainUI brightness level +# Map the System Value to MainUI brightness level get_brightness_level() { value=$(cat "$DEVICE_BRIGHTNESS_PATH") nearest=$(nearest_system_brightness "$value") @@ -100,6 +100,43 @@ volume_up_bg() { done } +run_dip_scene() { + state="$1" + echo "$(date '+%H:%M:%S') dip state $state" >> /tmp/buttons_watchdog_dip.log + [ -d /usr/trimui/scene ] || return 0 + + for scene in /usr/trimui/scene/*.sh; do + [ -f "$scene" ] || continue + echo "$(date '+%H:%M:%S') dip script $scene $state" >> /tmp/buttons_watchdog_dip.log + pkill -f "$(basename "$scene")" 2>/dev/null + sh "$scene" "$state" & + done +} + +dip_switch_bg() { + gpio="/sys/class/gpio/gpio363/value" + + if [ ! -f "$gpio" ]; then + echo 363 > /sys/class/gpio/export 2>/dev/null + echo -n in > /sys/class/gpio/gpio363/direction 2>/dev/null + fi + + last="" + while true; do + if [ -f "$gpio" ]; then + current="$(cat "$gpio" 2>/dev/null)" + if [ -n "$last" ] && [ "$current" != "$last" ]; then + run_dip_scene "$current" + fi + last="$current" + fi + sleep 0.2 + done +} + +dip_switch_bg & +DIP_WATCH_PID=$! + take_screenshot_bg() { timestamp=$(date '+_%Y.%m.%d_%H.%M.%S.%N.png') ss_name="/mnt/SDCARD/Saves/screenshots/$PLATFORM$timestamp" @@ -138,6 +175,7 @@ SS_B3_DOWN=false EVENTS="$EVENT_PATH_READ_INPUTS_SPRUCE" [ -n "$EVENT_PATH_VOLUME" ] && [ -c "$EVENT_PATH_VOLUME" ] && EVENTS="$EVENTS $EVENT_PATH_VOLUME" getevent $EVENTS | while read line; do + echo "$line" > /tmp/buttons_watchdog_last_event # first print event code to log file # handle hotkeys and volume buttons case $line in @@ -157,6 +195,18 @@ getevent $EVENTS | while read line; do brightness_up fi ;; + *"key $B_FN_LEFT 1"*) # Left Fn key down + fn_key_down left + ;; + *"key $B_FN_LEFT 0"*) # Left Fn key up + fn_key_up left + ;; + *"key $B_FN_RIGHT 1"*) # Right Fn key down + fn_key_down right + ;; + *"key $B_FN_RIGHT 0"*) # Right Fn key up + fn_key_up right + ;; *"key $SS_B1 1"*) # Screenshot key 1 down SS_B1_DOWN=true if [ "$SS_B2_DOWN" = true ] && [ "$SS_B3_DOWN" = true ] ; then @@ -217,3 +267,5 @@ getevent $EVENTS | while read line; do ;; esac done + +kill "$DIP_WATCH_PID" 2>/dev/null diff --git a/spruce/scripts/platform/SmartProS.cfg b/spruce/scripts/platform/SmartProS.cfg index 04f801d0a..3726eeafb 100644 --- a/spruce/scripts/platform/SmartProS.cfg +++ b/spruce/scripts/platform/SmartProS.cfg @@ -96,8 +96,10 @@ export B_L2="3 2 255" # 255 on push, 0 on release export B_R1="1 311" export B_R2="3 5 255" # 255 on push, 0 on release -export B_L3="1 317" # also logs left fnkey stuff -export B_R3="1 318" # also logs right fnkey stuff +export B_L3="1 317" +export B_R3="1 318" +export B_FN_LEFT="1 317" +export B_FN_RIGHT="1 318" export B_START="1 315" export B_START_2="enter_pressed" # only registers 0 on release, no 1. diff --git a/spruce/scripts/platform/device.sh b/spruce/scripts/platform/device.sh index 944f5918f..84cf02222 100644 --- a/spruce/scripts/platform/device.sh +++ b/spruce/scripts/platform/device.sh @@ -316,6 +316,14 @@ device_home_button_pressed() { log_message "Missing device_home_button_pressed function" -v } +fn_key_down() { + : +} + +fn_key_up() { + : +} + device_wifi_power_on() { log_message "Missing device_wifi_power_on function" -v } diff --git a/spruce/scripts/platform/device_functions/SmartProS.sh b/spruce/scripts/platform/device_functions/SmartProS.sh index d024c3136..78486e849 100644 --- a/spruce/scripts/platform/device_functions/SmartProS.sh +++ b/spruce/scripts/platform/device_functions/SmartProS.sh @@ -108,6 +108,36 @@ set_volume() { } +run_fn_config() { + config="$1" + echo "$(date '+%H:%M:%S') fn config $config" >> /tmp/buttons_watchdog_fn.log + [ -f "$config" ] || return 0 + + launch=$(jq -r '.launch // empty' "$config" 2>/dev/null) + echo "$(date '+%H:%M:%S') fn launch $launch" >> /tmp/buttons_watchdog_fn.log + [ -n "$launch" ] || return 0 + + case "$launch" in + */*) script="$launch" ;; + *) script="/mnt/SDCARD/App/fn_editor/$launch" ;; + esac + + [ -f "$script" ] || return 0 + echo "$(date '+%H:%M:%S') fn script $script" >> /tmp/buttons_watchdog_fn.log + sh "$script" & +} + +fn_key_down() { + case "$1" in + left) run_fn_config "/usr/trimui/fnkeys/f1key.json" ;; + right) run_fn_config "/usr/trimui/fnkeys/f2key.json" ;; + esac +} + +fn_key_up() { + : +} + get_volume_level() { jq -r '.vol' "$SYSTEM_JSON"