diff --git a/CHANGELOG.md b/CHANGELOG.md index ab0eccc8..940f0ff6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ [Compare the full difference.](https://github.com/SFTtech/abrechnung/compare/v0.14.0...HEAD) +- add Spanish and Tamil as supported languages +- rework group settings to just be a single page +- allow archiving of groups + ## 0.14.0 (2024-08-16) [Compare the full difference.](https://github.com/SFTtech/abrechnung/compare/v0.13.3...v0.14.0) diff --git a/README.md b/README.md index 9786fcf6..4203395f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Abrechnung [![GitHub Actions Status](https://github.com/SFTtech/abrechnung/actions/workflows/ci_testing.yaml/badge.svg)](https://github.com/SFTtech/abrechnung/actions/workflows/ci_testing.yaml) +[![Translation Status](https://hosted.weblate.org/widget/abrechnung/svg-badge.svg)](https://hosted.weblate.org/engage/abrechnung/) The *Abrechnung* (German for *reckoning*, *settlement*, *revenge*) aims to be a versatile and user-centric **payment**, **transaction** and **bookkeeping** management tool for human groups and events. @@ -54,6 +55,12 @@ If there is **that feature** you really want to see implemented, you found a **b * [Code contributions](https://github.com/SFTtech/abrechnung/pulls) * [Development roadmap](https://github.com/SFTtech/abrechnung/projects) +### Translations + +Translations are managed using the hosted weblate service [here](https://hosted.weblate.org/engage/abrechnung/). + +[![Translation Status](https://hosted.weblate.org/widget/abrechnung/multi-auto.svg)](https://hosted.weblate.org/engage/abrechnung/) + ## Contact diff --git a/frontend/apps/web/src/components/LanguageSelect.tsx b/frontend/apps/web/src/components/LanguageSelect.tsx index 4afdfcaf..2a02f7ea 100644 --- a/frontend/apps/web/src/components/LanguageSelect.tsx +++ b/frontend/apps/web/src/components/LanguageSelect.tsx @@ -22,6 +22,8 @@ export const LanguageSelect: React.FC = (props) => { > {t("languages.en")} {t("languages.de")} + {t("languages.es")} + {t("languages.ta")} ); }; diff --git a/frontend/apps/web/src/i18n.ts b/frontend/apps/web/src/i18n.ts index 2cfee5e6..b3c8bd84 100644 --- a/frontend/apps/web/src/i18n.ts +++ b/frontend/apps/web/src/i18n.ts @@ -10,7 +10,9 @@ i18n.use(LanguageDetector) resources, defaultNS, lng: "en-US", - fallbackLng: "en-US", + fallbackLng: { + default: ["en"], + }, debug: true, interpolation: { escapeValue: false }, }); diff --git a/frontend/libs/translations/src/lib/en.json b/frontend/libs/translations/src/lib/en.json index 2cc0636e..d633b3de 100644 --- a/frontend/libs/translations/src/lib/en.json +++ b/frontend/libs/translations/src/lib/en.json @@ -273,6 +273,8 @@ }, "languages": { "en": "English", - "de": "German" + "de": "German", + "es": "Spanish", + "ta": "Tamil" } } diff --git a/frontend/libs/translations/src/lib/index.ts b/frontend/libs/translations/src/lib/index.ts index f1bafbfc..693c8e04 100644 --- a/frontend/libs/translations/src/lib/index.ts +++ b/frontend/libs/translations/src/lib/index.ts @@ -1,5 +1,7 @@ import en from "./en.json"; import de from "./de.json"; +import es from "./es.json"; +import ta from "./ta.json"; export const defaultNS = "translations"; @@ -8,4 +10,6 @@ export const resources = { translations: en, }, de: { translations: de }, + es: { translations: es }, + ta: { translations: ta }, }; diff --git a/pyproject.toml b/pyproject.toml index 406f1c0f..41c2f751 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -14,22 +14,22 @@ dynamic = ["version", "description"] classifiers = [ "Operating System :: OS Independent", "Programming Language :: Python :: 3", - "License :: OSI Approved :: GNU General Public License v3 (GPLv3)", + "License :: OSI Approved :: GNU Affero General Public License v3 (AGPLv3)", "Development Status :: 5 - Production/Stable", ] requires-python = ">=3.10" dependencies = [ - "typer~=0.9.0", - "fastapi==0.110.0", - "pydantic[email]~=2.6.0", - "pydantic-settings==2.2.1", - "uvicorn[standard]~=0.27.0", + "typer~=0.15.1", + "fastapi==0.115.6", + "pydantic[email]~=2.10.3", + "pydantic-settings==2.6.1", + "uvicorn[standard]~=0.32.1", "python-jose[cryptography]~=3.3.0", - "asyncpg~=0.29.0", + "asyncpg~=0.30.0", "passlib[bcrypt]~=1.7.0", - "websockets~=12.0.0", - "python-multipart~=0.0.9", - "PyYAML~=6.0.0", + "websockets~=14.1", + "python-multipart~=0.0.19", + "PyYAML~=6.0.2", ] [project.optional-dependencies] @@ -43,9 +43,9 @@ test = [ dev = [ "isort", "black", - "mypy==1.8.0", + "mypy==1.13.0", "types-PyYAML~=6.0", - "pylint==3.1.0", + "pylint==3.3.2", "bump-my-version~=0.18" ] docs = [ diff --git a/tests/http_tests/common.py b/tests/http_tests/common.py index 2633a399..6db1d08c 100644 --- a/tests/http_tests/common.py +++ b/tests/http_tests/common.py @@ -1,5 +1,5 @@ # pylint: disable=attribute-defined-outside-init -from httpx import AsyncClient +from httpx import ASGITransport, AsyncClient from abrechnung.http.api import Api from tests.common import TEST_CONFIG, BaseTestCase @@ -12,7 +12,8 @@ async def asyncSetUp(self) -> None: self.http_service = Api(config=self.test_config) await self.http_service._setup() - self.client = AsyncClient(app=self.http_service.api, base_url="https://abrechnung.sft.lol") + self.transport = ASGITransport(app=self.http_service.api) + self.client = AsyncClient(transport=self.transport, base_url="https://abrechnung.sft.lol") self.transaction_service = self.http_service.transaction_service self.account_service = self.http_service.account_service self.group_service = self.http_service.group_service