Skip to content

Commit 4aa2246

Browse files
authored
Merge pull request #1564 from vigstudio/feature/vietnamese-i18n
Improve Vietnamese language pack with bundled fonts and i18n infrastructure
2 parents 1d9489b + 64afe0b commit 4aa2246

50 files changed

Lines changed: 1644 additions & 539 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
130 KB
Binary file not shown.
134 KB
Binary file not shown.

App/PyUI/fonts/README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
# PyUI bundled fonts
2+
3+
Fonts in this folder can be referenced from language packs via the `fonts` object in `App/PyUI/lang/<Language>.json`.
4+
5+
## Vietnamese (`Vietnamese.json`)
6+
7+
- **Be Vietnam Pro** — menus, lists, grid, and shadowed text (supports Vietnamese diacritics)
8+
9+
## Files
10+
11+
| File | Use |
12+
|------|-----|
13+
| `BeVietnamPro-Regular.ttf` | Body text, menus, lists, grid |
14+
| `BeVietnamPro-SemiBold.ttf` | Shadowed / emphasized text |
15+
16+
License text: `Licenses/fonts/bevietnampro.txt`

App/PyUI/lang/English.json

Lines changed: 319 additions & 4 deletions
Large diffs are not rendered by default.

App/PyUI/lang/Vietnamese.json

Lines changed: 616 additions & 121 deletions
Large diffs are not rendered by default.

App/PyUI/main-ui/devices/device_common.py

Lines changed: 21 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from pathlib import Path
1010
from audio.audio_player_none import AudioPlayerNone
1111
from controller.controller_inputs import ControllerInput
12+
from menus.language.language import Language
1213
from devices.abstract_device import AbstractDevice
1314
from devices.miyoo.device_user_config import DeviceUserConfig
1415
from devices.utils.process_runner import ProcessRunner
@@ -38,11 +39,11 @@ def prompt_power_down(self):
3839
while(True):
3940
PyUiLogger.get_logger().info("Prompting for shutdown")
4041
Display.clear("Power")
41-
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)
42+
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)
4243
if(self.reboot_cmd() is not None):
43-
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)
44+
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)
4445
else:
45-
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)
46+
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)
4647
Display.present()
4748
if(Controller.get_input()):
4849
if(Controller.last_input() == ControllerInput.A):
@@ -248,7 +249,11 @@ def get_wifi_status(self):
248249
if not self.is_wifi_enabled():
249250
return WifiStatus.OFF
250251

251-
if self.get_ip_addr_text() in ["Off", "Error", "Connecting"]:
252+
if self.get_ip_addr_text() in [
253+
Language.label("wifiStatusOff", "Off"),
254+
Language.label("wifiStatusError", "Error"),
255+
Language.label("wifiStatusConnecting", "Connecting"),
256+
]:
252257
return WifiStatus.OFF
253258

254259
info = self.get_wifi_connection_quality_info()
@@ -300,15 +305,15 @@ def start_wifi_services(self, foreground_call=False):
300305
if not self.connection_seems_up():
301306
PyUiLogger.get_logger().info("Starting WiFi Services")
302307
if(foreground_call):
303-
Display.display_message("Turning on WiFi Power")
308+
Display.display_message(Language.label("turningOnWifiPower", "Turning on WiFi Power"))
304309

305310
self.set_wifi_power(1)
306311
time.sleep(1)
307312
if(foreground_call):
308-
Display.display_message("Starting WiFi process")
313+
Display.display_message(Language.label("startingWifiProcess", "Starting WiFi process"))
309314
self.start_wpa_supplicant()
310315
if(foreground_call):
311-
Display.display_message("Starting ip address assignment process")
316+
Display.display_message(Language.label("startingIpAssignment", "Starting ip address assignment process"))
312317
self.start_udhcpc()
313318

314319

@@ -317,7 +322,7 @@ def get_ip_addr_text(self):
317322
import subprocess
318323

319324
if not self.is_wifi_enabled():
320-
return "Off"
325+
return Language.label("wifiStatusOff", "Off")
321326

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

338-
return "Connecting"
343+
return Language.label("wifiStatusConnecting", "Connecting")
339344

340345
except Exception:
341-
return "Error"
346+
return Language.label("wifiStatusError", "Error")
342347

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

469474
def get_fw_version(self):
470-
return "Unknown"
475+
return Language.label("aboutUnknown", "Unknown")
471476

472477
def get_about_info_entries(self):
473478
about_info_entries = []
474-
about_info_entries.append( ("IP Address", self.get_ip_addr_text()) )
475-
about_info_entries.append( ("Mac Address", self.get_mac_address()) )
476-
about_info_entries.append( ("FW Version",self.get_fw_version()) )
479+
about_info_entries.append( (Language.label("aboutIpAddress", "IP Address"), self.get_ip_addr_text()) )
480+
about_info_entries.append( (Language.label("aboutMacAddress", "Mac Address"), self.get_mac_address()) )
481+
about_info_entries.append( (Language.label("aboutFwVersion", "FW Version"),self.get_fw_version()) )
477482
about_info_entries.extend(self.get_device_specific_about_info_entries())
478483
return about_info_entries
479484

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

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

