Skip to content

Adds English support #6

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions minesweeper/auth/Auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from tkinter import messagebox
import pickle
import os

import settings
from minesweeper.languages.language import text_messages

class Auth:
def __init__(self):
Expand All @@ -11,6 +12,7 @@ def __init__(self):
self.current_user = None
self.users = []

self.text_messages = text_messages
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Creating this variable inside each class is useless if you can use it directly from import.

try:
with open(self.__path, 'rb') as f:
self.users = pickle.load(f)
Expand All @@ -33,7 +35,7 @@ def sign_in(self, login, password):
if password == 'admin':
return 'admin'
else:
return 'Невірний пароль admin-а'
return self.text_messages[settings.language.lower()].auth.sign_in.invalid_admin_password
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Taking strings directly from the array could be tricky because every time you need to write [setting...]. First of all, this makes a lot of useless code, secondly, it leaves a place for errors.

The better way is to create a class, that will automatically provide the string with the right language. But I think that this implementation would require more work and maybe additional libraries.

If you want to do it simpler, you can do it this way: assign the text_messages variable needed translation at the start of the game.


user = next((user for user in self.users if user.login == login), None)

Expand All @@ -43,9 +45,9 @@ def sign_in(self, login, password):
self.current_user = user
return self.current_user
else:
return 'Невірний пароль'
return self.text_messages[settings.language.lower()].auth.sign_in.invalid_password
else:
if messagebox.askyesno('Авторизація', 'Створити нового гравця: {}, з паролем: {}?'.format(login, password)):
if messagebox.askyesno(self.text_messages[settings.language.lower()].auth.sign_in.authorization, '{}{}{}{}?'.format(self.text_messages[settings.language.lower()].auth.sign_in.create_new_player, login, self.text_messages[settings.language.lower()].auth.sign_in.with_password, password)):
self.current_user = self.__new_user(login, password)
return self.current_user
else:
Expand Down
32 changes: 21 additions & 11 deletions minesweeper/game/GameSession.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,27 @@
from enum import Enum
import time
from tkinter import messagebox
import settings
from minesweeper.languages.language import text_messages


class DifficultyLevel(Enum):
EASY = 'Новачок'
MEDIUM = 'Любитель'
HARD = 'Професіонал'
if settings.language.lower() == 'en':
EASY = 'Easy'
MEDIUM = 'Medium'
HARD = 'Hard'
elif settings.language.lower() == 'ur':
EASY = 'Новачок'
MEDIUM = 'Любитель'
HARD = 'Професіонал'


class GameSession:
def __init__(self, difficulty):
self.difficulty = difficulty

self.text_messages = text_messages

if difficulty is DifficultyLevel.EASY:
self.num_rows = 9
self.num_cols = 9
Expand Down Expand Up @@ -70,7 +79,7 @@ def start(self, master, on_end, on_stop):

def __menu_widget(self):
def update_time():
string = time.strftime('Час: %M:%S', time.gmtime(self.seconds_elapsed))
string = time.strftime(self.text_messages[settings.language.lower()].update_time.time + ': %M:%S', time.gmtime(self.seconds_elapsed))
lbl_time.configure(text=string)
if self.is_playing:
self.seconds_elapsed += 1
Expand All @@ -79,7 +88,8 @@ def update_time():
frm = tk.Frame(self.master)
frm.pack(side=tk.LEFT, fill=tk.Y, pady=2, padx=2)

btn_exit = tk.Button(frm, text='Вихід', command=self.__on_exit, width=15)
btn_exit = tk.Button(frm, text=self.text_messages[settings.language.lower()].menu_widget.entrance, command=self.__on_exit, width=15)

btn_exit.pack()

tk.Frame(frm, height=15).pack()
Expand All @@ -88,15 +98,15 @@ def update_time():
lbl_time.pack(fill=tk.X)
update_time()

lbl_num_mines = tk.Label(frm, text='Мін: {}'.format(self.num_mines), anchor=tk.W)
lbl_num_mines = tk.Label(frm, text= '{} :{}'.format(self.text_messages[settings.language.lower()].menu_widget.mine,self.num_mines), anchor=tk.W)
lbl_num_mines.pack(fill=tk.X)

self.lbl_flags = tk.Label(frm, anchor=tk.W)
self.lbl_flags.pack(fill=tk.X)
self.__update_flags()

def __update_flags(self):
self.lbl_flags.configure(text='Залишилося флагів: {}'.format(self.flags_left))
self.lbl_flags.configure(text='{}: {}'.format(self.text_messages[settings.language.lower()].update_flags, self.flags_left))

def __board_widget(self):
frm_board = tk.Frame(self.master)
Expand Down Expand Up @@ -238,7 +248,7 @@ def __end_on_mine(self):
tile.wrong_flag()

def f():
self.__display_message('ПРОГРАШ')
self.__display_message(self.text_messages[settings.language.lower()].end_on_mine)
self.on_end(self.difficulty, False, time.gmtime(self.seconds_elapsed))
self.master.after(200, f)

Expand All @@ -251,15 +261,15 @@ def __end_on_success(self):
tile.open(is_safe=True)

