I'm encountering an error when attempting to change the language in my Tkinter application. The application has a button that, when clicked, is supposed to change the language displayed on the UI elements and update the tooltips accordingly. changing UI elements language is working but I'm getting error from tooltips. I have separated file and method which is changing languages for all elements (buttons)I wanted to add part where I change tooltip language too. The method is called when I click on button that is changing language.
main file
lang_manager = LanguageManager(current_language="en")
for i, addon in enumerate(addon_db_url):
addon_var = tk.BooleanVar()
addon_vars.append(addon_var)
addon_checkbox = cus.CTkCheckBox(addon_frame, fg_color="#0a4a0c", hover_color="#0c6e0f", text=addon["Name"], text_color="#f7f5ed", variable=addon_var)
addon_checkbox.pack(anchor="w", pady=(0, 2))
CTkToolTip(addon_checkbox, message=lang_manager.addon_tooltips_en[i], delay=0.2)
addon_var.trace_add("write", lambda *args: check_addon_selection(addon_db_url, download_button_addon))
addon["var"] = addon_var
def change_and_map_language():
lang_manager.change_language(language_button, download_button_addon, download_button_patches,
default_location_button, check_detection_button, launch_wow_button, addon_db_url)
lang_manager.tooltip_mapper(addon_checkbox, addon_db_url)
language_button = cus.CTkButton(master=window, command=change_and_map_language)
I'm using CTkToolTip here bcz default language of app is English. I tried to separate methods one for changing ui's language (buttons) and one for tooltips.
file for changing language
class LanguageManager:
def __init__(self, current_language):
self.current_language = current_language
self.addon_tooltips_en = [
"text_eng",
"text_eng2",
"text_eng3",
"text_eng4",
... ]
self.current_language = current_language
self.addon_tooltips_geo = [
"text_b",
"text_b2",
"text_b3",
"text_b4",
... ]
def tooltip_mapper(self, addon_chckboxes, addon_db_url):
if self.current_language == "ge":
for i, addon_chckboxes in enumerate(addon_db_url):
CTkToolTip(addon_chckboxes, message=self.addon_tooltips_en[i], delay=0.2)
else:
for i, addon_chckboxes in enumerate(addon_db_url):
CTkToolTip(addon_chckboxes, message=self.addon_tooltips_geo[i], delay=0.2)
def change_language(self, language_button, download_button_addon, download_button_patches,
default_location_button, check_detection_button, launch_wow_button):
if self.current_language == "ge":
self.current_language = "en"
language_button.configure(image=img_lang_en, text="ENG")
download_button_addon.configure(text="Download Addons", width=150, height=45, font=("cursive", 18))
download_button_patches.configure(text="Download Patches", width=150, height=45, font=("cursive", 18))
default_location_button.configure(text="Choose Default Location", width=200, height=50, font=("cursive", 18))
check_detection_button.configure(text="Check Downloads", width=170, height=45, font=("cursive", 18))
launch_wow_button.configure(text="Start The Game", width=150, height=50, font=("cursive", 18))
else:
self.current_language = "ge"
language_button.configure(image=img_lang_geo, text="GEO")
download_button_addon.configure(text=" changed text", width=150, height=45, font=("Arial", 20, 'bold'))
download_button_patches.configure(text=" changed text", width=150, height=45, font=("Arial", 20, 'bold'))
default_location_button.configure(text=" changed text", width=200, height=50, font=("Arial", 20, 'bold'))
check_detection_button.configure(text=" changed text", width=170, height=45, font=("Arial", 20, 'bold'))
launch_wow_button.configure(text=" changed text", width=150, height=50, font=("Arial", 20, 'bold'))
When I run app tooltip on everycheckbox working fine but when I click on language_button I'm getting this error
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\tkinter\__init__.py", line 1967, in __call__
return self.func(*args)
^^^^^^^^^^^^^^^^
File "C:\Users\AppData\Local\Programs\Python\Python312\Lib\site-packages\customtkinter\windows\widgets\ctk_button.py", line 554, in _clicked
self._command()
File "C:\Users\user\Desktop\app", line 293, in change_and_map_language
lang_manager.tooltip_mapper(addon_checkbox, addon_db_url)
File "C:\Users\user\Desktop\-main\Lang_manager.py", line 73, in tooltip_mapper
CTkToolTip(addon_chckboxes, message=self.addon_tooltips_en[i], delay=0.2)
File "C:\Users\user\AppData\Local\Programs\Python\Python312\Lib\site-packages\CTkToolTip\ctk_tooltip.py", line 42, in __init__
self.transparent_color = self.widget._apply_appearance_mode(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'dict' object has no attribute '_apply_appearance_mode'
addon_db_url is a .json file which I using like this:
core.py class utils
class Utils:
def __init__(self, lang_manager):
self.lang_manager = lang_manager
self.config_file = "config.json"
self.config = self.load_config()
def load_addon_urls(self):
bundle_dir = self.get_bundle_dir()
addon_json_path = os.path.join(bundle_dir, 'json', 'addon_wotlk_db_url.json')
with open(addon_json_path, 'r') as addon_file:
return json.load(addon_file)
main file
import Core
core_utils_instance = Core.Utils()
addon_db_url = core_utils_instance.load_addon_urls()
addon_wotlk_db_url.json
[
{"Name": "addon name 1", "Url": "direct download link"},
{"Name": "addon name 2", "Url": "direct download link"},
{"Name": "addon name 3", "Url": "direct download link"},
{"Name": "addon name 4", "Url": "direct download link"},
...
]
Inside tooltip_mapper()
:
for i, addon_chckboxes in enumerate(addon_db_url):
CTkToolTip(addon_chckboxes, message=self.addon_tooltips_en[i], delay=0.2)
Since addon_db_url
is a list of dictionaries, so addon_chckboxes
is a dictionary. Exception is raised when it is passed as the first argument to CTkToolTip()
which expects the first argument is a widget.
To change the tooltip, you should use the already created instance of CTkToolTip()
instead of creating new one.
Suggestions:
LanguageManager
instead of separate instance variables:class LanguageManager:
def __init__(self, current_language="en"):
self.current_language = current_language
# use a dictionary instead of separate variables
self.addon_tooltips = {
"en": [
"text_eng",
"text_eng2",
"text_eng3",
"text_eng4",
],
"ge": [
"text_b",
"text_b2",
"text_b3",
"text_b4",
],
}
...
CTkToolTip()
:addon_tooltips = []
for i, addon in enumerate(addon_db_url):
addon_var = cus.BooleanVar()
addon_vars.append(addon_var)
addon_checkbox = cus.CTkCheckBox(addon_frame, fg_color="#0a4a0c", hover_color="#0c6e0f",
text=addon["Name"], text_color="#f7f5ed", variable=addon_var)
addon_checkbox.pack(anchor="w", pady=(0, 2))
# save the instance of CTkToolTip
addon_tooltips.append(CTkToolTip(addon_checkbox, message=lang_manager.addon_tooltips["en"][i], delay=0.2))
...
Then rewrite tooltip_mapper()
and change_and_map_language()
as below:
class LanugageManager:
...
def tooltip_mapper(self, addon_tooltips):
for i, tooltip in enumerate(addon_tooltips):
tooltip.configure(message=self.addon_tooltips[self.current_language][i])
def change_and_map_language():
...
lang_manager.tooltip_mapper(addon_tooltips)
Below is a simplified example:
import customtkinter as cus
from CTkToolTip import CTkToolTip
addon_db_url = [
{"Name": "addon name 1", "Url": "direct download link 1"},
{"Name": "addon name 2", "Url": "direct download link 2"},
{"Name": "addon name 3", "Url": "direct download link 3"},
{"Name": "addon name 4", "Url": "direct download link 4"},
]
class LanguageManager:
def __init__(self, current_language="en"):
self.current_language = current_language
self.addon_tooltips = {
"en": [
"text_eng",
"text_eng2",
"text_eng3",
"text_eng4",
],
"ge": [
"text_b",
"text_b2",
"text_b3",
"text_b4",
],
}
def change_language(self, language_button):
if self.current_language == "ge":
self.current_language = "en"
language_button.configure(text="ENG")
else:
self.current_language = "ge"
language_button.configure(text="GEO")
def tooltip_mapper(self, addon_tooltips):
for i, tooltip in enumerate(addon_tooltips):
tooltip.configure(message=self.addon_tooltips[self.current_language][i])
window = cus.CTk()
addon_frame = cus.CTkFrame(window)
addon_frame.pack(padx=100, pady=100)
addon_vars = []
addon_tooltips = []
lang_manager = LanguageManager(current_language="en")
for i, addon in enumerate(addon_db_url):
addon_var = cus.BooleanVar()
addon_vars.append(addon_var)
addon_checkbox = cus.CTkCheckBox(addon_frame, fg_color="#0a4a0c", hover_color="#0c6e0f",
text=addon["Name"], text_color="#f7f5ed", variable=addon_var)
addon_checkbox.pack(anchor="w", pady=(0, 2))
addon_tooltips.append(CTkToolTip(addon_checkbox, message=lang_manager.addon_tooltips["en"][i], delay=0.2))
def change_and_map_language():
lang_manager.change_language(language_button)
lang_manager.tooltip_mapper(addon_tooltips)
language_button = cus.CTkButton(master=window, text="ENG", command=change_and_map_language)
language_button.pack(pady=10)
window.mainloop()