generated from geekiot/python-template
feature/locales - add locales support for urfu-daddy #3
5 changed files with 157 additions and 0 deletions
|
|
@ -6,6 +6,7 @@ readme = "README.md"
|
|||
requires-python = ">=3.13,<3.14"
|
||||
dependencies = [
|
||||
"aiogram>=3.22.0",
|
||||
"babel>=2.17.0",
|
||||
"loguru>=0.7.3",
|
||||
"pydantic>=2.11.10",
|
||||
"pydantic-settings>=2.11.0",
|
||||
|
|
|
|||
104
scripts/pybabel.py
Normal file
104
scripts/pybabel.py
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
# /// script
|
||||
# requires-python = ">=3.13"
|
||||
# dependencies = [
|
||||
# "argparse",
|
||||
# "pathlib",
|
||||
# ]
|
||||
# ///
|
||||
|
||||
import argparse
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
LOCALES_DIR = Path("src/locales")
|
||||
LOCALES_DOMAIN = "messages"
|
||||
LOCALES_POT = LOCALES_DIR / f"{LOCALES_DOMAIN}.pot"
|
||||
LOCALES_WIDTH = 80
|
||||
|
||||
|
||||
def run_cmd(cmds: list[list[str]]) -> None:
|
||||
try:
|
||||
for cmd in cmds:
|
||||
# INFO: User input is safe.
|
||||
result = subprocess.run( # noqa: S603
|
||||
cmd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
shell=False,
|
||||
)
|
||||
print(result.stderr) # noqa: T201
|
||||
except Exception as error:
|
||||
print(f"Error: {error}") # noqa: T201
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Wrapper for pybabel operations."
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"operation",
|
||||
choices=["extract", "update", "compile", "init"],
|
||||
help="Type of pybabel operation.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"language",
|
||||
nargs="?",
|
||||
default="all",
|
||||
choices=["ru", "en", "zh", "es", "ar", "fr", "de", "all"],
|
||||
help=""
|
||||
+ "Language code. "
|
||||
+ "If omitted, all locales are processed. "
|
||||
+ "Only for update & compile operations.",
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.operation == "init" and args.language == "all":
|
||||
print("Error: You need to specify new language.") # noqa: T201
|
||||
return
|
||||
|
||||
cmd = list()
|
||||
cmd.append("pybabel")
|
||||
cmd.append(args.operation)
|
||||
|
||||
if args.operation == "extract":
|
||||
cmd.append(".")
|
||||
cmd.append("-o")
|
||||
cmd.append(str(LOCALES_POT))
|
||||
|
||||
run_cmd([cmd])
|
||||
return
|
||||
|
||||
cmd.append("-D")
|
||||
cmd.append(LOCALES_DOMAIN)
|
||||
|
||||
cmd.append("-d")
|
||||
cmd.append(str(LOCALES_DIR))
|
||||
|
||||
if args.operation in ("update", "init"):
|
||||
cmd.append("-i")
|
||||
cmd.append(str(LOCALES_POT))
|
||||
|
||||
if args.operation == "update":
|
||||
cmd.append("-w")
|
||||
cmd.append(str(LOCALES_WIDTH))
|
||||
|
||||
if args.language == "all":
|
||||
langs = [
|
||||
str(path_name.name)
|
||||
for path_name in LOCALES_DIR.iterdir()
|
||||
if path_name.is_dir()
|
||||
]
|
||||
else:
|
||||
langs = [args.language]
|
||||
|
||||
cmds = [cmd + ["-l"] + [lang] for lang in langs]
|
||||
|
||||
run_cmd(cmds)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
20
src/locales/en/LC_MESSAGES/messages.po
Normal file
20
src/locales/en/LC_MESSAGES/messages.po
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
# English translations for PROJECT.
|
||||
# Copyright (C) 2025 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-10-19 17:13+0500\n"
|
||||
"PO-Revision-Date: 2025-10-19 17:54+0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: en\n"
|
||||
"Language-Team: en <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.17.0\n"
|
||||
|
||||
21
src/locales/ru/LC_MESSAGES/messages.po
Normal file
21
src/locales/ru/LC_MESSAGES/messages.po
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
# Russian translations for PROJECT.
|
||||
# Copyright (C) 2025 ORGANIZATION
|
||||
# This file is distributed under the same license as the PROJECT project.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: PROJECT VERSION\n"
|
||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
|
||||
"POT-Creation-Date: 2025-10-19 17:13+0500\n"
|
||||
"PO-Revision-Date: 2025-10-19 15:07+0500\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language: ru\n"
|
||||
"Language-Team: ru <LL@li.org>\n"
|
||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||
"n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=utf-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"Generated-By: Babel 2.17.0\n"
|
||||
|
||||
11
uv.lock
generated
11
uv.lock
generated
|
|
@ -101,6 +101,15 @@ wheels = [
|
|||
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "babel"
|
||||
version = "2.17.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/6b/d52e42361e1aa00709585ecc30b3f9684b3ab62530771402248b1b1d6240/babel-2.17.0.tar.gz", hash = "sha256:0c54cffb19f690cdcc52a3b50bcbf71e07a808d1c80d549f2459b9d2cf0afb9d", size = 9951852, upload-time = "2025-02-01T15:17:41.026Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/b7/b8/3fe70c75fe32afc4bb507f75563d39bc5642255d1d94f1f23604725780bf/babel-2.17.0-py3-none-any.whl", hash = "sha256:4d0b53093fdfb4b21c92b5213dba5a1b23885afa8383709427046b21c366e5f2", size = 10182537, upload-time = "2025-02-01T15:17:37.39Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "certifi"
|
||||
version = "2025.10.5"
|
||||
|
|
@ -457,6 +466,7 @@ version = "0.1.0"
|
|||
source = { virtual = "." }
|
||||
dependencies = [
|
||||
{ name = "aiogram" },
|
||||
{ name = "babel" },
|
||||
{ name = "loguru" },
|
||||
{ name = "pydantic" },
|
||||
{ name = "pydantic-settings" },
|
||||
|
|
@ -469,6 +479,7 @@ dependencies = [
|
|||
[package.metadata]
|
||||
requires-dist = [
|
||||
{ name = "aiogram", specifier = ">=3.22.0" },
|
||||
{ name = "babel", specifier = ">=2.17.0" },
|
||||
{ name = "loguru", specifier = ">=0.7.3" },
|
||||
{ name = "pydantic", specifier = ">=2.11.10" },
|
||||
{ name = "pydantic-settings", specifier = ">=2.11.0" },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue