Files
spoopyghosty0--frameport/tests/test_device_language.py
T
spoopyghosty0 3c43b0fb5d Per-game language setting (device.language, #354)
Lepton's Android is set to English (US), so games that follow the system language start in English.
device.language (Customize -> Game language) sets persist.sys.locale through its own LEPTON_GFXRECON_*
boot-property line, like device.hide_navbar. Verified on the Frame: the container reports de-DE and the
game's VM starts with user.locale=de-DE.
2026-10-17 14:32:16 -04:00

77 lines
3.3 KiB
Python

"""device.language (GitHub #354): the game's Android language, passed to Lepton as persist.sys.locale."""
import pytest
from frameport.core.models import Recipe
from frameport.install.installer import install_context
from frameport.patches import base
from frameport.patches.settings import LANGUAGE_TAG, Language
def _env(patches):
base.load_all()
return install_context(Recipe(package="com.example.game", patches=patches)).env
def test_language_rides_in_its_own_boot_property_line():
env = _env({"device.language": {"tag": "de-DE"}, "device.hide_navbar": {}})
assert env["LEPTON_GFXRECON_FP_LOCALE"] == "0\npersist.sys.locale=de-DE"
assert env["LEPTON_GFXRECON_FP_PROPS"] == "0\nqemu.hw.mainkeys=1" # both can be on
def test_default_changes_nothing():
assert "LEPTON_GFXRECON_FP_LOCALE" not in _env({"device.language": {"tag": ""}})
@pytest.mark.parametrize("tag", ["de-DE\nro.debuggable=1", "de DE", "../x", "DE"])
def test_only_language_tags_reach_the_boot_properties(tag):
with pytest.raises(ValueError):
_env({"device.language": {"tag": tag}})
def test_choices_are_valid_tags():
assert all(not k or LANGUAGE_TAG.match(k) for k, _label in Language.CHOICES)
assert Language.CHOICES[0][0] == "" and len({k for k, _ in Language.CHOICES}) == len(Language.CHOICES)
def test_language_dropdown_is_visible_and_default_removes_recipe_patch(monkeypatch):
from types import SimpleNamespace
import flet as ft
from frameport.core import library
from frameport.ui.views import game
base.load_all()
analysis = library.analysis_from_dict({"package": "test.game", "engine": "Unreal"})
# Use the real visibility filter: the language setting must be offered even while disabled.
from frameport.recommend import engine
patch = base.get("device.language")
shown, _ = engine.visible_patches(analysis, Recipe("test.game"))
assert patch in shown
monkeypatch.setattr(game.engine, "visible_patches", lambda *a: ([patch], []))
monkeypatch.setattr(library, "analysis_from_dict", lambda a: None)
monkeypatch.setattr(library, "setting", lambda *a: False)
monkeypatch.setattr(game.engine, "warnings", lambda *a: [])
saved = []
monkeypatch.setattr(game.pipeline, "set_recipe", lambda package, r: saved.append(library.recipe_to_dict(r)))
view = SimpleNamespace(app=SimpleNamespace(has_game_settings=lambda g: False),
g={"recipe": library.recipe_to_dict(Recipe("test.game")), "analysis": {}},
package="test.game", show_all=False)
panel = game.GameView.advanced_panel(view)
def walk(control):
yield control
for child in getattr(control, "controls", []) or []:
yield from walk(child)
if getattr(control, "content", None) is not None:
yield from walk(control.content)
picker = next(c for c in walk(panel) if isinstance(c, ft.Dropdown))
assert picker.value == ""
assert any(o.key == "de-DE" for o in picker.options)
picker.on_select(SimpleNamespace(control=SimpleNamespace(value="de-DE")))
assert saved[-1]["patches"]["device.language"] == {"tag": "de-DE"}
assert library.recipe_from_dict(saved[-1]).params("device.language") == {"tag": "de-DE"}
picker.on_select(SimpleNamespace(control=SimpleNamespace(value="")))
assert "device.language" not in saved[-1]["patches"]