Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internationalization - Proof of Concept #264

Open
wants to merge 42 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
62557b1
Prototype go at extracted string for i18n
jscheidtmann Jan 12, 2025
b146085
First i18n prototype that works
jscheidtmann Jan 12, 2025
a10cb48
Translate when displaying the menu
jscheidtmann Jan 14, 2025
3f3c90d
Checkin latest po.
jscheidtmann Jan 22, 2025
8d347f6
Update messages.po
laurentbourasseau Jan 22, 2025
ef1f378
Update messages.po
laurentbourasseau Jan 22, 2025
169d871
Update messages.po
laurentbourasseau Jan 22, 2025
8d9881a
Update messages.po
laurentbourasseau Jan 22, 2025
43eaac4
Update messages.po
laurentbourasseau Jan 22, 2025
8d63ab2
Update messages.po
laurentbourasseau Jan 22, 2025
09aedba
Update messages.po
laurentbourasseau Jan 22, 2025
5a3ae59
Menu entry "Language" added.
jscheidtmann Jan 22, 2025
04c2343
Update messages.po
laurentbourasseau Jan 22, 2025
903051b
Switch langauge on the fly.
jscheidtmann Jan 22, 2025
bba95da
Merge branch 'i18n' of github.com:jscheidtmann/PiFinder into i18n
jscheidtmann Jan 22, 2025
3047161
Update messages.po
laurentbourasseau Jan 22, 2025
37c2824
Merge branch 'i18n' of github.com:jscheidtmann/PiFinder into i18n
jscheidtmann Jan 22, 2025
2491d2c
Updated messages and cleaned up import in sys_utils
jscheidtmann Jan 22, 2025
87e2cb1
nox runs through with-out errors.
jscheidtmann Jan 23, 2025
596ad2a
Merge branch 'main' of github.com:brickbots/PiFinder into i18n
jscheidtmann Jan 23, 2025
514fc63
Update po and mo after merging.
jscheidtmann Jan 23, 2025
465c98c
Remove print from switch_language
jscheidtmann Jan 23, 2025
7af0b30
Update messages.po
laurentbourasseau Feb 1, 2025
5c16aca
Updated .mo-files
jscheidtmann Feb 7, 2025
ecafe45
Merge remote-tracking branch 'origin/main' into i18n
jscheidtmann Feb 7, 2025
942e5f4
make nox babel optional. Include info on I18N in developer docs.
jscheidtmann Feb 7, 2025
78edf9e
Fix formatting and typos.
jscheidtmann Feb 7, 2025
a2c8209
Catch ValueError, too, if starting cedar_detect fails
jscheidtmann Feb 8, 2025
fc4ca79
First pass over ui classes for i18n
jscheidtmann Feb 8, 2025
565cf88
Add TRANSLATORS comments to .po file.
jscheidtmann Feb 8, 2025
79cf6c1
Make mypy ignore _()
jscheidtmann Feb 8, 2025
b585b99
Remove wrong placed "nox"
jscheidtmann Feb 8, 2025
f7affcb
When logging observation, do not use empty set for German translation
jscheidtmann Feb 8, 2025
92a9ed3
Update messages.po
laurentbourasseau Feb 8, 2025
17feba6
Update messages.po
laurentbourasseau Feb 8, 2025
60e653c
Update messages.po
laurentbourasseau Feb 9, 2025
dcb8972
Update messages.po
laurentbourasseau Feb 9, 2025
7072def
Update french translation
jscheidtmann Feb 9, 2025
95bf203
Merge remote-tracking branch 'origin/main' into i18n
jscheidtmann Feb 9, 2025
c9c321a
Update messages.po
laurentbourasseau Feb 9, 2025
f8119bb
Update messages.po
laurentbourasseau Feb 9, 2025
e3096e0
Updates to french translation
jscheidtmann Feb 9, 2025
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
1 change: 1 addition & 0 deletions default_config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"gps_lock": false,
"timezone": "America/Los_Angeles"
},
"language": "en",
"camera_exp": 400000,
"camera_gain": 20,
"menu_anim_speed": 0.1,
Expand Down
32 changes: 31 additions & 1 deletion python/PiFinder/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

