mirror of
https://github.com/OMGeeky/Kivy-Shopping-List.git
synced 2026-02-23 15:38:26 +01:00
Add language support
This commit is contained in:
@@ -1 +1 @@
|
||||
from .settings import AppSettings
|
||||
from .settings import AppSettings, FILES_PATH
|
||||
@@ -1,5 +1,9 @@
|
||||
from dataclasses import dataclass, asdict
|
||||
import json
|
||||
from pathlib import Path
|
||||
|
||||
FILES_PATH = Path("files")
|
||||
settings_file_path = Path(FILES_PATH,'settings.json')
|
||||
|
||||
@dataclass
|
||||
class AppSettings:
|
||||
@@ -13,7 +17,9 @@ class AppSettings:
|
||||
def to_json_file(self):
|
||||
settings_dict = {"settings": asdict(self)}
|
||||
try:
|
||||
with open("settings.json", "x") as json_file:
|
||||
if not FILES_PATH.is_dir():
|
||||
FILES_PATH.mkdir()
|
||||
with open(settings_file_path, "x") as json_file:
|
||||
json.dump(settings_dict, json_file, indent=4)
|
||||
except FileExistsError:
|
||||
return
|
||||
@@ -23,7 +29,7 @@ class AppSettings:
|
||||
settings_dict = None
|
||||
|
||||
try:
|
||||
with open("settings.json", "r") as json_file:
|
||||
with open(settings_file_path, "r") as json_file:
|
||||
settings_dict = json.load(json_file)
|
||||
except FileNotFoundError:
|
||||
return None
|
||||
@@ -41,3 +47,13 @@ class AppSettings:
|
||||
|
||||
print(new_settings)
|
||||
return new_settings
|
||||
|
||||
@staticmethod
|
||||
def get_or_create():
|
||||
settings = AppSettings.from_json_file()
|
||||
|
||||
if settings is None:
|
||||
settings = AppSettings()
|
||||
settings.to_json_file()
|
||||
|
||||
return settings
|
||||
1
src/language/__init__.py
Normal file
1
src/language/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from .lang import TranslationProvider, LANGUAGES
|
||||
46
src/language/lang.py
Normal file
46
src/language/lang.py
Normal file
@@ -0,0 +1,46 @@
|
||||
|
||||
# from data import AppSettings
|
||||
|
||||
import json
|
||||
from pathlib import Path
|
||||
from typing import Dict, Optional
|
||||
|
||||
|
||||
LANGUAGES = { "DE": "Deutsch", "EN": "English", "FR": "Francais" }
|
||||
LANGUAGE_FOLDER = Path('res', "lang")
|
||||
|
||||
|
||||
class TranslationProvider:
|
||||
last_language_key: Optional[str] = None
|
||||
last_language_dict: Optional[Dict[str,str]] = None
|
||||
|
||||
@classmethod
|
||||
def get_language_file(cls, language: str) -> Dict[str, str]:
|
||||
if language not in list(LANGUAGES.keys()):
|
||||
raise ValueError('invalid language key: "{language}"')
|
||||
|
||||
if cls.last_language_key == language and cls.last_language_dict is not None:
|
||||
return cls.last_language_dict
|
||||
|
||||
path = Path(LANGUAGE_FOLDER, f'{language}.json' )
|
||||
try:
|
||||
with open(path, 'r', encoding='utf-8') as f:
|
||||
result = json.load(f)
|
||||
cls.last_language_key = language
|
||||
cls.last_language_dict = result
|
||||
return result
|
||||
|
||||
except FileNotFoundError:
|
||||
print(f'Language not found: "{language}"')
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def get_translated(cls, key:str, language:str) -> str:
|
||||
|
||||
lang_dict = cls.get_language_file(language)
|
||||
result = lang_dict.get(key, None)
|
||||
if result:
|
||||
return result
|
||||
|
||||
print(f'unsuccesful try to get {key} in language {language}')
|
||||
return f'key not found for language: \nkey:"{key}"\nlanguage:"{language}"'
|
||||
49
src/main.py
49
src/main.py
@@ -1,4 +1,5 @@
|
||||
from os import name
|
||||
from typing import Optional
|
||||
from kivy.app import App
|
||||
from kivy.properties import ListProperty, StringProperty, BooleanProperty, ObjectProperty
|
||||
from kivy.uix.boxlayout import BoxLayout
|
||||
@@ -16,8 +17,9 @@ from kivymd.uix.menu import MDDropdownMenu
|
||||
from kivymd.uix.list import OneLineAvatarIconListItem
|
||||
import json
|
||||
from data import AppSettings
|
||||
from language import TranslationProvider, LANGUAGES
|
||||
|
||||
|
||||
LANGUAGES = { "DE": "Deutsch", "EN": "English", "FR": "Francais" }
|
||||
if kivy.utils.platform not in ['android', 'ios']:
|
||||
Window.size = (400, 800)
|
||||
|
||||
@@ -34,8 +36,13 @@ class ShoppingEntry(OneLineAvatarIconListItem):
|
||||
class AddDialog(MDBoxLayout):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def get_translated(self, key:str)->str:
|
||||
settings = AppSettings.get_or_create()
|
||||
return TranslationProvider.get_translated(key, settings.language)
|
||||
|
||||
class ShoppingEntryScreen(Screen):
|
||||
settings : Optional[AppSettings] = None
|
||||
add_dialog = None
|
||||
|
||||
def on_bestaetigen(self, *args):
|
||||
@@ -55,14 +62,14 @@ class ShoppingEntryScreen(Screen):
|
||||
if self.add_dialog:
|
||||
return
|
||||
|
||||
# SPRACHE
|
||||
language = self.get_settings().language
|
||||
|
||||
buttons = [
|
||||
MDFlatButton(text='Abbrechen', on_release=self.close_add_popup),
|
||||
MDFlatButton(text='Bestätigen', on_release=lambda args: self.on_bestaetigen(args)),
|
||||
MDFlatButton(text=TranslationProvider.get_translated('cancel', language), on_release=self.close_add_popup),
|
||||
MDFlatButton(text=TranslationProvider.get_translated('confirm', language), on_release=lambda args: self.on_bestaetigen(args)),
|
||||
]
|
||||
# SPRACHE
|
||||
self.add_dialog = MDDialog(
|
||||
title='Eintrag hinzufügen',
|
||||
title=TranslationProvider.get_translated('add_entry', language),
|
||||
type='custom',
|
||||
content_cls=AddDialog(),
|
||||
buttons=buttons,
|
||||
@@ -89,6 +96,19 @@ class ShoppingEntryScreen(Screen):
|
||||
def navigate_to_settings(self):
|
||||
self.manager.transition.direction = 'left'
|
||||
self.manager.current = 'settings'
|
||||
self.settings = None # reset settings to reload them after change
|
||||
|
||||
def load_settings(self)->None:
|
||||
if not self.settings:
|
||||
self.settings = AppSettings.get_or_create()
|
||||
|
||||
def get_settings(self) -> AppSettings:
|
||||
self.load_settings()
|
||||
return self.settings # type: ignore
|
||||
|
||||
def get_translated(self, key) -> str:
|
||||
language = self.get_settings().language
|
||||
return TranslationProvider.get_translated(key,language)
|
||||
|
||||
class SettingsScreen(Screen):
|
||||
settings = ObjectProperty(None)
|
||||
@@ -96,7 +116,7 @@ class SettingsScreen(Screen):
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.load_settings()
|
||||
self.settings = AppSettings.get_or_create()
|
||||
|
||||
menu_items = [
|
||||
{
|
||||
@@ -127,16 +147,13 @@ class SettingsScreen(Screen):
|
||||
language = LANGUAGES.get(language_key)
|
||||
self.ids.language_drop_down.set_item(language)
|
||||
self.menu.dismiss()
|
||||
|
||||
def get_translated(self, key) -> str:
|
||||
if self.settings is None:
|
||||
self.settings = AppSettings.get_or_create()
|
||||
|
||||
def load_settings(self):
|
||||
settings = AppSettings.from_json_file()
|
||||
|
||||
if settings is None:
|
||||
self.create_settings_json()
|
||||
|
||||
def create_settings_json(self):
|
||||
settings = AppSettings()
|
||||
settings.to_json_file()
|
||||
language = self.settings.language
|
||||
return TranslationProvider.get_translated(key,language)
|
||||
|
||||
class ShoppingListApp(MDApp):
|
||||
def build(self):
|
||||
|
||||
15
src/res/lang/DE.json
Normal file
15
src/res/lang/DE.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"cancel": "Abbrechen"
|
||||
,"confirm": "Bestätigen"
|
||||
,"add_entry": "Eintrag hinzufügen"
|
||||
,"new_entry": "Neuer Eintrag"
|
||||
,"app_title":"Shopping-List-App"
|
||||
,"settings": "Einstellungen"
|
||||
,"language": "Sprache"
|
||||
,"theme":"Theme"
|
||||
,"mqtt-server":"MQTT-Server"
|
||||
,"mqtt-topic":"MQTT-Topic"
|
||||
,"mqtt-username":"MQTT-Benutzername"
|
||||
,"mqtt-password":"MQTT-Passwort"
|
||||
|
||||
}
|
||||
15
src/res/lang/EN.json
Normal file
15
src/res/lang/EN.json
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"cancel": "Cancel"
|
||||
,"confirm": "Confirm"
|
||||
,"add_entry": "Add Entry"
|
||||
,"new_entry": "New Entry"
|
||||
,"app_title":"Shopping-List-App"
|
||||
,"settings": "Settings"
|
||||
,"language": "Language"
|
||||
,"theme":"Theme"
|
||||
,"mqtt-server":"MQTT-Server"
|
||||
,"mqtt-topic":"MQTT-Topic"
|
||||
,"mqtt-username":"MQTT-Username"
|
||||
,"mqtt-password":"MQTT-Password"
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
id: shopping_entry_text
|
||||
pos_hint: { 'center_y': 0.4 }
|
||||
# SPRACHE
|
||||
hint_text: 'Neuer Eintrag'
|
||||
hint_text: root.get_translated('new_entry')
|
||||
mode: "round"
|
||||
|
||||
<ShoppingEntryScreen>:
|
||||
@@ -30,8 +30,7 @@
|
||||
pos_hint: { 'center_x': 0.5, 'center_y': 0.5 }
|
||||
|
||||
MDTopAppBar:
|
||||
#SPRACHE
|
||||
title: 'Shopping-List-App'
|
||||
title: root.get_translated('app_title')
|
||||
md_bg_color: app.theme_cls.primary_color
|
||||
specific_text_color: '#1C2120'
|
||||
right_action_items: [['res/settings.png', lambda x: root.navigate_to_settings()]]
|
||||
@@ -54,8 +53,7 @@
|
||||
orientation: 'vertical'
|
||||
|
||||
MDTopAppBar:
|
||||
#SPRACHE
|
||||
title: 'Einstellungen'
|
||||
title: root.get_translated('settings')
|
||||
md_bg_color: app.theme_cls.primary_color
|
||||
left_action_items: [['res/arrow_back.png', lambda x: root.navigate_to_shopping_list()]]
|
||||
|
||||
@@ -68,48 +66,46 @@
|
||||
row_force_default: True
|
||||
row_default_height: '75dp'
|
||||
|
||||
# SPRACHE
|
||||
MDLabel:
|
||||
text: 'Sprache'
|
||||
text: root.get_translated('language')
|
||||
MDDropDownItem:
|
||||
id: language_drop_down
|
||||
# SPRACHE?
|
||||
text: 'Deutsch'
|
||||
on_release: root.show_languages_menu()
|
||||
|
||||
# SPRACHE
|
||||
MDLabel:
|
||||
text: 'Theme'
|
||||
text: root.get_translated('theme')
|
||||
MDSwitch:
|
||||
id: theme_switch
|
||||
widget_style: "android"
|
||||
active: False
|
||||
|
||||
# SPRACHE
|
||||
MDLabel:
|
||||
text: 'MQTT-Server'
|
||||
text: root.get_translated('mqtt-server')
|
||||
MDTextField:
|
||||
id: mqtt_server_text_field
|
||||
# SPRACHE?
|
||||
hint_text: 'mqtt.server.de'
|
||||
mode: "round"
|
||||
|
||||
# SPRACHE
|
||||
MDLabel:
|
||||
text: 'MQTT-Topic'
|
||||
text: root.get_translated('mqtt-topic')
|
||||
MDTextField:
|
||||
id: mqtt_topic_text_field
|
||||
# SPRACHE?
|
||||
hint_text: 'topic'
|
||||
mode: "round"
|
||||
|
||||
# SPRACHE
|
||||
MDLabel:
|
||||
text: 'MQTT-Benutzername'
|
||||
text: root.get_translated('mqtt-username')
|
||||
MDTextField:
|
||||
# SPRACHE?
|
||||
hint_text: 'username'
|
||||
mode: "round"
|
||||
|
||||
# SPRACHE
|
||||
MDLabel:
|
||||
text: 'MQTT-Passwort'
|
||||
text: root.get_translated('mqtt-password')
|
||||
MDTextField:
|
||||
password: True
|
||||
mode: "round"
|
||||
|
||||
Reference in New Issue
Block a user