Skip to content

Commit 7e73541

Browse files
authored
Adding translations (#23)
* adding babel and pinning versions for dependencies * adding translations, fixes #10
1 parent cc8f7dc commit 7e73541

File tree

12 files changed

+184
-54
lines changed

12 files changed

+184
-54
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ coverage.xml
8989
cover/
9090

9191
# Translations
92-
*.mo
92+
*.po
9393
*.pot
9494

9595
# Django stuff:

babel.cfg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[python: **.py]

bin/translate.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/usr/bin/env python3
2+
import sys
3+
4+
import polib
5+
from deep_translator import GoogleTranslator
6+
7+
8+
def main(filename: str, language: str) -> None:
9+
po = polib.pofile(filename)
10+
translator = GoogleTranslator(source="en", target=language)
11+
12+
for entry in po:
13+
entry.msgstr = translator.translate(entry.msgid)
14+
15+
po.save(filename)
16+
17+
18+
if __name__ == "__main__":
19+
main(*sys.argv[1:])

bin/translate.sh

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#!/bin/sh
2+
uv run pybabel extract -F babel.cfg -o messages.pot .
3+
uv run pybabel init -i messages.pot -d translations -l es
4+
uv run pybabel init -i messages.pot -d translations -l it
5+
uv run pybabel init -i messages.pot -d translations -l fr
6+
echo "Translating..."
7+
uv run ./bin/translate.py translations/es/LC_MESSAGES/messages.po es
8+
uv run ./bin/translate.py translations/it/LC_MESSAGES/messages.po it
9+
uv run ./bin/translate.py translations/fr/LC_MESSAGES/messages.po fr
10+
uv run pybabel compile -d translations
11+
echo "Done."

pyproject.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ dependencies = [
2828
"pygit2==1.17.0",
2929
"textual==3.1.0",
3030
"pygithub==2.6.1",
31-
"pyyaml>=6.0",
32-
"platformdirs>=4.3.7",
31+
"pyyaml==6.0.2",
32+
"platformdirs==4.3.7",
33+
"babel==2.17.0",
3334
]
3435

3536
[project.urls]
@@ -51,9 +52,11 @@ path = "src/edit_python_pe/__about__.py"
5152
[dependency-groups]
5253
dev = [
5354
"black>=25.1.0",
55+
"deep-translator>=1.11.4",
5456
"isort>=6.0.1",
57+
"polib>=1.2.0",
5558
"pytest>=8.4.1",
56-
"textual-dev>=1.7.0",
59+
"textual-dev==1.7.0",
5760
]
5861

5962
[tool.black]

src/edit_python_pe/constants.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Locales
2+
EN_LOCALE = "en"
3+
ES_LOCALE = "es"
4+
IT_LOCALE = "it"
5+
FR_LOCALE = "fr"
6+
7+
# Social network options
8+
GITHUB_OPTION = ("GitHub", "github")
9+
GITLAB_OPTION = ("GitLab", "gitlab")
10+
BITBUCKET_OPTION = ("Bitbucket", "bitbucket")
11+
LINKEDIN_OPTION = ("LinkedIn", "linkedin")
12+
FACEBOOK_OPTION = ("Facebook", "facebook")
13+
INSTAGRAM_OPTION = ("Instagram", "instagram")
14+
X_OPTION = ("X", "x")
15+
YOUTUBE_OPTION = ("YouTube", "youtube")

src/edit_python_pe/main.py

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,17 @@
88
from textual.widgets import (Button, Input, ListItem, ListView, Select, Static,
99
TextArea)
1010

11+
from .constants import (BITBUCKET_OPTION, FACEBOOK_OPTION, GITHUB_OPTION,
12+
GITLAB_OPTION, INSTAGRAM_OPTION, LINKEDIN_OPTION,
13+
X_OPTION, YOUTUBE_OPTION)
1114
from .strings import (BUTTON_ADD, BUTTON_ADD_ALIAS, BUTTON_ADD_SOCIAL,
1215
BUTTON_BACK, BUTTON_DELETE, BUTTON_QUIT, BUTTON_SAVE,
13-
FORM_HEADER, LIST_TITLE, MESSAGE_EXIT, MESSAGE_QUIT,
14-
PLACEHOLDER_ALIAS, PLACEHOLDER_CITY, PLACEHOLDER_EMAIL,
16+
FORM_HEADER, LIST_TITLE, MESSAGE_EXIT, PLACEHOLDER_ALIAS,
17+
PLACEHOLDER_CITY, PLACEHOLDER_EMAIL,
1518
PLACEHOLDER_HOMEPAGE, PLACEHOLDER_NAME,
16-
PLACEHOLDER_SOCIAL_URL, SECTION_ALIASES, SECTION_AVAIL,
17-
SECTION_CONTRIB, SECTION_PYTHON, SECTION_SOCIAL,
18-
SECTION_WHO)
19+
PLACEHOLDER_SOCIAL_URL, PROMPT_SOCIAL_NETWORK,
20+
SECTION_ALIASES, SECTION_AVAIL, SECTION_CONTRIB,
21+
SECTION_PYTHON, SECTION_SOCIAL, SECTION_WHO)
1922
from .utils import (build_md_content, create_pr, fork_repo, get_repo,
2023
load_file_into_form)
2124

@@ -195,7 +198,7 @@ def on_button_pressed(self, event: Button.Pressed) -> None:
195198
self.clear_form()
196199
self.show_list()
197200
elif bid == "quit":
198-
self.exit(MESSAGE_QUIT)
201+
self.exit(message=MESSAGE_EXIT)
199202
elif bid and bid.startswith("delete_social_"):
200203
index = int(bid.replace("delete_social_", ""))
201204
self.remove_social_entry(index)
@@ -222,16 +225,16 @@ def __init__(se, index):
222225
se.index = index
223226
se.select = Select(
224227
options=[
225-
("GitHub", "github"),
226-
("GitLab", "gitlab"),
227-
("Bitbucket", "bitbucket"),
228-
("LinkedIn", "linkedin"),
229-
("Facebook", "facebook"),
230-
("Instagram", "instagram"),
231-
("X", "x"),
232-
("YouTube", "youtube"),
228+
GITHUB_OPTION,
229+
GITLAB_OPTION,
230+
BITBUCKET_OPTION,
231+
LINKEDIN_OPTION,
232+
FACEBOOK_OPTION,
233+
INSTAGRAM_OPTION,
234+
X_OPTION,
235+
YOUTUBE_OPTION,
233236
],
234-
prompt="Social Network",
237+
prompt=PROMPT_SOCIAL_NETWORK,
235238
)
236239
se.url_input = Input(placeholder=PLACEHOLDER_SOCIAL_URL)
237240
se.delete_btn = Button(

src/edit_python_pe/strings.py

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,56 +1,75 @@
1+
import gettext
2+
import locale
3+
from pathlib import Path
4+
5+
from .constants import EN_LOCALE, ES_LOCALE, FR_LOCALE, IT_LOCALE
6+
7+
default_locale = locale.getlocale()[0] or EN_LOCALE
8+
localedir = Path(__file__).parent.parent / "translations"
9+
_ = gettext.translation(
10+
domain="messages",
11+
localedir=localedir,
12+
languages=[default_locale, ES_LOCALE, IT_LOCALE, FR_LOCALE],
13+
fallback=True,
14+
).gettext
15+
116
# Field, control, and message labels for edit_python_pe
217

318
# List and form titles
4-
LIST_TITLE = "Files in 'blog/members':"
5-
FORM_HEADER = "Member Form"
19+
LIST_TITLE = _("Files in 'blog/members':")
20+
FORM_HEADER = _("Member Form")
621

722
# Button labels
8-
BUTTON_QUIT = "Quit"
9-
BUTTON_ADD = "Add"
10-
BUTTON_SAVE = "Save"
11-
BUTTON_BACK = "Back"
12-
BUTTON_ADD_SOCIAL = "Add Social Network"
13-
BUTTON_ADD_ALIAS = "Add Alias"
14-
BUTTON_DELETE = "Delete"
23+
BUTTON_QUIT = _("Quit")
24+
BUTTON_ADD = _("Add")
25+
BUTTON_SAVE = _("Save")
26+
BUTTON_BACK = _("Back")
27+
BUTTON_ADD_SOCIAL = _("Add Social Network")
28+
BUTTON_ADD_ALIAS = _("Add Alias")
29+
BUTTON_DELETE = _("Delete")
1530

1631
# Input placeholders
17-
PLACEHOLDER_NAME = "Name"
18-
PLACEHOLDER_EMAIL = "Email"
19-
PLACEHOLDER_CITY = "City"
20-
PLACEHOLDER_HOMEPAGE = "Homepage"
21-
PLACEHOLDER_SOCIAL_URL = "Social network URL"
22-
PLACEHOLDER_ALIAS = "Alias"
32+
PLACEHOLDER_NAME = _("Name")
33+
PLACEHOLDER_EMAIL = _("Email")
34+
PLACEHOLDER_CITY = _("City")
35+
PLACEHOLDER_HOMEPAGE = _("Homepage")
36+
PLACEHOLDER_SOCIAL_URL = _("Social network URL")
37+
PLACEHOLDER_ALIAS = _("Alias")
38+
39+
# Control prompts
40+
PROMPT_SOCIAL_NETWORK = _("Social Network")
2341

2442
# Section headers
25-
SECTION_SOCIAL = "Social Networks"
26-
SECTION_ALIASES = "Aliases"
27-
SECTION_WHO = "Who are you and what do you do?"
28-
SECTION_PYTHON = "How do you program in Python?"
29-
SECTION_CONTRIB = "Do you have any contributions to the Python community?"
30-
SECTION_AVAIL = "Are you available for mentoring, consulting, talks?"
43+
SECTION_SOCIAL = _("Social Networks")
44+
SECTION_ALIASES = _("Aliases")
45+
SECTION_WHO = _("Who are you and what do you do?")
46+
SECTION_PYTHON = _("How do you program in Python?")
47+
SECTION_CONTRIB = _("Do you have any contributions to the Python community?")
48+
SECTION_AVAIL = _("Are you available for mentoring, consulting, talks?")
3149

3250
# Messages
33-
MESSAGE_PROMPT_FOR_GITHUB_TOKEN = (
51+
MESSAGE_PROMPT_FOR_GITHUB_TOKEN = _(
3452
"Please enter your GitHub personal access token: "
3553
)
36-
MESSAGE_EXIT = "See you next time!"
37-
MESSAGE_QUIT = "Exiting the application."
38-
MESSAGE_FILE_READ_ERROR = "Error reading file {filename}: {error}"
39-
MESSAGE_UNAUTHORIZED = "Unauthorized access. Please check your access token."
40-
MESSAGE_REPO_NOT_FOUND = (
54+
MESSAGE_EXIT = _("See you next time!")
55+
MESSAGE_FILE_READ_ERROR = _("Error reading file {filename}: {error}")
56+
MESSAGE_UNAUTHORIZED = _(
57+
"Unauthorized access. Please check your access token."
58+
)
59+
MESSAGE_REPO_NOT_FOUND = _(
4160
"Repository not found. Please check your access token."
4261
)
43-
MESSAGE_FILE_EDITED_PR = (
62+
MESSAGE_FILE_EDITED_PR = _(
4463
"File {name_file} edited, commit and changes sent to existing PR."
4564
)
46-
MESSAGE_FILE_SAVED_PR = "File {name_file} saved, commit and PR ready."
47-
MESSAGE_CREATE_ENTRY = (
65+
MESSAGE_FILE_SAVED_PR = _("File {name_file} saved, commit and PR ready.")
66+
MESSAGE_CREATE_ENTRY = _(
4867
"Creating a new entry to `blog/members` for {name} (alias: {first_alias})."
4968
)
50-
MESSAGE_CHANGE_ENTRY = (
69+
MESSAGE_CHANGE_ENTRY = _(
5170
"Changing an entry to `blog/members` for {name} (alias: {first_alias})."
5271
)
53-
MESSAGE_LOAD_FILE_ERROR = "Error reading file {filename}: {error}"
72+
MESSAGE_LOAD_FILE_ERROR = _("Error reading file {filename}: {error}")
5473

5574
# build_md_content markdown dictionary (English keys, Spanish values for now)
5675
MD_CONTENT = {
2.59 KB
Binary file not shown.
2.65 KB
Binary file not shown.

0 commit comments

Comments
 (0)