Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added App/PyUI/fonts/BeVietnamPro-Regular.ttf
Binary file not shown.
Binary file added App/PyUI/fonts/BeVietnamPro-SemiBold.ttf
Binary file not shown.
16 changes: 16 additions & 0 deletions App/PyUI/fonts/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# PyUI bundled fonts

Fonts in this folder can be referenced from language packs via the `fonts` object in `App/PyUI/lang/<Language>.json`.

## Vietnamese (`Vietnamese.json`)

- **Be Vietnam Pro** — menus, lists, grid, and shadowed text (supports Vietnamese diacritics)

## Files

| File | Use |
|------|-----|
| `BeVietnamPro-Regular.ttf` | Body text, menus, lists, grid |
| `BeVietnamPro-SemiBold.ttf` | Shadowed / emphasized text |

License text: `Licenses/fonts/bevietnampro.txt`
323 changes: 319 additions & 4 deletions App/PyUI/lang/English.json

Large diffs are not rendered by default.

737 changes: 616 additions & 121 deletions App/PyUI/lang/Vietnamese.json

Large diffs are not rendered by default.

37 changes: 21 additions & 16 deletions App/PyUI/main-ui/devices/device_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from pathlib import Path
from audio.audio_player_none import AudioPlayerNone
from controller.controller_inputs import ControllerInput
from menus.language.language import Language
from devices.abstract_device import AbstractDevice
from devices.miyoo.device_user_config import DeviceUserConfig
from devices.utils.process_runner import ProcessRunner
Expand Down Expand Up @@ -38,11 +39,11 @@ def prompt_power_down(self):
while(True):
PyUiLogger.get_logger().info("Prompting for shutdown")
Display.clear("Power")
Display.render_text_centered(f"Would you like to power down?",self.screen_width()//2, self.screen_height()//2,Theme.text_color(FontPurpose.LIST), purpose=FontPurpose.LIST)
Display.render_text_centered(Language.label("powerDownPrompt", "Would you like to power down?"),self.screen_width()//2, self.screen_height()//2,Theme.text_color(FontPurpose.LIST), purpose=FontPurpose.LIST)
if(self.reboot_cmd() is not None):
Display.render_text_centered(f"A = Power Down, X = Reboot, B = Cancel",self.screen_width() //2, self.screen_height()//2+100,Theme.text_color(FontPurpose.LIST), purpose=FontPurpose.LIST)
Display.render_text_centered(Language.label("powerDownOptionsWithReboot", "A = Power Down, X = Reboot, B = Cancel"),self.screen_width() //2, self.screen_height()//2+100,Theme.text_color(FontPurpose.LIST), purpose=FontPurpose.LIST)
else:
Display.render_text_centered(f"A = Power Down, B = Cancel",self.screen_width() //2, self.screen_height()//2+100,Theme.text_color(FontPurpose.LIST), purpose=FontPurpose.LIST)
Display.render_text_centered(Language.label("powerDownOptions", "A = Power Down, B = Cancel"),self.screen_width() //2, self.screen_height()//2+100,Theme.text_color(FontPurpose.LIST), purpose=FontPurpose.LIST)
Display.present()
if(Controller.get_input()):
if(Controller.last_input() == ControllerInput.A):
Expand Down Expand Up @@ -248,7 +249,11 @@ def get_wifi_status(self):
if not self.is_wifi_enabled():
return WifiStatus.OFF

if self.get_ip_addr_text() in ["Off", "Error", "Connecting"]:
if self.get_ip_addr_text() in [
Language.label("wifiStatusOff", "Off"),
Language.label("wifiStatusError", "Error"),
Language.label("wifiStatusConnecting", "Connecting"),
]:
return WifiStatus.OFF

info = self.get_wifi_connection_quality_info()
Expand Down Expand Up @@ -300,15 +305,15 @@ def start_wifi_services(self, foreground_call=False):
if not self.connection_seems_up():
PyUiLogger.get_logger().info("Starting WiFi Services")
if(foreground_call):
Display.display_message("Turning on WiFi Power")
Display.display_message(Language.label("turningOnWifiPower", "Turning on WiFi Power"))

self.set_wifi_power(1)
time.sleep(1)
if(foreground_call):
Display.display_message("Starting WiFi process")
Display.display_message(Language.label("startingWifiProcess", "Starting WiFi process"))
self.start_wpa_supplicant()
if(foreground_call):
Display.display_message("Starting ip address assignment process")
Display.display_message(Language.label("startingIpAssignment", "Starting ip address assignment process"))
self.start_udhcpc()


Expand All @@ -317,7 +322,7 @@ def get_ip_addr_text(self):
import subprocess

if not self.is_wifi_enabled():
return "Off"
return Language.label("wifiStatusOff", "Off")

try:
# Query interface address
Expand All @@ -335,10 +340,10 @@ def get_ip_addr_text(self):
if line.startswith("inet "):
return line.split()[1].split("/")[0]

return "Connecting"
return Language.label("wifiStatusConnecting", "Connecting")

except Exception:
return "Error"
return Language.label("wifiStatusError", "Error")

def exit_pyui(self):
Display.deinit_display()
Expand Down Expand Up @@ -464,16 +469,16 @@ def get_mac_address(self,iface="wlan0"):
return f.read().strip()
except Exception as e:
PyUiLogger.get_logger().error(f"Could not read MAC address for interface {iface} : {e}")
return "Unknown"
return Language.label("aboutUnknown", "Unknown")

def get_fw_version(self):
return "Unknown"
return Language.label("aboutUnknown", "Unknown")

def get_about_info_entries(self):
about_info_entries = []
about_info_entries.append( ("IP Address", self.get_ip_addr_text()) )
about_info_entries.append( ("Mac Address", self.get_mac_address()) )
about_info_entries.append( ("FW Version",self.get_fw_version()) )
about_info_entries.append( (Language.label("aboutIpAddress", "IP Address"), self.get_ip_addr_text()) )
about_info_entries.append( (Language.label("aboutMacAddress", "Mac Address"), self.get_mac_address()) )
about_info_entries.append( (Language.label("aboutFwVersion", "FW Version"),self.get_fw_version()) )
about_info_entries.extend(self.get_device_specific_about_info_entries())
return about_info_entries

Expand Down Expand Up @@ -514,7 +519,7 @@ def is_filesystem_read_only(self,path="/mnt/SDCARD"):

def perform_sdcard_ro_check(self):
if self.is_filesystem_read_only("/mnt/SDCARD"):
Display.display_message("Warning: /mnt/SDCARD is read-only. Please check your SD card.", duration_ms=10000)
Display.display_message(Language.label("sdcardReadOnlyWarning", "Warning: /mnt/SDCARD is read-only. Please check your SD card."), duration_ms=10000)

def sync_hw_clock(self):
#Is this different per device? Should be right for the tina linux handhelds at least
Expand Down
15 changes: 10 additions & 5 deletions App/PyUI/main-ui/devices/gkd/connman_wifi_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,12 +71,17 @@ def connman_connect(self, id_str: str):
def switch_network(self, net: WiFiNetwork):
PyUiLogger.get_logger().info(f"Selected {net.ssid}!")
if(net.requires_password()):
password = self.on_screen_keyboard.get_input("WiFi Password")
password = self.on_screen_keyboard.get_input(Language.label("wifiPassword", "WiFi Password"))
if(password is not None and 8 <= len(password) <= 63):
self.write_connman_conf(net, password)
Display.display_message(f"Updating config file for {net.ssid} with password {password}", duration_ms=5000)
Display.display_message(
Language.label("updatingWifiConfig", "Updating config file for {ssid} with password {password}")
.replace("{ssid}", net.ssid)
.replace("{password}", password),
duration_ms=5000,
)
else:
Display.display_message("Invalid WiFi password length! Must be between 8 and 63", duration_ms=5000)
Display.display_message(Language.label("invalidWifiPasswordLength", "Invalid WiFi password length! Must be between 8 and 63"), duration_ms=5000)

self.connman_connect(net.id_str)

Expand All @@ -92,7 +97,7 @@ def _build_options(
option_list.append(
GridOrListEntry(
primary_text=Language.status(),
value_text="< " + ("On" if wifi_enabled else "Off") + " >",
value_text="< " + Language.on_off_label(wifi_enabled) + " >",
image_path=None,
image_path_selected=None,
description=None,
Expand Down Expand Up @@ -219,5 +224,5 @@ def _show_menu(self):
time.sleep(0.05)

finally:
Display.display_message("Stopping WiFi scanner...")
Display.display_message(Language.label("stoppingWifiScanner", "Stopping WiFi scanner..."))
self.wifi_scanner.stop()
5 changes: 3 additions & 2 deletions App/PyUI/main-ui/devices/trimui/trim_ui_smart_pro_s.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from devices.utils.file_watcher import FileWatcher
from devices.utils.process_runner import ProcessRunner
from display.display import Display
from menus.language.language import Language
from utils import throttle
from utils.config_copier import ConfigCopier

Expand Down Expand Up @@ -186,7 +187,7 @@ def _prepare_for_power_action(self):
time.sleep(1)

def power_off(self):
Display.display_message("Powering off...")
Display.display_message(Language.label("poweringOff", "Powering off..."))
self._prepare_for_power_action()
time.sleep(1)
super().power_off()
Expand All @@ -195,7 +196,7 @@ def power_off(self):


def reboot(self):
Display.display_message("Rebooting...")
Display.display_message(Language.label("rebooting", "Rebooting..."))
self._prepare_for_power_action()
time.sleep(1)
super().reboot()
Expand Down
2 changes: 1 addition & 1 deletion App/PyUI/main-ui/mainui.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,7 @@ def main():
PyUiConfig.init(args.pyUiConfig)
UserConfig.reload_config()
CfwSystemConfig.init(args.cfwConfig)
Language.init()

main_ui_mode = True

Expand All @@ -247,7 +248,6 @@ def main():
#2nd init is just to allow scaling if needed
Theme.convert_theme_if_needed(selected_theme, Device.get_device().screen_width(), Device.get_device().screen_height())
Controller.init()
Language.init()

Device.get_device().perform_sdcard_ro_check()

Expand Down
4 changes: 2 additions & 2 deletions App/PyUI/main-ui/menus/app/app_menu.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def append_pyui_apps(self, app_list):
primary_text=boxart_scraper_config.get_label() + "(Hidden)" if AppsManager.is_hidden(boxart_scraper_config) else boxart_scraper_config.get_label(),
image_path=None,
image_path_selected=None,
description="Scrape game boxart",
description=Language.label("scrapeBoxartDesc", "Scrape game boxart"),
icon=icon,
extra_data=boxart_scraper_config,
value=BoxArtScraper().scrape_boxart
Expand All @@ -66,7 +66,7 @@ def append_pyui_apps(self, app_list):
primary_text=activity_tracker_config.get_label() + "(Hidden)" if AppsManager.is_hidden(activity_tracker_config) else activity_tracker_config.get_label(),
image_path=None,
image_path_selected=None,
description="Track app usage",
description=Language.label("trackAppUsageDesc", "Track app usage"),
icon=icon,
extra_data=activity_tracker_config,
value=ActivityTracker().run_activity_tracking_app
Expand Down
5 changes: 3 additions & 2 deletions App/PyUI/main-ui/menus/common/bottom_bar.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from devices.device import Device
from display.font_purpose import FontPurpose
from display.render_mode import RenderMode
from menus.language.language import Language
from themes.theme import Theme
from utils.logger import PyUiLogger

Expand Down Expand Up @@ -46,7 +47,7 @@ def render_standard_bottom_bar(self):

if(Theme.show_bottom_bar_buttons()):
confirm_text_y = bottom_icons_y - confirm_icon_h//2
confirm_text_w, confirm_text_h = Display.render_text(Theme.confirm_text(),
confirm_text_w, confirm_text_h = Display.render_text(Language.label("confirmText", Theme.confirm_text()),
x_offset,
confirm_text_y,
Theme.text_color(FontPurpose.DESCRIPTIVE_LIST_TITLE),
Expand All @@ -59,7 +60,7 @@ def render_standard_bottom_bar(self):
back_icon, x_offset, bottom_icons_y, RenderMode.BOTTOM_LEFT_ALIGNED)
x_offset += padding + back_icon_w
back_text_y = bottom_icons_y - back_icon_h//2
back_text_w, back_text_h = Display.render_text(Theme.back_text(),
back_text_w, back_text_h = Display.render_text(Language.label("backText", Theme.back_text()),
x_offset,
back_text_y,
Theme.text_color(FontPurpose.DESCRIPTIVE_LIST_TITLE),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ def add_to_collection(self, collection_name):
CollectionsManager.add_game_to_collection(collection_name, self.rom_info)

def create_new_collection_and_add_to(self):
collection_name = OnScreenKeyboard().get_input("Collection Name:")
collection_name = OnScreenKeyboard().get_input(Language.label("collectionName", "Collection Name:"))
if(collection_name is not None and collection_name != ""):
self.add_to_collection(collection_name)

Expand All @@ -43,7 +43,7 @@ def build_options_list(self):
for collection_name in collections_containing:
option_list.append(
GridOrListEntry(
primary_text="Add to " + collection_name,
primary_text=Language.add_to() + " " + collection_name,
value_text="",
image_path=None,
image_path_selected=None,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def build_options_list(self):
for collection_name in collections_containing:
option_list.append(
GridOrListEntry(
primary_text="Remove from " + collection_name,
primary_text=Language.remove_from() + " " + collection_name,
value_text="",
image_path=None,
image_path_selected=None,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import json
import os

from menus.language.language import Language
from utils.logger import PyUiLogger

class FileBasedGameSystemConfig():
Expand All @@ -27,7 +28,8 @@ def get_emu_folder(self):
return self.emu_folder

def get_label(self):
return self._data.get('label')
raw_label = self._data.get('label')
return Language.game_system_label(self.system_name, raw_label)

def get_icon(self):
return self._data.get('icon')
Expand Down
Loading