519524
def sync_hw_clock(self):
520525
#Is this different per device? Should be right for the tina linux handhelds at least

App/PyUI/main-ui/devices/gkd/connman_wifi_menu.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,12 +71,17 @@ def connman_connect(self, id_str: str):
7171
def switch_network(self, net: WiFiNetwork):
7272
PyUiLogger.get_logger().info(f"Selected {net.ssid}!")
7373
if(net.requires_password()):
74-
password = self.on_screen_keyboard.get_input("WiFi Password")
74+
password = self.on_screen_keyboard.get_input(Language.label("wifiPassword", "WiFi Password"))
7575
if(password is not None and 8 <= len(password) <= 63):
7676
self.write_connman_conf(net, password)
77-
Display.display_message(f"Updating config file for {net.ssid} with password {password}", duration_ms=5000)
77+
Display.display_message(
78+
Language.label("updatingWifiConfig", "Updating config file for {ssid} with password {password}")
79+
.replace("{ssid}", net.ssid)
80+
.replace("{password}", password),
81+
duration_ms=5000,
82+
)
7883
else:
79-
Display.display_message("Invalid WiFi password length! Must be between 8 and 63", duration_ms=5000)
84+
Display.display_message(Language.label("invalidWifiPasswordLength", "Invalid WiFi password length! Must be between 8 and 63"), duration_ms=5000)
8085

8186
self.connman_connect(net.id_str)
8287

@@ -92,7 +97,7 @@ def _build_options(
9297
option_list.append(
9398
GridOrListEntry(
9499
primary_text=Language.status(),
95-
value_text="< " + ("On" if wifi_enabled else "Off") + " >",
100+
value_text="< " + Language.on_off_label(wifi_enabled) + " >",
96101
image_path=None,
97102
image_path_selected=None,
98103
description=None,
@@ -219,5 +224,5 @@ def _show_menu(self):
219224
time.sleep(0.05)
220225

221226
finally:
222-
Display.display_message("Stopping WiFi scanner...")
227+
Display.display_message(Language.label("stoppingWifiScanner", "Stopping WiFi scanner..."))
223228
self.wifi_scanner.stop()

App/PyUI/main-ui/devices/trimui/trim_ui_smart_pro_s.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
from devices.utils.file_watcher import FileWatcher
2020
from devices.utils.process_runner import ProcessRunner
2121
from display.display import Display
22+
from menus.language.language import Language
2223
from utils import throttle
2324
from utils.config_copier import ConfigCopier
2425

@@ -186,7 +187,7 @@ def _prepare_for_power_action(self):
186187
time.sleep(1)
187188

188189
def power_off(self):
189-
Display.display_message("Powering off...")
190+
Display.display_message(Language.label("poweringOff", "Powering off..."))
190191
self._prepare_for_power_action()
191192
time.sleep(1)
192193
super().power_off()
@@ -195,7 +196,7 @@ def power_off(self):
195196

196197

197198
def reboot(self):
198-
Display.display_message("Rebooting...")
199+
Display.display_message(Language.label("rebooting", "Rebooting..."))
199200
self._prepare_for_power_action()
200201
time.sleep(1)
201202
super().reboot()

App/PyUI/main-ui/mainui.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ def main():
221221
PyUiConfig.init(args.pyUiConfig)
222222
UserConfig.reload_config()
223223
CfwSystemConfig.init(args.cfwConfig)
224+
Language.init()
224225

225226
main_ui_mode = True
226227

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

252252
Device.get_device().perform_sdcard_ro_check()
253253

App/PyUI/main-ui/menus/app/app_menu.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ def append_pyui_apps(self, app_list):
5050
primary_text=boxart_scraper_config.get_label() + "(Hidden)" if AppsManager.is_hidden(boxart_scraper_config) else boxart_scraper_config.get_label(),
5151
image_path=None,
5252
image_path_selected=None,
53-
description="Scrape game boxart",
53+
description=Language.label("scrapeBoxartDesc", "Scrape game boxart"),
5454
icon=icon,
5555
extra_data=boxart_scraper_config,
5656
value=BoxArtScraper().scrape_boxart
@@ -66,7 +66,7 @@ def append_pyui_apps(self, app_list):
6666
primary_text=activity_tracker_config.get_label() + "(Hidden)" if AppsManager.is_hidden(activity_tracker_config) else activity_tracker_config.get_label(),
6767
image_path=None,
6868
image_path_selected=None,
69-
description="Track app usage",
69+
description=Language.label("trackAppUsageDesc", "Track app usage"),
7070
icon=icon,
7171
extra_data=activity_tracker_config,
7272
value=ActivityTracker().run_activity_tracking_app

0 commit comments

Comments
 (0)