def f():
self.__display_message('ПЕРЕМОГА')
self.__display_message(self.text_messages[settings.language.lower()].end_on_success)
self.on_end(self.difficulty, True, time.gmtime(self.seconds_elapsed))
self.master.after(200, f)

def __display_message(self, text):
gmt = time.gmtime(self.seconds_elapsed)
time_string = time.strftime('%M:%S', gmt)
messagebox.showinfo('Сапер', '{}\nЧас: {}'.format(text, time_string))
messagebox.showinfo('Сапер', '{}\n{}: {}'.format(text, self.text_messages[settings.language.lower()].update_time.time, time_string))

def __on_exit(self):
is_save = messagebox.askyesno("Сапер", "Зберегти гру?")
is_save = messagebox.askyesno("Сапер", self.text_messages[settings.language.lower()].on_exit)
self.on_stop(is_save)
10 changes: 7 additions & 3 deletions minesweeper/game/Leaderboard.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import tkinter as tk
from tkinter import ttk
import time

import settings
from minesweeper.languages.language import text_messages

class Leaderboard:
def __init__(self, master, auth, on_back):
Expand All @@ -17,6 +18,8 @@ def __init__(self, master, auth, on_back):
self.cmbb_user = None
self.lstb_results = None

self.text_messages = text_messages

self.__setup(on_back)

def __setup(self, on_back):
Expand All @@ -25,7 +28,8 @@ def __setup(self, on_back):
frm_left = tk.Frame(self.master)
frm_left.pack(side=tk.LEFT, fill=tk.Y)

btn_back = tk.Button(frm_left, text='Назад', command=on_back, width=15)

btn_back = tk.Button(frm_left, text=self.text_messages[settings.language.lower()].leader_board.back, command=on_back, width=15)
btn_back.grid(column=0, row=0, padx=2, pady=2)

options = [self.ALL] + list(self.user_logins)
Expand All @@ -50,7 +54,7 @@ def __on_update_list(self, event=None):
for result in results:
u = result[0]
r = result[1]
win = 'ВИГРАВ' if r.is_win else 'ПРОГРАВ'
win = self.text_messages[settings.language.lower()].leader_board.win if r.is_win else self.text_messages[settings.language.lower()].leader_board.loss
t_string = time.strftime('%M:%S', r.time_elapsed)
string = ' {}, {}, {}, {} '.format(u.login, win, r.difficulty.value, t_string)
self.lstb_results.insert(tk.END, string)
23 changes: 14 additions & 9 deletions minesweeper/game/LoginScreen.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
from tkinter import messagebox
from minesweeper.auth.User import User
from minesweeper.game.AdminScreen import AdminScreen

import settings
from minesweeper.languages.language import text_messages

class LoginScreen:
def __init__(self, root, auth, on_logged):
Expand All @@ -16,28 +17,32 @@ def __init__(self, root, auth, on_logged):
self.ent_login = None
self.ent_password = None

self.text_messages = text_messages

self.__setup()

def __setup(self):
self.master = tk.Frame(self.root)
self.master.pack(expand=True)

lbl = tk.Label(self.master, text='Хто ти?')
lbl = tk.Label(self.master, text=self.text_messages[settings.language.lower()].login_screen.setup.who_are_you)
lbl_login = tk.Label(self.master, text=self.text_messages[settings.language.lower()].login_screen.setup.login)
lbl_password = tk.Label(self.master, text=self.text_messages[settings.language.lower()].login_screen.setup.password)
btn_login = tk.Button(self.master, text=self.text_messages[settings.language.lower()].login_screen.setup.login_register, command=self.__on_login_tap)


lbl.grid(row=0, columnspan=2)

lbl_login = tk.Label(self.master, text='Логін: ')
self.ent_login = tk.Entry(self.master, width=20)
lbl_login.grid(row=1, column=0, sticky='e')
self.ent_login.grid(row=1, column=1)

lbl_password = tk.Label(self.master, text='Пароль:')
self.ent_password = tk.Entry(self.master, width=20, show='*')
lbl_password.grid(row=2, column=0, sticky='e')
self.ent_password.grid(row=2, column=1)

btn_login = tk.Button(self.master, text='Увійти / Зареєструватися', command=self.__on_login_tap)
btn_login.grid(row=3, column=0, columnspan=2, sticky='ew')

self.frm_hint = tk.Frame(self.root)
self.frm_hint.pack(fill=tk.BOTH)
lbl_admin = tk.Label(self.frm_hint, text='admin - admin', fg='gray')
Expand All @@ -47,8 +52,8 @@ def __on_login_tap(self):
login = self.ent_login.get()
password = self.ent_password.get()

if login == '' or password == '':
messagebox.showerror('Авторизація', 'Поля не можуть бути порожніми')
if login == '' or password == '':
messagebox.showerror(self.text_messages[settings.language.lower()].login_screen.on_login_tap.authorization, self.text_messages[settings.language.lower()].on_login_tap.empty_fields)
return

