diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8613258..867562b 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,6 +7,7 @@ py37: stage: test image: python:3.7-alpine before_script: + - apk add --no-cache gettext - pip install tox script: tox -e py3 @@ -14,6 +15,7 @@ py38: stage: test image: python:3.8-alpine before_script: + - apk add --no-cache gettext - pip install tox script: tox -e py3 @@ -22,6 +24,7 @@ py39: stage: test image: python:3.9-alpine before_script: + - apk add --no-cache gettext - pip install tox script: tox -e py3 @@ -29,6 +32,7 @@ linters: stage: quality-assurance image: python:3-alpine before_script: + - apk add --no-cache gettext - pip install tox script: tox -e linters allow_failure: true @@ -37,7 +41,7 @@ build-deb: image: debian:buster-slim stage: build before_script: - - apt-get update && apt-get -y --no-install-recommends install build-essential debmake dh-python debhelper python3-all python3-setuptools + - apt-get update && apt-get -y --no-install-recommends install build-essential debmake dh-python debhelper gettext python3-all python3-setuptools script: - dpkg-buildpackage - mkdir build && cp ../*.deb build/ diff --git a/squirrelbattle/tests/game_test.py b/squirrelbattle/tests/game_test.py index 8f5b1c1..9c950d6 100644 --- a/squirrelbattle/tests/game_test.py +++ b/squirrelbattle/tests/game_test.py @@ -4,18 +4,16 @@ import os import unittest -from squirrelbattle.resources import ResourceManager - -from squirrelbattle.enums import DisplayActions - -from squirrelbattle.bootstrap import Bootstrap -from squirrelbattle.display.display import Display -from squirrelbattle.display.display_manager import DisplayManager -from squirrelbattle.entities.player import Player -from squirrelbattle.game import Game, KeyValues, GameMode -from squirrelbattle.menus import MainMenuValues -from squirrelbattle.settings import Settings -from squirrelbattle.translations import gettext as _ +from ..bootstrap import Bootstrap +from ..display.display import Display +from ..display.display_manager import DisplayManager +from ..entities.player import Player +from ..enums import DisplayActions +from ..game import Game, KeyValues, GameMode +from ..menus import MainMenuValues +from ..resources import ResourceManager +from ..settings import Settings +from ..translations import gettext as _, Translator class TestGame(unittest.TestCase): @@ -277,6 +275,8 @@ class TestGame(unittest.TestCase): self.assertEqual(self.game.settings.TEXTURE_PACK, "ascii") # Change language + Translator.compilemessages() + Translator.refresh_translations() self.game.settings.LOCALE = "en" self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.ENTER) diff --git a/squirrelbattle/tests/translations_test.py b/squirrelbattle/tests/translations_test.py index 742edea..6c18840 100644 --- a/squirrelbattle/tests/translations_test.py +++ b/squirrelbattle/tests/translations_test.py @@ -5,6 +5,8 @@ from squirrelbattle.translations import gettext as _, Translator class TestTranslations(unittest.TestCase): def setUp(self) -> None: + Translator.compilemessages() + Translator.refresh_translations() Translator.setlocale("fr") def test_main_menu_translation(self) -> None: diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index dfd3cf3..cd5b7fc 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -18,15 +18,20 @@ class Translator: locale: str = "en" translators: dict = {} - for language in SUPPORTED_LOCALES: - dir = Path(__file__).parent / "locale" / language / "LC_MESSAGES" - dir.mkdir(parents=True) if not dir.is_dir() else None - if os.path.isfile(dir / "squirrelbattle.mo"): - translators[language] = gt.translation( - "squirrelbattle", - localedir=Path(__file__).parent / "locale", - languages=[language], - ) + @classmethod + def refresh_translations(cls) -> None: + """ + Load compiled translations. + """ + for language in cls.SUPPORTED_LOCALES: + rep = Path(__file__).parent / "locale" / language / "LC_MESSAGES" + rep.mkdir(parents=True) if not rep.is_dir() else None + if os.path.isfile(rep / "squirrelbattle.mo"): + cls.translators[language] = gt.translation( + "squirrelbattle", + localedir=Path(__file__).parent / "locale", + languages=[language], + ) @classmethod def setlocale(cls, lang: str) -> None: @@ -40,10 +45,13 @@ class Translator: @classmethod def get_translator(cls) -> Any: - return cls.translators.get(cls.locale) + return cls.translators.get(cls.locale, gt.NullTranslations()) @classmethod def makemessages(cls) -> None: # pragma: no cover + """ + Analyse all strings in the project and extract them. + """ for language in cls.SUPPORTED_LOCALES: file_name = Path(__file__).parent / "locale" / language \ / "LC_MESSAGES" / "squirrelbattle.po" @@ -61,10 +69,13 @@ class Translator: if file_name.is_file(): args.append("--join-existing") print(f"Make {language} messages...") - subprocess.Popen(args, stdin=find.stdout) + subprocess.Popen(args, stdin=find.stdout).wait() @classmethod - def compilemessages(cls) -> None: # pragma: no cover + def compilemessages(cls) -> None: + """ + Compile translation messages from source files. + """ for language in cls.SUPPORTED_LOCALES: args = ["msgfmt", "--check-format", "-o", Path(__file__).parent / "locale" / language @@ -72,7 +83,7 @@ class Translator: Path(__file__).parent / "locale" / language / "LC_MESSAGES" / "squirrelbattle.po"] print(f"Compiling {language} messages...") - subprocess.Popen(args) + subprocess.Popen(args).wait() def gettext(message: str) -> str: @@ -80,3 +91,6 @@ def gettext(message: str) -> str: Translate a message. """ return Translator.get_translator().gettext(message) + + +Translator.refresh_translations()