"""

import gettext

import os

# skyfield performance fix, see: https://rhodesmill.org/skyfield/accuracy-efficiency.html
Expand Down Expand Up @@ -51,6 +53,12 @@
from PiFinder.calc_utils import sf_utils
from PiFinder.displays import DisplayBase, get_display

# Install the _("text") into global context for Internationalization
# On RasPi/Ubuntu the default locale is C.utf8, see `locale -a`, which locales are available
# You need to install `apt install language-pack_xx`, where xx is the ISO country code.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this implies changes to pifinder_setup and pifinder_update so everyone gets the languages. Also, each time a new language is added, these scripts need to be updated - unless we have some queryable single source of languages like a file used by the setup scripts and the app

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When updating, we can check the python/locale folder for new subdirs and then install the respective packages/languages. Alternative could be to install „all“ languages once. I have to check which of these options is preferable.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #264 (comment) : At least on bullyeye, nothing like this is necessary.

# Passing nothing as third parameter means the language is determined from environment variables (e.g. LANG)
gettext.install("PiFinder", "locale")

logger = logging.getLogger("main")

hardware_platform = "Pi"
Expand Down Expand Up @@ -287,6 +295,13 @@ def main(
screen_brightness = cfg.get_option("display_brightness")
set_brightness(screen_brightness, cfg)

# Set user interface language
lang = cfg.get_option("language")
langXX = gettext.translation(
"messages", "locale", languages=[lang], fallback=(lang == "en")
)
langXX.install()

import PiFinder.manager_patch as patch

patch.apply()
Expand Down Expand Up @@ -722,6 +737,10 @@ def rotate_logs() -> Path:
return utils.data_dir / "pifinder.log"


#############################################################################################
#############################################################################################
#############################################################################################

if __name__ == "__main__":
print("Bootstrap logging configuration ...")
logging.basicConfig(format="%(asctime)s BASIC %(name)s: %(levelname)s %(message)s")
Expand Down Expand Up @@ -803,6 +822,11 @@ def rotate_logs() -> Path:
"-x", "--verbose", help="Set logging to debug mode", action="store_true"
)
parser.add_argument("-l", "--log", help="Log to file", action="store_true")
parser.add_argument(
"--lang",
help="Force user interface language (iso2 code). Changes configuration",
type=str,
)
args = parser.parse_args()
# add the handlers to the logger
if args.verbose:
Expand Down Expand Up @@ -850,7 +874,13 @@ def rotate_logs() -> Path:
elif args.keyboard.lower() == "none":
from PiFinder import keyboard_none as keyboard # type: ignore[no-redef]

rlogger.warn("using no keyboard")
rlogger.warning("using no keyboard")

if args.lang:
if args.lang.lower() not in ["en", "de", "fr", "es"]:
raise Exception(f"Unknown language '{args.lang}' passed via command line.")
else:
config.Config().set_option("language", args.lang)

# if args.log:
# datenow = datetime.datetime.now()
Expand Down
1 change: 1 addition & 0 deletions python/PiFinder/sys_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import re
from typing import Dict, Any


try:
import sh
from sh import wpa_cli, unzip, su, passwd
Expand Down
37 changes: 28 additions & 9 deletions python/PiFinder/ui/callbacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,19 @@

import datetime
import logging
import gettext

from typing import Any, TYPE_CHECKING
from PiFinder import utils
from PiFinder.ui.base import UIModule
from PiFinder.catalogs import CatalogFilter

if TYPE_CHECKING:

def _(a) -> Any:
return a


sys_utils = utils.get_sys_utils()


Expand All @@ -40,7 +48,7 @@ def reset_filters(ui_module: UIModule) -> None:

ui_module.catalogs.set_catalog_filter(new_filter)
ui_module.catalogs.filter_catalogs()
ui_module.message("Filters Reset")
ui_module.message(_("Filters Reset"))
ui_module.remove_from_stack()
return

Expand All @@ -54,7 +62,7 @@ def activate_debug(ui_module: UIModule) -> None:
ui_module.command_queues["console"].put("Debug: Activated")
dt = datetime.datetime(2024, 6, 1, 2, 0, 0)
ui_module.shared_state.set_datetime(dt)
ui_module.message("Test Mode")
ui_module.message(_("Test Mode"))


def set_exposure(ui_module: UIModule) -> None:
Expand All @@ -70,7 +78,7 @@ def shutdown(ui_module: UIModule) -> None:
"""
shuts down the Pi
"""
ui_module.message("Shutting Down", 10)
ui_module.message(_("Shutting Down"), 10)
sys_utils.shutdown()


Expand All @@ -79,26 +87,26 @@ def restart_pifinder(ui_module: UIModule) -> None:
Uses systemctl to restart the PiFinder
service
"""
ui_module.message("Restarting...", 2)
ui_module.message(_("Restarting..."), 2)
sys_utils.restart_pifinder()


def restart_system(ui_module: UIModule) -> None:
"""
Restarts the system
"""
ui_module.message("Restarting...", 2)
ui_module.message(_("Restarting..."), 2)
sys_utils.restart_system()


def switch_cam_imx477(ui_module: UIModule) -> None:
ui_module.message("Switching cam", 2)
ui_module.message(_("Switching cam"), 2)
sys_utils.switch_cam_imx477()
restart_system(ui_module)


def switch_cam_imx296(ui_module: UIModule) -> None:
ui_module.message("Switching cam", 2)
ui_module.message(_("Switching cam"), 2)
sys_utils.switch_cam_imx296()
restart_system(ui_module)

Expand Down Expand Up @@ -127,13 +135,24 @@ def get_camera_type(ui_module: UIModule) -> list:
return [cam_id]


def switch_language(ui_module: UIModule) -> None:
iso2_code = ui_module.config_object.get_option("language")
msg = str(f"Language: {iso2_code}")
ui_module.message(_(msg))
lang = gettext.translation(
"messages", "locale", languages=[iso2_code], fallback=(iso2_code == "en")
)
lang.install()
logger.info("Switch Language: %s", iso2_code)


def go_wifi_ap(ui_module: UIModule) -> None:
ui_module.message("WiFi to AP", 2)
ui_module.message(_("WiFi to AP"), 2)
sys_utils.go_wifi_ap()
restart_system(ui_module)


def go_wifi_cli(ui_module: UIModule) -> None:
ui_module.message("WiFi to Client", 2)
ui_module.message(_("WiFi to Client"), 2)
sys_utils.go_wifi_cli()
restart_system(ui_module)
Loading
Loading