res = self.auth.sign_in(login, password)
Expand All @@ -57,7 +62,7 @@ def __on_login_tap(self):
elif res == 'admin':
self.__on_admin()
elif isinstance(res, str):
messagebox.showerror('Авторизація', res)
messagebox.showerror(self.text_messages[settings.language.lower()].login_screen.on_login_tap.authorization, res)

def __on_admin(self):
self.master.destroy()
Expand Down
10 changes: 6 additions & 4 deletions minesweeper/game/Screens.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
import tkinter as tk

from minesweeper.game.GameSession import DifficultyLevel
import settings
from minesweeper.languages.language import text_messages


class Screens:
Expand All @@ -10,17 +12,17 @@ def home_scr(master, on_new_game, on_continue, on_leaderboard, on_exit):
def button(text, command):
return tk.Button(master, text=text, command=command, width=20)

btn_new = button(text='Нова гра', command=on_new_game)
btn_new = button(text=text_messages[settings.language.lower()].home_scr.new_game, command=on_new_game)
btn_new.pack()

if on_continue is not None:
btn_con = button(text='Продовижити', command=on_continue)
btn_con = button(text=text_messages[settings.language.lower()].home_scr.continue_btn, command=on_continue)
btn_con.pack()

btn_lea = button(text='Таблиця результатів', command=on_leaderboard)
btn_lea = button(text=text_messages[settings.language.lower()].home_scr.table_of_result, command=on_leaderboard)
btn_lea.pack()

btn_exi = button(text='Вихід', command=on_exit)
btn_exi = button(text=text_messages[settings.language.lower()].home_scr.entrance, command=on_exit)
btn_exi.pack()

master.pack(fill=tk.NONE, expand=True)
Expand Down
Empty file.
48 changes: 48 additions & 0 deletions minesweeper/languages/en.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
en = {
'update_time': {
'time': 'Time'
},
'menu_widget': {
'entrance': 'Entrance',
'mine': 'Min'
},
'update_flags': 'Remaining flags',
'end_on_mine': 'LOSS',
'end_on_success': 'VICTORY',
'on_exit': 'Save game?',

'leader_board': {
'back': 'Back',
'win': 'WIN',
'loss': 'LOSS'
},
'login_screen': {
'setup': {
'who_are_you': 'Who are you?',
'login': 'Login: ',
'password': 'Password: ',
'login_register': 'Login / Register'
},
'on_login_tap': {
'authorization': 'Authorization',
'empty_fields': 'Fields cannot be empty'
}
},

'home_scr': {
'new_game': 'New game',
'continue_btn': 'Continue',
'table_of_result': 'Table of results',
'entrance': 'Entrance'
},

'auth': {
'sign_in': {
'invalid_admin_password': 'Invalid admin password',
'invalid_password': 'Invalid password',
'authorization': 'Authorization',
'create_new_player': 'Create a new player: ',
'with_password': ', with password: '
}
}
}
17 changes: 17 additions & 0 deletions minesweeper/languages/language.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from types import SimpleNamespace
from minesweeper.languages.ur import ur
from minesweeper.languages.en import en

class NestedNamespace(SimpleNamespace):
def __init__(self, dictionary, **kwargs):
super().__init__(**kwargs)
for key, value in dictionary.items():
if isinstance(value, dict):
self.__setattr__(key, NestedNamespace(value))
else:
self.__setattr__(key, value)

global text_messages
text_messages = {}
text_messages.update({"ur": NestedNamespace(ur)})
text_messages.update({"en": NestedNamespace(en)})
48 changes: 48 additions & 0 deletions minesweeper/languages/ur.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
ur = {
'update_time': {
Copy link
Owner

@SashaKryzh SashaKryzh Dec 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t think that these "levels" are useful. Maybe, if sometime in the future, I would like to use the 'Час' outside the update_time widget and this groping would confuse me.

I would do everything in a flat structure without any groups.

'time': 'Час'
},
'menu_widget': {
'entrance': 'Вихід',
'mine': 'Мін'
},
'update_flags': 'Залишилося флагів',
'end_on_mine': 'ПРОГРАШ',
'end_on_success': 'ПЕРЕМОГА',
'on_exit': 'Зберегти гру?',

'leader_board': {
'back': 'Назад',
'win': 'ВИГРАВ',
'loss': 'ПРОГРАВ'
},
'login_screen': {
'setup': {
'who_are_you': 'Хто ти?',
'login': 'Логін: ',
'password': 'Пароль: ',
'login_register': 'Увійти / Зареєструватися'
},
'on_login_tap': {
'authorization': 'Авторизація',
'empty_fields': 'Поля не можуть бути порожніми'
}
},

'home_scr': {
'new_game': 'Нова гра',
'continue_btn': 'Продовижити',
'table_of_result': 'Таблиця результатів',
'entrance': 'Вихід'
},

'auth': {
'sign_in': {
'invalid_admin_password': 'Невірний пароль admin-а',
'invalid_password': 'Невірний пароль',
'authorization': 'Авторизація',
'create_new_player': 'Створити нового гравця: ',
'with_password': ', з паролем: '
}
}
}
1 change: 1 addition & 0 deletions settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
language="en"