From fbd033e6efb1f1746d6e8a34c6be9f069f0e06a0 Mon Sep 17 00:00:00 2001 From: Derinhelm Date: Sat, 5 Jun 2021 14:16:32 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=BB=D0=BE=D0=BA=D0=B0=D0=BB=D0=B8=D0=B7=D0=B0?= =?UTF-8?q?=D1=86=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Перед запуском программы сгенерировать mo-файл pybabel compile -D todo -i po/eng/LC_MESSAGES/todo.po -o po/eng/LC_MESSAGES/todo.mo --- .pre-commit-config.yaml | 2 +- README.md | 6 +++ frontend/login.py | 10 ++-- frontend/message.py | 9 ++-- frontend/po/eng/LC_MESSAGES/todo.po | 83 +++++++++++++++++++++++++++++ frontend/todo_tk.py | 6 ++- frontend/workspace.py | 23 ++++---- 7 files changed, 121 insertions(+), 18 deletions(-) create mode 100644 frontend/po/eng/LC_MESSAGES/todo.po diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5018379..ac96dba 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -15,4 +15,4 @@ repos: rev: 3.9.0 hooks: - id: flake8 - args: ["--ignore=E203,W503,FI10,FI11,FI12,FI13,FI14,FI15,FI16,FI17,FI58,E501"] + args: ["--ignore=E203,W503,FI10,FI11,FI12,FI13,FI14,FI15,FI16,FI17,FI58,E501", "--builtins=_"] diff --git a/README.md b/README.md index e886902..3045be1 100644 --- a/README.md +++ b/README.md @@ -32,10 +32,16 @@ ## Как запустить проект ### Frontend +Интерфейс на русском языке ```bash python3 todo_tk.py ``` +Интерфейс на английском языке +```bash +LANG=eng python3 todo_tk.py +``` + ### backend ```bash docker-compose up diff --git a/frontend/login.py b/frontend/login.py index 0efd7f9..b399254 100644 --- a/frontend/login.py +++ b/frontend/login.py @@ -1,7 +1,10 @@ +import gettext import tkinter as tk from user import User import message +gettext.install("todo", localedir="po") + class LoginFrame(tk.Frame): @@ -57,21 +60,22 @@ class LoginFrame(tk.Frame): tk.Grid.columnconfigure(self, columns, weight=1) # Подпись и поле ввода для логина - login_label = tk.Label(self, text="Введите логин") + t = _("Введите логин") + login_label = tk.Label(self, text=t) login_label.grid(row=9, column=12, columnspan=3, rowspan=1, sticky="nsew") self.login = tk.Entry(self) self.login.grid(row=10, column=12, columnspan=3, rowspan=1, sticky="nsew") # Подпись и поле ввода для пароля - password_label = tk.Label(self, text="Введите пароль") + password_label = tk.Label(self, text=_("Введите пароль")) password_label.grid(row=11, column=12, columnspan=3, rowspan=1, sticky="nsew") self.password = tk.Entry(self, show="*") self.password.grid(row=12, column=12, columnspan=3, rowspan=1, sticky="nsew") # Кнопка авториазции - btn = tk.Button(self, text="Войти", command=self.login_clicked) + btn = tk.Button(self, text=_("Войти"), command=self.login_clicked) btn.grid(row=14, column=12, columnspan=3, rowspan=1, sticky="nsew") # Если захочется реализовать в логине diff --git a/frontend/message.py b/frontend/message.py index 824d07b..5e2c784 100644 --- a/frontend/message.py +++ b/frontend/message.py @@ -1,8 +1,11 @@ from tkinter import messagebox as mb +import gettext -TITLE_INFO_BOX = "Сообщение!" -MESSAGE_INVALID_LOGIN = "Неправильный логин или пароль" -MESSAGE_EMPTY = "Сдесь могло быть ваше сообщение" +gettext.install("todo", localedir="po") + +TITLE_INFO_BOX = _("Сообщение!") +MESSAGE_INVALID_LOGIN = _("Неправильный логин или пароль") +MESSAGE_EMPTY = _("Сдесь могло быть ваше сообщение") def infobox(msg: str = None) -> None: diff --git a/frontend/po/eng/LC_MESSAGES/todo.po b/frontend/po/eng/LC_MESSAGES/todo.po new file mode 100644 index 0000000..427bd92 --- /dev/null +++ b/frontend/po/eng/LC_MESSAGES/todo.po @@ -0,0 +1,83 @@ +# English (United States) translations for PROJECT. +# Copyright (C) 2021 ORGANIZATION +# This file is distributed under the same license as the PROJECT project. +# FIRST AUTHOR , 2021. +# +msgid "" +msgstr "" +"Project-Id-Version: PROJECT VERSION\n" +"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" +"POT-Creation-Date: 2021-06-06 23:42+0300\n" +"PO-Revision-Date: 2021-06-07 00:24+0300\n" +"Last-Translator: FULL NAME \n" +"Language: en_US\n" +"Language-Team: en_US \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.8.1\n" + +#: todo_tk.py:20 +msgid "Приложение для планирования" +msgstr "ToDo Application" + +#: message.py:6 +msgid "Сообщение!" +msgstr "Message!" + +#: message.py:7 +msgid "Неправильный логин или пароль" +msgstr "Wrong login or password" + +#: message.py:8 +msgid "Сдесь могло быть ваше сообщение" +msgstr "This could have been your message" + +#: login.py:63 +msgid "Введите логин" +msgstr "Enter your username" + +#: login.py:71 +msgid "Введите пароль" +msgstr "Enter your password" + +#: login.py:78 +msgid "Войти" +msgstr "Enter" + +#: workspace.py:17 +msgid "Не реализовано" +msgstr "Not implemented" + +#: workspace.py:25 +msgid "Текст" +msgstr "Text" + +#: workspace.py:28 +msgid "Выполнено" +msgstr "Done" + +#: workspace.py:31 +msgid "Создано" +msgstr "Created" + +#: workspace.py:60 +msgid "Удалить" +msgstr "Delete" + +#: workspace.py:88 +msgid "Добавить заметку" +msgstr "Add note" + +#: workspace.py:91 +msgid "Удалить лист" +msgstr "Delete list" + +#: workspace.py:149 +msgid "Запомнить меня" +msgstr "Remember me" + +#: workspace.py:158 +msgid "Добавить лист" +msgstr "Add list" diff --git a/frontend/todo_tk.py b/frontend/todo_tk.py index 50a43e5..366c67f 100644 --- a/frontend/todo_tk.py +++ b/frontend/todo_tk.py @@ -1,11 +1,14 @@ #!/usr/bin/env python3 +import gettext import sys import tkinter as tk from login import LoginFrame from workspace import WorkSpaceFrame from user import User +gettext.install("todo", localedir="po") + if "win" in sys.platform.lower(): DEFAULT_URL = "http://localhost:8000" else: @@ -14,7 +17,7 @@ else: BASE_W = 600 BASE_H = 400 -TITLE_APP = "ToDo Application" +TITLE_APP = _("Приложение для планирования") class Application(tk.Tk): @@ -50,7 +53,6 @@ class Application(tk.Tk): def center_window(self, width: str = BASE_W, heigh: str = BASE_H) -> None: """ Центрирует приложение по центру экрана - :param width: ширина окна :param heigh: высота окна """ diff --git a/frontend/workspace.py b/frontend/workspace.py index 73875e7..a92a744 100644 --- a/frontend/workspace.py +++ b/frontend/workspace.py @@ -1,5 +1,8 @@ +import gettext import tkinter as tk +gettext.install("todo", localedir="po") + def str_time(time): return time.strftime("%Y-%m-%d %H:%M:%S") @@ -11,7 +14,7 @@ TODO_ITEM_TABLE_CREATED_AT_WIDTH = 15 def placeholder(): - print("Не реализовано") + print(_("Не реализовано")) class ToDoItemWidget(tk.Frame): @@ -19,13 +22,13 @@ class ToDoItemWidget(tk.Frame): def header(parent): body = tk.Frame(parent) - text = tk.Label(body, text="Текст", width=TODO_ITEM_TABLE_TEXT_WIDTH) + text = tk.Label(body, text=_("Текст"), width=TODO_ITEM_TABLE_TEXT_WIDTH) text.pack(side="left") - text = tk.Label(body, text="Выполнено", width=TODO_ITEM_TABLE_FINISHED_WIDTH) + text = tk.Label(body, text=_("Выполнено"), width=TODO_ITEM_TABLE_FINISHED_WIDTH) text.pack(side="left") - text = tk.Label(body, text="Создано", width=TODO_ITEM_TABLE_CREATED_AT_WIDTH) + text = tk.Label(body, text=_("Создано"), width=TODO_ITEM_TABLE_CREATED_AT_WIDTH) text.pack(side="left") return body @@ -53,7 +56,9 @@ class ToDoItemWidget(tk.Frame): ) self.createdAt.pack(side="left") - self.remove = tk.Button(self, text="Удалить", command=lambda: self.parent.remove(self.item)) + self.remove = tk.Button( + self, text=_("Удалить"), command=lambda: self.parent.remove(self.item) + ) self.remove.pack(side="left") def finishedButton_command(self): @@ -80,10 +85,10 @@ class ToDoListWidget(tk.Frame): self.itemToAdd = tk.Text(self, width=15, height=1) self.itemToAdd.pack(side="top") - add = tk.Button(self, text="Добавить заметку", command=self.add_command) + add = tk.Button(self, text=_("Добавить заметку"), command=self.add_command) add.pack(side="top") - delete = tk.Button(self, text="Удалить лист", command=self.delete_list) + delete = tk.Button(self, text=_("Удалить лист"), command=self.delete_list) delete.pack(side="top") def update(self, itemList=None): @@ -141,7 +146,7 @@ class WorkSpaceFrame(tk.Frame): # Запомнить пользователя self.rbtn_var = tk.IntVar(value=1) - rbtn = tk.Checkbutton(self, text="Запомнить меня", variable=self.rbtn_var, command=None) + rbtn = tk.Checkbutton(self, text=_("Запомнить меня"), variable=self.rbtn_var, command=None) rbtn.pack(anchor="n") # data @@ -150,7 +155,7 @@ class WorkSpaceFrame(tk.Frame): self.add_list_text = tk.Text(self, width=15, height=1) self.add_list_text.pack(anchor="sw") - add = tk.Button(self, text="Добавить лист", command=self.add_list) + add = tk.Button(self, text=_("Добавить лист"), command=self.add_list) add.pack(anchor="sw") # select list box From bb8e1365bb9823496efdda58a7eceb4f877bcf61 Mon Sep 17 00:00:00 2001 From: Derinhelm Date: Mon, 7 Jun 2021 16:36:01 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=20=D0=BF=D1=83=D1=82=D1=8C=20=D0=BA=20=D0=B4=D0=B8=D1=80=D0=B5?= =?UTF-8?q?=D0=BA=D1=82=D0=BE=D1=80=D0=B8=D0=B8=20po?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/login.py | 3 ++- frontend/message.py | 5 +++-- frontend/todo_tk.py | 3 ++- frontend/workspace.py | 3 ++- 4 files changed, 9 insertions(+), 5 deletions(-) diff --git a/frontend/login.py b/frontend/login.py index b399254..7830608 100644 --- a/frontend/login.py +++ b/frontend/login.py @@ -1,9 +1,10 @@ import gettext +import os import tkinter as tk from user import User import message -gettext.install("todo", localedir="po") +gettext.install("todo", os.path.join(os.path.dirname(__file__), "po")) class LoginFrame(tk.Frame): diff --git a/frontend/message.py b/frontend/message.py index 5e2c784..c088893 100644 --- a/frontend/message.py +++ b/frontend/message.py @@ -1,7 +1,8 @@ -from tkinter import messagebox as mb import gettext +import os +from tkinter import messagebox as mb -gettext.install("todo", localedir="po") +gettext.install("todo", os.path.join(os.path.dirname(__file__), "po")) TITLE_INFO_BOX = _("Сообщение!") MESSAGE_INVALID_LOGIN = _("Неправильный логин или пароль") diff --git a/frontend/todo_tk.py b/frontend/todo_tk.py index 366c67f..9ecf288 100644 --- a/frontend/todo_tk.py +++ b/frontend/todo_tk.py @@ -1,13 +1,14 @@ #!/usr/bin/env python3 import gettext +import os import sys import tkinter as tk from login import LoginFrame from workspace import WorkSpaceFrame from user import User -gettext.install("todo", localedir="po") +gettext.install("todo", os.path.join(os.path.dirname(__file__), "po")) if "win" in sys.platform.lower(): DEFAULT_URL = "http://localhost:8000" diff --git a/frontend/workspace.py b/frontend/workspace.py index a92a744..c418616 100644 --- a/frontend/workspace.py +++ b/frontend/workspace.py @@ -1,7 +1,8 @@ import gettext +import os import tkinter as tk -gettext.install("todo", localedir="po") +gettext.install("todo", os.path.join(os.path.dirname(__file__), "po")) def str_time(time): From 16c151a1f31afd700c8b163b39a30d0b55337630 Mon Sep 17 00:00:00 2001 From: Derinhelm Date: Mon, 7 Jun 2021 20:47:42 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D0=B5=D0=BD?= =?UTF-8?q?=20=D0=B8=D0=BD=D1=82=D0=B5=D0=B9=D1=80=D1=84=D0=B5=D0=B9=D1=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/todo_tk.py | 2 +- frontend/workspace.py | 120 ++++++++++++++++++++++++++++-------------- 2 files changed, 82 insertions(+), 40 deletions(-) diff --git a/frontend/todo_tk.py b/frontend/todo_tk.py index 9ecf288..ce4fa50 100644 --- a/frontend/todo_tk.py +++ b/frontend/todo_tk.py @@ -15,7 +15,7 @@ if "win" in sys.platform.lower(): else: DEFAULT_URL = "http://0.0.0.0:8000" -BASE_W = 600 +BASE_W = 900 BASE_H = 400 TITLE_APP = _("Приложение для планирования") diff --git a/frontend/workspace.py b/frontend/workspace.py index c418616..fe4ba2f 100644 --- a/frontend/workspace.py +++ b/frontend/workspace.py @@ -9,9 +9,10 @@ def str_time(time): return time.strftime("%Y-%m-%d %H:%M:%S") -TODO_ITEM_TABLE_TEXT_WIDTH = 15 -TODO_ITEM_TABLE_FINISHED_WIDTH = 8 -TODO_ITEM_TABLE_CREATED_AT_WIDTH = 15 +TODO_ITEM_TABLE_TEXT_WIDTH = 25 +TODO_ITEM_TABLE_FINISHED_WIDTH = 20 + +TODO_ITEM_TABLE_CREATED_AT_WIDTH = 25 def placeholder(): @@ -19,48 +20,46 @@ def placeholder(): class ToDoItemWidget(tk.Frame): - @staticmethod - def header(parent): - body = tk.Frame(parent) - - text = tk.Label(body, text=_("Текст"), width=TODO_ITEM_TABLE_TEXT_WIDTH) - text.pack(side="left") - - text = tk.Label(body, text=_("Выполнено"), width=TODO_ITEM_TABLE_FINISHED_WIDTH) - text.pack(side="left") - - text = tk.Label(body, text=_("Создано"), width=TODO_ITEM_TABLE_CREATED_AT_WIDTH) - text.pack(side="left") - - return body - - def __init__(self, *args, item, **argv): + def __init__(self, *args, row_number, item, table, **argv): super().__init__(*args, **argv) self.parent = self.master self.item = item - self.noteLabel = tk.Label(self, text=item.text, width=TODO_ITEM_TABLE_TEXT_WIDTH) - self.noteLabel.pack(side="left") + self.noteLabel = tk.Label( + table, + text=item.text, + width=TODO_ITEM_TABLE_TEXT_WIDTH, + justify="center", + font=("Arial", 8), + ) + self.noteLabel.grid(row=row_number, column=0) self.finished = tk.IntVar(value=int(item.finished)) self.finishedButton = tk.Checkbutton( - self, + table, variable=self.finished, command=self.finishedButton_command, width=TODO_ITEM_TABLE_FINISHED_WIDTH, + justify="center", ) - self.finishedButton.pack(side="left") + self.finishedButton.grid(row=row_number, column=1) self.createdAt = tk.Label( - self, text=str_time(item.created_at), width=TODO_ITEM_TABLE_CREATED_AT_WIDTH + table, + text=str_time(item.created_at), + width=TODO_ITEM_TABLE_CREATED_AT_WIDTH, + justify="center", ) - self.createdAt.pack(side="left") + self.createdAt.grid(row=row_number, column=2) self.remove = tk.Button( - self, text=_("Удалить"), command=lambda: self.parent.remove(self.item) + table, + text=_("Удалить"), + command=lambda: self.parent.remove(self.item), + justify="center", ) - self.remove.pack(side="left") + self.remove.grid(row=row_number, column=3) def finishedButton_command(self): self.item.modify(finished=self.finished.get() > 0) @@ -71,26 +70,69 @@ class ToDoListWidget(tk.Frame): super().__init__(*args, **argv) self.delete_list = delete_list - def fill(self, itemList): + def create_table_header(self, body): - header = ToDoItemWidget.header(self) - header.pack(side="left") - header.pack(side="top", fill="y") + header_font = ("Arial", "10", "bold") + text = tk.Label( + body, + text=_("Текст"), + width=TODO_ITEM_TABLE_TEXT_WIDTH, + justify="center", + font=header_font, + ) + text.grid(row=0, column=0) + + done = tk.Label( + body, + text=_("Выполнено"), + width=TODO_ITEM_TABLE_FINISHED_WIDTH, + justify="center", + font=header_font, + ) + done.grid(row=0, column=1) + + created = tk.Label( + body, + text=_("Создано"), + width=TODO_ITEM_TABLE_CREATED_AT_WIDTH, + justify="center", + font=header_font, + ) + created.grid(row=0, column=2) + + def create_table(self, itemList): + table = tk.LabelFrame(self, relief=tk.GROOVE) + table.grid() + self.create_table_header(table) self.itemList = itemList - + row_number = 1 for item in itemList: - item = ToDoItemWidget(self, item=item) - item.pack(side="top", fill="y") + item = ToDoItemWidget(self, row_number=row_number, item=item, table=table) + row_number += 1 + return table - self.itemToAdd = tk.Text(self, width=15, height=1) - self.itemToAdd.pack(side="top") + def create_new_item(self): + table = tk.LabelFrame(self, relief=tk.GROOVE) + table.grid() + self.itemToAdd = tk.Text(table, width=15, height=1) + self.itemToAdd.grid(row=0, column=0) - add = tk.Button(self, text=_("Добавить заметку"), command=self.add_command) - add.pack(side="top") + add = tk.Button(table, text=_("Добавить заметку"), command=self.add_command) + add.grid(row=0, column=1) + return table + + def fill(self, itemList): + self.frame = tk.LabelFrame(self, relief=tk.GROOVE) + self.frame.grid(sticky="NEWS") + table = self.create_table(itemList) + table.grid(row=0, column=0) + + new = self.create_new_item() + new.grid(row=2, column=0) delete = tk.Button(self, text=_("Удалить лист"), command=self.delete_list) - delete.pack(side="top") + delete.grid(row=4, column=0) def update(self, itemList=None): self.clear()