-
I have several languages for my UI stored in a dictionary. which can be accessed like so: |
Beta Was this translation helpful? Give feedback.
Replies: 6 comments 6 replies
-
Thats a wonderful question. And not super easy to answer I fear. Your language lookup in the dict evaluates to a mutable string. It can not change afterwards. But NiceGUI provides a binding mechanism to auto-update data. I could not find an existing translation libs which could be used as data storage for our bindings. So here is what I came up so far: from nicegui import ui
class Translator:
def __init__(self, language: str = "en") -> None:
self.language = language
self.data = {
'de':
{
'hello_world': 'Hallo Welt',
'goodbye_world': 'Auf Wiedersehen Welt'
},
'en':
{
'hello_world': 'Hello World',
'goodbye_world': 'Goodbye World'
}
}
def set_language(self, language: str) -> None:
self.language = language
@staticmethod
def get_key() -> str:
return str(inspect.stack()[1][3])
@property
def hello_world(self) -> str:
return self.data[self.language][self.get_key()]
@property
def goodbye_world(self):
return self.data[self.language][self.get_key()]
t = Translator()
ui.label().bind_text(t, 'hello_world')
ui.toggle(['en', 'de'], value='en', on_change=lambda e: t.set_language(e.value))
ui.run() The repeating of |
Beta Was this translation helpful? Give feedback.
-
Maybe it's better to bind against the language property which is only a string? class Translator:
def __init__(self, language: str = "en") -> None:
self.language = language
self.data = {
'de':
{
'hello_world': 'Hallo Welt',
'goodbye': 'Auf Wiedersehen'
},
'en':
{
'hello_world': 'Hello World',
'goodbye': 'Goodbye'
}
}
def set_language(self, language: str) -> None:
self.language = language
def get(self, key: str) -> str:
return self.data[self.language][key]
t = Translator()
ui.toggle(['en', 'de'], value='en', on_change=lambda e: t.set_language(e.value))
ui.label().bind_text_from(t, 'language', backward=lambda _: t.get('hello_world'))
ui.label().bind_text_from(t, 'language', backward=lambda _: t.get('goodbye')) |
Beta Was this translation helpful? Give feedback.
-
A bit nicer if english is used as lookup key: class Translator:
def __init__(self, language: str = "en") -> None:
self.language = language
self.data = {
'Hello World':
{
'de': 'Hallo Welt',
'fr': 'Bonjour le monde'
},
'Goodbye':
{
'de': 'Auf Wiedersehen',
'fr': 'Au revoir'
}
}
def set_language(self, language: str) -> None:
self.language = language
def __call__(self, key: str) -> str:
if self.language == 'en':
return key
return self.data[key][self.language]
t = Translator()
ui.toggle(['en', 'de', 'fr'], value='en', on_change=lambda e: t.set_language(e.value))
ui.label().bind_text_from(t, 'language', backward=lambda _: t('Hello World'))
ui.label().bind_text_from(t, 'language', backward=lambda _: t('Goodbye')) |
Beta Was this translation helpful? Give feedback.
-
Or with subclassing label: class Translator:
def __init__(self, language: str = "en") -> None:
self.language = language
self.data = {
'Hello World':
{
'de': 'Hallo Welt',
'fr': 'Bonjour le monde'
},
'Goodbye':
{
'de': 'Auf Wiedersehen',
'fr': 'Au revoir'
}
}
def set_language(self, language: str) -> None:
self.language = language
def __call__(self, key: str) -> str:
if self.language == 'en':
return key
return self.data[key][self.language]
t = Translator()
ui.toggle(['en', 'de', 'fr'], value='en', on_change=lambda e: t.set_language(e.value))
class label_i18n(ui.label):
def __init__(self, text: str = '') -> None:
super().__init__(t(text))
self.bind_text_from(t, 'language', backward=lambda _: t(text))
label_i18n('Hello World')
label_i18n('Goodbye')
ui.run() Maybe we could integrate something like this into NiceGUI core? What do you think? |
Beta Was this translation helpful? Give feedback.
-
My solution now... JSON data imported as 'data': {
"de": {
"id": "de",
"name": "Deutsch",
"flag": "de",
"pin_wrong": "PIN falsch",
"panel0_title": "Willkommen",
"active": true
},
"en": {
"id": "en",
"name": "English",
"flag": "en",
"pin_wrong": "PIN incorrect",
"panel0_title": "Welcome",
"active": true
}
} Select Dropdown on homepage: language_dict = {}
for i, languages in enumerate(t.data):
if list(t.data.values())[i]["active"] == True:
language_dict.update({list(t.data.keys())[i] : list(t.data.values())[i]["name"]})
if settings["language_select"] == True and len(language_dict) > 1:
language_dropdown = ui.select(language_dict, value=settings["language_default"], on_change=lambda e: t.set_language(e.value)) Then use like: ui.label().bind_text_from(t, 'language', backward=lambda _: t.get('panel0_title')) Question would be if this could be bound to all elements (?), as panels dont seem to work? |
Beta Was this translation helpful? Give feedback.
-
@falkoschindler thanks for reminding me about re-generating the whole UI. I think this is the way to go: class Translator:
def __init__(self, language: str = "en") -> None:
self.language = language
self.data = {
'Hello World':
{
'de': 'Hallo Welt',
'fr': 'Bonjour le monde'
},
'Goodbye':
{
'de': 'Auf Wiedersehen',
'fr': 'Au revoir'
}
}
def __call__(self, key: str) -> str:
if self.language == 'en':
return key
return self.data[key][self.language]
@ui.page('/')
@ui.page('/{language}')
def index(language: str = 'en'):
t = Translator(language)
ui.toggle(['en', 'de', 'fr'], value=t.language, on_change=lambda e: ui.open(f'/{e.value}'))
ui.label(t('Hello World'))
ui.label(t('Goodbye')) In this code snipped I use a simple Translator class. But the benefit of this approach is the compatibility to all the great translation packages which are already available for Pyhthon like Babel, gettext, PyICU or polib, to name a few. You can easily replace the translation class mechanism with any of these packages to provide more comprehensive and manageable translations. |
Beta Was this translation helpful? Give feedback.
My solution now...
JSON data imported as 'data':
Select Dropdown on homepage: