Merge branch 'add_ui_multilingual_support' into develop
This commit is contained in:
136
VRCT.py
136
VRCT.py
@@ -8,11 +8,11 @@ from customtkinter import CTk, CTkFrame, CTkCheckBox, CTkFont, CTkButton, CTkIma
|
||||
from PIL.Image import open as Image_open
|
||||
from flashtext import KeywordProcessor
|
||||
|
||||
from utils import save_json, print_textbox, thread_fnc
|
||||
from utils import save_json, print_textbox, thread_fnc, get_localized_text, widget_main_window_label_setter
|
||||
from osc_tools import send_typing, send_message
|
||||
from window_config import ToplevelWindowConfig
|
||||
from window_information import ToplevelWindowInformation
|
||||
from languages import transcription_lang, translators, translation_lang
|
||||
from languages import transcription_lang, translators, translation_lang, selectable_languages
|
||||
from audio_utils import get_input_device_list, get_output_device_list, get_default_input_device, get_default_output_device
|
||||
from audio_recorder import SelectedMicRecorder, SelectedSpeakerRecorder
|
||||
from audio_transcriber import AudioTranscriber
|
||||
@@ -39,6 +39,7 @@ class App(CTk):
|
||||
self.APPEARANCE_THEME = "System"
|
||||
self.UI_SCALING = "100%"
|
||||
self.FONT_FAMILY = "Yu Gothic UI"
|
||||
self.UI_LANGUAGE = "en"
|
||||
## Translation
|
||||
self.CHOICE_TRANSLATOR = translators[0]
|
||||
self.INPUT_SOURCE_LANG = list(translation_lang[self.CHOICE_TRANSLATOR].keys())[0]
|
||||
@@ -108,6 +109,9 @@ class App(CTk):
|
||||
if "FONT_FAMILY" in config.keys():
|
||||
if config["FONT_FAMILY"] in list(tk.font.families()):
|
||||
self.FONT_FAMILY = config["FONT_FAMILY"]
|
||||
if "UI_LANGUAGE" in config.keys():
|
||||
if config["UI_LANGUAGE"] in list(selectable_languages.keys()):
|
||||
self.UI_LANGUAGE = config["UI_LANGUAGE"]
|
||||
|
||||
# translation
|
||||
if "CHOICE_TRANSLATOR" in config.keys():
|
||||
@@ -208,6 +212,7 @@ class App(CTk):
|
||||
"TRANSPARENCY": self.TRANSPARENCY,
|
||||
"APPEARANCE_THEME": self.APPEARANCE_THEME,
|
||||
"UI_SCALING": self.UI_SCALING,
|
||||
"UI_LANGUAGE": self.UI_LANGUAGE,
|
||||
"FONT_FAMILY": self.FONT_FAMILY,
|
||||
"CHOICE_TRANSLATOR": self.CHOICE_TRANSLATOR,
|
||||
"INPUT_SOURCE_LANG": self.INPUT_SOURCE_LANG,
|
||||
@@ -255,10 +260,12 @@ class App(CTk):
|
||||
self.sidebar_frame.grid(row=0, column=0, rowspan=4, sticky="nsw")
|
||||
self.sidebar_frame.grid_rowconfigure(5, weight=1)
|
||||
|
||||
init_lang_text = "Loading..."
|
||||
|
||||
# add checkbox translation
|
||||
self.checkbox_translation = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="translation",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_translation_callback,
|
||||
@@ -269,7 +276,7 @@ class App(CTk):
|
||||
# add checkbox transcription send
|
||||
self.checkbox_transcription_send = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="voice2chatbox",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_transcription_send_callback,
|
||||
@@ -280,7 +287,7 @@ class App(CTk):
|
||||
# add checkbox transcription receive
|
||||
self.checkbox_transcription_receive = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="speaker2log",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_transcription_receive_callback,
|
||||
@@ -291,7 +298,7 @@ class App(CTk):
|
||||
# add checkbox foreground
|
||||
self.checkbox_foreground = CTkCheckBox(
|
||||
self.sidebar_frame,
|
||||
text="foreground",
|
||||
text=init_lang_text,
|
||||
onvalue=True,
|
||||
offvalue=False,
|
||||
command=self.checkbox_foreground_callback,
|
||||
@@ -321,56 +328,10 @@ class App(CTk):
|
||||
self.button_config.grid(row=5, column=1, padx=(5, 10), pady=(5, 5), sticky="wse")
|
||||
self.config_window = None
|
||||
|
||||
# load ui language data
|
||||
language_yaml_data = get_localized_text(f"{self.UI_LANGUAGE}")
|
||||
# add tabview textbox
|
||||
self.tabview_logs = CTkTabview(master=self)
|
||||
self.tabview_logs.add("log")
|
||||
self.tabview_logs.add("send")
|
||||
self.tabview_logs.add("receive")
|
||||
self.tabview_logs.add("system")
|
||||
self.tabview_logs.grid(row=0, column=1, padx=0, pady=0, sticky="nsew")
|
||||
self.tabview_logs._segmented_button.configure(font=CTkFont(family=self.FONT_FAMILY))
|
||||
self.tabview_logs._segmented_button.grid(sticky="W")
|
||||
self.tabview_logs.tab("log").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("log").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("send").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("send").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("receive").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("receive").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("system").grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab("system").grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.configure(fg_color="transparent")
|
||||
|
||||
# add textbox message log
|
||||
self.textbox_message_log = CTkTextbox(
|
||||
self.tabview_logs.tab("log"),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_log.configure(state='disabled')
|
||||
|
||||
# add textbox message send log
|
||||
self.textbox_message_send_log = CTkTextbox(
|
||||
self.tabview_logs.tab("send"),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_send_log.configure(state='disabled')
|
||||
|
||||
# add textbox message receive log
|
||||
self.textbox_message_receive_log = CTkTextbox(
|
||||
self.tabview_logs.tab("receive"),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_receive_log.configure(state='disabled')
|
||||
|
||||
# add textbox message system log
|
||||
self.textbox_message_system_log = CTkTextbox(
|
||||
self.tabview_logs.tab("system"),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_system_log.configure(state='disabled')
|
||||
self.add_tabview_logs(language_yaml_data)
|
||||
|
||||
# add entry message box
|
||||
self.entry_message_box = CTkEntry(
|
||||
@@ -667,6 +628,71 @@ class App(CTk):
|
||||
self.quit()
|
||||
self.destroy()
|
||||
|
||||
def delete_tabview_logs(self, pre_language_yaml_data):
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_log"])
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_send"])
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_receive"])
|
||||
self.tabview_logs.delete(pre_language_yaml_data["main_tab_title_system"])
|
||||
|
||||
def add_tabview_logs(self, language_yaml_data):
|
||||
main_tab_title_log = language_yaml_data["main_tab_title_log"]
|
||||
main_tab_title_send = language_yaml_data["main_tab_title_send"]
|
||||
main_tab_title_receive = language_yaml_data["main_tab_title_receive"]
|
||||
main_tab_title_system = language_yaml_data["main_tab_title_system"]
|
||||
|
||||
# add tabview textbox
|
||||
self.tabview_logs = CTkTabview(master=self)
|
||||
self.tabview_logs.add(main_tab_title_log)
|
||||
self.tabview_logs.add(main_tab_title_send)
|
||||
self.tabview_logs.add(main_tab_title_receive)
|
||||
self.tabview_logs.add(main_tab_title_system)
|
||||
self.tabview_logs.grid(row=0, column=1, padx=0, pady=0, sticky="nsew")
|
||||
self.tabview_logs._segmented_button.configure(font=CTkFont(family=self.FONT_FAMILY))
|
||||
self.tabview_logs._segmented_button.grid(sticky="W")
|
||||
self.tabview_logs.tab(main_tab_title_log).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_log).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_send).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_send).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_receive).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_receive).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_system).grid_rowconfigure(0, weight=1)
|
||||
self.tabview_logs.tab(main_tab_title_system).grid_columnconfigure(0, weight=1)
|
||||
self.tabview_logs.configure(fg_color="transparent")
|
||||
|
||||
# add textbox message log
|
||||
self.textbox_message_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_log),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_log.configure(state='disabled')
|
||||
|
||||
# add textbox message send log
|
||||
self.textbox_message_send_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_send),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_send_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_send_log.configure(state='disabled')
|
||||
|
||||
# add textbox message receive log
|
||||
self.textbox_message_receive_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_receive),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_receive_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_receive_log.configure(state='disabled')
|
||||
|
||||
# add textbox message system log
|
||||
self.textbox_message_system_log = CTkTextbox(
|
||||
self.tabview_logs.tab(main_tab_title_system),
|
||||
font=CTkFont(family=self.FONT_FAMILY)
|
||||
)
|
||||
self.textbox_message_system_log.grid(row=0, column=0, padx=0, pady=0, sticky="nsew")
|
||||
self.textbox_message_system_log.configure(state='disabled')
|
||||
|
||||
widget_main_window_label_setter(self, language_yaml_data)
|
||||
|
||||
if __name__ == "__main__":
|
||||
try:
|
||||
app = App()
|
||||
|
||||
@@ -279,3 +279,9 @@ translation_lang["Bing(web)"] = {
|
||||
"punjabi":"pa",
|
||||
"irish":"ga"
|
||||
}
|
||||
|
||||
selectable_languages = {
|
||||
"en": "English",
|
||||
"ja": "日本語",
|
||||
# 新しい言語とキーを追加する場合はここに追記してください
|
||||
}
|
||||
125
locales.yml
Normal file
125
locales.yml
Normal file
@@ -0,0 +1,125 @@
|
||||
en:
|
||||
# main window
|
||||
checkbox_translation: "Translation"
|
||||
checkbox_transcription_send: "Voice2chatbox"
|
||||
checkbox_transcription_receive: "Speaker2log"
|
||||
checkbox_foreground: "Foreground"
|
||||
|
||||
# main tabview
|
||||
main_tab_title_log: "Log"
|
||||
main_tab_title_send: "Send"
|
||||
main_tab_title_receive: "Receive"
|
||||
main_tab_title_system: "System"
|
||||
|
||||
|
||||
# configure window
|
||||
# config tabview
|
||||
config_tab_title_ui: "UI"
|
||||
config_tab_title_translation: "Translation"
|
||||
config_tab_title_transcription: "Transcription"
|
||||
config_tab_title_parameter: "Parameter"
|
||||
config_tab_title_others: "Others"
|
||||
# tab UI
|
||||
label_transparency: "Transparency"
|
||||
label_appearance_theme: "Appearance Theme"
|
||||
label_ui_scaling: "UI Scaling"
|
||||
label_font_family: "Font Family"
|
||||
label_ui_language: "UI Language"
|
||||
|
||||
# tab Translation
|
||||
label_translation_translator: "Select Translator"
|
||||
label_translation_input_language: "Send Language"
|
||||
label_translation_output_language: "Receive Language"
|
||||
|
||||
# tab Transcription
|
||||
label_input_mic_host: "Input Mic Host"
|
||||
label_input_mic_device: "Input Mic Device"
|
||||
label_input_mic_voice_language: "Input Mic Voice Language"
|
||||
label_input_mic_energy_threshold: "Input Mic Energy Threshold"
|
||||
checkbox_input_mic_threshold_check: "Check threshold point"
|
||||
label_input_mic_dynamic_energy_threshold: "Input Mic Dynamic Energy Threshold"
|
||||
label_input_mic_record_timeout: "Input Mic Record Timeout"
|
||||
label_input_mic_phrase_timeout: "Input Mic Phrase Timeout"
|
||||
label_input_mic_max_phrases: "Input Mic Max Phrases"
|
||||
label_input_mic_word_filter: "Input Mic Word Filter"
|
||||
|
||||
label_input_speaker_device: "Input Speaker Device"
|
||||
label_input_speaker_voice_language: "Input Speaker Voice Language"
|
||||
label_input_speaker_energy_threshold: "Input Speaker Energy Threshold"
|
||||
checkbox_input_speaker_threshold_check: "Check threshold point"
|
||||
label_input_speaker_dynamic_energy_threshold: "Input Speaker Dynamic Energy Threshold"
|
||||
label_input_speaker_record_timeout: "Input Speaker Record Timeout"
|
||||
label_input_speaker_phrase_timeout: "Input Speaker Phrase Timeout"
|
||||
label_input_speaker_max_phrases: "Input Speaker Max Phrases"
|
||||
|
||||
# tab Parameter
|
||||
label_ip_address: "OSC IP address"
|
||||
label_port: "OSC Port"
|
||||
label_authkey: "DeepL Auth Key"
|
||||
label_message_format: "Message Format"
|
||||
|
||||
# tab Others
|
||||
label_checkbox_auto_clear_chatbox: "Auto clear chat box"
|
||||
|
||||
|
||||
ja:
|
||||
# main window
|
||||
checkbox_translation: "翻訳"
|
||||
checkbox_transcription_send: "マイク->チャットボックス"
|
||||
checkbox_transcription_receive: "スピーカー->ログ"
|
||||
checkbox_foreground: "最前面表示"
|
||||
|
||||
# main tabview
|
||||
main_tab_title_log: "ログ"
|
||||
main_tab_title_send: "送信"
|
||||
main_tab_title_receive: "受信"
|
||||
main_tab_title_system: "システム"
|
||||
|
||||
|
||||
# configure window
|
||||
# config tabview
|
||||
config_tab_title_ui: "UI"
|
||||
config_tab_title_translation: "翻訳方法"
|
||||
config_tab_title_transcription: "音声認識"
|
||||
config_tab_title_parameter: "パラメーター"
|
||||
config_tab_title_others: "その他"
|
||||
|
||||
# tab UI
|
||||
label_transparency: "透過度"
|
||||
label_appearance_theme: "外観テーマを選択"
|
||||
label_ui_scaling: "UIの拡大縮小"
|
||||
label_font_family: "使用フォントの変更"
|
||||
label_ui_language: "UI 言語"
|
||||
|
||||
# tab Translation
|
||||
label_translation_translator: "翻訳エンジンの選択"
|
||||
label_translation_input_language: "送信言語-->翻訳言語"
|
||||
label_translation_output_language: "受信言語-->翻訳言語"
|
||||
|
||||
# tab Transcription
|
||||
label_input_mic_host: "マイク入力ホスト"
|
||||
label_input_mic_device: "マイク入力デバイス"
|
||||
label_input_mic_voice_language: "マイクで話す言語"
|
||||
label_input_mic_energy_threshold: "音声取得のしきい値"
|
||||
label_input_mic_dynamic_energy_threshold: "音声取得のしきい値の自動調整"
|
||||
label_input_mic_record_timeout: "マイク音声の区切りの無音時間"
|
||||
# label_input_mic_phrase_timeout: ""
|
||||
label_input_mic_max_phrases: "保留する単語の上限(マイク)"
|
||||
|
||||
label_input_speaker_device: "スピーカー(聞き取りたいデバイス)"
|
||||
label_input_speaker_voice_language: "聞き取る音声の言語"
|
||||
label_input_speaker_energy_threshold: "音声取得のしきい値"
|
||||
label_input_speaker_dynamic_energy_threshold: "音声取得のしきい値の自動調整"
|
||||
label_input_speaker_record_timeout: "スピーカー音声の区切りの無音時間"
|
||||
# label_input_speaker_phrase_timeout: ""
|
||||
label_input_speaker_max_phrases: "保留する単語の上限(スピーカー)"
|
||||
|
||||
# tab Parameter
|
||||
# label_ip_address: ""
|
||||
# label_port: ""
|
||||
# label_authkey: ""
|
||||
label_message_format: "送信するメッセージのフォーマット"
|
||||
|
||||
# tab Others
|
||||
label_checkbox_auto_clear_chatbox: "送信後はチャットボックスを空にする"
|
||||
|
||||
@@ -4,3 +4,4 @@ python-osc
|
||||
customtkinter
|
||||
deepl
|
||||
flashtext
|
||||
pyyaml
|
||||
89
utils.py
89
utils.py
@@ -1,4 +1,6 @@
|
||||
from json import load, dump
|
||||
from os import path as os_path
|
||||
import yaml
|
||||
from datetime import datetime
|
||||
from threading import Thread, Event
|
||||
|
||||
@@ -39,3 +41,90 @@ class thread_fnc(Thread):
|
||||
if self.stopped():
|
||||
return
|
||||
self.fnc(*self._args, **self._kwargs)
|
||||
|
||||
def get_localized_text(language):
|
||||
file_path = os_path.join(os_path.dirname(__file__), "locales.yml")
|
||||
|
||||
with open(file_path, encoding="utf-8") as file:
|
||||
languages_yaml_data = yaml.safe_load(file)
|
||||
default_language = "en"
|
||||
if language in languages_yaml_data:
|
||||
localized_text = languages_yaml_data[language]
|
||||
if default_language in languages_yaml_data:
|
||||
default_text = languages_yaml_data[default_language]
|
||||
merged_text = {**default_text, **localized_text}
|
||||
return merged_text
|
||||
else:
|
||||
return localized_text
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_key_by_value(dictionary, value):
|
||||
for key, val in dictionary.items():
|
||||
if val == value:
|
||||
return key
|
||||
return None
|
||||
|
||||
def widget_config_window_label_setter(self, language_yaml_data):
|
||||
widget_names = [
|
||||
# tab UI
|
||||
"label_transparency",
|
||||
"label_appearance_theme",
|
||||
"label_ui_scaling",
|
||||
"label_font_family",
|
||||
"label_ui_language",
|
||||
|
||||
# tab Translation
|
||||
"label_translation_translator",
|
||||
"label_translation_input_language",
|
||||
"label_translation_output_language",
|
||||
|
||||
# tab Transcription
|
||||
"label_input_mic_host",
|
||||
"label_input_mic_device",
|
||||
"label_input_mic_voice_language",
|
||||
"label_input_mic_energy_threshold",
|
||||
"checkbox_input_mic_threshold_check",
|
||||
"label_input_mic_dynamic_energy_threshold",
|
||||
"label_input_mic_record_timeout",
|
||||
"label_input_mic_phrase_timeout",
|
||||
"label_input_mic_max_phrases",
|
||||
"label_input_mic_word_filter",
|
||||
|
||||
"label_input_speaker_device",
|
||||
"label_input_speaker_voice_language",
|
||||
"label_input_speaker_energy_threshold",
|
||||
"checkbox_input_speaker_threshold_check",
|
||||
"label_input_speaker_dynamic_energy_threshold",
|
||||
"label_input_speaker_record_timeout",
|
||||
"label_input_speaker_phrase_timeout",
|
||||
"label_input_speaker_max_phrases",
|
||||
|
||||
|
||||
# tab Parameter
|
||||
"label_ip_address",
|
||||
"label_port",
|
||||
"label_authkey",
|
||||
"label_message_format",
|
||||
|
||||
# tab Others
|
||||
"label_checkbox_auto_clear_chatbox"
|
||||
]
|
||||
for name in widget_names:
|
||||
widget = getattr(self, name)
|
||||
text_value = language_yaml_data.get(name)
|
||||
if widget is not None and text_value is not None:
|
||||
widget.configure(text=text_value + ":")
|
||||
|
||||
def widget_main_window_label_setter(self, language_yaml_data):
|
||||
widget_names = [
|
||||
"checkbox_translation",
|
||||
"checkbox_transcription_send",
|
||||
"checkbox_transcription_receive",
|
||||
"checkbox_foreground",
|
||||
]
|
||||
for name in widget_names:
|
||||
widget = getattr(self, name)
|
||||
text_value = language_yaml_data.get(name)
|
||||
if widget is not None and text_value is not None:
|
||||
widget.configure(text=text_value)
|
||||
1354
window_config.py
1354
window_config.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user