From d697c5026809f8cac3263671d365d031428d01d3 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 20 Nov 2020 14:29:30 +0100 Subject: [PATCH 01/54] Fix badges in README and doc index --- README.md | 2 +- docs/index.rst | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d340eee..6ad3063 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ [![pipeline status](https://gitlab.crans.org/ynerant/squirrel-battle/badges/master/pipeline.svg)](https://gitlab.crans.org/ynerant/squirrel-battle/-/commits/master) [![coverage report](https://gitlab.crans.org/ynerant/squirrel-battle/badges/master/coverage.svg)](https://gitlab.crans.org/ynerant/squirrel-battle/-/commits/master) [![Documentation Status](https://readthedocs.org/projects/squirrel-battle/badge/?version=latest)](https://squirrel-battle.readthedocs.io/fr/latest/?badge=latest) -[![PyPI](https://img.shields.io/pypi/v/dungeon-battle)](https://pypi.org/project/squirrel-battle/) +[![PyPI](https://img.shields.io/pypi/v/squirrel-battle)](https://pypi.org/project/squirrel-battle/) [![PYPI downloads](https://img.shields.io/pypi/dm/squirrel-battle)](https://pypi.org/project/squirrel-battle/) [![AUR version](https://img.shields.io/aur/version/python-squirrel-battle)](https://aur.archlinux.org/packages/python-squirrel-battle/) [![License: GPL v3](https://img.shields.io/badge/License-GPL%20v3-blue.svg)](https://www.gnu.org/licenses/gpl-3.0.txt) diff --git a/docs/index.rst b/docs/index.rst index ce312c3..e7e3569 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -13,11 +13,11 @@ Bienvenue dans la documentation de Squirrel Battle ! :target: https://squirrel-battle.readthedocs.io/fr/latest/?badge=latest :alt: Documentation Status -.. image:: https://img.shields.io/pypi/v/dungeon-battle +.. image:: https://img.shields.io/pypi/v/squirrel-battle :target: https://pypi.org/project/squirrel-battle/ :alt: PyPI -.. image:: https://img.shields.io/pypi/dm/dungeon-battle +.. image:: https://img.shields.io/pypi/dm/squirrel-battle :target: https://pypi.org/project/squirrel-battle/ :alt: PyPI downloads From 762fa9acd430e813a804e2b9c95ef4e10876bf84 Mon Sep 17 00:00:00 2001 From: eichhornchen Date: Fri, 20 Nov 2020 15:26:02 +0100 Subject: [PATCH 02/54] A test --- squirrelbattle/display/texturepack.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/squirrelbattle/display/texturepack.py b/squirrelbattle/display/texturepack.py index 0ae8f56..4296393 100644 --- a/squirrelbattle/display/texturepack.py +++ b/squirrelbattle/display/texturepack.py @@ -65,7 +65,7 @@ TexturePack.SQUIRREL_PACK = TexturePack( EMPTY=' ', WALL='đŸ§±', FLOOR='██', - PLAYER='🐿 ', + PLAYER='đŸżïž ', HEDGEHOG='🩔', HEART='💜', BOMB='💣', From 62599ea72c5f5fdeaa085186b64ec7c9eb2c3605 Mon Sep 17 00:00:00 2001 From: Nicolas Margulies Date: Fri, 20 Nov 2020 16:05:21 +0100 Subject: [PATCH 03/54] Clear menu pads before putting the new text in them, see #15 --- squirrelbattle/display/menudisplay.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index fca1ddf..082772b 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -34,6 +34,7 @@ class MenuDisplay(Display): if self.height - 2 >= self.trueheight - self.menu.position else 0 # Menu box + self.menubox.clear() self.menubox.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓") for i in range(1, self.height - 1): self.menubox.addstr(i, 0, "┃" + " " * (self.width - 2) + "┃") @@ -43,6 +44,7 @@ class MenuDisplay(Display): self.menubox.refresh(0, 0, self.y, self.x, self.height + self.y, self.width + self.x) + self.pad.clear() self.update_pad() self.pad.refresh(cornery, 0, self.y + 1, self.x + 2, self.height - 2 + self.y, From 7e636078363d2b105cd137dc0501122092809e29 Mon Sep 17 00:00:00 2001 From: Nicolas Margulies Date: Fri, 20 Nov 2020 16:52:04 +0100 Subject: [PATCH 04/54] Added vertical and horizontal lines as display elements --- squirrelbattle/display/display.py | 40 +++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index 1e47189..eba86b9 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -50,3 +50,43 @@ class Display: @property def cols(self) -> int: return curses.COLS if self.screen else 42 + + +class VerticalSplit(Display): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.pad = self.newpad(self.rows, 1) + + @property + def width(self) -> int: + return 1 + + @width.setter + def width(self, val: Any) -> None: + pass + + def display(self) -> None: + for i in range(self.height): + self.pad.addstr(i, 0, "┃") + self.pad.refresh(0, 0, self.y, self.x, self.y + self.height, self.x) + + +class HorizontalSplit(Display): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.pad = self.newpad(1, self.cols) + + @property + def height(self) -> int: + return 1 + + @height.setter + def height(self, val: Any) -> None: + pass + + def display(self) -> None: + for i in range(self.width): + self.pad.addstr(0, i, "━") + self.pad.refresh(0, 0, self.y, self.x, self.y, self.x + self.width) From 685606fdb60622d2533dc8aab790d705dfb1712b Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 20 Nov 2020 17:32:26 +0100 Subject: [PATCH 05/54] Documentation on packaging --- docs/deployment.rst | 311 ++++++++++++++++++++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 312 insertions(+) create mode 100644 docs/deployment.rst diff --git a/docs/deployment.rst b/docs/deployment.rst new file mode 100644 index 0000000..1a4860d --- /dev/null +++ b/docs/deployment.rst @@ -0,0 +1,311 @@ +DĂ©ploiement du projet +===================== + +.. _PyPI: https://pypi.org/project/squirrel-battle/ +.. _AUR: https://aur.archlinux.org/packages/python-squirrel-battle/ +.. _Debian: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14_all.deb?job=build-deb +.. _installation: install.html + +À chaque nouvelle version du projet, il est compilĂ© et dĂ©ployĂ© dans PyPI_, dans +l'AUR_ et un paquet Debian_ est crĂ©Ă©, voir la page d'installation_. + + +PyPI +---- + +DĂ©finition du paquet +~~~~~~~~~~~~~~~~~~~~ + +.. _setup.py: https://gitlab.crans.org/ynerant/squirrel-battle/-/blob/master/setup.py + +La documentation sur le packaging dans PyPI_ est disponible `ici +`_. + +Le fichier `setup.py`_ contient l'ensemble des instructions d'installation du +paquet ainsi que des dĂ©tails Ă  fournir Ă  PyPI : + +.. code:: python + + #!/usr/bin/env python3 + import os + + from setuptools import find_packages, setup + + with open("README.md", "r") as f: + long_description = f.read() + + setup( + name="squirrel-battle", + version="3.14", + author="ynerant", + author_email="ynerant@crans.org", + description="Watch out for squirrel's knifes!", + long_description=long_description, + long_description_content_type="text/markdown", + url="https://gitlab.crans.org/ynerant/squirrel-battle", + packages=find_packages(), + license='GPLv3', + classifiers=[ + "Development Status :: 4 - Beta", + "Environment :: Console :: Curses", + "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "Natural Language :: French", + "Operating System :: OS Independent", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Games/Entertainment", + ], + python_requires='>=3.6', + include_package_data=True, + package_data={"squirrelbattle": ["assets/*"]}, + entry_points={ + "console_scripts": [ + "squirrel-battle = squirrelbattle.bootstrap:Bootstrap.run_game", + ] + } + ) + +Ce fichier contient le nom du paquet, sa version, l'auteur et son contact, +sa description en une ligne et sa description longue, le lien d'accueil du projet, +sa licence, ses classificateurs et son exĂ©cutable. + +Le paramĂštre ``entry_points`` dĂ©finit un exĂ©cutable nommĂ© ``squirrel-battle``, +qui permet de lancer le jeu. + + +Installation locale du paquet +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +L'installation du paquet localement dans son environnement Python (virtuel ou non) +peut se faire en exĂ©cutant ``pip install -e .``. + + +GĂ©nĂ©ration des binaires +~~~~~~~~~~~~~~~~~~~~~~~ + +Les paquets ``setuptools`` (``python3-setuptools`` pour APT, ``python-setuptools`` +pour pacman) et ``wheel`` (``python3-wheel`` pour APT, ``python-wheel`` pour pacman) +sont nĂ©cessaires. Une fois installĂ©s, il faut appeler la commande : + +.. code:: bash + + python3 setup.py sdist bdist_wheel + +Une fois cela fait, le dossier ``dist/`` contiendra les archives Ă  transmettre Ă  PyPI. + + +Publier sur PyPI +~~~~~~~~~~~~~~~~ + +Il faut avant tout avoir un compte sur PyPI. Dans `votre compte PyPI +`_, il faut gĂ©nĂ©rer un jeton d'accĂšs API. + +Dans le fichier ``.pypirc`` dans le rĂ©pertoire principal de l'utilisateur, +il faut ajouter le jeton d'accĂšs : + +.. code:: + + [pypi] + username = __token__ + password = pypi-my-pypi-api-access-token + +Cela permet de s'authentifier directement par ce jeton. + +Ensuite, il faut installer ``twine``, qui permet de publier sur PyPI. + +Il suffit ensuite d'appeler : + +.. code:: bash + + twine upload dist/* + +pour envoyer le paquet sur PyPI. + + +.. note:: + + À des fins de tests, il est possible d'utiliser le dĂ©pĂŽt ``_. + Les diffĂ©rences sont au niveau de l'authentification, oĂč il faut l'en-tĂȘte + ``[testpypi]`` dans le ``.pypirc``, et il faut envoyer le paquet avec + ``twine upload --repository testpypi dist/``. + + +Publier dans l'AUR +------------------ + +Fonctionnement du packaging +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +.. _python-squirrel-battle: https://aur.archlinux.org/packages/python-squirrel-battle/ +.. _python-squirrel-battle-git: https://aur.archlinux.org/packages/python-squirrel-battle-git/ + +Deux paquets sont publiĂ©s dans l'AUR (Arch User Repository) : + +- python-squirrel-battle_ +- python-squirrel-battle-git_ + +Le packaging dans Arch Linux se fait en commitant un fichier ``PKGBUILD`` dans +le dĂ©pĂŽt Ă  l'adresse ``ssh://aur@aur.archlinux.org/packagename.git``, +en remplaçant ``packagename`` par le nom du paquet. + +Le second paquet compile directement le jeu Ă  partir de la branche ``master`` +du dĂ©pĂŽt Git. Le fichier ``PKGBUILD`` dispose de cette structure : + +.. code:: + + # Maintainer: Yohann D'ANELLO + + pkgbase=squirrel-battle + pkgname=python-squirrel-battle-git + pkgver=3.14 + pkgrel=2 + pkgdesc="Watch out for squirrel's knives!" + arch=('any') + url="https://gitlab.crans.org/ynerant/squirrel-battle" + license=('GPLv3') + depends=('python') + makedepends=('python-setuptools') + depends=('noto-fonts-emoji') + checkdepends=('python-tox') + ssource=("git+https://gitlab.crans.org/ynerant/squirrel-battle.git") + sha256sums=("SKIP") + + pkgver() { + cd pkgbase + git describe --long --tags | sed -r 's/^v//;s/([^-]*-g)/r\1/;s/-/./g' + } + build() { + cd $pkgbase + python setup.py build + } + + check() { + cd $pkgbase + tox -e py3 + tox -e linters + } + + package() { + cd $pkgbase + python setup.py install --skip-build \ + --optimize=1 \ + --root="${pkgdir}" + install -vDm 644 README.md \ + -t "${pkgdir}/usr/share/doc/${pkgname}" + install -vDm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}" + } + +Ces instructions permettent de cloner le dĂ©pĂŽt, l'installer et exĂ©cuter des tests, +en plus de dĂ©finir les attributs du paquet. + +Le fichier ``PKGBUILD`` du paquet ``python-squirrel-battle``, synchronisĂ© avec +les releases, est plus ou moins similaire : + +.. code:: + + # Maintainer: Yohann D'ANELLO + + pkgbase=squirrel-battle + pkgname=python-squirrel-battle + pkgver=3.14 + pkgrel=2 + pkgdesc="Watch out for squirrel's knives!" + arch=('any') + url="https://gitlab.crans.org/ynerant/squirrel-battle" + license=('GPLv3') + depends=('python') + makedepends=('python-setuptools') + depends=('noto-fonts-emoji') + checkdepends=('python-tox') + source=("https://gitlab.crans.org/ynerant/squirrel-battle/-/archive/v3.14/$pkgbase-v$pkgver.tar.gz") + sha256sums=("6090534d598c0b3a8f5acdb553c12908ba8107d62d08e17747d1dbb397bddef0") + + build() { + cd $pkgbase-v$pkgver + python setup.py build + } + + check() { + cd $pkgbase-v$pkgver + tox -e py3 + tox -e linters + } + + package() { + cd $pkgbase-v$pkgver + python setup.py install --skip-build \ + --optimize=1 \ + --root="${pkgdir}" + install -vDm 644 README.md \ + -t "${pkgdir}/usr/share/doc/${pkgname}" + install -vDm 644 LICENSE -t "${pkgdir}/usr/share/licenses/${pkgname}" + } + +Il se contente ici de tĂ©lĂ©charger l'archive de la derniĂšre release, et de travailler +dessus. + + +Mettre Ă  jour +~~~~~~~~~~~~~ + +Pour mettre Ă  jour le dĂ©pĂŽt, une fois les dĂ©pĂŽts +``ssh://aur@aur.archlinux.org/python-squirrel-battle.git`` et +``ssh://aur@aur.archlinux.org/python-squirrel-battle-git.git`` clonĂ©s, +il suffit de mettre Ă  jour le paramĂštre ``pkgver`` pour la bonne version, +de rĂ©gĂ©nĂ©rer le fichier ``.SRCINFO`` en faisant +``makepkg --printsrcinfo > .SRCINFO``, puis de committer/pousser. + + +Construction du paquet Debian +----------------------------- + +Structure du paquet +------------------- + +L'ensemble des instructions pour construire le paquet Debian est situĂ© dans le +dossier ``debian/``. + +Le fichier ``changelog`` est Ă  modifier Ă  chaque nouvelle version, le fichier +``compat`` contient la version minimale de Debian requise (``10`` pour Debian +Buster), le fichier ``copyright`` contient la liste des fichiers distribuĂ©s sous +quelle licence (ici GPLv3), le fichier ``control`` contient les informations du +paquet, le fichier ``install`` les fichiers de configuration Ă  installer +(ici le fix de l'affichage de l'Ă©curueil), et enfin le fichier ``rules`` l'ensemble +des instructions Ă  exĂ©cuter pour installer. + +Le paquet ``fonts-noto-color-emoji`` est en dĂ©pendance pour le bon affichage +des Ă©mojis. + +Mettre Ă  jour le paquet +----------------------- + +Pour changer la version du paquet, il faut ajouter des lignes dans le fichier +``changelog``. + + +Construire le paquet +-------------------- + +Il faut partir d'une installation de Debian. + +D'abord on installe les paquets nĂ©cessaires : + +.. code:: + + apt update + apt --no-install-recommends install build-essential debmake dh-python debhelper python3-all python3-setuptools + +On peut ensuite construire le paquet : + +.. code:: bash + + dpkg-buildpackage + mkdir build && cp ../*.deb build/ + +Le paquet sera installĂ© dans ``build/python3-squirrel-battle_3.14_all.deb``. + +Le paquet Debian_ est construit par l'intĂ©gration continue Gitlab et ajoutĂ© +Ă  chaque release. diff --git a/docs/index.rst b/docs/index.rst index e7e3569..5a3af7b 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,6 +37,7 @@ Bienvenue dans la documentation de Squirrel Battle ! install-dev tests display/index + deployment .. toctree:: :maxdepth: 3 From ebb5f2e7d301a71097aef629c21ce4062a88f1ff Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 20 Nov 2020 17:55:21 +0100 Subject: [PATCH 06/54] Documentation on documentation --- docs/documentation.rst | 31 +++++++++++++++++++++++++++++++ docs/index.rst | 1 + 2 files changed, 32 insertions(+) create mode 100644 docs/documentation.rst diff --git a/docs/documentation.rst b/docs/documentation.rst new file mode 100644 index 0000000..74965be --- /dev/null +++ b/docs/documentation.rst @@ -0,0 +1,31 @@ +Documentation +============= + +La documentation est gĂ©rĂ©e grĂące Ă  Sphinx. Le thĂšme est le thĂšme officiel de +ReadTheDocs ``sphinx-rtd-theme``. + +GĂ©nĂ©rer localement la documentation +----------------------------------- + +On commence par se rendre au bon endroit et installer les bonnes dĂ©pendances : + +.. code:: bash + + cd docs + pip install -r requirements.txt + +La documentation se gĂ©nĂšre Ă  partir d'appels Ă  ``make``, selon le type de +documentation voulue. + +Par exemple, ``make html`` construit la documentation web, ``make latexpdf`` +construit un livre PDF avec cette documentation. + + +Documentation externe +--------------------- + +À chaque commit, un webhook est envoyĂ© Ă  ``_, qui construit +tout seul la documentation Sphinx, la publiant Ă  l'adresse +``_. + +De plus, les documentations sont sauvegardĂ©es Ă  chaque release taguĂ©e. diff --git a/docs/index.rst b/docs/index.rst index 5a3af7b..ff6bcf3 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -38,6 +38,7 @@ Bienvenue dans la documentation de Squirrel Battle ! tests display/index deployment + documentation .. toctree:: :maxdepth: 3 From fb3f3ee5e838ac38bc14e588d94c9abe912a0887 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 20 Nov 2020 18:02:08 +0100 Subject: [PATCH 07/54] Beaver is a tiger --- docs/entities/monsters.rst | 10 +++++----- docs/texture-pack.rst | 6 +++--- squirrelbattle/display/texturepack.py | 4 ++-- squirrelbattle/entities/monsters.py | 6 +++--- squirrelbattle/interfaces.py | 8 ++++---- squirrelbattle/tests/entities_test.py | 10 +++++----- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/docs/entities/monsters.rst b/docs/entities/monsters.rst index b719c1b..b6f287c 100644 --- a/docs/entities/monsters.rst +++ b/docs/entities/monsters.rst @@ -25,14 +25,14 @@ Dans le `pack de textures`_ ASCII, il est reprĂ©sentĂ© par le caractĂšre ``*``. Dans le `pack de textures`_ Ă©cureuil, il est reprĂ©sentĂ© par l'Ă©moji ``🩔``. -Castor ------- +Tigre +----- -Son nom est fixĂ© Ă  `beaver`. Il a par dĂ©faut une force Ă  **2** et **20** points de vie. +Son nom est fixĂ© Ă  `tiger`. Il a par dĂ©faut une force Ă  **2** et **20** points de vie. -Dans le `pack de textures`_ ASCII, il est reprĂ©sentĂ© par le caractĂšre ``_``. +Dans le `pack de textures`_ ASCII, il est reprĂ©sentĂ© par le caractĂšre ``n``. -Dans le `pack de textures`_ Ă©cureuil, il est reprĂ©sentĂ© par l'Ă©moji ``đŸŠ«``. +Dans le `pack de textures`_ Ă©cureuil, il est reprĂ©sentĂ© par l'Ă©moji ``🐅``. Lapin diff --git a/docs/texture-pack.rst b/docs/texture-pack.rst index 3bb5b4d..377a3cf 100644 --- a/docs/texture-pack.rst +++ b/docs/texture-pack.rst @@ -12,7 +12,7 @@ Pack de textures .. _CƓur: entities/items.html#coeur .. _Bombe: entities/items.html#bombe .. _Lapin: entities/monsters.html#lapin -.. _Castor: entities/monsters.html#castor +.. _Tigre: entities/monsters.html#tigre .. _Nounours: entities/monsters.html#nounours Chaque entitĂ©_ et chaque tuile_ de la carte_ est associĂ© Ă  un caractĂšre pour @@ -42,7 +42,7 @@ Chaque tuile fait un caractĂšre de large. * CƓur_ : ``❀`` * Bombe_ : ``o`` * Lapin_ : ``Y`` - * Castor_ : ``_`` + * Tigre_ : ``n`` * Nounours_ : ``8`` @@ -61,5 +61,5 @@ Chaque tuile fait 2 caractĂšres de large pour afficher les Ă©mojis proprement. * CƓur_ : ``💜`` * Bombe_ : ``💣`` * Lapin_ : ``🐇`` - * Castor_ : ``đŸŠ«`` + * Tigre_ : ``🐅`` * Nounours_ : ``🧾`` diff --git a/squirrelbattle/display/texturepack.py b/squirrelbattle/display/texturepack.py index 0ae8f56..ce2dd28 100644 --- a/squirrelbattle/display/texturepack.py +++ b/squirrelbattle/display/texturepack.py @@ -51,7 +51,7 @@ TexturePack.ASCII_PACK = TexturePack( HEART='❀', BOMB='o', RABBIT='Y', - BEAVER='_', + TIGER='n', TEDDY_BEAR='8', ) @@ -70,6 +70,6 @@ TexturePack.SQUIRREL_PACK = TexturePack( HEART='💜', BOMB='💣', RABBIT='🐇', - BEAVER='đŸŠ«', + TIGER='🐅', TEDDY_BEAR='🧾', ) diff --git a/squirrelbattle/entities/monsters.py b/squirrelbattle/entities/monsters.py index 8192b8e..cf4ba39 100644 --- a/squirrelbattle/entities/monsters.py +++ b/squirrelbattle/entities/monsters.py @@ -52,13 +52,13 @@ class Monster(FightingEntity): break -class Beaver(Monster): +class Tiger(Monster): """ - A beaver monster + A tiger monster """ def __init__(self, strength: int = 2, maxhealth: int = 20, *args, **kwargs) -> None: - super().__init__(name="beaver", strength=strength, + super().__init__(name="tiger", strength=strength, maxhealth=maxhealth, *args, **kwargs) diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index d1baa2a..5cbe48f 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -318,9 +318,9 @@ class Entity: Returns all entities subclasses """ from squirrelbattle.entities.items import Heart, Bomb - from squirrelbattle.entities.monsters import Beaver, Hedgehog, \ + from squirrelbattle.entities.monsters import Tiger, Hedgehog, \ Rabbit, TeddyBear - return [Beaver, Bomb, Heart, Hedgehog, Rabbit, TeddyBear] + return [Tiger, Bomb, Heart, Hedgehog, Rabbit, TeddyBear] @staticmethod def get_all_entity_classes_in_a_dict() -> dict: @@ -328,11 +328,11 @@ class Entity: Returns all entities subclasses in a dictionary """ from squirrelbattle.entities.player import Player - from squirrelbattle.entities.monsters import Beaver, Hedgehog, Rabbit, \ + from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, \ TeddyBear from squirrelbattle.entities.items import Bomb, Heart return { - "Beaver": Beaver, + "Tiger": Tiger, "Bomb": Bomb, "Heart": Heart, "Hedgehog": Hedgehog, diff --git a/squirrelbattle/tests/entities_test.py b/squirrelbattle/tests/entities_test.py index 0c8ee3c..b92a2c4 100644 --- a/squirrelbattle/tests/entities_test.py +++ b/squirrelbattle/tests/entities_test.py @@ -1,7 +1,7 @@ import unittest from squirrelbattle.entities.items import Bomb, Heart, Item -from squirrelbattle.entities.monsters import Beaver, Hedgehog, Rabbit, TeddyBear +from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit, TeddyBear from squirrelbattle.entities.player import Player from squirrelbattle.interfaces import Entity, Map from squirrelbattle.resources import ResourceManager @@ -36,17 +36,17 @@ class TestEntities(unittest.TestCase): """ Test some random stuff with fighting entities. """ - entity = Beaver() + entity = Tiger() self.map.add_entity(entity) self.assertEqual(entity.maxhealth, 20) self.assertEqual(entity.maxhealth, entity.health) self.assertEqual(entity.strength, 2) for _ in range(9): self.assertEqual(entity.hit(entity), - "beaver hits beaver. beaver takes 2 damage.") + "tiger hits tiger. tiger takes 2 damage.") self.assertFalse(entity.dead) - self.assertEqual(entity.hit(entity), "beaver hits beaver. " - + "beaver takes 2 damage. beaver dies.") + self.assertEqual(entity.hit(entity), "tiger hits tiger. " + + "tiger takes 2 damage. tiger dies.") self.assertTrue(entity.dead) entity = Rabbit() From 700ba161868987e85f99c0866439cf095a347745 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 20 Nov 2020 18:04:44 +0100 Subject: [PATCH 08/54] Don't need to install the most recent version of the noto emojis since beaver is finally a tiger --- docs/install.rst | 12 +----------- docs/troubleshooting.rst | 19 +++++-------------- 2 files changed, 6 insertions(+), 25 deletions(-) diff --git a/docs/install.rst b/docs/install.rst index d73b5a9..26f8b42 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -67,17 +67,7 @@ Un paquet_ est gĂ©nĂ©rĂ© par l'intĂ©gration continue de Gitlab Ă  chaque commit. Ils sont Ă©galement attachĂ©s Ă  chaque nouvelle release. Il dĂ©pend du paquet ``fonts-noto-color-emoji``, permettant d'afficher les Ă©mojis -dans le terminal. Il peut ĂȘtre installĂ© via APT normalement sur une distribution -rĂ©cente, toutefois sur les versions les plus vieilles, incluant Debian Buster, -certains Ă©mojis n'apparaissent pas. Il est essentiel de maintenir ce paquet Ă  -jour. Pour installer manuellement la derniĂšre version de ce paquet, -il suffit d'exĂ©cuter : - -.. code:: bash - - wget http://ftp.fr.debian.org/debian/pool/main/f/fonts-noto-color-emoji/fonts-noto-color-emoji_0~20200916-1_all.deb - dpkg -i fonts-noto-color-emoji_0~20200916-1_all.deb - rm fonts-noto-color-emoji_0~20200916-1_all.deb +dans le terminal. Il peut ĂȘtre installĂ© via APT. Pour installer ce paquet, il suffit de le tĂ©lĂ©charger et d'appeler ``dpkg`` : diff --git a/docs/troubleshooting.rst b/docs/troubleshooting.rst index 8a26c19..6e400f6 100644 --- a/docs/troubleshooting.rst +++ b/docs/troubleshooting.rst @@ -24,21 +24,12 @@ Sous Ubuntu/Debian ^^^^^^^^^^^^^^^^^^ À nouveau, le terminal `xfce4-terminal` est recommandĂ©. Le paquet -`fonts-noto-color-emoji`. Toutefois, le rythme de mise Ă  jour de Debian Ă©tant -lent, le paquet le plus rĂ©cent ne contient pas tous les Ă©mojis. Sur Debian, -il faudra donc installer le paquet le plus rĂ©cent, ce qui fonctionne sans -dĂ©pendance supplĂ©mentaire : +`fonts-noto-color-emoji`. -.. code:: bash - - wget http://ftp.fr.debian.org/debian/pool/main/f/fonts-noto-color-emoji/fonts-noto-color-emoji_0~20200916-1_all.deb - dpkg -i fonts-noto-color-emoji_0~20200916-1_all.deb - rm fonts-noto-color-emoji_0~20200916-1_all.deb - -Il reste le problĂšme de l'Ă©cureuil. Sous Ubuntu et Debian, le caractĂšre Ă©cureuil -existe dĂ©jĂ , mais ne s'affiche pas proprement. On peut appliquer un patch qui -permet d'afficher les Ă©mojis correctement dans son terminal. Pour cela, il -suffit de faire : +Toutefois, un problĂšme reste avec l'Ă©cureuil. Sous Ubuntu et Debian, le +caractĂšre Ă©cureuil existe dĂ©jĂ , mais ne s'affiche pas proprement. On peut +appliquer un patch qui permet d'afficher les Ă©mojis correctement dans son +terminal. Pour cela, il suffit de faire : .. code:: bash From 9ca6561bc3e83f27203e28981c6eb63c936a1b8e Mon Sep 17 00:00:00 2001 From: Nicolas Margulies Date: Fri, 20 Nov 2020 18:06:43 +0100 Subject: [PATCH 09/54] Added a box element --- squirrelbattle/display/display.py | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index eba86b9..d1ead44 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -33,7 +33,7 @@ class Display: self.width = width self.height = height if hasattr(self, "pad") and resize_pad: - self.pad.resize(self.height, self.width) + self.pad.resize(self.height + 1, self.width + 1) def refresh(self, *args, resize_pad: bool = True) -> None: if len(args) == 4: @@ -69,7 +69,7 @@ class VerticalSplit(Display): def display(self) -> None: for i in range(self.height): self.pad.addstr(i, 0, "┃") - self.pad.refresh(0, 0, self.y, self.x, self.y + self.height, self.x) + self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x) class HorizontalSplit(Display): @@ -89,4 +89,19 @@ class HorizontalSplit(Display): def display(self) -> None: for i in range(self.width): self.pad.addstr(0, i, "━") - self.pad.refresh(0, 0, self.y, self.x, self.y, self.x + self.width) + self.pad.refresh(0, 0, self.y, self.x, self.y, self.x + self.width - 1) + +class Box(Display): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.pad = self.newpad(self.rows, self.cols) + + def display(self) -> None: + self.pad.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓") + for i in range(1, self.height - 1): + self.pad.addstr(i, 0, "┃") + self.pad.addstr(i, self.width - 1, "┃") + self.pad.addstr(self.height - 1, 0, + "┗" + "━" * (self.width - 2) + "┛") + self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x + self.width - 1) From ca57fae19d39b1aeb32dbe36abe6ea9abd6f9a66 Mon Sep 17 00:00:00 2001 From: Nicolas Margulies Date: Fri, 20 Nov 2020 18:07:09 +0100 Subject: [PATCH 10/54] Reshaped the game layout using new lines and boxes --- squirrelbattle/display/display_manager.py | 17 +++++++++++------ squirrelbattle/display/logsdisplay.py | 4 ++-- squirrelbattle/display/menudisplay.py | 21 ++++++--------------- squirrelbattle/display/statsdisplay.py | 18 +++++++----------- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/squirrelbattle/display/display_manager.py b/squirrelbattle/display/display_manager.py index a4636eb..d50dfa1 100644 --- a/squirrelbattle/display/display_manager.py +++ b/squirrelbattle/display/display_manager.py @@ -1,4 +1,5 @@ import curses +from squirrelbattle.display.display import VerticalSplit, HorizontalSplit from squirrelbattle.display.mapdisplay import MapDisplay from squirrelbattle.display.statsdisplay import StatsDisplay from squirrelbattle.display.menudisplay import SettingsMenuDisplay, \ @@ -22,6 +23,8 @@ class DisplayManager: screen, pack) self.settingsmenudisplay = SettingsMenuDisplay(screen, pack) self.logsdisplay = LogsDisplay(screen, pack) + self.hbar = HorizontalSplit(screen, pack) + self.vbar = VerticalSplit(screen, pack) self.displays = [self.statsdisplay, self.mapdisplay, self.mainmenudisplay, self.settingsmenudisplay, self.logsdisplay] @@ -44,12 +47,14 @@ class DisplayManager: def refresh(self) -> None: if self.game.state == GameMode.PLAY: # The map pad has already the good size - self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, self.cols, - resize_pad=False) - self.statsdisplay.refresh(self.rows * 4 // 5, 0, - self.rows // 10, self.cols) - self.logsdisplay.refresh(self.rows * 9 // 10, 0, - self.rows // 10, self.cols) + self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, + self.cols * 4 // 5, resize_pad=False) + self.statsdisplay.refresh(0, self.cols * 4 // 5 + 1, + self.rows, self.cols // 5 - 1) + self.logsdisplay.refresh(self.rows * 4 // 5 + 1, 0, + self.rows // 5 - 1, self.cols * 4 // 5) + self.hbar.refresh(self.rows * 4 // 5, 0, 1, self.cols * 4 // 5) + self.vbar.refresh(0, self.cols * 4 // 5, self.rows, 1) if self.game.state == GameMode.MAINMENU: self.mainmenudisplay.refresh(0, 0, self.rows, self.cols) if self.game.state == GameMode.SETTINGS: diff --git a/squirrelbattle/display/logsdisplay.py b/squirrelbattle/display/logsdisplay.py index 0d95915..368c036 100644 --- a/squirrelbattle/display/logsdisplay.py +++ b/squirrelbattle/display/logsdisplay.py @@ -19,5 +19,5 @@ class LogsDisplay(Display): for i in range(min(self.height, len(messages))): self.pad.addstr(self.height - i - 1, self.x, messages[i][:self.width]) - self.pad.refresh(0, 0, self.y, self.x, self.y + self.height, - self.x + self.width) + self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, + self.x + self.width - 1) diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index 082772b..443722f 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -1,16 +1,16 @@ from typing import List from squirrelbattle.menus import Menu, MainMenu -from .display import Display +from .display import Display, Box from ..resources import ResourceManager class MenuDisplay(Display): position: int - def __init__(self, *args): - super().__init__(*args) - self.menubox = self.newpad(self.rows, self.cols) + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.menubox = Box(*args, **kwargs) def update_menu(self, menu: Menu) -> None: self.menu = menu @@ -34,16 +34,7 @@ class MenuDisplay(Display): if self.height - 2 >= self.trueheight - self.menu.position else 0 # Menu box - self.menubox.clear() - self.menubox.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓") - for i in range(1, self.height - 1): - self.menubox.addstr(i, 0, "┃" + " " * (self.width - 2) + "┃") - self.menubox.addstr(self.height - 1, 0, - "┗" + "━" * (self.width - 2) + "┛") - - self.menubox.refresh(0, 0, self.y, self.x, - self.height + self.y, - self.width + self.x) + self.menubox.refresh(self.y, self.x, self.height, self.width) self.pad.clear() self.update_pad() self.pad.refresh(cornery, 0, self.y + 1, self.x + 2, @@ -90,7 +81,7 @@ class MainMenuDisplay(Display): for i in range(len(self.title)): self.pad.addstr(4 + i, max(self.width // 2 - len(self.title[0]) // 2 - 1, 0), self.title[i]) - self.pad.refresh(0, 0, self.y, self.x, self.height, self.width) + self.pad.refresh(0, 0, self.y, self.x, self.height + self.y - 1, self.width + self.x - 1) menuwidth = min(self.menudisplay.preferred_width, self.width) menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1 self.menudisplay.refresh( diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index 77ddb30..bc7a864 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -17,31 +17,27 @@ class StatsDisplay(Display): self.player = p def update_pad(self) -> None: - string = "" - for _ in range(self.width - 1): - string = string + "-" - self.pad.addstr(0, 0, string) - string2 = "Player -- LVL {} EXP {}/{} HP {}/{}"\ + string2 = "Player -- LVL {}\nEXP {}/{}\nHP {}/{}"\ .format(self.player.level, self.player.current_xp, self.player.max_xp, self.player.health, self.player.maxhealth) for _ in range(self.width - len(string2) - 1): string2 = string2 + " " - self.pad.addstr(1, 0, string2) - string3 = "Stats : STR {} INT {} CHR {} DEX {} CON {}"\ + self.pad.addstr(0, 0, string2) + string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}"\ .format(self.player.strength, self.player.intelligence, self.player.charisma, self.player.dexterity, self.player.constitution) for _ in range(self.width - len(string3) - 1): string3 = string3 + " " - self.pad.addstr(2, 0, string3) + self.pad.addstr(3, 0, string3) inventory_str = "Inventaire : " + "".join( self.pack[item.name.upper()] for item in self.player.inventory) - self.pad.addstr(3, 0, inventory_str) + self.pad.addstr(8, 0, inventory_str) if self.player.dead: - self.pad.addstr(4, 0, "VOUS ÊTES MORT", + self.pad.addstr(10, 0, "VOUS ÊTES MORT", curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT | self.color_pair(3)) @@ -49,4 +45,4 @@ class StatsDisplay(Display): self.pad.clear() self.update_pad() self.pad.refresh(0, 0, self.y, self.x, - 4 + self.y, self.width + self.x) + self.y + self.height - 1, self.width + self.x - 1) From 223c20e792e61fcfc16b65738bb2bf1f513599bf Mon Sep 17 00:00:00 2001 From: Nicolas Margulies Date: Fri, 20 Nov 2020 18:09:39 +0100 Subject: [PATCH 11/54] Linting --- squirrelbattle/display/display.py | 9 +++++---- squirrelbattle/display/menudisplay.py | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index d1ead44..0cdba98 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -91,17 +91,18 @@ class HorizontalSplit(Display): self.pad.addstr(0, i, "━") self.pad.refresh(0, 0, self.y, self.x, self.y, self.x + self.width - 1) + class Box(Display): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.pad = self.newpad(self.rows, self.cols) - + def display(self) -> None: self.pad.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓") for i in range(1, self.height - 1): self.pad.addstr(i, 0, "┃") self.pad.addstr(i, self.width - 1, "┃") - self.pad.addstr(self.height - 1, 0, - "┗" + "━" * (self.width - 2) + "┛") - self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x + self.width - 1) + self.pad.addstr(self.height - 1, 0, "┗" + "━" * (self.width - 2) + "┛") + self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, + self.x + self.width - 1) diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index 443722f..3c4e5a1 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -81,7 +81,8 @@ class MainMenuDisplay(Display): for i in range(len(self.title)): self.pad.addstr(4 + i, max(self.width // 2 - len(self.title[0]) // 2 - 1, 0), self.title[i]) - self.pad.refresh(0, 0, self.y, self.x, self.height + self.y - 1, self.width + self.x - 1) + self.pad.refresh(0, 0, self.y, self.x, self.height + self.y - 1, + self.width + self.x - 1) menuwidth = min(self.menudisplay.preferred_width, self.width) menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1 self.menudisplay.refresh( From b3df257103f619686c9c8ffc20db8e7bb3ca4aa9 Mon Sep 17 00:00:00 2001 From: Nicolas Margulies Date: Fri, 20 Nov 2020 18:12:30 +0100 Subject: [PATCH 12/54] Removed useless code --- squirrelbattle/display/statsdisplay.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index bc7a864..f47862e 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -21,15 +21,11 @@ class StatsDisplay(Display): .format(self.player.level, self.player.current_xp, self.player.max_xp, self.player.health, self.player.maxhealth) - for _ in range(self.width - len(string2) - 1): - string2 = string2 + " " self.pad.addstr(0, 0, string2) string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}"\ .format(self.player.strength, self.player.intelligence, self.player.charisma, self.player.dexterity, self.player.constitution) - for _ in range(self.width - len(string3) - 1): - string3 = string3 + " " self.pad.addstr(3, 0, string3) inventory_str = "Inventaire : " + "".join( From 8b187ec2b39f8f3723f2ec979981bdf55d86869d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 12:35:52 +0100 Subject: [PATCH 13/54] Use custom function to render a string message onto a pad --- squirrelbattle/display/display.py | 16 ++++++++++------ squirrelbattle/display/logsdisplay.py | 4 ++-- squirrelbattle/display/mapdisplay.py | 8 ++++---- squirrelbattle/display/menudisplay.py | 10 +++++----- squirrelbattle/display/statsdisplay.py | 12 ++++++------ 5 files changed, 27 insertions(+), 23 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index 0cdba98..ecfb2ec 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -19,6 +19,9 @@ class Display: def newpad(self, height: int, width: int) -> Union[FakePad, Any]: return curses.newpad(height, width) if self.screen else FakePad() + def addstr(self, pad: Any, y: int, x: int, msg: str, *options) -> None: + return pad.addstr(y, x, msg, *options) + def init_pair(self, number: int, foreground: int, background: int) -> None: return curses.init_pair(number, foreground, background) \ if self.screen else None @@ -68,7 +71,7 @@ class VerticalSplit(Display): def display(self) -> None: for i in range(self.height): - self.pad.addstr(i, 0, "┃") + self.addstr(self.pad, i, 0, "┃") self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x) @@ -88,7 +91,7 @@ class HorizontalSplit(Display): def display(self) -> None: for i in range(self.width): - self.pad.addstr(0, i, "━") + self.addstr(self.pad, 0, i, "━") self.pad.refresh(0, 0, self.y, self.x, self.y, self.x + self.width - 1) @@ -99,10 +102,11 @@ class Box(Display): self.pad = self.newpad(self.rows, self.cols) def display(self) -> None: - self.pad.addstr(0, 0, "┏" + "━" * (self.width - 2) + "┓") + self.addstr(self.pad, 0, 0, "┏" + "━" * (self.width - 2) + "┓") for i in range(1, self.height - 1): - self.pad.addstr(i, 0, "┃") - self.pad.addstr(i, self.width - 1, "┃") - self.pad.addstr(self.height - 1, 0, "┗" + "━" * (self.width - 2) + "┛") + self.addstr(self.pad, i, 0, "┃") + self.addstr(self.pad, i, self.width - 1, "┃") + self.addstr(self.pad, self.height - 1, 0, + "┗" + "━" * (self.width - 2) + "┛") self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x + self.width - 1) diff --git a/squirrelbattle/display/logsdisplay.py b/squirrelbattle/display/logsdisplay.py index 368c036..304cf7b 100644 --- a/squirrelbattle/display/logsdisplay.py +++ b/squirrelbattle/display/logsdisplay.py @@ -17,7 +17,7 @@ class LogsDisplay(Display): messages = messages[::-1] self.pad.clear() for i in range(min(self.height, len(messages))): - self.pad.addstr(self.height - i - 1, self.x, - messages[i][:self.width]) + self.addstr(self.pad, self.height - i - 1, self.x, + messages[i][:self.width]) self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x + self.width - 1) diff --git a/squirrelbattle/display/mapdisplay.py b/squirrelbattle/display/mapdisplay.py index e6cc278..571c527 100644 --- a/squirrelbattle/display/mapdisplay.py +++ b/squirrelbattle/display/mapdisplay.py @@ -15,11 +15,11 @@ class MapDisplay(Display): def update_pad(self) -> None: self.init_pair(1, self.pack.tile_fg_color, self.pack.tile_bg_color) self.init_pair(2, self.pack.entity_fg_color, self.pack.entity_bg_color) - self.pad.addstr(0, 0, self.map.draw_string(self.pack), - self.color_pair(1)) + self.addstr(self.pad, 0, 0, self.map.draw_string(self.pack), + self.color_pair(1)) for e in self.map.entities: - self.pad.addstr(e.y, self.pack.tile_width * e.x, - self.pack[e.name.upper()], self.color_pair(2)) + self.addstr(self.pad, e.y, self.pack.tile_width * e.x, + self.pack[e.name.upper()], self.color_pair(2)) def display(self) -> None: y, x = self.map.currenty, self.pack.tile_width * self.map.currentx diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index 3c4e5a1..8d03017 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -20,13 +20,13 @@ class MenuDisplay(Display): # Menu values are printed in pad self.pad = self.newpad(self.trueheight, self.truewidth + 2) for i in range(self.trueheight): - self.pad.addstr(i, 0, " " + self.values[i]) + self.addstr(self.pad, i, 0, " " + self.values[i]) def update_pad(self) -> None: for i in range(self.trueheight): - self.pad.addstr(i, 0, " " + self.values[i]) + self.addstr(self.pad, i, 0, " " + self.values[i]) # set a marker on the selected line - self.pad.addstr(self.menu.position, 0, ">") + self.addstr(self.pad, self.menu.position, 0, ">") def display(self) -> None: cornery = 0 if self.height - 2 >= self.menu.position - 1 \ @@ -79,8 +79,8 @@ class MainMenuDisplay(Display): def display(self) -> None: for i in range(len(self.title)): - self.pad.addstr(4 + i, max(self.width // 2 - - len(self.title[0]) // 2 - 1, 0), self.title[i]) + self.addstr(self.pad, 4 + i, max(self.width // 2 + - len(self.title[0]) // 2 - 1, 0), self.title[i]) self.pad.refresh(0, 0, self.y, self.x, self.height + self.y - 1, self.width + self.x - 1) menuwidth = min(self.menudisplay.preferred_width, self.width) diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index f47862e..bd20ede 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -21,21 +21,21 @@ class StatsDisplay(Display): .format(self.player.level, self.player.current_xp, self.player.max_xp, self.player.health, self.player.maxhealth) - self.pad.addstr(0, 0, string2) + self.addstr(self.pad, 0, 0, string2) string3 = "STR {}\nINT {}\nCHR {}\nDEX {}\nCON {}"\ .format(self.player.strength, self.player.intelligence, self.player.charisma, self.player.dexterity, self.player.constitution) - self.pad.addstr(3, 0, string3) + self.addstr(self.pad, 3, 0, string3) inventory_str = "Inventaire : " + "".join( self.pack[item.name.upper()] for item in self.player.inventory) - self.pad.addstr(8, 0, inventory_str) + self.addstr(self.pad, 8, 0, inventory_str) if self.player.dead: - self.pad.addstr(10, 0, "VOUS ÊTES MORT", - curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT - | self.color_pair(3)) + self.addstr(self.pad, 10, 0, "VOUS ÊTES MORT", + curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT + | self.color_pair(3)) def display(self) -> None: self.pad.clear() From f2318ed30863ae88fe85e8abcfd21ec7f782be74 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 20:04:54 +0100 Subject: [PATCH 14/54] Truncate messages if they are too large --- squirrelbattle/display/display.py | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index ecfb2ec..0a06c65 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -19,8 +19,21 @@ class Display: def newpad(self, height: int, width: int) -> Union[FakePad, Any]: return curses.newpad(height, width) if self.screen else FakePad() + def truncate(self, msg: str, height: int, width: int) -> str: + lines = msg.split("\n") + lines = lines[:height] + lines = [line[:width] for line in lines] + return "\n".join(lines) + def addstr(self, pad: Any, y: int, x: int, msg: str, *options) -> None: - return pad.addstr(y, x, msg, *options) + """ + Display a message onto the pad. + If the message is too large, it is truncated vertically and horizontally + """ + height, width = pad.getmaxyx() + msg = self.truncate(msg, height - y, width - x) + if msg.replace("\n", ""): + return pad.addstr(y, x, msg, *options) def init_pair(self, number: int, foreground: int, background: int) -> None: return curses.init_pair(number, foreground, background) \ From ca03caf3bacaa80cfa22c97bc61525e9c752bab1 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 20:35:10 +0100 Subject: [PATCH 15/54] Don't render message on negative indexes --- squirrelbattle/display/display.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index 0a06c65..d5e3078 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -20,6 +20,8 @@ class Display: return curses.newpad(height, width) if self.screen else FakePad() def truncate(self, msg: str, height: int, width: int) -> str: + height = max(0, height) + width = max(0, width) lines = msg.split("\n") lines = lines[:height] lines = [line[:width] for line in lines] @@ -31,8 +33,8 @@ class Display: If the message is too large, it is truncated vertically and horizontally """ height, width = pad.getmaxyx() - msg = self.truncate(msg, height - y, width - x) - if msg.replace("\n", ""): + msg = self.truncate(msg, height - y, width - x - 1) + if msg.replace("\n", "") and x >= 0 and y >= 0: return pad.addstr(y, x, msg, *options) def init_pair(self, number: int, foreground: int, background: int) -> None: From f2f34bfbc66486a6efda6763dace7b8ace3d88a5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 20:58:46 +0100 Subject: [PATCH 16/54] Don't refresh pads with invalid coordinates. The window should be fully resizable, closes #20 --- squirrelbattle/display/display.py | 33 ++++++++++++++++++++++---- squirrelbattle/display/logsdisplay.py | 4 ++-- squirrelbattle/display/mapdisplay.py | 3 ++- squirrelbattle/display/menudisplay.py | 5 ++-- squirrelbattle/display/statsdisplay.py | 2 +- 5 files changed, 36 insertions(+), 11 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index d5e3078..1d70159 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -50,7 +50,8 @@ class Display: self.y = y self.width = width self.height = height - if hasattr(self, "pad") and resize_pad: + if hasattr(self, "pad") and resize_pad and \ + self.height >= 0 and self.width >= 0: self.pad.resize(self.height + 1, self.width + 1) def refresh(self, *args, resize_pad: bool = True) -> None: @@ -58,6 +59,26 @@ class Display: self.resize(*args, resize_pad) self.display() + def refresh_pad(self, pad: Any, top_y: int, top_x: int, + window_y: int, window_x: int, + last_y: int, last_x: int) -> None: + """ + Refresh a pad on a part of the window. + The refresh starts at coordinates (top_y, top_x) from the pad, + and is drawn from (window_y, window_x) to (last_y, last_x). + If coordinates are invalid (negative indexes/length..., then nothing + is drawn and no error is raised. + """ + top_y, top_x = max(0, top_y), max(0, top_x) + window_y, window_x = max(0, window_y), max(0, window_x) + screen_max_y, screen_max_x = self.screen.getmaxyx() + last_y, last_x = min(screen_max_y - 1, last_y), \ + min(screen_max_x - 1, last_x) + + if last_y >= window_y and last_x >= window_x: + # Refresh the pad only if coordinates are valid + pad.refresh(top_y, top_x, window_y, window_x, last_y, last_x) + def display(self) -> None: raise NotImplementedError @@ -87,7 +108,8 @@ class VerticalSplit(Display): def display(self) -> None: for i in range(self.height): self.addstr(self.pad, i, 0, "┃") - self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, self.x) + self.refresh_pad(self.pad, 0, 0, self.y, self.x, + self.y + self.height - 1, self.x) class HorizontalSplit(Display): @@ -107,7 +129,8 @@ class HorizontalSplit(Display): def display(self) -> None: for i in range(self.width): self.addstr(self.pad, 0, i, "━") - self.pad.refresh(0, 0, self.y, self.x, self.y, self.x + self.width - 1) + self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.y, + self.x + self.width - 1) class Box(Display): @@ -123,5 +146,5 @@ class Box(Display): self.addstr(self.pad, i, self.width - 1, "┃") self.addstr(self.pad, self.height - 1, 0, "┗" + "━" * (self.width - 2) + "┛") - self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, - self.x + self.width - 1) + self.refresh_pad(self.pad, 0, 0, self.y, self.x, + self.y + self.height - 1, self.x + self.width - 1) diff --git a/squirrelbattle/display/logsdisplay.py b/squirrelbattle/display/logsdisplay.py index 304cf7b..d332b69 100644 --- a/squirrelbattle/display/logsdisplay.py +++ b/squirrelbattle/display/logsdisplay.py @@ -19,5 +19,5 @@ class LogsDisplay(Display): for i in range(min(self.height, len(messages))): self.addstr(self.pad, self.height - i - 1, self.x, messages[i][:self.width]) - self.pad.refresh(0, 0, self.y, self.x, self.y + self.height - 1, - self.x + self.width - 1) + self.refresh_pad(self.pad, 0, 0, self.y, self.x, + self.y + self.height - 1, self.x + self.width - 1) diff --git a/squirrelbattle/display/mapdisplay.py b/squirrelbattle/display/mapdisplay.py index 571c527..ce134a5 100644 --- a/squirrelbattle/display/mapdisplay.py +++ b/squirrelbattle/display/mapdisplay.py @@ -36,4 +36,5 @@ class MapDisplay(Display): pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol)) self.pad.clear() self.update_pad() - self.pad.refresh(pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol) + self.refresh_pad(self.pad, pminrow, pmincol, sminrow, smincol, smaxrow, + smaxcol) diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index 8d03017..2338e0d 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -37,7 +37,7 @@ class MenuDisplay(Display): self.menubox.refresh(self.y, self.x, self.height, self.width) self.pad.clear() self.update_pad() - self.pad.refresh(cornery, 0, self.y + 1, self.x + 2, + self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 2, self.height - 2 + self.y, self.width - 2 + self.x) @@ -81,7 +81,8 @@ class MainMenuDisplay(Display): for i in range(len(self.title)): self.addstr(self.pad, 4 + i, max(self.width // 2 - len(self.title[0]) // 2 - 1, 0), self.title[i]) - self.pad.refresh(0, 0, self.y, self.x, self.height + self.y - 1, + self.refresh_pad(self.pad, 0, 0, self.y, self.x, + self.height + self.y - 1, self.width + self.x - 1) menuwidth = min(self.menudisplay.preferred_width, self.width) menuy, menux = len(self.title) + 8, self.width // 2 - menuwidth // 2 - 1 diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index bd20ede..988d99c 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -40,5 +40,5 @@ class StatsDisplay(Display): def display(self) -> None: self.pad.clear() self.update_pad() - self.pad.refresh(0, 0, self.y, self.x, + self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.y + self.height - 1, self.width + self.x - 1) From 3e7dabc94e8e9beb61e2e5b16d215e3e51a95387 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 21:59:48 +0100 Subject: [PATCH 17/54] Wrap perfectly the map on the screen, bricks won't teleport randomly anymore --- squirrelbattle/display/display_manager.py | 5 ++++- squirrelbattle/display/mapdisplay.py | 8 ++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/squirrelbattle/display/display_manager.py b/squirrelbattle/display/display_manager.py index d50dfa1..2c7baf1 100644 --- a/squirrelbattle/display/display_manager.py +++ b/squirrelbattle/display/display_manager.py @@ -48,7 +48,10 @@ class DisplayManager: if self.game.state == GameMode.PLAY: # The map pad has already the good size self.mapdisplay.refresh(0, 0, self.rows * 4 // 5, - self.cols * 4 // 5, resize_pad=False) + self.mapdisplay.pack.tile_width + * (self.cols * 4 // 5 + // self.mapdisplay.pack.tile_width), + resize_pad=False) self.statsdisplay.refresh(0, self.cols * 4 // 5 + 1, self.rows, self.cols // 5 - 1) self.logsdisplay.refresh(self.rows * 4 // 5 + 1, 0, diff --git a/squirrelbattle/display/mapdisplay.py b/squirrelbattle/display/mapdisplay.py index ce134a5..ae4caa3 100644 --- a/squirrelbattle/display/mapdisplay.py +++ b/squirrelbattle/display/mapdisplay.py @@ -31,9 +31,17 @@ class MapDisplay(Display): smaxrow = min(smaxrow, self.height - 1) smaxcol = self.pack.tile_width * self.map.width - \ (x + deltax) + self.width - 1 + + # Wrap perfectly the map according to the width of the tiles + pmincol = self.pack.tile_width * (pmincol // self.pack.tile_width) + smincol = self.pack.tile_width * (smincol // self.pack.tile_width) + smaxcol = self.pack.tile_width \ + * (smaxcol // self.pack.tile_width + 1) - 1 + smaxcol = min(smaxcol, self.width - 1) pminrow = max(0, min(self.map.height, pminrow)) pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol)) + self.pad.clear() self.update_pad() self.refresh_pad(self.pad, pminrow, pmincol, sminrow, smincol, smaxrow, From 1e48bd16b37a64613394ad934d47ae6ad9e256ce Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 22:20:14 +0100 Subject: [PATCH 18/54] Erase pads instead of clearing them, fixes #21 --- squirrelbattle/display/logsdisplay.py | 2 +- squirrelbattle/display/mapdisplay.py | 2 +- squirrelbattle/display/menudisplay.py | 2 +- squirrelbattle/display/statsdisplay.py | 2 +- squirrelbattle/game.py | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/squirrelbattle/display/logsdisplay.py b/squirrelbattle/display/logsdisplay.py index d332b69..43a18dc 100644 --- a/squirrelbattle/display/logsdisplay.py +++ b/squirrelbattle/display/logsdisplay.py @@ -15,7 +15,7 @@ class LogsDisplay(Display): print(type(self.logs.messages), flush=True) messages = self.logs.messages[-self.height:] messages = messages[::-1] - self.pad.clear() + self.pad.erase() for i in range(min(self.height, len(messages))): self.addstr(self.pad, self.height - i - 1, self.x, messages[i][:self.width]) diff --git a/squirrelbattle/display/mapdisplay.py b/squirrelbattle/display/mapdisplay.py index ae4caa3..9599a54 100644 --- a/squirrelbattle/display/mapdisplay.py +++ b/squirrelbattle/display/mapdisplay.py @@ -42,7 +42,7 @@ class MapDisplay(Display): pminrow = max(0, min(self.map.height, pminrow)) pmincol = max(0, min(self.pack.tile_width * self.map.width, pmincol)) - self.pad.clear() + self.pad.erase() self.update_pad() self.refresh_pad(self.pad, pminrow, pmincol, sminrow, smincol, smaxrow, smaxcol) diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index 2338e0d..b04ac37 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -35,7 +35,7 @@ class MenuDisplay(Display): # Menu box self.menubox.refresh(self.y, self.x, self.height, self.width) - self.pad.clear() + self.pad.erase() self.update_pad() self.refresh_pad(self.pad, cornery, 0, self.y + 1, self.x + 2, self.height - 2 + self.y, diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index 988d99c..d33f55c 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -38,7 +38,7 @@ class StatsDisplay(Display): | self.color_pair(3)) def display(self) -> None: - self.pad.clear() + self.pad.erase() self.update_pad() self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.y + self.height - 1, self.width + self.x - 1) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 0bb3024..dce1165 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -55,7 +55,7 @@ class Game: when the given key gets pressed. """ while True: # pragma no cover - screen.clear() + screen.erase() screen.refresh() self.display_actions(DisplayActions.REFRESH) key = screen.getkey() From 0726a8db9e756aa44908d580d6fd6611b4c2ad4d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 22:29:10 +0100 Subject: [PATCH 19/54] A print instruction remains. It was rendered on the screen. Awkward... --- squirrelbattle/display/logsdisplay.py | 1 - 1 file changed, 1 deletion(-) diff --git a/squirrelbattle/display/logsdisplay.py b/squirrelbattle/display/logsdisplay.py index 43a18dc..7bed61e 100644 --- a/squirrelbattle/display/logsdisplay.py +++ b/squirrelbattle/display/logsdisplay.py @@ -12,7 +12,6 @@ class LogsDisplay(Display): self.logs = logs def display(self) -> None: - print(type(self.logs.messages), flush=True) messages = self.logs.messages[-self.height:] messages = messages[::-1] self.pad.erase() From 2690eb8760a570fea44ee3c03f95b4d5010903bb Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 26 Nov 2020 22:32:25 +0100 Subject: [PATCH 20/54] Update FakePad to fix tests --- squirrelbattle/display/display.py | 3 ++- squirrelbattle/tests/screen.py | 8 +++++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index 1d70159..bd16344 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -71,7 +71,8 @@ class Display: """ top_y, top_x = max(0, top_y), max(0, top_x) window_y, window_x = max(0, window_y), max(0, window_x) - screen_max_y, screen_max_x = self.screen.getmaxyx() + screen_max_y, screen_max_x = self.screen.getmaxyx() if self.screen \ + else 42, 42 last_y, last_x = min(screen_max_y - 1, last_y), \ min(screen_max_x - 1, last_x) diff --git a/squirrelbattle/tests/screen.py b/squirrelbattle/tests/screen.py index 6eb2cd0..a6b3c9a 100644 --- a/squirrelbattle/tests/screen.py +++ b/squirrelbattle/tests/screen.py @@ -1,3 +1,6 @@ +from typing import Tuple + + class FakePad: """ In order to run tests, we simulate a fake curses pad that accepts functions @@ -10,8 +13,11 @@ class FakePad: smincol: int, smaxrow: int, smaxcol: int) -> None: pass - def clear(self) -> None: + def erase(self) -> None: pass def resize(self, height: int, width: int) -> None: pass + + def getmaxyx(self) -> Tuple[int, int]: + return 42, 42 From 0c25dd4ffea86b9f5e40b33227be94bf32dc6080 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 14:04:51 +0100 Subject: [PATCH 21/54] Display got broken --- squirrelbattle/display/display.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index bd16344..9f2f86a 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -72,7 +72,7 @@ class Display: top_y, top_x = max(0, top_y), max(0, top_x) window_y, window_x = max(0, window_y), max(0, window_x) screen_max_y, screen_max_x = self.screen.getmaxyx() if self.screen \ - else 42, 42 + else (42, 42) last_y, last_x = min(screen_max_y - 1, last_y), \ min(screen_max_x - 1, last_x) From 1782ffcffb13963d4bbc20a0656fda6a813a6ffa Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 16:16:19 +0100 Subject: [PATCH 22/54] Rename LICENSE to COPYING --- LICENSE => COPYING | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename LICENSE => COPYING (100%) diff --git a/LICENSE b/COPYING similarity index 100% rename from LICENSE rename to COPYING From 0d3e33d960b96047479c89ce6eaee525273333e2 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 16:33:17 +0100 Subject: [PATCH 23/54] Declare the license, we use GNU GPL --- COPYING | 2 +- debian/copyright | 6 +++--- main.py | 6 +++++- setup.py | 4 ++++ squirrelbattle/__init__.py | 2 ++ squirrelbattle/bootstrap.py | 3 +++ squirrelbattle/display/__init__.py | 2 ++ squirrelbattle/display/display.py | 3 +++ squirrelbattle/display/display_manager.py | 3 +++ squirrelbattle/display/logsdisplay.py | 3 +++ squirrelbattle/display/mapdisplay.py | 4 +++- squirrelbattle/display/menudisplay.py | 3 +++ squirrelbattle/display/statsdisplay.py | 3 +++ squirrelbattle/display/texturepack.py | 3 +++ squirrelbattle/entities/__init__.py | 2 ++ squirrelbattle/entities/items.py | 3 +++ squirrelbattle/entities/monsters.py | 3 +++ squirrelbattle/entities/player.py | 3 +++ squirrelbattle/enums.py | 3 +++ squirrelbattle/game.py | 3 +++ squirrelbattle/interfaces.py | 4 +++- squirrelbattle/menus.py | 3 +++ squirrelbattle/resources.py | 3 +++ squirrelbattle/settings.py | 3 +++ squirrelbattle/term_manager.py | 3 +++ squirrelbattle/tests/__init__.py | 2 ++ squirrelbattle/tests/entities_test.py | 3 +++ squirrelbattle/tests/game_test.py | 3 +++ squirrelbattle/tests/interfaces_test.py | 3 +++ squirrelbattle/tests/screen.py | 3 +++ squirrelbattle/tests/settings_test.py | 3 +++ 31 files changed, 90 insertions(+), 7 deletions(-) diff --git a/COPYING b/COPYING index 7d821ed..e3107c7 100644 --- a/COPYING +++ b/COPYING @@ -652,7 +652,7 @@ Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: - Squirrel Battle Copyright (C) 2020 ynerant + Squirrel Battle Copyright (C) 2020 ĂżnĂ©rant, eichhornchen, nicomarg, charlse This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. diff --git a/debian/copyright b/debian/copyright index c616d56..6d35767 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1,11 +1,11 @@ Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ -Upstream-Name: Yohann D'ANELLO -Upstream-Contact: Yohann D'ANELLO +Upstream-Name: ĂżnĂ©rant, eichhornchen, nicomarg, charlse +Upstream-Contact: ĂżnĂ©rant, eichhornchen, nicomarg, charlse Source: https://gitlab.crans.org/ynerant/squirrel-battle Files: * -Copyright: 2020 Yohann D'ANELLO +Copyright: 2020 ĂżnĂ©rant, eichhornchen, nicomarg, charlse License: GPL-3+ This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public diff --git a/main.py b/main.py index 64972f1..e8c333e 100755 --- a/main.py +++ b/main.py @@ -1,4 +1,8 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 + +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from squirrelbattle.bootstrap import Bootstrap if __name__ == "__main__": diff --git a/setup.py b/setup.py index dfb15ef..2cd5038 100644 --- a/setup.py +++ b/setup.py @@ -1,4 +1,8 @@ #!/usr/bin/env python3 + +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import os from setuptools import find_packages, setup diff --git a/squirrelbattle/__init__.py b/squirrelbattle/__init__.py index e69de29..1cc6688 100644 --- a/squirrelbattle/__init__.py +++ b/squirrelbattle/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/squirrelbattle/bootstrap.py b/squirrelbattle/bootstrap.py index 45c2ad1..f041aef 100644 --- a/squirrelbattle/bootstrap.py +++ b/squirrelbattle/bootstrap.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from squirrelbattle.game import Game from squirrelbattle.display.display_manager import DisplayManager from squirrelbattle.term_manager import TermManager diff --git a/squirrelbattle/display/__init__.py b/squirrelbattle/display/__init__.py index e69de29..1cc6688 100644 --- a/squirrelbattle/display/__init__.py +++ b/squirrelbattle/display/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index 9f2f86a..00169f5 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import curses from typing import Any, Optional, Union diff --git a/squirrelbattle/display/display_manager.py b/squirrelbattle/display/display_manager.py index 2c7baf1..061d8c0 100644 --- a/squirrelbattle/display/display_manager.py +++ b/squirrelbattle/display/display_manager.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import curses from squirrelbattle.display.display import VerticalSplit, HorizontalSplit from squirrelbattle.display.mapdisplay import MapDisplay diff --git a/squirrelbattle/display/logsdisplay.py b/squirrelbattle/display/logsdisplay.py index 7bed61e..b768a0e 100644 --- a/squirrelbattle/display/logsdisplay.py +++ b/squirrelbattle/display/logsdisplay.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from squirrelbattle.display.display import Display from squirrelbattle.interfaces import Logs diff --git a/squirrelbattle/display/mapdisplay.py b/squirrelbattle/display/mapdisplay.py index 9599a54..445f736 100644 --- a/squirrelbattle/display/mapdisplay.py +++ b/squirrelbattle/display/mapdisplay.py @@ -1,4 +1,6 @@ -#!/usr/bin/env python +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from squirrelbattle.interfaces import Map from .display import Display diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index b04ac37..731ecee 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from typing import List from squirrelbattle.menus import Menu, MainMenu diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index d33f55c..b65e716 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import curses from .display import Display diff --git a/squirrelbattle/display/texturepack.py b/squirrelbattle/display/texturepack.py index 375172a..dfee866 100644 --- a/squirrelbattle/display/texturepack.py +++ b/squirrelbattle/display/texturepack.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import curses from typing import Any diff --git a/squirrelbattle/entities/__init__.py b/squirrelbattle/entities/__init__.py index e69de29..1cc6688 100644 --- a/squirrelbattle/entities/__init__.py +++ b/squirrelbattle/entities/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/squirrelbattle/entities/items.py b/squirrelbattle/entities/items.py index 9927ef4..147d72c 100644 --- a/squirrelbattle/entities/items.py +++ b/squirrelbattle/entities/items.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from typing import Optional from .player import Player diff --git a/squirrelbattle/entities/monsters.py b/squirrelbattle/entities/monsters.py index cf4ba39..624f8a3 100644 --- a/squirrelbattle/entities/monsters.py +++ b/squirrelbattle/entities/monsters.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from random import choice from .player import Player diff --git a/squirrelbattle/entities/player.py b/squirrelbattle/entities/player.py index 702b055..e452c8d 100644 --- a/squirrelbattle/entities/player.py +++ b/squirrelbattle/entities/player.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from random import randint from typing import Dict, Tuple diff --git a/squirrelbattle/enums.py b/squirrelbattle/enums.py index 350c196..024f167 100644 --- a/squirrelbattle/enums.py +++ b/squirrelbattle/enums.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from enum import Enum, auto from typing import Optional diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index dce1165..c60d93f 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from random import randint from typing import Any, Optional import json diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index 5cbe48f..8958e7b 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -1,4 +1,6 @@ -#!/usr/bin/env python +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from enum import Enum, auto from math import sqrt from random import choice, randint diff --git a/squirrelbattle/menus.py b/squirrelbattle/menus.py index cd7604a..31c50ea 100644 --- a/squirrelbattle/menus.py +++ b/squirrelbattle/menus.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from enum import Enum from typing import Any, Optional diff --git a/squirrelbattle/resources.py b/squirrelbattle/resources.py index fc6f708..b3421db 100644 --- a/squirrelbattle/resources.py +++ b/squirrelbattle/resources.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from pathlib import Path diff --git a/squirrelbattle/settings.py b/squirrelbattle/settings.py index 6c2e31c..9601457 100644 --- a/squirrelbattle/settings.py +++ b/squirrelbattle/settings.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import json import os from typing import Any, Generator diff --git a/squirrelbattle/term_manager.py b/squirrelbattle/term_manager.py index b1f10b1..6284173 100644 --- a/squirrelbattle/term_manager.py +++ b/squirrelbattle/term_manager.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import curses from types import TracebackType diff --git a/squirrelbattle/tests/__init__.py b/squirrelbattle/tests/__init__.py index e69de29..1cc6688 100644 --- a/squirrelbattle/tests/__init__.py +++ b/squirrelbattle/tests/__init__.py @@ -0,0 +1,2 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later diff --git a/squirrelbattle/tests/entities_test.py b/squirrelbattle/tests/entities_test.py index b92a2c4..8f4e0c2 100644 --- a/squirrelbattle/tests/entities_test.py +++ b/squirrelbattle/tests/entities_test.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import unittest from squirrelbattle.entities.items import Bomb, Heart, Item diff --git a/squirrelbattle/tests/game_test.py b/squirrelbattle/tests/game_test.py index 61c6c8e..28b354d 100644 --- a/squirrelbattle/tests/game_test.py +++ b/squirrelbattle/tests/game_test.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import os import unittest diff --git a/squirrelbattle/tests/interfaces_test.py b/squirrelbattle/tests/interfaces_test.py index 62f2092..c9f7253 100644 --- a/squirrelbattle/tests/interfaces_test.py +++ b/squirrelbattle/tests/interfaces_test.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import unittest from squirrelbattle.display.texturepack import TexturePack diff --git a/squirrelbattle/tests/screen.py b/squirrelbattle/tests/screen.py index a6b3c9a..9a8afe6 100644 --- a/squirrelbattle/tests/screen.py +++ b/squirrelbattle/tests/screen.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + from typing import Tuple diff --git a/squirrelbattle/tests/settings_test.py b/squirrelbattle/tests/settings_test.py index 76bcaba..cef60c0 100644 --- a/squirrelbattle/tests/settings_test.py +++ b/squirrelbattle/tests/settings_test.py @@ -1,3 +1,6 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + import unittest from squirrelbattle.settings import Settings From f0488690b79620ccca5af2882fd624e32eb471eb Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 16:53:16 +0100 Subject: [PATCH 24/54] Forgot some author mentions in some files, closes #23 --- COPYING | 2 +- debian/README.debian | 2 +- debian/changelog | 2 +- debian/control | 2 +- docs/deployment.rst | 10 +++++----- setup.py | 6 +++--- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/COPYING b/COPYING index e3107c7..1bc08a5 100644 --- a/COPYING +++ b/COPYING @@ -632,7 +632,7 @@ state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Squirrel Battle - Copyright (C) 2020 ynerant + Copyright (C) 2020 ĂżnĂ©rant, eichhornchen, nicomarg, charlse This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/debian/README.debian b/debian/README.debian index 8404efb..6961b22 100644 --- a/debian/README.debian +++ b/debian/README.debian @@ -2,4 +2,4 @@ Squirrel Battle Watch out for squirrel's knifes! - -- Yohann D'ANELLO Thu, 19 Nov 2020 03:30:42 +0100 + -- Yohann D'ANELLO Thu, 19 Nov 2020 03:30:42 +0100 diff --git a/debian/changelog b/debian/changelog index d1afdad..536fca5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -2,4 +2,4 @@ python3-squirrel-battle (3.14) beta; urgency=low * Initial release. - -- Yohann D'ANELLO Thu, 19 Nov 2020 03:30:42 +0100 + -- Yohann D'ANELLO Thu, 19 Nov 2020 03:30:42 +0100 diff --git a/debian/control b/debian/control index e36e424..fc52e38 100644 --- a/debian/control +++ b/debian/control @@ -1,7 +1,7 @@ Source: python3-squirrel-battle Section: devel Priority: optional -Maintainer: ynerant +Maintainer: ynerant Build-Depends: debhelper (>=10~), dh-python, python3-all, python3-setuptools Depends: fonts-noto-color-emoji Standards-Version: 4.1.4 diff --git a/docs/deployment.rst b/docs/deployment.rst index 1a4860d..99b15f9 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -37,9 +37,9 @@ paquet ainsi que des dĂ©tails Ă  fournir Ă  PyPI : setup( name="squirrel-battle", version="3.14", - author="ynerant", - author_email="ynerant@crans.org", - description="Watch out for squirrel's knifes!", + author="ĂżnĂ©rant, eichhornchen, nicomarg, charlse", + author_email="squirrel-battle@crans.org", + description="Watch out for squirrel's knives!", long_description=long_description, long_description_content_type="text/markdown", url="https://gitlab.crans.org/ynerant/squirrel-battle", @@ -156,7 +156,7 @@ du dĂ©pĂŽt Git. Le fichier ``PKGBUILD`` dispose de cette structure : .. code:: - # Maintainer: Yohann D'ANELLO + # Maintainer: Yohann D'ANELLO pkgbase=squirrel-battle pkgname=python-squirrel-battle-git @@ -206,7 +206,7 @@ les releases, est plus ou moins similaire : .. code:: - # Maintainer: Yohann D'ANELLO + # Maintainer: Yohann D'ANELLO pkgbase=squirrel-battle pkgname=python-squirrel-battle diff --git a/setup.py b/setup.py index 2cd5038..ef34c31 100644 --- a/setup.py +++ b/setup.py @@ -13,9 +13,9 @@ with open("README.md", "r") as f: setup( name="squirrel-battle", version="3.14", - author="ynerant", - author_email="ynerant@crans.org", - description="Watch out for squirrel's knifes!", + author="ĂżnĂ©rant, eichhornchen, nicomarg, charlse", + author_email="squirrel-battle@crans.org", + description="Watch out for squirrel's knives!", long_description=long_description, long_description_content_type="text/markdown", url="https://gitlab.crans.org/ynerant/squirrel-battle", From 461d176ce42b304d8a805191e1ed5784ae0c78af Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 16:54:47 +0100 Subject: [PATCH 25/54] Build debian packages only on pipelines that run on the master branch --- .gitlab-ci.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 6cb844c..8613258 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -45,3 +45,5 @@ build-deb: paths: - build/*.deb expire_in: 1 week + only: + - master From 5cdb12e8a83a84ed6d83cfdee1d91ae5bea6ed08 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 17:32:26 +0100 Subject: [PATCH 26/54] Display a message on a popup --- squirrelbattle/display/display_manager.py | 14 +++++++++++- squirrelbattle/display/messagedisplay.py | 26 +++++++++++++++++++++++ squirrelbattle/game.py | 1 + 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 squirrelbattle/display/messagedisplay.py diff --git a/squirrelbattle/display/display_manager.py b/squirrelbattle/display/display_manager.py index 061d8c0..869b7d4 100644 --- a/squirrelbattle/display/display_manager.py +++ b/squirrelbattle/display/display_manager.py @@ -4,6 +4,7 @@ import curses from squirrelbattle.display.display import VerticalSplit, HorizontalSplit from squirrelbattle.display.mapdisplay import MapDisplay +from squirrelbattle.display.messagedisplay import MessageDisplay from squirrelbattle.display.statsdisplay import StatsDisplay from squirrelbattle.display.menudisplay import SettingsMenuDisplay, \ MainMenuDisplay @@ -26,11 +27,12 @@ class DisplayManager: screen, pack) self.settingsmenudisplay = SettingsMenuDisplay(screen, pack) self.logsdisplay = LogsDisplay(screen, pack) + self.messagedisplay = MessageDisplay(screen) self.hbar = HorizontalSplit(screen, pack) self.vbar = VerticalSplit(screen, pack) self.displays = [self.statsdisplay, self.mapdisplay, self.mainmenudisplay, self.settingsmenudisplay, - self.logsdisplay] + self.logsdisplay, self.messagedisplay] self.update_game_components() def handle_display_action(self, action: DisplayActions) -> None: @@ -46,6 +48,7 @@ class DisplayManager: self.statsdisplay.update_player(self.game.player) self.settingsmenudisplay.update_menu(self.game.settings_menu) self.logsdisplay.update_logs(self.game.logs) + self.messagedisplay.update_message(self.game.message) def refresh(self) -> None: if self.game.state == GameMode.PLAY: @@ -65,6 +68,15 @@ class DisplayManager: self.mainmenudisplay.refresh(0, 0, self.rows, self.cols) if self.game.state == GameMode.SETTINGS: self.settingsmenudisplay.refresh(0, 0, self.rows, self.cols - 1) + + if self.game.message: + height, width = 0, 0 + for line in self.game.message.split("\n"): + height += 1 + width = max(width, len(line)) + y, x = (self.rows - height) // 2, (self.cols - width) // 2 + self.messagedisplay.refresh(y, x, height, width) + self.resize_window() def resize_window(self) -> bool: diff --git a/squirrelbattle/display/messagedisplay.py b/squirrelbattle/display/messagedisplay.py new file mode 100644 index 0000000..34c6586 --- /dev/null +++ b/squirrelbattle/display/messagedisplay.py @@ -0,0 +1,26 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + +from squirrelbattle.display.display import Box, Display + + +class MessageDisplay(Display): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + + self.box = Box(*args, **kwargs) + self.message = "" + self.pad = self.newpad(1, 1) + + def update_message(self, msg: str) -> None: + self.message = msg + + def display(self) -> None: + self.box.refresh(self.y - 1, self.x - 2, + self.height + 2, self.width + 4) + self.box.display() + self.pad.erase() + self.addstr(self.pad, 0, 0, self.message) + self.refresh_pad(self.pad, 0, 0, self.y, self.x, + self.height + self.y - 1, + self.width + self.x - 1) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index c60d93f..4553392 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -37,6 +37,7 @@ class Game: self.settings.write_settings() self.settings_menu.update_values(self.settings) self.logs = Logs() + self.message = "Vive les Ă©cureuils" def new_game(self) -> None: """ From b7f61d9485473398cd92eced6f76d2c9631e4398 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 17:35:51 +0100 Subject: [PATCH 27/54] Close popup if there is a message --- squirrelbattle/display/messagedisplay.py | 4 ++++ squirrelbattle/game.py | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/squirrelbattle/display/messagedisplay.py b/squirrelbattle/display/messagedisplay.py index 34c6586..9e4ffae 100644 --- a/squirrelbattle/display/messagedisplay.py +++ b/squirrelbattle/display/messagedisplay.py @@ -5,6 +5,10 @@ from squirrelbattle.display.display import Box, Display class MessageDisplay(Display): + """ + Display a message in a popup. + """ + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 4553392..4eb38c1 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -72,6 +72,10 @@ class Game: Indicates what should be done when the given key is pressed, according to the current game state. """ + if self.message: + self.message = None + return + if self.state == GameMode.PLAY: self.handle_key_pressed_play(key) elif self.state == GameMode.MAINMENU: From fb8d8f033b5be942c9a8bed84ff903111189201f Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 17:52:26 +0100 Subject: [PATCH 28/54] Popup border color is red --- squirrelbattle/display/display.py | 16 +++++++++++----- squirrelbattle/display/display_manager.py | 2 +- squirrelbattle/display/messagedisplay.py | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/squirrelbattle/display/display.py b/squirrelbattle/display/display.py index 00169f5..9cc1456 100644 --- a/squirrelbattle/display/display.py +++ b/squirrelbattle/display/display.py @@ -139,16 +139,22 @@ class HorizontalSplit(Display): class Box(Display): - def __init__(self, *args, **kwargs): + def __init__(self, *args, fg_border_color: Optional[int] = None, **kwargs): super().__init__(*args, **kwargs) self.pad = self.newpad(self.rows, self.cols) + self.fg_border_color = fg_border_color or curses.COLOR_WHITE + + pair_number = 4 + self.fg_border_color + self.init_pair(pair_number, self.fg_border_color, curses.COLOR_BLACK) + self.pair = self.color_pair(pair_number) def display(self) -> None: - self.addstr(self.pad, 0, 0, "┏" + "━" * (self.width - 2) + "┓") + self.addstr(self.pad, 0, 0, "┏" + "━" * (self.width - 2) + "┓", + self.pair) for i in range(1, self.height - 1): - self.addstr(self.pad, i, 0, "┃") - self.addstr(self.pad, i, self.width - 1, "┃") + self.addstr(self.pad, i, 0, "┃", self.pair) + self.addstr(self.pad, i, self.width - 1, "┃", self.pair) self.addstr(self.pad, self.height - 1, 0, - "┗" + "━" * (self.width - 2) + "┛") + "┗" + "━" * (self.width - 2) + "┛", self.pair) self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.y + self.height - 1, self.x + self.width - 1) diff --git a/squirrelbattle/display/display_manager.py b/squirrelbattle/display/display_manager.py index 869b7d4..f7a0882 100644 --- a/squirrelbattle/display/display_manager.py +++ b/squirrelbattle/display/display_manager.py @@ -27,7 +27,7 @@ class DisplayManager: screen, pack) self.settingsmenudisplay = SettingsMenuDisplay(screen, pack) self.logsdisplay = LogsDisplay(screen, pack) - self.messagedisplay = MessageDisplay(screen) + self.messagedisplay = MessageDisplay(screen=screen, pack=None) self.hbar = HorizontalSplit(screen, pack) self.vbar = VerticalSplit(screen, pack) self.displays = [self.statsdisplay, self.mapdisplay, diff --git a/squirrelbattle/display/messagedisplay.py b/squirrelbattle/display/messagedisplay.py index 9e4ffae..c237b6b 100644 --- a/squirrelbattle/display/messagedisplay.py +++ b/squirrelbattle/display/messagedisplay.py @@ -1,5 +1,6 @@ # Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later +import curses from squirrelbattle.display.display import Box, Display @@ -12,7 +13,7 @@ class MessageDisplay(Display): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) - self.box = Box(*args, **kwargs) + self.box = Box(fg_border_color=curses.COLOR_RED, *args, **kwargs) self.message = "" self.pad = self.newpad(1, 1) From be9c726fa02d8b014b7c765ad4303d8a1987b883 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 17:54:31 +0100 Subject: [PATCH 29/54] Display message in bold format --- squirrelbattle/display/messagedisplay.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/squirrelbattle/display/messagedisplay.py b/squirrelbattle/display/messagedisplay.py index c237b6b..bcc2539 100644 --- a/squirrelbattle/display/messagedisplay.py +++ b/squirrelbattle/display/messagedisplay.py @@ -25,7 +25,7 @@ class MessageDisplay(Display): self.height + 2, self.width + 4) self.box.display() self.pad.erase() - self.addstr(self.pad, 0, 0, self.message) + self.addstr(self.pad, 0, 0, self.message, curses.A_BOLD) self.refresh_pad(self.pad, 0, 0, self.y, self.x, self.height + self.y - 1, self.width + self.x - 1) From 25ba94b9ac5a1fcbf0007e1f5434fee28c29b15e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 18:09:08 +0100 Subject: [PATCH 30/54] Game displays an error message when a save file could not be loaded. --- squirrelbattle/game.py | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 4eb38c1..28d20de 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -1,6 +1,6 @@ # Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later - +from json import JSONDecodeError from random import randint from typing import Any, Optional import json @@ -37,7 +37,7 @@ class Game: self.settings.write_settings() self.settings_menu.update_values(self.settings) self.logs = Logs() - self.message = "Vive les Ă©cureuils" + self.message = None def new_game(self) -> None: """ @@ -139,8 +139,15 @@ class Game: Loads the game from a dictionary """ self.map.load_state(d) - # noinspection PyTypeChecker - self.player = self.map.find_entities(Player)[0] + players = self.map.find_entities(Player) + if not players: + self.message = "No player was found on this map!\n" \ + "Maybe you died?" + self.player.health = 0 + self.display_actions(DisplayActions.UPDATE) + return + + self.player = players[0] self.display_actions(DisplayActions.UPDATE) def load_game(self) -> None: @@ -150,7 +157,14 @@ class Game: file_path = ResourceManager.get_config_path("save.json") if os.path.isfile(file_path): with open(file_path, "r") as f: - self.load_state(json.loads(f.read())) + try: + state = json.loads(f.read()) + self.load_state(state) + except JSONDecodeError: + self.message = "The JSON file is not correct.\n" \ + "Your save seems corrupted. It got deleted." + os.unlink(file_path) + self.display_actions(DisplayActions.UPDATE) def save_game(self) -> None: """ From 5faebfe556b31131a11924ea68d37643975564d8 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 18:12:27 +0100 Subject: [PATCH 31/54] Test message display --- squirrelbattle/game.py | 1 + squirrelbattle/tests/game_test.py | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 28d20de..93af352 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -74,6 +74,7 @@ class Game: """ if self.message: self.message = None + self.display_actions(DisplayActions.REFRESH) return if self.state == GameMode.PLAY: diff --git a/squirrelbattle/tests/game_test.py b/squirrelbattle/tests/game_test.py index 28b354d..a466fa9 100644 --- a/squirrelbattle/tests/game_test.py +++ b/squirrelbattle/tests/game_test.py @@ -4,6 +4,8 @@ import os import unittest +from squirrelbattle.enums import DisplayActions + from squirrelbattle.bootstrap import Bootstrap from squirrelbattle.display.display import Display from squirrelbattle.display.display_manager import DisplayManager @@ -292,3 +294,13 @@ class TestGame(unittest.TestCase): Check that some functions are not implemented, only for coverage. """ self.assertRaises(NotImplementedError, Display.display, None) + + def test_messages(self) -> None: + """ + Display error messages. + """ + self.game.message = "I am an error" + self.game.display_actions(DisplayActions.UPDATE) + self.game.display_actions(DisplayActions.REFRESH) + self.game.handle_key_pressed(None, "random key") + self.assertIsNone(self.game.message) From b0e352444bdb13cb62d846d653f17a762d8c7fff Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 18:16:54 +0100 Subject: [PATCH 32/54] Test loading wrong saves --- squirrelbattle/game.py | 10 +++++++++- squirrelbattle/tests/game_test.py | 23 +++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 93af352..a64d82e 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -139,7 +139,15 @@ class Game: """ Loads the game from a dictionary """ - self.map.load_state(d) + try: + self.map.load_state(d) + except KeyError: + self.message = "Some keys are missing in your save file.\n" \ + "Your save seems to be corrupt. It got deleted." + os.unlink(ResourceManager.get_config_path("save.json")) + self.display_actions(DisplayActions.UPDATE) + return + players = self.map.find_entities(Player) if not players: self.message = "No player was found on this map!\n" \ diff --git a/squirrelbattle/tests/game_test.py b/squirrelbattle/tests/game_test.py index a466fa9..5081912 100644 --- a/squirrelbattle/tests/game_test.py +++ b/squirrelbattle/tests/game_test.py @@ -4,6 +4,8 @@ import os import unittest +from squirrelbattle.resources import ResourceManager + from squirrelbattle.enums import DisplayActions from squirrelbattle.bootstrap import Bootstrap @@ -43,6 +45,27 @@ class TestGame(unittest.TestCase): new_state = self.game.save_state() self.assertEqual(old_state, new_state) + # Error on loading save + with open(ResourceManager.get_config_path("save.json"), "w") as f: + f.write("I am not a JSON file") + self.assertIsNone(self.game.message) + self.game.load_game() + self.assertIsNotNone(self.game.message) + self.game.message = None + + with open(ResourceManager.get_config_path("save.json"), "w") as f: + f.write("{}") + self.assertIsNone(self.game.message) + self.game.load_game() + self.assertIsNotNone(self.game.message) + self.game.message = None + + # Load game with a dead player + self.game.map.remove_entity(self.game.player) + self.game.save_game() + self.game.load_game() + self.assertIsNotNone(self.game.message) + def test_bootstrap_fail(self) -> None: """ Ensure that the test can't play the game, From d85ee1758fcdfaf41625a16a180ddc372419b928 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 18:27:28 +0100 Subject: [PATCH 33/54] Release v3.14.1 --- debian/changelog | 6 ++++++ docs/deployment.rst | 16 ++++++++-------- docs/install.rst | 4 ++-- setup.py | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/debian/changelog b/debian/changelog index 536fca5..887634f 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,11 @@ python3-squirrel-battle (3.14) beta; urgency=low + * Some graphical improvements. + + -- Yohann D'ANELLO Thu, 27 Nov 2020 18:25:42 +0100 + + python3-squirrel-battle (3.14) beta; urgency=low + * Initial release. -- Yohann D'ANELLO Thu, 19 Nov 2020 03:30:42 +0100 diff --git a/docs/deployment.rst b/docs/deployment.rst index 99b15f9..a9f58ee 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -3,7 +3,7 @@ DĂ©ploiement du projet .. _PyPI: https://pypi.org/project/squirrel-battle/ .. _AUR: https://aur.archlinux.org/packages/python-squirrel-battle/ -.. _Debian: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14_all.deb?job=build-deb +.. _Debian: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14.1_all.deb?job=build-deb .. _installation: install.html À chaque nouvelle version du projet, il est compilĂ© et dĂ©ployĂ© dans PyPI_, dans @@ -36,7 +36,7 @@ paquet ainsi que des dĂ©tails Ă  fournir Ă  PyPI : setup( name="squirrel-battle", - version="3.14", + version="3.14.1", author="ĂżnĂ©rant, eichhornchen, nicomarg, charlse", author_email="squirrel-battle@crans.org", description="Watch out for squirrel's knives!", @@ -160,8 +160,8 @@ du dĂ©pĂŽt Git. Le fichier ``PKGBUILD`` dispose de cette structure : pkgbase=squirrel-battle pkgname=python-squirrel-battle-git - pkgver=3.14 - pkgrel=2 + pkgver=3.14.1 + pkgrel=1 pkgdesc="Watch out for squirrel's knives!" arch=('any') url="https://gitlab.crans.org/ynerant/squirrel-battle" @@ -210,8 +210,8 @@ les releases, est plus ou moins similaire : pkgbase=squirrel-battle pkgname=python-squirrel-battle - pkgver=3.14 - pkgrel=2 + pkgver=3.14.1 + pkgrel=1 pkgdesc="Watch out for squirrel's knives!" arch=('any') url="https://gitlab.crans.org/ynerant/squirrel-battle" @@ -220,7 +220,7 @@ les releases, est plus ou moins similaire : makedepends=('python-setuptools') depends=('noto-fonts-emoji') checkdepends=('python-tox') - source=("https://gitlab.crans.org/ynerant/squirrel-battle/-/archive/v3.14/$pkgbase-v$pkgver.tar.gz") + source=("https://gitlab.crans.org/ynerant/squirrel-battle/-/archive/v3.14.1/$pkgbase-v$pkgver.tar.gz") sha256sums=("6090534d598c0b3a8f5acdb553c12908ba8107d62d08e17747d1dbb397bddef0") build() { @@ -305,7 +305,7 @@ On peut ensuite construire le paquet : dpkg-buildpackage mkdir build && cp ../*.deb build/ -Le paquet sera installĂ© dans ``build/python3-squirrel-battle_3.14_all.deb``. +Le paquet sera installĂ© dans ``build/python3-squirrel-battle_3.14.1_all.deb``. Le paquet Debian_ est construit par l'intĂ©gration continue Gitlab et ajoutĂ© Ă  chaque release. diff --git a/docs/install.rst b/docs/install.rst index 26f8b42..5cc2351 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -61,7 +61,7 @@ Le jeu peut ĂȘtre ensuite lancĂ© via la commande ``squirrel-battle``. Sur Ubuntu/Debian ~~~~~~~~~~~~~~~~~ -.. _paquet: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14_all.deb?job=build-deb +.. _paquet: https://gitlab.crans.org/ynerant/squirrel-battle/-/jobs/artifacts/master/raw/build/python3-squirrelbattle_3.14.1_all.deb?job=build-deb Un paquet_ est gĂ©nĂ©rĂ© par l'intĂ©gration continue de Gitlab Ă  chaque commit. Ils sont Ă©galement attachĂ©s Ă  chaque nouvelle release. @@ -73,7 +73,7 @@ Pour installer ce paquet, il suffit de le tĂ©lĂ©charger et d'appeler ``dpkg`` : .. code:: bash - dpkg -i python3-squirrelbattle_3.14_all.deb + dpkg -i python3-squirrelbattle_3.14.1_all.deb Ce paquet inclut un patch pour afficher les Ă©mojis Ă©cureuil correctement. diff --git a/setup.py b/setup.py index ef34c31..6287f7d 100644 --- a/setup.py +++ b/setup.py @@ -12,7 +12,7 @@ with open("README.md", "r") as f: setup( name="squirrel-battle", - version="3.14", + version="3.14.1", author="ĂżnĂ©rant, eichhornchen, nicomarg, charlse", author_email="squirrel-battle@crans.org", description="Watch out for squirrel's knives!", From cb18b3881f15785c194776ee670d2f896bcf4295 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 19:42:45 +0100 Subject: [PATCH 34/54] Fix Debian package version --- debian/changelog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/changelog b/debian/changelog index 887634f..2399e41 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -python3-squirrel-battle (3.14) beta; urgency=low +python3-squirrel-battle (3.14.1) beta; urgency=low * Some graphical improvements. From e3be4b4f3f62689202a627035b853be294196e3d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 20:32:40 +0100 Subject: [PATCH 35/54] First setup for translation --- locale/en/LC_MESSAGES/squirrelbattle.mo | Bin 0 -> 371 bytes locale/en/LC_MESSAGES/squirrelbattle.po | 22 ++++++++++++++++++++++ locale/fr/LC_MESSAGES/squirrelbattle.mo | Bin 0 -> 371 bytes locale/fr/LC_MESSAGES/squirrelbattle.po | 22 ++++++++++++++++++++++ squirrelbattle/translations.py | 15 +++++++++++++++ 5 files changed, 59 insertions(+) create mode 100644 locale/en/LC_MESSAGES/squirrelbattle.mo create mode 100644 locale/en/LC_MESSAGES/squirrelbattle.po create mode 100644 locale/fr/LC_MESSAGES/squirrelbattle.mo create mode 100644 locale/fr/LC_MESSAGES/squirrelbattle.po create mode 100644 squirrelbattle/translations.py diff --git a/locale/en/LC_MESSAGES/squirrelbattle.mo b/locale/en/LC_MESSAGES/squirrelbattle.mo new file mode 100644 index 0000000000000000000000000000000000000000..ecca9e27bf3bf4b3c848e637f5bb9cf11bef0958 GIT binary patch literal 371 zcmYL@u};G<5QYOPOGXwJ2JdhMw#pP#)3_zVPC}Yig3Yuh7!|v+T?7xp>+vjH5Td{C zlYG*D^7nn%`${nT$T4z?93VraONI21d*o;@Nfv**#W&7xy4(LWF1n=h?o}@%)oN(8dZR?JVmj|k zhC+!5+mCEsaZ^v~0=vr$|8?sJ1aQGdj<%~~0INtQ3l2OY2G%>)L!UZ?e} VJ#f2pD`Q(q22UoYNuxtdegF@5)Y literal 0 HcmV?d00001 diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po new file mode 100644 index 0000000..85d099d --- /dev/null +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -0,0 +1,22 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-27 20:06+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: squirrelbattle/translations.py:7 +msgid "Toto" +msgstr "Test" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.mo b/locale/fr/LC_MESSAGES/squirrelbattle.mo new file mode 100644 index 0000000000000000000000000000000000000000..ecca9e27bf3bf4b3c848e637f5bb9cf11bef0958 GIT binary patch literal 371 zcmYL@u};G<5QYOPOGXwJ2JdhMw#pP#)3_zVPC}Yig3Yuh7!|v+T?7xp>+vjH5Td{C zlYG*D^7nn%`${nT$T4z?93VraONI21d*o;@Nfv**#W&7xy4(LWF1n=h?o}@%)oN(8dZR?JVmj|k zhC+!5+mCEsaZ^v~0=vr$|8?sJ1aQGdj<%~~0INtQ3l2OY2G%>)L!UZ?e} VJ#f2pD`Q(q22UoYNuxtdegF@5)Y literal 0 HcmV?d00001 diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/locale/fr/LC_MESSAGES/squirrelbattle.po new file mode 100644 index 0000000..85d099d --- /dev/null +++ b/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -0,0 +1,22 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2020-11-27 20:06+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: squirrelbattle/translations.py:7 +msgid "Toto" +msgstr "Test" diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py new file mode 100644 index 0000000..27ec288 --- /dev/null +++ b/squirrelbattle/translations.py @@ -0,0 +1,15 @@ +# Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# SPDX-License-Identifier: GPL-3.0-or-later + +import gettext + + +_TRANSLATORS = dict() +for language in ["en", "fr"]: + _TRANSLATORS[language] = gettext.translation("squirrelbattle", + localedir="locale", + languages=[language]) + + +def gettext(message: str) -> str: + return _TRANSLATORS.get("en", _TRANSLATORS.get("en")).gettext(message) From 2498fd2a61517aa562fdcab9e66359212cb7834c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 20:42:19 +0100 Subject: [PATCH 36/54] Translate strings --- locale/en/LC_MESSAGES/squirrelbattle.mo | Bin 371 -> 337 bytes locale/en/LC_MESSAGES/squirrelbattle.po | 68 ++++++++++++++++++++-- locale/fr/LC_MESSAGES/squirrelbattle.mo | Bin 371 -> 1445 bytes locale/fr/LC_MESSAGES/squirrelbattle.po | 74 ++++++++++++++++++++++-- squirrelbattle/display/statsdisplay.py | 8 +-- squirrelbattle/game.py | 15 +++-- squirrelbattle/interfaces.py | 12 ++-- squirrelbattle/menus.py | 15 ++--- 8 files changed, 163 insertions(+), 29 deletions(-) diff --git a/locale/en/LC_MESSAGES/squirrelbattle.mo b/locale/en/LC_MESSAGES/squirrelbattle.mo index ecca9e27bf3bf4b3c848e637f5bb9cf11bef0958..6c5906d1cd061dff54de8b533942893de34efc9e 100644 GIT binary patch delta 65 wcmey&bdky8o)F7a1|VPrVi_P-0b*t#)&XJ=umEClprj>`2C0F8jiHi^0R0~YqyPW_ delta 100 zcmcb}^qDF2o)F7a1|VPpVi_RT0b*7lwgF-g2moRhAPxj#aYhD)FepC{$Oa-X0O^H; Sko=PTjTVxOtRbnzB@6)iEeZ($ diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po index 85d099d..31fcdec 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 20:06+0100\n" +"POT-Creation-Date: 2020-11-27 20:39+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,66 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: squirrelbattle/translations.py:7 -msgid "Toto" -msgstr "Test" +#: squirrelbattle/display/statsdisplay.py:34 +msgid "Inventory:" +msgstr "" + +#: squirrelbattle/display/statsdisplay.py:39 +msgid "YOU ARE DEAD" +msgstr "" + +#: squirrelbattle/interfaces.py:394 +#, python-brace-format +msgid "{name} hits {opponent}." +msgstr "" + +#: squirrelbattle/interfaces.py:405 +#, python-brace-format +msgid "{name} takes {amount} damage." +msgstr "" + +#: squirrelbattle/menus.py:45 +msgid "New game" +msgstr "" + +#: squirrelbattle/menus.py:46 +msgid "Resume" +msgstr "" + +#: squirrelbattle/menus.py:47 +msgid "Save" +msgstr "" + +#: squirrelbattle/menus.py:48 +msgid "Load" +msgstr "" + +#: squirrelbattle/menus.py:49 +msgid "Settings" +msgstr "" + +#: squirrelbattle/menus.py:50 +msgid "Exit" +msgstr "" + +#: squirrelbattle/menus.py:71 +msgid "Back" +msgstr "" + +#: squirrelbattle/game.py:147 +msgid "" +"Some keys are missing in your save file.\n" +"Your save seems to be corrupt. It got deleted." +msgstr "" + +#: squirrelbattle/game.py:155 +msgid "" +"No player was found on this map!\n" +"Maybe you died?" +msgstr "" + +#: squirrelbattle/game.py:175 +msgid "" +"The JSON file is not correct.\n" +"Your save seems corrupted.It got deleted." +msgstr "" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.mo b/locale/fr/LC_MESSAGES/squirrelbattle.mo index ecca9e27bf3bf4b3c848e637f5bb9cf11bef0958..7e3ecd63e13fc07cf7b1df1e42fa1bffd4ee8666 100644 GIT binary patch literal 1445 zcmbu8yRREX6vihIUgjmyAS94ZDiCOw&_yPYY_2yKhxG$LF1mDM@9}zay)(M1 z6m*CZL{Ek3DXC0DL4zm}eM{$+Ay;haj&w9Lwa&?C@^j^=l+~q1N3JGJD^pXh zIKL(a>}s4F$|WA`z0!pfLsK%H@XC?2Or>%T%cOKTXUV~rW@^E4ox{l8SA5tD^wocs0$a3Op_Y@UNqpP3TL90^xUN5G#NylUerqHonEuke(i%^ zH*I9n`DkRNb_BP><)k{&na;={IRQm)5a=YdpFcT{-s) zWzE<|sh*k~U$;qDCdxOU2aj(m-m8`OY z+tdto=$9pJ)_$`lZ{Y_ztS%%?;mmZY(dXJno9{eA;>j*rni}H7P17|I`cS$?lA%PB zLfRbfeQ9O6`4&f)`JW1A diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/locale/fr/LC_MESSAGES/squirrelbattle.po index 85d099d..ab04ec8 100644 --- a/locale/fr/LC_MESSAGES/squirrelbattle.po +++ b/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 20:06+0100\n" +"POT-Creation-Date: 2020-11-27 20:39+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,72 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -#: squirrelbattle/translations.py:7 -msgid "Toto" -msgstr "Test" +#: squirrelbattle/display/statsdisplay.py:34 +msgid "Inventory:" +msgstr "Inventaire :" + +#: squirrelbattle/display/statsdisplay.py:39 +msgid "YOU ARE DEAD" +msgstr "VOUS ÊTES MORT" + +#: squirrelbattle/interfaces.py:394 +#, python-brace-format +msgid "{name} hits {opponent}." +msgstr "{name} frappe {opponent}." + +#: squirrelbattle/interfaces.py:405 +#, python-brace-format +msgid "{name} takes {amount} damage." +msgstr "{name} prend {amount} points de dĂ©gĂąt." + +#: squirrelbattle/menus.py:45 +msgid "New game" +msgstr "Nouvelle partie" + +#: squirrelbattle/menus.py:46 +msgid "Resume" +msgstr "Continuer" + +#: squirrelbattle/menus.py:47 +msgid "Save" +msgstr "Sauvegarder" + +#: squirrelbattle/menus.py:48 +msgid "Load" +msgstr "Charger" + +#: squirrelbattle/menus.py:49 +msgid "Settings" +msgstr "ParamĂštres" + +#: squirrelbattle/menus.py:50 +msgid "Exit" +msgstr "Quitter" + +#: squirrelbattle/menus.py:71 +msgid "Back" +msgstr "Retour" + +#: squirrelbattle/game.py:147 +msgid "" +"Some keys are missing in your save file.\n" +"Your save seems to be corrupt. It got deleted." +msgstr "" +"Certaines clĂ©s de votre ficher de sauvegarde sont manquantes.\n" +"Votre sauvegarde semble corrompue. Elle a Ă©tĂ© supprimĂ©e." + +#: squirrelbattle/game.py:155 +msgid "" +"No player was found on this map!\n" +"Maybe you died?" +msgstr "" +"Aucun joueur n'a Ă©tĂ© trouvĂ© sur la carte !\n" +"Peut-ĂȘtre ĂȘtes-vous mort ?" + +#: squirrelbattle/game.py:175 +msgid "" +"The JSON file is not correct.\n" +"Your save seems corrupted.It got deleted." +msgstr "" +"Le fichier JSON de sauvegarde est incorrect.\n" +"Votre sauvegarde semble corrompue. Elle a Ă©tĂ© supprimĂ©e." diff --git a/squirrelbattle/display/statsdisplay.py b/squirrelbattle/display/statsdisplay.py index b65e716..da9213f 100644 --- a/squirrelbattle/display/statsdisplay.py +++ b/squirrelbattle/display/statsdisplay.py @@ -3,10 +3,10 @@ import curses +from ..entities.player import Player +from ..translations import gettext as _ from .display import Display -from squirrelbattle.entities.player import Player - class StatsDisplay(Display): player: Player @@ -31,12 +31,12 @@ class StatsDisplay(Display): self.player.dexterity, self.player.constitution) self.addstr(self.pad, 3, 0, string3) - inventory_str = "Inventaire : " + "".join( + inventory_str = _("Inventory:") + " " + "".join( self.pack[item.name.upper()] for item in self.player.inventory) self.addstr(self.pad, 8, 0, inventory_str) if self.player.dead: - self.addstr(self.pad, 10, 0, "VOUS ÊTES MORT", + self.addstr(self.pad, 10, 0, _("YOU ARE DEAD"), curses.A_BOLD | curses.A_BLINK | curses.A_STANDOUT | self.color_pair(3)) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index a64d82e..a9689a5 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -1,5 +1,6 @@ # Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later + from json import JSONDecodeError from random import randint from typing import Any, Optional @@ -13,6 +14,7 @@ from .interfaces import Map, Logs from .resources import ResourceManager from .settings import Settings from . import menus +from .translations import gettext as _ from typing import Callable @@ -142,16 +144,16 @@ class Game: try: self.map.load_state(d) except KeyError: - self.message = "Some keys are missing in your save file.\n" \ - "Your save seems to be corrupt. It got deleted." + self.message = _("Some keys are missing in your save file.\n" + "Your save seems to be corrupt. It got deleted.") os.unlink(ResourceManager.get_config_path("save.json")) self.display_actions(DisplayActions.UPDATE) return players = self.map.find_entities(Player) if not players: - self.message = "No player was found on this map!\n" \ - "Maybe you died?" + self.message = _("No player was found on this map!\n" + "Maybe you died?") self.player.health = 0 self.display_actions(DisplayActions.UPDATE) return @@ -170,8 +172,9 @@ class Game: state = json.loads(f.read()) self.load_state(state) except JSONDecodeError: - self.message = "The JSON file is not correct.\n" \ - "Your save seems corrupted. It got deleted." + self.message = _("The JSON file is not correct.\n" + "Your save seems corrupted." + "It got deleted.") os.unlink(file_path) self.display_actions(DisplayActions.UPDATE) diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index 8958e7b..0e51589 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -6,7 +6,8 @@ from math import sqrt from random import choice, randint from typing import List, Optional -from squirrelbattle.display.texturepack import TexturePack +from .display.texturepack import TexturePack +from .translations import gettext as _ class Logs: @@ -390,7 +391,8 @@ class FightingEntity(Entity): """ Deals damage to the opponent, based on the stats """ - return f"{self.name} hits {opponent.name}. "\ + return _("{name} hits {opponent}.")\ + .format(name=str(self), opponent=str(opponent)) + " "\ + opponent.take_damage(self, self.strength) def take_damage(self, attacker: "Entity", amount: int) -> str: @@ -400,8 +402,10 @@ class FightingEntity(Entity): self.health -= amount if self.health <= 0: self.die() - return f"{self.name} takes {amount} damage."\ - + (f" {self.name} dies." if self.health <= 0 else "") + return _("{name} takes {amount} damage.")\ + .format(name=str(self), amount=str(amount)) \ + + (" " + "{name} dies.".format(name=str(self)) + if self.health <= 0 else "") def die(self) -> None: """ diff --git a/squirrelbattle/menus.py b/squirrelbattle/menus.py index 31c50ea..3c2d9e8 100644 --- a/squirrelbattle/menus.py +++ b/squirrelbattle/menus.py @@ -7,6 +7,7 @@ from typing import Any, Optional from .display.texturepack import TexturePack from .enums import GameMode, KeyValues, DisplayActions from .settings import Settings +from .translations import gettext as _ class Menu: @@ -41,12 +42,12 @@ class MainMenuValues(Enum): """ Values of the main menu """ - START = 'Nouvelle partie' - RESUME = 'Continuer' - SAVE = 'Sauvegarder' - LOAD = 'Charger' - SETTINGS = 'ParamĂštres' - EXIT = 'Quitter' + START = _("New game") + RESUME = _("Resume") + SAVE = _("Save") + LOAD = _("Load") + SETTINGS = _("Settings") + EXIT = _("Exit") def __str__(self): return self.value @@ -67,7 +68,7 @@ class SettingsMenu(Menu): def update_values(self, settings: Settings) -> None: self.values = list(settings.__dict__.items()) - self.values.append(("RETURN", ["", "Retour"])) + self.values.append(("RETURN", ["", _("Back")])) def handle_key_pressed(self, key: Optional[KeyValues], raw_key: str, game: Any) -> None: From 4287b4f045f91139b0c4d9c45965d2cab0adba60 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 20:53:24 +0100 Subject: [PATCH 37/54] Add possibility to change the language --- squirrelbattle/game.py | 3 ++- squirrelbattle/interfaces.py | 8 ++++---- squirrelbattle/menus.py | 8 +++++++- squirrelbattle/settings.py | 2 ++ squirrelbattle/translations.py | 17 +++++++++++++++-- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index a9689a5..be1e01a 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -14,7 +14,7 @@ from .interfaces import Map, Logs from .resources import ResourceManager from .settings import Settings from . import menus -from .translations import gettext as _ +from .translations import gettext as _, setlocale from typing import Callable @@ -38,6 +38,7 @@ class Game: self.settings.load_settings() self.settings.write_settings() self.settings_menu.update_values(self.settings) + setlocale(self.settings.LOCALE) self.logs = Logs() self.message = None diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index 0e51589..845e3bd 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -129,7 +129,7 @@ class Map: """ Put randomly {count} hedgehogs on the map, where it is available. """ - for _ in range(count): + for ignored in range(count): y, x = 0, 0 while True: y, x = randint(0, self.height - 1), randint(0, self.width - 1) @@ -392,7 +392,7 @@ class FightingEntity(Entity): Deals damage to the opponent, based on the stats """ return _("{name} hits {opponent}.")\ - .format(name=str(self), opponent=str(opponent)) + " "\ + .format(name=self.name, opponent=opponent.name) + " "\ + opponent.take_damage(self, self.strength) def take_damage(self, attacker: "Entity", amount: int) -> str: @@ -403,8 +403,8 @@ class FightingEntity(Entity): if self.health <= 0: self.die() return _("{name} takes {amount} damage.")\ - .format(name=str(self), amount=str(amount)) \ - + (" " + "{name} dies.".format(name=str(self)) + .format(name=self.name, amount=str(amount)) \ + + (" " + "{name} dies.".format(name=self.name) if self.health <= 0 else "") def die(self) -> None: diff --git a/squirrelbattle/menus.py b/squirrelbattle/menus.py index 3c2d9e8..56a7db2 100644 --- a/squirrelbattle/menus.py +++ b/squirrelbattle/menus.py @@ -7,7 +7,7 @@ from typing import Any, Optional from .display.texturepack import TexturePack from .enums import GameMode, KeyValues, DisplayActions from .settings import Settings -from .translations import gettext as _ +from .translations import gettext as _, setlocale class Menu: @@ -96,6 +96,12 @@ class SettingsMenu(Menu): game.settings.TEXTURE_PACK) game.settings.write_settings() self.update_values(game.settings) + elif option == "LOCALE": + game.settings.LOCALE = 'fr' if game.settings.LOCALE == 'en'\ + else 'en' + setlocale(game.settings.LOCALE) + game.settings.write_settings() + self.update_values(game.settings) else: self.waiting_for_key = True self.update_values(game.settings) diff --git a/squirrelbattle/settings.py b/squirrelbattle/settings.py index 9601457..726d96c 100644 --- a/squirrelbattle/settings.py +++ b/squirrelbattle/settings.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later import json +import locale import os from typing import Any, Generator @@ -35,6 +36,7 @@ class Settings: self.KEY_ENTER = \ ['\n', 'Touche pour valider un menu'] self.TEXTURE_PACK = ['ascii', 'Pack de textures utilisĂ©'] + self.LOCALE = [locale.getlocale()[0][:2], 'Langue'] def __getattribute__(self, item: str) -> Any: superattribute = super().__getattribute__(item) diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index 27ec288..fa8196d 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -4,12 +4,25 @@ import gettext +SUPPORTED_LOCALES = ["en", "fr"] +DEFAULT_LOCALE = "en" + +_current_locale = DEFAULT_LOCALE + _TRANSLATORS = dict() -for language in ["en", "fr"]: +for language in SUPPORTED_LOCALES: _TRANSLATORS[language] = gettext.translation("squirrelbattle", localedir="locale", languages=[language]) def gettext(message: str) -> str: - return _TRANSLATORS.get("en", _TRANSLATORS.get("en")).gettext(message) + return _TRANSLATORS.get(_current_locale, + _TRANSLATORS.get("en")).gettext(message) + + +def setlocale(lang: str) -> None: + global _current_locale + lang = lang[:2] + if lang in SUPPORTED_LOCALES: + _current_locale = lang From c151e0f65620d4e0854b6b5bc7eb59b83fc7eb8e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 21:44:17 +0100 Subject: [PATCH 38/54] Menu items are translated --- locale/en/LC_MESSAGES/squirrelbattle.po | 20 ++++++++++---------- locale/fr/LC_MESSAGES/squirrelbattle.po | 20 ++++++++++---------- squirrelbattle/display/menudisplay.py | 2 +- squirrelbattle/menus.py | 14 +++++++------- squirrelbattle/tests/translations_test.py | 19 +++++++++++++++++++ 5 files changed, 47 insertions(+), 28 deletions(-) create mode 100644 squirrelbattle/tests/translations_test.py diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po index 31fcdec..fb84fe2 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 20:39+0100\n" +"POT-Creation-Date: 2020-11-27 21:43+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -35,27 +35,27 @@ msgstr "" msgid "{name} takes {amount} damage." msgstr "" -#: squirrelbattle/menus.py:45 +#: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14 msgid "New game" msgstr "" -#: squirrelbattle/menus.py:46 +#: squirrelbattle/menus.py:46 squirrelbattle/tests/translations_test.py:15 msgid "Resume" msgstr "" -#: squirrelbattle/menus.py:47 +#: squirrelbattle/menus.py:47 squirrelbattle/tests/translations_test.py:17 msgid "Save" msgstr "" -#: squirrelbattle/menus.py:48 +#: squirrelbattle/menus.py:48 squirrelbattle/tests/translations_test.py:16 msgid "Load" msgstr "" -#: squirrelbattle/menus.py:49 +#: squirrelbattle/menus.py:49 squirrelbattle/tests/translations_test.py:18 msgid "Settings" msgstr "" -#: squirrelbattle/menus.py:50 +#: squirrelbattle/menus.py:50 squirrelbattle/tests/translations_test.py:19 msgid "Exit" msgstr "" @@ -63,19 +63,19 @@ msgstr "" msgid "Back" msgstr "" -#: squirrelbattle/game.py:147 +#: squirrelbattle/game.py:147 squirrelbattle/game.py:148 msgid "" "Some keys are missing in your save file.\n" "Your save seems to be corrupt. It got deleted." msgstr "" -#: squirrelbattle/game.py:155 +#: squirrelbattle/game.py:155 squirrelbattle/game.py:156 msgid "" "No player was found on this map!\n" "Maybe you died?" msgstr "" -#: squirrelbattle/game.py:175 +#: squirrelbattle/game.py:175 squirrelbattle/game.py:176 msgid "" "The JSON file is not correct.\n" "Your save seems corrupted.It got deleted." diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/locale/fr/LC_MESSAGES/squirrelbattle.po index ab04ec8..0068f30 100644 --- a/locale/fr/LC_MESSAGES/squirrelbattle.po +++ b/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 20:39+0100\n" +"POT-Creation-Date: 2020-11-27 21:43+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -35,27 +35,27 @@ msgstr "{name} frappe {opponent}." msgid "{name} takes {amount} damage." msgstr "{name} prend {amount} points de dĂ©gĂąt." -#: squirrelbattle/menus.py:45 +#: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14 msgid "New game" msgstr "Nouvelle partie" -#: squirrelbattle/menus.py:46 +#: squirrelbattle/menus.py:46 squirrelbattle/tests/translations_test.py:15 msgid "Resume" msgstr "Continuer" -#: squirrelbattle/menus.py:47 +#: squirrelbattle/menus.py:47 squirrelbattle/tests/translations_test.py:17 msgid "Save" msgstr "Sauvegarder" -#: squirrelbattle/menus.py:48 +#: squirrelbattle/menus.py:48 squirrelbattle/tests/translations_test.py:16 msgid "Load" msgstr "Charger" -#: squirrelbattle/menus.py:49 +#: squirrelbattle/menus.py:49 squirrelbattle/tests/translations_test.py:18 msgid "Settings" msgstr "ParamĂštres" -#: squirrelbattle/menus.py:50 +#: squirrelbattle/menus.py:50 squirrelbattle/tests/translations_test.py:19 msgid "Exit" msgstr "Quitter" @@ -63,7 +63,7 @@ msgstr "Quitter" msgid "Back" msgstr "Retour" -#: squirrelbattle/game.py:147 +#: squirrelbattle/game.py:147 squirrelbattle/game.py:148 msgid "" "Some keys are missing in your save file.\n" "Your save seems to be corrupt. It got deleted." @@ -71,7 +71,7 @@ msgstr "" "Certaines clĂ©s de votre ficher de sauvegarde sont manquantes.\n" "Votre sauvegarde semble corrompue. Elle a Ă©tĂ© supprimĂ©e." -#: squirrelbattle/game.py:155 +#: squirrelbattle/game.py:155 squirrelbattle/game.py:156 msgid "" "No player was found on this map!\n" "Maybe you died?" @@ -79,7 +79,7 @@ msgstr "" "Aucun joueur n'a Ă©tĂ© trouvĂ© sur la carte !\n" "Peut-ĂȘtre ĂȘtes-vous mort ?" -#: squirrelbattle/game.py:175 +#: squirrelbattle/game.py:175 squirrelbattle/game.py:176 msgid "" "The JSON file is not correct.\n" "Your save seems corrupted.It got deleted." diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index 731ecee..e388a83 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -18,7 +18,7 @@ class MenuDisplay(Display): def update_menu(self, menu: Menu) -> None: self.menu = menu self.trueheight = len(self.values) - self.truewidth = max([len(a) for a in self.values]) + self.truewidth = max([len(str(a)) for a in self.values]) # Menu values are printed in pad self.pad = self.newpad(self.trueheight, self.truewidth + 2) diff --git a/squirrelbattle/menus.py b/squirrelbattle/menus.py index 56a7db2..3f6f7a0 100644 --- a/squirrelbattle/menus.py +++ b/squirrelbattle/menus.py @@ -42,15 +42,15 @@ class MainMenuValues(Enum): """ Values of the main menu """ - START = _("New game") - RESUME = _("Resume") - SAVE = _("Save") - LOAD = _("Load") - SETTINGS = _("Settings") - EXIT = _("Exit") + START = "New game" + RESUME = "Resume" + SAVE = "Save" + LOAD = "Load" + SETTINGS = "Settings" + EXIT = "Exit" def __str__(self): - return self.value + return _(self.value) class MainMenu(Menu): diff --git a/squirrelbattle/tests/translations_test.py b/squirrelbattle/tests/translations_test.py new file mode 100644 index 0000000..de93eb4 --- /dev/null +++ b/squirrelbattle/tests/translations_test.py @@ -0,0 +1,19 @@ +import unittest + +from squirrelbattle.translations import gettext as _, setlocale + + +class TestTranslations(unittest.TestCase): + def setUp(self) -> None: + setlocale("fr") + + def test_translations(self): + """ + Ensure that some strings are well-translated. + """ + self.assertEqual(_("New game"), "Nouvelle partie") + self.assertEqual(_("Resume"), "Continuer") + self.assertEqual(_("Load"), "Charger") + self.assertEqual(_("Save"), "Sauvegarder") + self.assertEqual(_("Settings"), "ParamĂštres") + self.assertEqual(_("Exit"), "Quitter") From 31b7ece449ed66187a8cfb61d3d143d1956d56c5 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 21:51:54 +0100 Subject: [PATCH 39/54] Main menu width must be updated when the language got changed --- squirrelbattle/display/menudisplay.py | 10 ++++++++-- squirrelbattle/game.py | 2 +- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index e388a83..e6bb00d 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -17,8 +17,6 @@ class MenuDisplay(Display): def update_menu(self, menu: Menu) -> None: self.menu = menu - self.trueheight = len(self.values) - self.truewidth = max([len(str(a)) for a in self.values]) # Menu values are printed in pad self.pad = self.newpad(self.trueheight, self.truewidth + 2) @@ -44,6 +42,14 @@ class MenuDisplay(Display): self.height - 2 + self.y, self.width - 2 + self.x) + @property + def truewidth(self) -> int: + return max([len(str(a)) for a in self.values]) + + @property + def trueheight(self) -> int: + return len(self.values) + @property def preferred_width(self) -> int: return self.truewidth + 6 diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index be1e01a..ad2f1cc 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -37,8 +37,8 @@ class Game: self.settings = Settings() self.settings.load_settings() self.settings.write_settings() - self.settings_menu.update_values(self.settings) setlocale(self.settings.LOCALE) + self.settings_menu.update_values(self.settings) self.logs = Logs() self.message = None From f07324662a594ac9b7a2a765147e55e090908b8e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 21:56:25 +0100 Subject: [PATCH 40/54] Cover the language change --- squirrelbattle/tests/game_test.py | 15 +++++++++++---- squirrelbattle/tests/translations_test.py | 2 +- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/squirrelbattle/tests/game_test.py b/squirrelbattle/tests/game_test.py index 5081912..8f5b1c1 100644 --- a/squirrelbattle/tests/game_test.py +++ b/squirrelbattle/tests/game_test.py @@ -15,6 +15,7 @@ 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 _ class TestGame(unittest.TestCase): @@ -275,12 +276,18 @@ class TestGame(unittest.TestCase): self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.TEXTURE_PACK, "ascii") + # Change language + self.game.settings.LOCALE = "en" + self.game.handle_key_pressed(KeyValues.DOWN) + self.game.handle_key_pressed(KeyValues.ENTER) + self.assertEqual(self.game.settings.LOCALE, "fr") + self.assertEqual(_("New game"), "Nouvelle partie") + self.game.handle_key_pressed(KeyValues.ENTER) + self.assertEqual(self.game.settings.LOCALE, "en") + self.assertEqual(_("New game"), "New game") + # Navigate to "back" button self.game.handle_key_pressed(KeyValues.DOWN) - self.game.handle_key_pressed(KeyValues.DOWN) - self.game.handle_key_pressed(KeyValues.DOWN) - self.game.handle_key_pressed(KeyValues.DOWN) - self.game.handle_key_pressed(KeyValues.DOWN) self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.state, GameMode.MAINMENU) diff --git a/squirrelbattle/tests/translations_test.py b/squirrelbattle/tests/translations_test.py index de93eb4..e51cb8a 100644 --- a/squirrelbattle/tests/translations_test.py +++ b/squirrelbattle/tests/translations_test.py @@ -7,7 +7,7 @@ class TestTranslations(unittest.TestCase): def setUp(self) -> None: setlocale("fr") - def test_translations(self): + def test_translations(self) -> None: """ Ensure that some strings are well-translated. """ From d2d74c97a4d5fe26145d4aaf7b1e84d9fecdd30c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 22:19:41 +0100 Subject: [PATCH 41/54] Settings menu was not translated --- locale/en/LC_MESSAGES/squirrelbattle.po | 47 +++++++++++++++++++++- locale/fr/LC_MESSAGES/squirrelbattle.mo | Bin 1445 -> 2310 bytes locale/fr/LC_MESSAGES/squirrelbattle.po | 47 +++++++++++++++++++++- squirrelbattle/display/menudisplay.py | 6 ++- squirrelbattle/game.py | 4 +- squirrelbattle/settings.py | 36 +++++++---------- squirrelbattle/tests/settings_test.py | 2 +- squirrelbattle/tests/translations_test.py | 21 ++++++++++ 8 files changed, 134 insertions(+), 29 deletions(-) diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po index fb84fe2..9ca5419 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 21:43+0100\n" +"POT-Creation-Date: 2020-11-27 22:05+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -36,6 +36,7 @@ msgid "{name} takes {amount} damage." msgstr "" #: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14 +#: squirrelbattle/tests/game_test.py:284 squirrelbattle/tests/game_test.py:287 msgid "New game" msgstr "" @@ -80,3 +81,47 @@ msgid "" "The JSON file is not correct.\n" "Your save seems corrupted.It got deleted." msgstr "" + +#: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 +msgid "Main key to move up" +msgstr "" + +#: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23 +msgid "Secondary key to move up" +msgstr "" + +#: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25 +msgid "Main key to move down" +msgstr "" + +#: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27 +msgid "Secondary key to move down" +msgstr "" + +#: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29 +msgid "Main key to move left" +msgstr "" + +#: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31 +msgid "Secondary key to move left" +msgstr "" + +#: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33 +msgid "Main key to move right" +msgstr "" + +#: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35 +msgid "Secondary key to move right" +msgstr "" + +#: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37 +msgid "Key to validate a menu" +msgstr "" + +#: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39 +msgid "Texture pack" +msgstr "" + +#: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 +msgid "Language" +msgstr "" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.mo b/locale/fr/LC_MESSAGES/squirrelbattle.mo index 7e3ecd63e13fc07cf7b1df1e42fa1bffd4ee8666..bc9146e56582ef46663f44ca84d8b24c1f344325 100644 GIT binary patch literal 2310 zcmbu9%WoVt9LHTK6qa`>?;`ywgb1o;3AeHonr(I(w%td%y9o*)BxlFF>t@CtY|p0K zDp!Pn8-f!T5JCiQ^w0}JNPFim01j|07bI?6_G~hw48}LWli)Eddd`6_f-(3I_!)Q} z{2II${0qDf{0H>=k3gB(M&L#$JuCxSIJr7<4~L+jj9PiHD3t;h|e zrG%#^3UxkO6*STrMN&j(SWDOp``UbnkLYR@aWmR&;oeKRnR_oyY~6be2DgQCQuQrs z>qK~Umbej=NNX`o2og**WMLNdWGsq>mF=+=BC$TyaHOk^$x>IOs-wPk6p2_k5fxcS zTy_~wOns_413~B8%|?C{AruOteyixZ-6v1a#3{EQy3$;tax0`tSgx?E3IX4sfpnIx z>NM2~m9SCVns&=N!G_XHJGScz7`ax17egG!m+XqM{LlW#Q}VWGyY z3p$1?8*`LqiOwz6YSbv#LpmMS%hlRkxl(C`?e^;sofK!#5j-hTt=w2x@|K*g)#hSZ z)TX~90}JZadbnfu%f;EkyjBiw2c1z0dmMuP66#N?SE)PT#tQe^Qs-Q7YDdnS)e|NN zRaZwyb%{=`N>@M~IwY7~%%pR|Oz#z!$Y6Za=@*gUlLv2RP% zNY#}okEgqM9AnQA0VhnYa(fU#jw|IAA51nfTDk+t3L5at;i_gs0lQG5#!11-Sr<-S z(wTsp>IF{YO*h^oXCMb!%*LF$5EgWzuqZMYjK6gV5Wd0&L!IG@qi*O7^I4H9Lp<6X zO8VSHJF&5oTkb=fNAy2qv!CGYvDsht*4XSPJB`gEH#`}C1Me)G7sjEYgr#mg-n6*l zG}PYjopoRsgcQe z(_dCR9{zk^*LX}Ut4*{@sLkJ#TXhTT@N#XxEB{CHa&xIo;}1Jwo9fM0XX{bv8J?zM cujeK;0#E(+bCYVR@Gil=XuR1Uf9ZTyp*O-h1s`J1e~vl5HtSg(#9&X@FUd^n# zM2{&?v4sWfIQuxE9$|!g)aPzbM9MN0>2p(M;R)$$LmQrxoV88uA{UO>p^mjS)X+b0 y4Cb+aNQbx}`3@L|JZ diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/locale/fr/LC_MESSAGES/squirrelbattle.po index 0068f30..9dac712 100644 --- a/locale/fr/LC_MESSAGES/squirrelbattle.po +++ b/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 21:43+0100\n" +"POT-Creation-Date: 2020-11-27 22:05+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -36,6 +36,7 @@ msgid "{name} takes {amount} damage." msgstr "{name} prend {amount} points de dĂ©gĂąt." #: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14 +#: squirrelbattle/tests/game_test.py:284 squirrelbattle/tests/game_test.py:287 msgid "New game" msgstr "Nouvelle partie" @@ -86,3 +87,47 @@ msgid "" msgstr "" "Le fichier JSON de sauvegarde est incorrect.\n" "Votre sauvegarde semble corrompue. Elle a Ă©tĂ© supprimĂ©e." + +#: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 +msgid "Main key to move up" +msgstr "Touche principale pour aller vers le haut" + +#: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23 +msgid "Secondary key to move up" +msgstr "Touche secondaire pour aller vers le haut" + +#: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25 +msgid "Main key to move down" +msgstr "Touche principale pour aller vers le bas" + +#: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27 +msgid "Secondary key to move down" +msgstr "Touche secondaire pour aller vers le bas" + +#: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29 +msgid "Main key to move left" +msgstr "Touche principale pour aller vers la gauche" + +#: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31 +msgid "Secondary key to move left" +msgstr "Touche secondaire pour aller vers la gauche" + +#: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33 +msgid "Main key to move right" +msgstr "Touche principale pour aller vers la droite" + +#: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35 +msgid "Secondary key to move right" +msgstr "Touche secondaire pour aller vers la droite" + +#: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37 +msgid "Key to validate a menu" +msgstr "Touche pour valider un menu" + +#: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39 +msgid "Texture pack" +msgstr "Pack de textures" + +#: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 +msgid "Language" +msgstr "Langue" diff --git a/squirrelbattle/display/menudisplay.py b/squirrelbattle/display/menudisplay.py index e6bb00d..b3036a0 100644 --- a/squirrelbattle/display/menudisplay.py +++ b/squirrelbattle/display/menudisplay.py @@ -6,6 +6,7 @@ from typing import List from squirrelbattle.menus import Menu, MainMenu from .display import Display, Box from ..resources import ResourceManager +from ..translations import gettext as _ class MenuDisplay(Display): @@ -66,9 +67,10 @@ class MenuDisplay(Display): class SettingsMenuDisplay(MenuDisplay): @property def values(self) -> List[str]: - return [a[1][1] + (" : " + return [_(a[1][1]) + (" : " + ("?" if self.menu.waiting_for_key - and a == self.menu.validate() else a[1][0]) + and a == self.menu.validate() else a[1][0] + .replace("\n", "\\n")) if a[1][0] else "") for a in self.menu.values] diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index ad2f1cc..7851aee 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -32,12 +32,12 @@ class Game: Init the game. """ self.state = GameMode.MAINMENU - self.main_menu = menus.MainMenu() - self.settings_menu = menus.SettingsMenu() self.settings = Settings() self.settings.load_settings() self.settings.write_settings() setlocale(self.settings.LOCALE) + self.main_menu = menus.MainMenu() + self.settings_menu = menus.SettingsMenu() self.settings_menu.update_values(self.settings) self.logs = Logs() self.message = None diff --git a/squirrelbattle/settings.py b/squirrelbattle/settings.py index 726d96c..3090679 100644 --- a/squirrelbattle/settings.py +++ b/squirrelbattle/settings.py @@ -7,6 +7,7 @@ import os from typing import Any, Generator from .resources import ResourceManager +from .translations import gettext as _ class Settings: @@ -17,26 +18,17 @@ class Settings: We can define the setting by simply use settings.TEXTURE_PACK = 'new_key' """ def __init__(self): - self.KEY_UP_PRIMARY = \ - ['z', 'Touche principale pour aller vers le haut'] - self.KEY_UP_SECONDARY = \ - ['KEY_UP', 'Touche secondaire pour aller vers le haut'] - self.KEY_DOWN_PRIMARY = \ - ['s', 'Touche principale pour aller vers le bas'] - self.KEY_DOWN_SECONDARY = \ - ['KEY_DOWN', 'Touche secondaire pour aller vers le bas'] - self.KEY_LEFT_PRIMARY = \ - ['q', 'Touche principale pour aller vers la gauche'] - self.KEY_LEFT_SECONDARY = \ - ['KEY_LEFT', 'Touche secondaire pour aller vers la gauche'] - self.KEY_RIGHT_PRIMARY = \ - ['d', 'Touche principale pour aller vers la droite'] - self.KEY_RIGHT_SECONDARY = \ - ['KEY_RIGHT', 'Touche secondaire pour aller vers la droite'] - self.KEY_ENTER = \ - ['\n', 'Touche pour valider un menu'] - self.TEXTURE_PACK = ['ascii', 'Pack de textures utilisĂ©'] - self.LOCALE = [locale.getlocale()[0][:2], 'Langue'] + self.KEY_UP_PRIMARY = ['z', 'Main key to move up'] + self.KEY_UP_SECONDARY = ['KEY_UP', 'Secondary key to move up'] + self.KEY_DOWN_PRIMARY = ['s', 'Main key to move down'] + self.KEY_DOWN_SECONDARY = ['KEY_DOWN', 'Secondary key to move down'] + self.KEY_LEFT_PRIMARY = ['q', 'Main key to move left'] + self.KEY_LEFT_SECONDARY = ['KEY_LEFT', 'Secondary key to move left'] + self.KEY_RIGHT_PRIMARY = ['d', 'Main key to move right'] + self.KEY_RIGHT_SECONDARY = ['KEY_RIGHT', 'Secondary key to move right'] + self.KEY_ENTER = ['\n', 'Key to validate a menu'] + self.TEXTURE_PACK = ['ascii', 'Texture pack'] + self.LOCALE = [locale.getlocale()[0][:2], 'Language'] def __getattribute__(self, item: str) -> Any: superattribute = super().__getattribute__(item) @@ -55,10 +47,10 @@ class Settings: Retrieve the comment of a setting. """ if item in self.settings_keys: - return object.__getattribute__(self, item)[1] + return _(object.__getattribute__(self, item)[1]) for key in self.settings_keys: if getattr(self, key) == item: - return object.__getattribute__(self, key)[1] + return _(object.__getattribute__(self, key)[1]) @property def settings_keys(self) -> Generator[str, Any, None]: diff --git a/squirrelbattle/tests/settings_test.py b/squirrelbattle/tests/settings_test.py index cef60c0..b0d9739 100644 --- a/squirrelbattle/tests/settings_test.py +++ b/squirrelbattle/tests/settings_test.py @@ -24,7 +24,7 @@ class TestSettings(unittest.TestCase): self.assertEqual(settings.get_comment(settings.TEXTURE_PACK), settings.get_comment('TEXTURE_PACK')) self.assertEqual(settings.get_comment(settings.TEXTURE_PACK), - 'Pack de textures utilisĂ©') + 'Texture pack') settings.TEXTURE_PACK = 'squirrel' self.assertEqual(settings.TEXTURE_PACK, 'squirrel') diff --git a/squirrelbattle/tests/translations_test.py b/squirrelbattle/tests/translations_test.py index e51cb8a..0d190d6 100644 --- a/squirrelbattle/tests/translations_test.py +++ b/squirrelbattle/tests/translations_test.py @@ -17,3 +17,24 @@ class TestTranslations(unittest.TestCase): self.assertEqual(_("Save"), "Sauvegarder") self.assertEqual(_("Settings"), "ParamĂštres") self.assertEqual(_("Exit"), "Quitter") + + self.assertEqual(_("Main key to move up"), + "Touche principale pour aller vers le haut") + self.assertEqual(_("Secondary key to move up"), + "Touche secondaire pour aller vers le haut") + self.assertEqual(_("Main key to move down"), + "Touche principale pour aller vers le bas") + self.assertEqual(_("Secondary key to move down"), + "Touche secondaire pour aller vers le bas") + self.assertEqual(_("Main key to move left"), + "Touche principale pour aller vers la gauche") + self.assertEqual(_("Secondary key to move left"), + "Touche secondaire pour aller vers la gauche") + self.assertEqual(_("Main key to move right"), + "Touche principale pour aller vers la droite") + self.assertEqual(_("Secondary key to move right"), + "Touche secondaire pour aller vers la droite") + self.assertEqual(_("Key to validate a menu"), + "Touche pour valider un menu") + self.assertEqual(_("Texture pack"), "Pack de textures") + self.assertEqual(_("Language"), "Langue") From 8f85093eb8b0796859be289ad23eb999c0591a25 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 22:21:16 +0100 Subject: [PATCH 42/54] One string was missing --- locale/en/LC_MESSAGES/squirrelbattle.po | 9 +++++++-- locale/fr/LC_MESSAGES/squirrelbattle.po | 9 +++++++-- squirrelbattle/game.py | 2 +- squirrelbattle/interfaces.py | 2 +- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po index 9ca5419..a027782 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 22:05+0100\n" +"POT-Creation-Date: 2020-11-27 22:20+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -79,7 +79,7 @@ msgstr "" #: squirrelbattle/game.py:175 squirrelbattle/game.py:176 msgid "" "The JSON file is not correct.\n" -"Your save seems corrupted.It got deleted." +"Your save seems corrupted. It got deleted." msgstr "" #: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 @@ -125,3 +125,8 @@ msgstr "" #: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 msgid "Language" msgstr "" + +#: squirrelbattle/interfaces.py:407 +#, python-brace-format +msgid "{name} dies." +msgstr "" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/locale/fr/LC_MESSAGES/squirrelbattle.po index 9dac712..c47f2ca 100644 --- a/locale/fr/LC_MESSAGES/squirrelbattle.po +++ b/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 22:05+0100\n" +"POT-Creation-Date: 2020-11-27 22:20+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -83,7 +83,7 @@ msgstr "" #: squirrelbattle/game.py:175 squirrelbattle/game.py:176 msgid "" "The JSON file is not correct.\n" -"Your save seems corrupted.It got deleted." +"Your save seems corrupted. It got deleted." msgstr "" "Le fichier JSON de sauvegarde est incorrect.\n" "Votre sauvegarde semble corrompue. Elle a Ă©tĂ© supprimĂ©e." @@ -131,3 +131,8 @@ msgstr "Pack de textures" #: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 msgid "Language" msgstr "Langue" + +#: squirrelbattle/interfaces.py:407 +#, python-brace-format +msgid "{name} dies." +msgstr "{name} meurt." diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 7851aee..09f1328 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -174,7 +174,7 @@ class Game: self.load_state(state) except JSONDecodeError: self.message = _("The JSON file is not correct.\n" - "Your save seems corrupted." + "Your save seems corrupted. " "It got deleted.") os.unlink(file_path) self.display_actions(DisplayActions.UPDATE) diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index 845e3bd..78c1a15 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -404,7 +404,7 @@ class FightingEntity(Entity): self.die() return _("{name} takes {amount} damage.")\ .format(name=self.name, amount=str(amount)) \ - + (" " + "{name} dies.".format(name=self.name) + + (" " + _("{name} dies.").format(name=self.name) if self.health <= 0 else "") def die(self) -> None: From 70ae60b9a428c129355361aa6f71175155bd16bc Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Fri, 27 Nov 2020 22:33:58 +0100 Subject: [PATCH 43/54] Translate entities --- locale/en/LC_MESSAGES/squirrelbattle.po | 47 ++++++++++++++++++++-- locale/fr/LC_MESSAGES/squirrelbattle.mo | Bin 2310 -> 2607 bytes locale/fr/LC_MESSAGES/squirrelbattle.po | 47 ++++++++++++++++++++-- squirrelbattle/interfaces.py | 14 +++++-- squirrelbattle/tests/translations_test.py | 19 ++++++++- 5 files changed, 113 insertions(+), 14 deletions(-) diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po index a027782..d77e823 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 22:20+0100\n" +"POT-Creation-Date: 2020-11-27 22:31+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -25,12 +25,12 @@ msgstr "" msgid "YOU ARE DEAD" msgstr "" -#: squirrelbattle/interfaces.py:394 +#: squirrelbattle/interfaces.py:394 squirrelbattle/interfaces.py:398 #, python-brace-format msgid "{name} hits {opponent}." msgstr "" -#: squirrelbattle/interfaces.py:405 +#: squirrelbattle/interfaces.py:405 squirrelbattle/interfaces.py:410 #, python-brace-format msgid "{name} takes {amount} damage." msgstr "" @@ -83,50 +83,89 @@ msgid "" msgstr "" #: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 +#: squirrelbattle/tests/translations_test.py:25 msgid "Main key to move up" msgstr "" #: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23 +#: squirrelbattle/tests/translations_test.py:27 msgid "Secondary key to move up" msgstr "" #: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25 +#: squirrelbattle/tests/translations_test.py:29 msgid "Main key to move down" msgstr "" #: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27 +#: squirrelbattle/tests/translations_test.py:31 msgid "Secondary key to move down" msgstr "" #: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29 +#: squirrelbattle/tests/translations_test.py:33 msgid "Main key to move left" msgstr "" #: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31 +#: squirrelbattle/tests/translations_test.py:35 msgid "Secondary key to move left" msgstr "" #: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33 +#: squirrelbattle/tests/translations_test.py:37 msgid "Main key to move right" msgstr "" #: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35 +#: squirrelbattle/tests/translations_test.py:39 msgid "Secondary key to move right" msgstr "" #: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37 +#: squirrelbattle/tests/translations_test.py:41 msgid "Key to validate a menu" msgstr "" #: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39 +#: squirrelbattle/tests/translations_test.py:43 msgid "Texture pack" msgstr "" #: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 +#: squirrelbattle/tests/translations_test.py:44 msgid "Language" msgstr "" -#: squirrelbattle/interfaces.py:407 +#: squirrelbattle/interfaces.py:407 squirrelbattle/interfaces.py:412 #, python-brace-format msgid "{name} dies." msgstr "" + +#: squirrelbattle/tests/translations_test.py:47 +msgid "player" +msgstr "" + +#: squirrelbattle/tests/translations_test.py:49 +msgid "tiger" +msgstr "" + +#: squirrelbattle/tests/translations_test.py:50 +msgid "hedgehog" +msgstr "" + +#: squirrelbattle/tests/translations_test.py:51 +msgid "rabbit" +msgstr "" + +#: squirrelbattle/tests/translations_test.py:52 +msgid "teddy bear" +msgstr "" + +#: squirrelbattle/tests/translations_test.py:54 +msgid "bomb" +msgstr "" + +#: squirrelbattle/tests/translations_test.py:55 +msgid "heart" +msgstr "" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.mo b/locale/fr/LC_MESSAGES/squirrelbattle.mo index bc9146e56582ef46663f44ca84d8b24c1f344325..12e6fe990a48a5dcee90cc5a5049f39393074960 100644 GIT binary patch delta 938 zcmXxiKWGzS7{~D^?U~l9Rnz#VYBdcM8Z1%lBnkylP{Bng9p%oP$w`xomqe%{w>b#n za5~vt0)k){XSIVU=-?m@oeB;*h?5Tf`TpYF!@ck4-rSq#{d>3YtQc<;oJU5KDTgR? zIkRJUdWeeni4Ois{exq)hlkDf;y8}t460uh_uzc$1ysK)IDt1&{qNy%v)B?|^8D}` zmEbKNzz?Zk@gVIyANOM!mEaUE;aS{{t9Ty!Y5NEA*k7tG=uqi@W2o^a2F47=i&iv^ zJT^zAgePzxF5na{sm<>6Pzml+jo?EZOaL{}KJwT)mA=2jS^S7c@po#4j}^wZMP7Dd zj2H0%ZpF{I4L4BTpkh+? zGX3xd$zku)_9xsydjlu&8_r^$ZDT_QlPx0i8w|{e4R%gfNIRRwVP1Aqv`e}pWu1Q( zO03YpS?C^U#yWS!^na{?C5l$9&;`>G=)84QigAi2tzmTC6U+omsm)^d*-o zB`2M!1utxR*6`h^OI@q`jj(R*Wp~AoEOI?B=vvpW)mBO#U920_`TcgwZTfdgwZQLG z*A|_Yb4f{jySkqAB5S8gf5hy{pwnU;5x|Bgi6ir$UVvCayZW7ccHMIoM(h&59 zmWZIezn~gw)Fr5?rSG}k3+H|Aeeb?^-Z}R!(g@c-!p^xcrim!gCgzDp9~Z{DU&O(@ zwSc{>cW@l{u?LUs^9GKwKDAz=i3yRqw3u{rBihwTG>7^#F>4BESnuH^ z)=)pt#4WtUe*D2z^zpa4&f)|Xa26}Nrl>R2eAfYyAo=B%iN4^WCVEEQ@MboMd|`}r z3l}iLLv;n?SjHi|z#QIS2*0rp|4`o#20QO1th*Q|znn19jrUl?CmhBl$~?pzY61_Z z@C9S|j`ozOq*E=$nf8MjG}nAfJ4%C0VdeoBJ;uDAi4Oe%9hyLsg$ZppIb?*;iu4>K zgmy~@4KZVo>wuk$_v>%_qS>l@a8z}RrE;lSDlW?Q+NPV_$hhfDGVLt~Do(Q\n" "Language-Team: LANGUAGE \n" @@ -25,12 +25,12 @@ msgstr "Inventaire :" msgid "YOU ARE DEAD" msgstr "VOUS ÊTES MORT" -#: squirrelbattle/interfaces.py:394 +#: squirrelbattle/interfaces.py:394 squirrelbattle/interfaces.py:398 #, python-brace-format msgid "{name} hits {opponent}." msgstr "{name} frappe {opponent}." -#: squirrelbattle/interfaces.py:405 +#: squirrelbattle/interfaces.py:405 squirrelbattle/interfaces.py:410 #, python-brace-format msgid "{name} takes {amount} damage." msgstr "{name} prend {amount} points de dĂ©gĂąt." @@ -89,50 +89,89 @@ msgstr "" "Votre sauvegarde semble corrompue. Elle a Ă©tĂ© supprimĂ©e." #: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 +#: squirrelbattle/tests/translations_test.py:25 msgid "Main key to move up" msgstr "Touche principale pour aller vers le haut" #: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23 +#: squirrelbattle/tests/translations_test.py:27 msgid "Secondary key to move up" msgstr "Touche secondaire pour aller vers le haut" #: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25 +#: squirrelbattle/tests/translations_test.py:29 msgid "Main key to move down" msgstr "Touche principale pour aller vers le bas" #: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27 +#: squirrelbattle/tests/translations_test.py:31 msgid "Secondary key to move down" msgstr "Touche secondaire pour aller vers le bas" #: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29 +#: squirrelbattle/tests/translations_test.py:33 msgid "Main key to move left" msgstr "Touche principale pour aller vers la gauche" #: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31 +#: squirrelbattle/tests/translations_test.py:35 msgid "Secondary key to move left" msgstr "Touche secondaire pour aller vers la gauche" #: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33 +#: squirrelbattle/tests/translations_test.py:37 msgid "Main key to move right" msgstr "Touche principale pour aller vers la droite" #: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35 +#: squirrelbattle/tests/translations_test.py:39 msgid "Secondary key to move right" msgstr "Touche secondaire pour aller vers la droite" #: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37 +#: squirrelbattle/tests/translations_test.py:41 msgid "Key to validate a menu" msgstr "Touche pour valider un menu" #: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39 +#: squirrelbattle/tests/translations_test.py:43 msgid "Texture pack" msgstr "Pack de textures" #: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 +#: squirrelbattle/tests/translations_test.py:44 msgid "Language" msgstr "Langue" -#: squirrelbattle/interfaces.py:407 +#: squirrelbattle/interfaces.py:407 squirrelbattle/interfaces.py:412 #, python-brace-format msgid "{name} dies." msgstr "{name} meurt." + +#: squirrelbattle/tests/translations_test.py:47 +msgid "player" +msgstr "joueur" + +#: squirrelbattle/tests/translations_test.py:49 +msgid "tiger" +msgstr "tigre" + +#: squirrelbattle/tests/translations_test.py:50 +msgid "hedgehog" +msgstr "hĂ©risson" + +#: squirrelbattle/tests/translations_test.py:51 +msgid "rabbit" +msgstr "lapin" + +#: squirrelbattle/tests/translations_test.py:52 +msgid "teddy bear" +msgstr "nounours" + +#: squirrelbattle/tests/translations_test.py:54 +msgid "bomb" +msgstr "bombe" + +#: squirrelbattle/tests/translations_test.py:55 +msgid "heart" +msgstr "cƓur" diff --git a/squirrelbattle/interfaces.py b/squirrelbattle/interfaces.py index 78c1a15..90e5d69 100644 --- a/squirrelbattle/interfaces.py +++ b/squirrelbattle/interfaces.py @@ -315,6 +315,10 @@ class Entity: from squirrelbattle.entities.items import Item return isinstance(self, Item) + @property + def translated_name(self) -> str: + return _(self.name.replace("_", " ")) + @staticmethod def get_all_entity_classes(): """ @@ -392,8 +396,9 @@ class FightingEntity(Entity): Deals damage to the opponent, based on the stats """ return _("{name} hits {opponent}.")\ - .format(name=self.name, opponent=opponent.name) + " "\ - + opponent.take_damage(self, self.strength) + .format(name=_(self.translated_name.capitalize()), + opponent=_(opponent.translated_name)) + " " + \ + opponent.take_damage(self, self.strength) def take_damage(self, attacker: "Entity", amount: int) -> str: """ @@ -403,8 +408,9 @@ class FightingEntity(Entity): if self.health <= 0: self.die() return _("{name} takes {amount} damage.")\ - .format(name=self.name, amount=str(amount)) \ - + (" " + _("{name} dies.").format(name=self.name) + .format(name=self.translated_name.capitalize(), amount=str(amount))\ + + (" " + _("{name} dies.") + .format(name=self.translated_name.capitalize()) if self.health <= 0 else "") def die(self) -> None: diff --git a/squirrelbattle/tests/translations_test.py b/squirrelbattle/tests/translations_test.py index 0d190d6..1931224 100644 --- a/squirrelbattle/tests/translations_test.py +++ b/squirrelbattle/tests/translations_test.py @@ -7,9 +7,9 @@ class TestTranslations(unittest.TestCase): def setUp(self) -> None: setlocale("fr") - def test_translations(self) -> None: + def test_main_menu_translation(self) -> None: """ - Ensure that some strings are well-translated. + Ensure that the main menu is translated. """ self.assertEqual(_("New game"), "Nouvelle partie") self.assertEqual(_("Resume"), "Continuer") @@ -18,6 +18,10 @@ class TestTranslations(unittest.TestCase): self.assertEqual(_("Settings"), "ParamĂštres") self.assertEqual(_("Exit"), "Quitter") + def test_settings_menu_translation(self) -> None: + """ + Ensure that the settings menu is translated. + """ self.assertEqual(_("Main key to move up"), "Touche principale pour aller vers le haut") self.assertEqual(_("Secondary key to move up"), @@ -38,3 +42,14 @@ class TestTranslations(unittest.TestCase): "Touche pour valider un menu") self.assertEqual(_("Texture pack"), "Pack de textures") self.assertEqual(_("Language"), "Langue") + + def test_entities_translation(self) -> None: + self.assertEqual(_("player"), "joueur") + + self.assertEqual(_("tiger"), "tigre") + self.assertEqual(_("hedgehog"), "hĂ©risson") + self.assertEqual(_("rabbit"), "lapin") + self.assertEqual(_("teddy bear"), "nounours") + + self.assertEqual(_("bomb"), "bombe") + self.assertEqual(_("heart"), "cƓur") From 138b2c6d54c8a4df83f56d4057238730427878b3 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 01:25:35 +0100 Subject: [PATCH 44/54] Logs are capitalized --- squirrelbattle/tests/entities_test.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/squirrelbattle/tests/entities_test.py b/squirrelbattle/tests/entities_test.py index 8f4e0c2..371bfc7 100644 --- a/squirrelbattle/tests/entities_test.py +++ b/squirrelbattle/tests/entities_test.py @@ -46,10 +46,10 @@ class TestEntities(unittest.TestCase): self.assertEqual(entity.strength, 2) for _ in range(9): self.assertEqual(entity.hit(entity), - "tiger hits tiger. tiger takes 2 damage.") + "Tiger hits tiger. Tiger takes 2 damage.") self.assertFalse(entity.dead) - self.assertEqual(entity.hit(entity), "tiger hits tiger. " - + "tiger takes 2 damage. tiger dies.") + self.assertEqual(entity.hit(entity), "Tiger hits tiger. " + + "Tiger takes 2 damage. Tiger dies.") self.assertTrue(entity.dead) entity = Rabbit() @@ -70,8 +70,8 @@ class TestEntities(unittest.TestCase): self.assertTrue(entity.y == 2 and entity.x == 6) self.assertEqual(old_health - entity.strength, self.player.health) self.assertEqual(self.map.logs.messages[-1], - f"{entity.name} hits {self.player.name}. \ -{self.player.name} takes {entity.strength} damage.") + f"{entity.name.capitalize()} hits {self.player.name}. \ +{self.player.name.capitalize()} takes {entity.strength} damage.") # Fight the rabbit old_health = entity.health From 7d026044071ce214bb50d1648ca981fb4327a85e Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 01:59:52 +0100 Subject: [PATCH 45/54] Clean the translation module --- squirrelbattle/game.py | 4 +- squirrelbattle/menus.py | 4 +- squirrelbattle/tests/translations_test.py | 4 +- squirrelbattle/translations.py | 52 +++++++++++++++-------- 4 files changed, 40 insertions(+), 24 deletions(-) diff --git a/squirrelbattle/game.py b/squirrelbattle/game.py index 09f1328..44ad349 100644 --- a/squirrelbattle/game.py +++ b/squirrelbattle/game.py @@ -14,7 +14,7 @@ from .interfaces import Map, Logs from .resources import ResourceManager from .settings import Settings from . import menus -from .translations import gettext as _, setlocale +from .translations import gettext as _, Translator from typing import Callable @@ -35,7 +35,7 @@ class Game: self.settings = Settings() self.settings.load_settings() self.settings.write_settings() - setlocale(self.settings.LOCALE) + Translator.setlocale(self.settings.LOCALE) self.main_menu = menus.MainMenu() self.settings_menu = menus.SettingsMenu() self.settings_menu.update_values(self.settings) diff --git a/squirrelbattle/menus.py b/squirrelbattle/menus.py index 3f6f7a0..1fba7ea 100644 --- a/squirrelbattle/menus.py +++ b/squirrelbattle/menus.py @@ -7,7 +7,7 @@ from typing import Any, Optional from .display.texturepack import TexturePack from .enums import GameMode, KeyValues, DisplayActions from .settings import Settings -from .translations import gettext as _, setlocale +from .translations import gettext as _, Translator class Menu: @@ -99,7 +99,7 @@ class SettingsMenu(Menu): elif option == "LOCALE": game.settings.LOCALE = 'fr' if game.settings.LOCALE == 'en'\ else 'en' - setlocale(game.settings.LOCALE) + Translator.setlocale(game.settings.LOCALE) game.settings.write_settings() self.update_values(game.settings) else: diff --git a/squirrelbattle/tests/translations_test.py b/squirrelbattle/tests/translations_test.py index 1931224..742edea 100644 --- a/squirrelbattle/tests/translations_test.py +++ b/squirrelbattle/tests/translations_test.py @@ -1,11 +1,11 @@ import unittest -from squirrelbattle.translations import gettext as _, setlocale +from squirrelbattle.translations import gettext as _, Translator class TestTranslations(unittest.TestCase): def setUp(self) -> None: - setlocale("fr") + Translator.setlocale("fr") def test_main_menu_translation(self) -> None: """ diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index fa8196d..47ec9fb 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -1,28 +1,44 @@ # Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later -import gettext +import gettext as gt +from typing import Any, List -SUPPORTED_LOCALES = ["en", "fr"] -DEFAULT_LOCALE = "en" +class Translator: + """ + This module uses gettext to translate strings. + Translator.setlocale defines the language of the strings, + then gettext() translates the message. + """ + SUPPORTED_LOCALES: List[str] = ["en", "fr"] + locale: str = "en" + translators: dict = {} -_current_locale = DEFAULT_LOCALE + for language in SUPPORTED_LOCALES: + translators[language] = gt.translation( + "squirrelbattle", + localedir="locale", + languages=[language], + ) -_TRANSLATORS = dict() -for language in SUPPORTED_LOCALES: - _TRANSLATORS[language] = gettext.translation("squirrelbattle", - localedir="locale", - languages=[language]) + @classmethod + def setlocale(cls, lang: str) -> None: + """ + Define the language used to translate the game. + The language must be supported, otherwise nothing is done. + """ + lang = lang[:2] + if lang in cls.SUPPORTED_LOCALES: + cls.locale = lang + + @classmethod + def get_translator(cls) -> Any: + return cls.translators.get(cls.locale) def gettext(message: str) -> str: - return _TRANSLATORS.get(_current_locale, - _TRANSLATORS.get("en")).gettext(message) - - -def setlocale(lang: str) -> None: - global _current_locale - lang = lang[:2] - if lang in SUPPORTED_LOCALES: - _current_locale = lang + """ + Translate a message. + """ + return Translator.get_translator().gettext(message) From ffc8b904417fdb23def673a097ade06fea0003d8 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 02:54:04 +0100 Subject: [PATCH 46/54] Create functions that call xgettext or msgfmt --- locale/en/LC_MESSAGES/squirrelbattle.po | 10 ++++----- locale/fr/LC_MESSAGES/squirrelbattle.po | 10 ++++----- squirrelbattle/translations.py | 27 +++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/locale/en/LC_MESSAGES/squirrelbattle.po index d77e823..21e45e6 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/locale/en/LC_MESSAGES/squirrelbattle.po @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. +# Copyright (C) YEAR ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# This file is distributed under the same license as the squirrelbattle package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 22:31+0100\n" +"Project-Id-Version: squirrelbattle 3.14.1\n" +"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" +"POT-Creation-Date: 2020-11-28 02:50+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/locale/fr/LC_MESSAGES/squirrelbattle.po index fa4e1b0..b14ef50 100644 --- a/locale/fr/LC_MESSAGES/squirrelbattle.po +++ b/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -1,14 +1,14 @@ # SOME DESCRIPTIVE TITLE. -# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. +# Copyright (C) YEAR ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# This file is distributed under the same license as the squirrelbattle package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" -"Project-Id-Version: PACKAGE VERSION\n" -"Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2020-11-27 22:31+0100\n" +"Project-Id-Version: squirrelbattle 3.14.1\n" +"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" +"POT-Creation-Date: 2020-11-28 02:50+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index 47ec9fb..1cee88b 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later import gettext as gt +import subprocess from typing import Any, List @@ -36,6 +37,32 @@ class Translator: def get_translator(cls) -> Any: return cls.translators.get(cls.locale) + @classmethod + def makemessages(cls) -> None: + for language in cls.SUPPORTED_LOCALES: + args = ["find", "squirrelbattle/", "-iname", "*.py"] + find = subprocess.Popen(args, stdout=subprocess.PIPE) + args = ["xargs", "xgettext", "--from-code", "utf-8", + "--join-existing", + "--add-comments", + "--package-name=squirrelbattle", + "--package-version=3.14.1", + "--copyright-holder=ĂżnĂ©rant, eichhornchen, " + "nicomarg, charlse", + "--msgid-bugs-address=squirrel-battle@crans.org", + "-o", f"locale/{language}/LC_MESSAGES/squirrelbattle.po"] + print(f"Make {language} messages...") + subprocess.Popen(args, stdin=find.stdout) + + @classmethod + def compilemessages(cls) -> None: + for language in cls.SUPPORTED_LOCALES: + args = ["msgfmt", "--check-format", + "-o", f"locale/{language}/LC_MESSAGES/squirrelbattle.mo", + f"locale/{language}/LC_MESSAGES/squirrelbattle.po"] + print(f"Compiling {language} messages...") + subprocess.Popen(args) + def gettext(message: str) -> str: """ From 8aad15f07b6821e024665323049ac5d49c92688d Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 03:04:28 +0100 Subject: [PATCH 47/54] Move translation files in the module --- .../locale}/en/LC_MESSAGES/squirrelbattle.mo | Bin 337 -> 368 bytes .../locale}/en/LC_MESSAGES/squirrelbattle.po | 2 +- .../locale}/fr/LC_MESSAGES/squirrelbattle.mo | Bin 2607 -> 2638 bytes .../locale}/fr/LC_MESSAGES/squirrelbattle.po | 0 squirrelbattle/translations.py | 21 +++++++++++------- 5 files changed, 14 insertions(+), 9 deletions(-) rename {locale => squirrelbattle/locale}/en/LC_MESSAGES/squirrelbattle.mo (59%) rename {locale => squirrelbattle/locale}/en/LC_MESSAGES/squirrelbattle.po (99%) rename {locale => squirrelbattle/locale}/fr/LC_MESSAGES/squirrelbattle.mo (84%) rename {locale => squirrelbattle/locale}/fr/LC_MESSAGES/squirrelbattle.po (100%) diff --git a/locale/en/LC_MESSAGES/squirrelbattle.mo b/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.mo similarity index 59% rename from locale/en/LC_MESSAGES/squirrelbattle.mo rename to squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.mo index 6c5906d1cd061dff54de8b533942893de34efc9e..14164ec0ffb6694d6c55f833f37252bf09f9cc75 100644 GIT binary patch delta 84 zcmcb}^nq!D3ZvOXRSnnT!qUv5qSTzE#FCPnR0U%_LlZqiuAtO{{Gt+F-{SPl6kVs% d^kUtRd@BW*T3v`@hvcHfykfolqV$Qy_W;)<9*O_} delta 53 zcmeysbdhO-3ZwW$RSmTOM`v$GcUOfl*Pviee?P9E)Pnq?5?$Zo^vo1pr_%Id-H?1M Jg^82y0RXnd5qJOq diff --git a/locale/en/LC_MESSAGES/squirrelbattle.po b/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po similarity index 99% rename from locale/en/LC_MESSAGES/squirrelbattle.po rename to squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po index 21e45e6..9600c79 100644 --- a/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: squirrelbattle 3.14.1\n" "Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" -"POT-Creation-Date: 2020-11-28 02:50+0100\n" +"POT-Creation-Date: 2020-11-28 03:01+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.mo b/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.mo similarity index 84% rename from locale/fr/LC_MESSAGES/squirrelbattle.mo rename to squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.mo index 12e6fe990a48a5dcee90cc5a5049f39393074960..eb2e033a3be0be6f3613020253fa56fa6f3334af 100644 GIT binary patch delta 359 zcmZ24a!zD}4r9F;BLhPzD+2=?0|UbvAi)l#Hv?%NAiWz%O9SZ>KpKb`o&X7u{A(bs z0i-_zX>A}a0~7?&9za?XNS6RBYJs`Bn-rwYm_+4#`D{dBuA9Md_Q@vo^2*03~%f A8vpr)_4~CeqbJTp}`{xN(d=oMIFg$dCg??Vm7#S4`o@GRbC= zzKH=ev4lg^@s3`6qPqWfi}?$Pc>X~Ks(=ovgA?rG9D^7qrHvU>4@{B2%hGa#4B1im zlkBbaBN8DOtG}V2{-Ki+Ve(=jfv#=VUULL$xqLZSFk&sE-Y8ZpqnQ@op0&R73xSj+ AjQ{`u diff --git a/locale/fr/LC_MESSAGES/squirrelbattle.po b/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.po similarity index 100% rename from locale/fr/LC_MESSAGES/squirrelbattle.po rename to squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.po diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index 1cee88b..7a0e524 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -3,6 +3,7 @@ import gettext as gt import subprocess +from pathlib import Path from typing import Any, List @@ -19,7 +20,7 @@ class Translator: for language in SUPPORTED_LOCALES: translators[language] = gt.translation( "squirrelbattle", - localedir="locale", + localedir=Path(__file__).parent / "locale", languages=[language], ) @@ -38,10 +39,11 @@ class Translator: return cls.translators.get(cls.locale) @classmethod - def makemessages(cls) -> None: + def makemessages(cls) -> None: # pragma: no cover for language in cls.SUPPORTED_LOCALES: - args = ["find", "squirrelbattle/", "-iname", "*.py"] - find = subprocess.Popen(args, stdout=subprocess.PIPE) + args = ["find", "squirrelbattle", "-iname", "*.py"] + find = subprocess.Popen(args, cwd=Path(__file__).parent.parent, + stdout=subprocess.PIPE) args = ["xargs", "xgettext", "--from-code", "utf-8", "--join-existing", "--add-comments", @@ -50,16 +52,19 @@ class Translator: "--copyright-holder=ĂżnĂ©rant, eichhornchen, " "nicomarg, charlse", "--msgid-bugs-address=squirrel-battle@crans.org", - "-o", f"locale/{language}/LC_MESSAGES/squirrelbattle.po"] + "-o", Path(__file__).parent / "locale" / language + / "LC_MESSAGES" / "squirrelbattle.po"] print(f"Make {language} messages...") subprocess.Popen(args, stdin=find.stdout) @classmethod - def compilemessages(cls) -> None: + def compilemessages(cls) -> None: # pragma: no cover for language in cls.SUPPORTED_LOCALES: args = ["msgfmt", "--check-format", - "-o", f"locale/{language}/LC_MESSAGES/squirrelbattle.mo", - f"locale/{language}/LC_MESSAGES/squirrelbattle.po"] + "-o", Path(__file__).parent / "locale" / language + / "LC_MESSAGES" / "squirrelbattle.mo", + Path(__file__).parent / "locale" / language + / "LC_MESSAGES" / "squirrelbattle.po"] print(f"Compiling {language} messages...") subprocess.Popen(args) From 7c0cf3e029d408e857e7172a0567af387216eed2 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 03:21:20 +0100 Subject: [PATCH 48/54] CLI to manage messages --- main.py | 18 +++++++++++++++++- squirrelbattle/translations.py | 22 ++++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/main.py b/main.py index e8c333e..fbbbb35 100755 --- a/main.py +++ b/main.py @@ -2,8 +2,24 @@ # Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later +import argparse +import sys from squirrelbattle.bootstrap import Bootstrap +from squirrelbattle.translations import Translator if __name__ == "__main__": - Bootstrap.run_game() + parser = argparse.ArgumentParser() + + parser.add_argument("--makemessages", "-mm", action="store_true", + help="Extract translatable strings") + parser.add_argument("--compilemessages", "-cm", action="store_true", + help="Compile translatable strings") + + args = parser.parse_args(sys.argv[1:]) + if args.makemessages: + Translator.makemessages() + elif args.compilemessages: + Translator.compilemessages() + else: + Bootstrap.run_game() diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index 7a0e524..dfd3cf3 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -2,6 +2,7 @@ # SPDX-License-Identifier: GPL-3.0-or-later import gettext as gt +import os import subprocess from pathlib import Path from typing import Any, List @@ -18,11 +19,14 @@ class Translator: translators: dict = {} for language in SUPPORTED_LOCALES: - translators[language] = gt.translation( - "squirrelbattle", - localedir=Path(__file__).parent / "locale", - languages=[language], - ) + 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 setlocale(cls, lang: str) -> None: @@ -41,19 +45,21 @@ class Translator: @classmethod def makemessages(cls) -> None: # pragma: no cover for language in cls.SUPPORTED_LOCALES: + file_name = Path(__file__).parent / "locale" / language \ + / "LC_MESSAGES" / "squirrelbattle.po" args = ["find", "squirrelbattle", "-iname", "*.py"] find = subprocess.Popen(args, cwd=Path(__file__).parent.parent, stdout=subprocess.PIPE) args = ["xargs", "xgettext", "--from-code", "utf-8", - "--join-existing", "--add-comments", "--package-name=squirrelbattle", "--package-version=3.14.1", "--copyright-holder=ĂżnĂ©rant, eichhornchen, " "nicomarg, charlse", "--msgid-bugs-address=squirrel-battle@crans.org", - "-o", Path(__file__).parent / "locale" / language - / "LC_MESSAGES" / "squirrelbattle.po"] + "-o", file_name] + if file_name.is_file(): + args.append("--join-existing") print(f"Make {language} messages...") subprocess.Popen(args, stdin=find.stdout) From 5ce62c15f7a4f771b094cb420cf0dc5ab9dc77af Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 03:23:04 +0100 Subject: [PATCH 49/54] Include locale files in Python setup script --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6287f7d..a9b8379 100644 --- a/setup.py +++ b/setup.py @@ -36,7 +36,7 @@ setup( ], python_requires='>=3.6', include_package_data=True, - package_data={"squirrelbattle": ["assets/*"]}, + package_data={"squirrelbattle": ["assets/*", "locale/*"]}, entry_points={ "console_scripts": [ "squirrel-battle = squirrelbattle.bootstrap:Bootstrap.run_game", From a34dae2ad0fe0db769bb08605976b46819af8b11 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 13:49:28 +0100 Subject: [PATCH 50/54] Compile messages on setup --- .gitignore | 3 +++ setup.py | 14 ++++++++++++-- .../locale/en/LC_MESSAGES/squirrelbattle.mo | Bin 368 -> 0 bytes .../locale/fr/LC_MESSAGES/squirrelbattle.mo | Bin 2638 -> 0 bytes 4 files changed, 15 insertions(+), 2 deletions(-) delete mode 100644 squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.mo delete mode 100644 squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.mo diff --git a/.gitignore b/.gitignore index f30aa49..8499d7c 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,6 @@ save.json # Don't commit docs output docs/_build + +# Don't commit compiled messages +*.mo diff --git a/setup.py b/setup.py index a9b8379..00bd56b 100644 --- a/setup.py +++ b/setup.py @@ -3,13 +3,23 @@ # Copyright (C) 2020 by ĂżnĂ©rant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later -import os +import subprocess from setuptools import find_packages, setup with open("README.md", "r") as f: long_description = f.read() +# Compile messages +for language in ["en", "fr"]: + args = ["msgfmt", "--check-format", + "-o", f"squirrelbattle/locale/{language}/LC_MESSAGES" + "/squirrelbattle.mo", + f"squirrelbattle/locale/{language}/LC_MESSAGES" + "/squirrelbattle.po"] + print(f"Compiling {language} messages...") + subprocess.Popen(args) + setup( name="squirrel-battle", version="3.14.1", @@ -36,7 +46,7 @@ setup( ], python_requires='>=3.6', include_package_data=True, - package_data={"squirrelbattle": ["assets/*", "locale/*"]}, + package_data={"squirrelbattle": ["assets/*", "locale/*/*/*"]}, entry_points={ "console_scripts": [ "squirrel-battle = squirrelbattle.bootstrap:Bootstrap.run_game", diff --git a/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.mo b/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.mo deleted file mode 100644 index 14164ec0ffb6694d6c55f833f37252bf09f9cc75..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 368 zcmYL^zfQw25Qjl9Wn^aXzy=qnK&Y5Msv&NPWH(isBEjaSCKv^~*e-$x;q`bHE63^1&Ug2-xBIA*gv=7EvO2Yfbc(2=~ zim}z?G##9!gQV1J=Of6_m=)Y^ngEsSUHFqnwO2Nz&Ns=dfKq>$?n}s2)Ra7OR)Q=b zW8}V|GCzDOraTcUM5wy9Rz>G2883t&QzkjN;*#ZJ#Img9^Z5;`w%MpgL#5RlC4x;S z3pPPdh*4|0sl7uYBy-R4x diff --git a/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.mo b/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.mo deleted file mode 100644 index eb2e033a3be0be6f3613020253fa56fa6f3334af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2638 zcmbuA&yQ3^5XW0V)ImYPpNQH^Ld3uuSTTkSC=AR1gEKqp%q(QRn4WpPZyMg~esuR6 z7zzIXCllh$c<|&Hd ze*^Jj|6q6s+=zkp_hejD5a{toU1cVdxv8hjP>;8yTs@C^6`_$YV>+zf7j(X@XnNc#>= z7=pC_1CZpt0^bL}0iOViP|^h(AnCsW!gO|P!tX)+*bf-U-k&DxzkpD|ex1z!03XNv zFYtMAGn};t+zrAVBOOnHFn4q=!Zq?6r4RXa+FrsRPok5LC_i?gPaEl_M(0i&4sNH%A98jHTP{E~2d$z(d@Mswd)jwd3W$<;)^EqUK$JXA6~${NyT*w++2 z46ErnYs3-v8`)=gTYPdz0#3mO_NAE&T(NSPn2_5=5P{BwA{fgzNBKA z&n+&`os@|qSK}fbV{MlDJg;~j8P7u*OE1GbYst$#gT|CX)#^%qrdgjGsp4>jhA3^7 z9lu)hL?^VY(z;k*;KfFnm&(NwYn!Cax>8t=F^pu_L~QJQW<|S=?0_X6yo#h{ zS2Tijm0a)g(@9r($FG<)H5#dOb$Q*33lbkhf*^YA5ec#=&*rT;53_?x7@U>XDWePA zUCb0N6Ssx;vE&Eyv#;l8a}Ajq>w}t$R2Ur3A{VsGifk|zKGv~9yS%YcZoVEgWKWUG zpo9!A@Wpbm5!C8IsmM>)3$@DLck6TITva$9v}ju_kopCFa-mw~bH!SjA1T+0mFlr# zsnjSpn{PpMocuvcilo4+#ko@p#Z!>0R*%JsPF;~H@La7@E3e#YHh&;@!e|e#1g(Aw zdpv@=A1+qnfYM&nTLZgN*DA@h7y8=;zt=pMd=LwXbKz>2^+5X#*M28xpsZutS9(i->fft zuW#0qo%m*6Sdk1r#qAtBA+1M7Nyj_!aNtlvc+b$imlT3yY3`P9$sMkaN~$kr0-5RZ zxw9kLyCr1OhS#Zzm?X_)o|h>KQ-8ZGO|43X1A5CSPNbjm8pX=7>iATJV@LJs-m|6i zsEo^X>;Ig5w!YBh!)vW_lh^8v)~J?A*7^E6-bi;iu&BdEvvIPpSfolbjXH!E;;58a pIjvp^vdJ&ktR*YbRIXLcQY-PVXt|oDMro8i+%FssqTwe{@h?*k&%yuz From f78c73a7035c61bfc279ec451101e426e613413a Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 14:02:23 +0100 Subject: [PATCH 51/54] Tests and the CI are compiling messages --- .gitlab-ci.yml | 6 +++- squirrelbattle/tests/game_test.py | 24 +++++++------- squirrelbattle/tests/translations_test.py | 2 ++ squirrelbattle/translations.py | 40 +++++++++++++++-------- 4 files changed, 46 insertions(+), 26 deletions(-) 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() From aade89de7b944b98671de16175cc1a3112904a70 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 14:10:31 +0100 Subject: [PATCH 52/54] Tests and the CI are compiling messages --- .gitlab-ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 867562b..ff5c142 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -32,7 +32,6 @@ 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 From 6b09d488b63f978e77df9f5f53fb89a33df321ed Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 16:00:17 +0100 Subject: [PATCH 53/54] Documentation on translation --- debian/control | 2 +- docs/deployment.rst | 20 ++++++-- docs/index.rst | 1 + docs/install-dev.rst | 21 +++++--- docs/translation.rst | 120 +++++++++++++++++++++++++++++++++++++++++++ setup.py | 2 +- 6 files changed, 154 insertions(+), 12 deletions(-) create mode 100644 docs/translation.rst diff --git a/debian/control b/debian/control index fc52e38..b59997d 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: python3-squirrel-battle Section: devel Priority: optional Maintainer: ynerant -Build-Depends: debhelper (>=10~), dh-python, python3-all, python3-setuptools +Build-Depends: debhelper (>=10~), dh-python, gettext, python3-all, python3-setuptools Depends: fonts-noto-color-emoji Standards-Version: 4.1.4 Homepage: https://gitlab.crans.org/ynerant/squirrel-battle diff --git a/docs/deployment.rst b/docs/deployment.rst index a9f58ee..6a57b58 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -34,6 +34,16 @@ paquet ainsi que des dĂ©tails Ă  fournir Ă  PyPI : with open("README.md", "r") as f: long_description = f.read() + # Compile messages + for language in ["en", "fr"]: + args = ["msgfmt", "--check-format", + "-o", f"squirrelbattle/locale/{language}/LC_MESSAGES" + "/squirrelbattle.mo", + f"squirrelbattle/locale/{language}/LC_MESSAGES" + "/squirrelbattle.po"] + print(f"Compiling {language} messages...") + subprocess.Popen(args) + setup( name="squirrel-battle", version="3.14.1", @@ -60,7 +70,7 @@ paquet ainsi que des dĂ©tails Ă  fournir Ă  PyPI : ], python_requires='>=3.6', include_package_data=True, - package_data={"squirrelbattle": ["assets/*"]}, + package_data={"squirrelbattle": ["assets/*", "locale/*/*/*.mo"]}, entry_points={ "console_scripts": [ "squirrel-battle = squirrelbattle.bootstrap:Bootstrap.run_game", @@ -72,6 +82,8 @@ Ce fichier contient le nom du paquet, sa version, l'auteur et son contact, sa description en une ligne et sa description longue, le lien d'accueil du projet, sa licence, ses classificateurs et son exĂ©cutable. +Il commence tout d'abord par compiler les fichiers de `traduction `_. + Le paramĂštre ``entry_points`` dĂ©finit un exĂ©cutable nommĂ© ``squirrel-battle``, qui permet de lancer le jeu. @@ -167,7 +179,7 @@ du dĂ©pĂŽt Git. Le fichier ``PKGBUILD`` dispose de cette structure : url="https://gitlab.crans.org/ynerant/squirrel-battle" license=('GPLv3') depends=('python') - makedepends=('python-setuptools') + makedepends=('gettext' 'python-setuptools') depends=('noto-fonts-emoji') checkdepends=('python-tox') ssource=("git+https://gitlab.crans.org/ynerant/squirrel-battle.git") @@ -217,7 +229,7 @@ les releases, est plus ou moins similaire : url="https://gitlab.crans.org/ynerant/squirrel-battle" license=('GPLv3') depends=('python') - makedepends=('python-setuptools') + makedepends=('gettext' 'python-setuptools') depends=('noto-fonts-emoji') checkdepends=('python-tox') source=("https://gitlab.crans.org/ynerant/squirrel-battle/-/archive/v3.14.1/$pkgbase-v$pkgver.tar.gz") @@ -296,7 +308,7 @@ D'abord on installe les paquets nĂ©cessaires : .. code:: apt update - apt --no-install-recommends install build-essential debmake dh-python debhelper python3-all python3-setuptools + apt --no-install-recommends install build-essential debmake dh-python debhelper gettext python3-all python3-setuptools On peut ensuite construire le paquet : diff --git a/docs/index.rst b/docs/index.rst index ff6bcf3..1cb7d83 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -37,6 +37,7 @@ Bienvenue dans la documentation de Squirrel Battle ! install-dev tests display/index + translation deployment documentation diff --git a/docs/install-dev.rst b/docs/install-dev.rst index db611e0..973c0e0 100644 --- a/docs/install-dev.rst +++ b/docs/install-dev.rst @@ -1,16 +1,19 @@ Installation d'un environnement de dĂ©veloppement ================================================ -Il est toujours prĂ©fĂ©rable de travailler dans un environnement Python isolĂ© du reste de son instalation. +Il est toujours prĂ©fĂ©rable de travailler dans un environnement Python isolĂ© du +reste de son instalation. 1. **Installation des dĂ©pendances de la distribution.** - Vous devez dĂ©jĂ  installer Python et le module qui permet de crĂ©er des environnements virtuels. - On donne ci-dessous l'exemple pour une distribution basĂ©e sur Debian, mais vous pouvez facilement adapter pour ArchLinux ou autre. + Vous devez dĂ©jĂ  installer Python et le module qui permet de crĂ©er des + environnements virtuels. + On donne ci-dessous l'exemple pour une distribution basĂ©e sur Debian, + mais vous pouvez facilement adapter pour ArchLinux ou autre. .. code:: bash $ sudo apt update - $ sudo apt install --no-install-recommends -y python3-setuptools python3-venv python3-dev git + $ sudo apt install --no-install-recommends -y python3-setuptools python3-venv python3-dev gettext git 2. **Clonage du dĂ©pot** lĂ  oĂč vous voulez : @@ -25,7 +28,13 @@ Il est toujours prĂ©fĂ©rable de travailler dans un environnement Python isolĂ© d $ python3 -m venv env $ source env/bin/activate # entrer dans l'environnement - (env)$ pip3 install -r requirements.txt - (env)$ deactivate # sortir de l'environnement + (env) $ pip3 install -r requirements.txt + (env) $ deactivate # sortir de l'environnement + +4. **Compilation des messages de traduction.** + +.. code:: bash + + (env) $ python3 main.py --compilemessages Le lancement du jeu se fait en lançant la commande ``python3 main.py``. \ No newline at end of file diff --git a/docs/translation.rst b/docs/translation.rst new file mode 100644 index 0000000..ab3da46 --- /dev/null +++ b/docs/translation.rst @@ -0,0 +1,120 @@ +Traduction +========== + +Le jeu Squirrel Battle est entiĂšrement traduit en anglais et en français. +La langue se choisit dans les `paramĂštres `_. + + +Utitisation +----------- + +Les traductions sont gĂ©rĂ©es grĂące au module natif ``gettext``. Le module +``squirrelbattle.translations`` s'occupe d'installer les traductions, et de +donner les chaĂźnes traduites. + +Pour choisir la langue, il faut appeler ``Translator.setlocale(language: str)``, +oĂč ``language`` correspond au code Ă  2 lettres de la langue. + +Enfin, le module expose une fonction ``gettext(str) -> str`` qui permet de +traduire les chaĂźnes. + +Il est courant et recommandĂ© d'importer cette fonction sous l'alias ``_``, +afin de limiter la verbositer et de permettre de rendre facilement une chaĂźne +traduisible. + +.. code:: python + + from squirrelbattle.translations import gettext as _, Translator + + Translator.setlocale("fr") + print(_("I am a translatable string")) + print("I am not translatable") + +Si les traductions sont bien faites (voir ci-dessous), cela donnera : + +.. code:: + + Je suis une chaĂźne traduisible + I am not translatable + +À noter que si la chaĂźne n'est pas traduite, alors par dĂ©faut on renvoie la +chaĂźne elle-mĂȘme. + + +Extraction des chaĂźnes Ă  traduire +--------------------------------- + +L'appel Ă  ``gettext`` ne fait pas que traduire les chaĂźnes : il est possible +Ă©galement d'extraire toutes les chaĂźnes Ă  traduire. + +Il est nĂ©cessaire d'installer le paquet Linux ``gettext`` pour cela. + +L'utilitaire ``xgettext`` s'occupe de cette extraction. Il s'utilise de la façon +suivante : + +.. code:: bash + + xgettext --from-code utf-8 -o output_file.po source_1.py ... source_n.py + +Afin de ne pas avoir Ă  sĂ©lectionner manuellement chaque fichier, il est possible +d'appeler directement ``python3 main.py --makemessages``. Cela a pour effet +d'exĂ©cuter pour chaque langue ```` : + +.. code:: bash + + find squirrelbattle -iname '*.py' | xargs xgettext --from-code utf-8 + --add-comments + --package-name=squirrelbattle + --package-version=3.14.1 + "--copyright-holder=ĂżnĂ©rant, eichhornchen, nicomarg, charlse" + --msgid-bugs-address=squirrel-battle@crans.org + -o squirrelbattle/locale//LC_MESSAGES/squirrelbattle.po + +Les fichiers de traductions se trouvent alors dans +``squirrelbattle/locale//LC_MESSAGES/squirrelbattle.po``. + + +Traduire les chaĂźnes +-------------------- + +AprĂšs extraction des chaĂźnes, les chaĂźnes Ă  traduire se trouvent dans +``squirrelbattle/locale//LC_MESSAGES/squirrelbattle.po``, comme indiquĂ© +ci-dessus. + +Ce fichier peut-ĂȘtre Ă©ditĂ© avec un utilitaire tel que ``poedit``, sur +l'interface Web sur ``_, +mais surtout manuellement avec un Ă©diteur de texte. + +Dans ce fichier, on obtient pour chaque chaĂźne Ă  traduire un paragraphe de la +forme : + +.. code:: po + + #: main.py:4 + msgid "I am a translatable string" + msgstr "Je suis une chaĂźne traduisible" + +Il sufift de remplir les champs ``msgstr``. + + +Compilation des chaĂźnes +----------------------- + +Pour gagner en efficacitĂ©, les chaĂźnes sont compilĂ©es dans un fichier avec +l'extension ``.mo``. Ce sont ces fichiers qui sont lus par le module de traduction. + +Pour compiler les traductions, c'est l'utilitaire ``msgfmt`` fourni toujours par +le paquet Linux ``gettext`` que nous utilisons. Il s'utilise assez simplement : + +.. code:: bash + + msgfmt po_file.po -o mo_file.mo + +À nouveau, il est possible de compiler automatiquement les messages en exĂ©cutant +``python3 main.py --compilemessages``. + +.. warning:: + + On ne partagera pas dans le dĂ©pĂŽt Git les fichiers compilĂ©. En dĂ©veloppement, + on compilera soi-mĂȘme les messages, et en production, la construction des + paquets se charge de compiler automatiquement les traductions. diff --git a/setup.py b/setup.py index 00bd56b..b9e493a 100644 --- a/setup.py +++ b/setup.py @@ -46,7 +46,7 @@ setup( ], python_requires='>=3.6', include_package_data=True, - package_data={"squirrelbattle": ["assets/*", "locale/*/*/*"]}, + package_data={"squirrelbattle": ["assets/*", "locale/*/*/*.mo"]}, entry_points={ "console_scripts": [ "squirrel-battle = squirrelbattle.bootstrap:Bootstrap.run_game", From 9f0a29302dd84691938642dd030a65a4db6eebd6 Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Sat, 28 Nov 2020 16:22:06 +0100 Subject: [PATCH 54/54] Add german translation --- docs/deployment.rst | 2 +- docs/translation.rst | 2 +- setup.py | 2 +- .../locale/de/LC_MESSAGES/squirrelbattle.po | 166 ++++++++++++++++++ .../locale/en/LC_MESSAGES/squirrelbattle.po | 26 ++- .../locale/fr/LC_MESSAGES/squirrelbattle.po | 26 ++- squirrelbattle/menus.py | 2 +- squirrelbattle/tests/game_test.py | 3 + squirrelbattle/translations.py | 2 +- 9 files changed, 224 insertions(+), 7 deletions(-) create mode 100644 squirrelbattle/locale/de/LC_MESSAGES/squirrelbattle.po diff --git a/docs/deployment.rst b/docs/deployment.rst index 6a57b58..9477a10 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -35,7 +35,7 @@ paquet ainsi que des dĂ©tails Ă  fournir Ă  PyPI : long_description = f.read() # Compile messages - for language in ["en", "fr"]: + for language in ["de", "en", "fr"]: args = ["msgfmt", "--check-format", "-o", f"squirrelbattle/locale/{language}/LC_MESSAGES" "/squirrelbattle.mo", diff --git a/docs/translation.rst b/docs/translation.rst index ab3da46..f3d2584 100644 --- a/docs/translation.rst +++ b/docs/translation.rst @@ -1,7 +1,7 @@ Traduction ========== -Le jeu Squirrel Battle est entiĂšrement traduit en anglais et en français. +Le jeu Squirrel Battle est entiĂšrement traduit en anglais, en français et en allement. La langue se choisit dans les `paramĂštres `_. diff --git a/setup.py b/setup.py index b9e493a..f051bbb 100644 --- a/setup.py +++ b/setup.py @@ -11,7 +11,7 @@ with open("README.md", "r") as f: long_description = f.read() # Compile messages -for language in ["en", "fr"]: +for language in ["de", "en", "fr"]: args = ["msgfmt", "--check-format", "-o", f"squirrelbattle/locale/{language}/LC_MESSAGES" "/squirrelbattle.mo", diff --git a/squirrelbattle/locale/de/LC_MESSAGES/squirrelbattle.po b/squirrelbattle/locale/de/LC_MESSAGES/squirrelbattle.po new file mode 100644 index 0000000..dfd3365 --- /dev/null +++ b/squirrelbattle/locale/de/LC_MESSAGES/squirrelbattle.po @@ -0,0 +1,166 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR ĂżnĂ©rant, eichhornchen, nicomarg, charlse +# This file is distributed under the same license as the squirrelbattle package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: squirrelbattle 3.14.1\n" +"Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" +"POT-Creation-Date: 2020-11-28 16:03+0100\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: squirrelbattle/tests/game_test.py:284 squirrelbattle/tests/game_test.py:287 +#: squirrelbattle/tests/translations_test.py:16 +msgid "New game" +msgstr "Neu Spiel" + +#: squirrelbattle/tests/translations_test.py:17 +msgid "Resume" +msgstr "Weitergehen" + +#: squirrelbattle/tests/translations_test.py:18 +msgid "Load" +msgstr "Laden" + +#: squirrelbattle/tests/translations_test.py:19 +msgid "Save" +msgstr "Speichern" + +#: squirrelbattle/tests/translations_test.py:20 +msgid "Settings" +msgstr "Einstellungen" + +#: squirrelbattle/tests/translations_test.py:21 +msgid "Exit" +msgstr "Verlassen" + +#: squirrelbattle/tests/translations_test.py:27 +msgid "Main key to move up" +msgstr "Haupttaste zum Obengehen" + +#: squirrelbattle/tests/translations_test.py:29 +msgid "Secondary key to move up" +msgstr "SekundĂ€rtaste zum Obengehen" + +#: squirrelbattle/tests/translations_test.py:31 +msgid "Main key to move down" +msgstr "Haupttaste zum Untergehen" + +#: squirrelbattle/tests/translations_test.py:33 +msgid "Secondary key to move down" +msgstr "SekundĂ€rtaste zum Untergehen" + +#: squirrelbattle/tests/translations_test.py:35 +msgid "Main key to move left" +msgstr "Haupttaste zum Linksgehen" + +#: squirrelbattle/tests/translations_test.py:37 +msgid "Secondary key to move left" +msgstr "SekundĂ€rtaste zum Linksgehen" + +#: squirrelbattle/tests/translations_test.py:39 +msgid "Main key to move right" +msgstr "Haupttaste zum Rechtsgehen" + +#: squirrelbattle/tests/translations_test.py:41 +msgid "Secondary key to move right" +msgstr "SekundĂ€rtaste zum Rechtsgehen" + +#: squirrelbattle/tests/translations_test.py:43 +msgid "Key to validate a menu" +msgstr "MenĂŒtaste" + +#: squirrelbattle/tests/translations_test.py:45 +msgid "Texture pack" +msgstr "Textur-Packung" + +#: squirrelbattle/tests/translations_test.py:46 +msgid "Language" +msgstr "Sprache" + +#: squirrelbattle/tests/translations_test.py:49 +msgid "player" +msgstr "Spieler" + +#: squirrelbattle/tests/translations_test.py:51 +msgid "tiger" +msgstr "Tiger" + +#: squirrelbattle/tests/translations_test.py:52 +msgid "hedgehog" +msgstr "Igel" + +#: squirrelbattle/tests/translations_test.py:53 +msgid "rabbit" +msgstr "Kanninchen" + +#: squirrelbattle/tests/translations_test.py:54 +msgid "teddy bear" +msgstr "TeddybĂ€r" + +#: squirrelbattle/tests/translations_test.py:56 +msgid "bomb" +msgstr "Bombe" + +#: squirrelbattle/tests/translations_test.py:57 +msgid "heart" +msgstr "Herz" + +#: squirrelbattle/display/statsdisplay.py:34 +msgid "Inventory:" +msgstr "Bestand:" + +#: squirrelbattle/display/statsdisplay.py:39 +msgid "YOU ARE DEAD" +msgstr "SIE WURDEN GESTORBEN" + +#: squirrelbattle/interfaces.py:398 +#, python-brace-format +msgid "{name} hits {opponent}." +msgstr "{name} schlĂ€gt {opponent}." + +#: squirrelbattle/interfaces.py:410 +#, python-brace-format +msgid "{name} takes {amount} damage." +msgstr "{name} nimmt {amount} Schadenspunkte." + +#: squirrelbattle/interfaces.py:412 +#, python-brace-format +msgid "{name} dies." +msgstr "{name} stirbt." + +#: squirrelbattle/menus.py:71 +msgid "Back" +msgstr "ZurĂŒck" + +#: squirrelbattle/game.py:148 +msgid "" +"Some keys are missing in your save file.\n" +"Your save seems to be corrupt. It got deleted." +msgstr "" +"In Ihrer Speicherdatei fehlen einige SchlĂŒssel.\n" +"Ihre Speicherung scheint korrupt zu sein. Es wird gelöscht." + +#: squirrelbattle/game.py:156 +msgid "" +"No player was found on this map!\n" +"Maybe you died?" +msgstr "" +"Auf dieser Karte wurde kein Spieler gefunden!\n" +"Vielleicht sind Sie gestorben?" + +#: squirrelbattle/game.py:176 +msgid "" +"The JSON file is not correct.\n" +"Your save seems corrupted. It got deleted." +msgstr "" +"Die JSON-Datei ist nicht korrekt.\n" +"Ihre Speicherung scheint korrumpiert. Sie wurde gelöscht." diff --git a/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po b/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po index 9600c79..3f563fa 100644 --- a/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po +++ b/squirrelbattle/locale/en/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: squirrelbattle 3.14.1\n" "Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" -"POT-Creation-Date: 2020-11-28 03:01+0100\n" +"POT-Creation-Date: 2020-11-28 16:03+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -37,26 +37,32 @@ msgstr "" #: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14 #: squirrelbattle/tests/game_test.py:284 squirrelbattle/tests/game_test.py:287 +#: squirrelbattle/tests/translations_test.py:16 msgid "New game" msgstr "" #: squirrelbattle/menus.py:46 squirrelbattle/tests/translations_test.py:15 +#: squirrelbattle/tests/translations_test.py:17 msgid "Resume" msgstr "" #: squirrelbattle/menus.py:47 squirrelbattle/tests/translations_test.py:17 +#: squirrelbattle/tests/translations_test.py:19 msgid "Save" msgstr "" #: squirrelbattle/menus.py:48 squirrelbattle/tests/translations_test.py:16 +#: squirrelbattle/tests/translations_test.py:18 msgid "Load" msgstr "" #: squirrelbattle/menus.py:49 squirrelbattle/tests/translations_test.py:18 +#: squirrelbattle/tests/translations_test.py:20 msgid "Settings" msgstr "" #: squirrelbattle/menus.py:50 squirrelbattle/tests/translations_test.py:19 +#: squirrelbattle/tests/translations_test.py:21 msgid "Exit" msgstr "" @@ -84,56 +90,67 @@ msgstr "" #: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 #: squirrelbattle/tests/translations_test.py:25 +#: squirrelbattle/tests/translations_test.py:27 msgid "Main key to move up" msgstr "" #: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23 #: squirrelbattle/tests/translations_test.py:27 +#: squirrelbattle/tests/translations_test.py:29 msgid "Secondary key to move up" msgstr "" #: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25 #: squirrelbattle/tests/translations_test.py:29 +#: squirrelbattle/tests/translations_test.py:31 msgid "Main key to move down" msgstr "" #: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27 #: squirrelbattle/tests/translations_test.py:31 +#: squirrelbattle/tests/translations_test.py:33 msgid "Secondary key to move down" msgstr "" #: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29 #: squirrelbattle/tests/translations_test.py:33 +#: squirrelbattle/tests/translations_test.py:35 msgid "Main key to move left" msgstr "" #: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31 #: squirrelbattle/tests/translations_test.py:35 +#: squirrelbattle/tests/translations_test.py:37 msgid "Secondary key to move left" msgstr "" #: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33 #: squirrelbattle/tests/translations_test.py:37 +#: squirrelbattle/tests/translations_test.py:39 msgid "Main key to move right" msgstr "" #: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35 #: squirrelbattle/tests/translations_test.py:39 +#: squirrelbattle/tests/translations_test.py:41 msgid "Secondary key to move right" msgstr "" #: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37 #: squirrelbattle/tests/translations_test.py:41 +#: squirrelbattle/tests/translations_test.py:43 msgid "Key to validate a menu" msgstr "" #: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39 #: squirrelbattle/tests/translations_test.py:43 +#: squirrelbattle/tests/translations_test.py:45 msgid "Texture pack" msgstr "" #: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 #: squirrelbattle/tests/translations_test.py:44 +#: squirrelbattle/tests/translations_test.py:46 msgid "Language" msgstr "" @@ -143,29 +160,36 @@ msgid "{name} dies." msgstr "" #: squirrelbattle/tests/translations_test.py:47 +#: squirrelbattle/tests/translations_test.py:49 msgid "player" msgstr "" #: squirrelbattle/tests/translations_test.py:49 +#: squirrelbattle/tests/translations_test.py:51 msgid "tiger" msgstr "" #: squirrelbattle/tests/translations_test.py:50 +#: squirrelbattle/tests/translations_test.py:52 msgid "hedgehog" msgstr "" #: squirrelbattle/tests/translations_test.py:51 +#: squirrelbattle/tests/translations_test.py:53 msgid "rabbit" msgstr "" #: squirrelbattle/tests/translations_test.py:52 +#: squirrelbattle/tests/translations_test.py:54 msgid "teddy bear" msgstr "" #: squirrelbattle/tests/translations_test.py:54 +#: squirrelbattle/tests/translations_test.py:56 msgid "bomb" msgstr "" #: squirrelbattle/tests/translations_test.py:55 +#: squirrelbattle/tests/translations_test.py:57 msgid "heart" msgstr "" diff --git a/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.po b/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.po index b14ef50..d46cee6 100644 --- a/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.po +++ b/squirrelbattle/locale/fr/LC_MESSAGES/squirrelbattle.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: squirrelbattle 3.14.1\n" "Report-Msgid-Bugs-To: squirrel-battle@crans.org\n" -"POT-Creation-Date: 2020-11-28 02:50+0100\n" +"POT-Creation-Date: 2020-11-28 16:03+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -37,26 +37,32 @@ msgstr "{name} prend {amount} points de dĂ©gĂąt." #: squirrelbattle/menus.py:45 squirrelbattle/tests/translations_test.py:14 #: squirrelbattle/tests/game_test.py:284 squirrelbattle/tests/game_test.py:287 +#: squirrelbattle/tests/translations_test.py:16 msgid "New game" msgstr "Nouvelle partie" #: squirrelbattle/menus.py:46 squirrelbattle/tests/translations_test.py:15 +#: squirrelbattle/tests/translations_test.py:17 msgid "Resume" msgstr "Continuer" #: squirrelbattle/menus.py:47 squirrelbattle/tests/translations_test.py:17 +#: squirrelbattle/tests/translations_test.py:19 msgid "Save" msgstr "Sauvegarder" #: squirrelbattle/menus.py:48 squirrelbattle/tests/translations_test.py:16 +#: squirrelbattle/tests/translations_test.py:18 msgid "Load" msgstr "Charger" #: squirrelbattle/menus.py:49 squirrelbattle/tests/translations_test.py:18 +#: squirrelbattle/tests/translations_test.py:20 msgid "Settings" msgstr "ParamĂštres" #: squirrelbattle/menus.py:50 squirrelbattle/tests/translations_test.py:19 +#: squirrelbattle/tests/translations_test.py:21 msgid "Exit" msgstr "Quitter" @@ -90,56 +96,67 @@ msgstr "" #: squirrelbattle/settings.py:21 squirrelbattle/tests/translations_test.py:21 #: squirrelbattle/tests/translations_test.py:25 +#: squirrelbattle/tests/translations_test.py:27 msgid "Main key to move up" msgstr "Touche principale pour aller vers le haut" #: squirrelbattle/settings.py:22 squirrelbattle/tests/translations_test.py:23 #: squirrelbattle/tests/translations_test.py:27 +#: squirrelbattle/tests/translations_test.py:29 msgid "Secondary key to move up" msgstr "Touche secondaire pour aller vers le haut" #: squirrelbattle/settings.py:23 squirrelbattle/tests/translations_test.py:25 #: squirrelbattle/tests/translations_test.py:29 +#: squirrelbattle/tests/translations_test.py:31 msgid "Main key to move down" msgstr "Touche principale pour aller vers le bas" #: squirrelbattle/settings.py:24 squirrelbattle/tests/translations_test.py:27 #: squirrelbattle/tests/translations_test.py:31 +#: squirrelbattle/tests/translations_test.py:33 msgid "Secondary key to move down" msgstr "Touche secondaire pour aller vers le bas" #: squirrelbattle/settings.py:25 squirrelbattle/tests/translations_test.py:29 #: squirrelbattle/tests/translations_test.py:33 +#: squirrelbattle/tests/translations_test.py:35 msgid "Main key to move left" msgstr "Touche principale pour aller vers la gauche" #: squirrelbattle/settings.py:26 squirrelbattle/tests/translations_test.py:31 #: squirrelbattle/tests/translations_test.py:35 +#: squirrelbattle/tests/translations_test.py:37 msgid "Secondary key to move left" msgstr "Touche secondaire pour aller vers la gauche" #: squirrelbattle/settings.py:27 squirrelbattle/tests/translations_test.py:33 #: squirrelbattle/tests/translations_test.py:37 +#: squirrelbattle/tests/translations_test.py:39 msgid "Main key to move right" msgstr "Touche principale pour aller vers la droite" #: squirrelbattle/settings.py:29 squirrelbattle/tests/translations_test.py:35 #: squirrelbattle/tests/translations_test.py:39 +#: squirrelbattle/tests/translations_test.py:41 msgid "Secondary key to move right" msgstr "Touche secondaire pour aller vers la droite" #: squirrelbattle/settings.py:30 squirrelbattle/tests/translations_test.py:37 #: squirrelbattle/tests/translations_test.py:41 +#: squirrelbattle/tests/translations_test.py:43 msgid "Key to validate a menu" msgstr "Touche pour valider un menu" #: squirrelbattle/settings.py:31 squirrelbattle/tests/translations_test.py:39 #: squirrelbattle/tests/translations_test.py:43 +#: squirrelbattle/tests/translations_test.py:45 msgid "Texture pack" msgstr "Pack de textures" #: squirrelbattle/settings.py:32 squirrelbattle/tests/translations_test.py:40 #: squirrelbattle/tests/translations_test.py:44 +#: squirrelbattle/tests/translations_test.py:46 msgid "Language" msgstr "Langue" @@ -149,29 +166,36 @@ msgid "{name} dies." msgstr "{name} meurt." #: squirrelbattle/tests/translations_test.py:47 +#: squirrelbattle/tests/translations_test.py:49 msgid "player" msgstr "joueur" #: squirrelbattle/tests/translations_test.py:49 +#: squirrelbattle/tests/translations_test.py:51 msgid "tiger" msgstr "tigre" #: squirrelbattle/tests/translations_test.py:50 +#: squirrelbattle/tests/translations_test.py:52 msgid "hedgehog" msgstr "hĂ©risson" #: squirrelbattle/tests/translations_test.py:51 +#: squirrelbattle/tests/translations_test.py:53 msgid "rabbit" msgstr "lapin" #: squirrelbattle/tests/translations_test.py:52 +#: squirrelbattle/tests/translations_test.py:54 msgid "teddy bear" msgstr "nounours" #: squirrelbattle/tests/translations_test.py:54 +#: squirrelbattle/tests/translations_test.py:56 msgid "bomb" msgstr "bombe" #: squirrelbattle/tests/translations_test.py:55 +#: squirrelbattle/tests/translations_test.py:57 msgid "heart" msgstr "cƓur" diff --git a/squirrelbattle/menus.py b/squirrelbattle/menus.py index 1fba7ea..4fcfabe 100644 --- a/squirrelbattle/menus.py +++ b/squirrelbattle/menus.py @@ -98,7 +98,7 @@ class SettingsMenu(Menu): self.update_values(game.settings) elif option == "LOCALE": game.settings.LOCALE = 'fr' if game.settings.LOCALE == 'en'\ - else 'en' + else 'de' if game.settings.LOCALE == 'fr' else 'en' Translator.setlocale(game.settings.LOCALE) game.settings.write_settings() self.update_values(game.settings) diff --git a/squirrelbattle/tests/game_test.py b/squirrelbattle/tests/game_test.py index 9c950d6..a23b6f9 100644 --- a/squirrelbattle/tests/game_test.py +++ b/squirrelbattle/tests/game_test.py @@ -283,6 +283,9 @@ class TestGame(unittest.TestCase): self.assertEqual(self.game.settings.LOCALE, "fr") self.assertEqual(_("New game"), "Nouvelle partie") self.game.handle_key_pressed(KeyValues.ENTER) + self.assertEqual(self.game.settings.LOCALE, "de") + self.assertEqual(_("New game"), "Neu Spiel") + self.game.handle_key_pressed(KeyValues.ENTER) self.assertEqual(self.game.settings.LOCALE, "en") self.assertEqual(_("New game"), "New game") diff --git a/squirrelbattle/translations.py b/squirrelbattle/translations.py index cd5b7fc..f532bb0 100644 --- a/squirrelbattle/translations.py +++ b/squirrelbattle/translations.py @@ -14,7 +14,7 @@ class Translator: Translator.setlocale defines the language of the strings, then gettext() translates the message. """ - SUPPORTED_LOCALES: List[str] = ["en", "fr"] + SUPPORTED_LOCALES: List[str] = ["de", "en", "fr"] locale: str = "en" translators: dict = {}