Merge branch 'add_ui_multilingual_support' into develop

This commit is contained in:
misygauziya
2023-07-13 09:17:12 +09:00
6 changed files with 1017 additions and 700 deletions

136
VRCT.py
View File

@@ -8,11 +8,11 @@ from customtkinter import CTk, CTkFrame, CTkCheckBox, CTkFont, CTkButton, CTkIma
from PIL.Image import open as Image_open from PIL.Image import open as Image_open
from flashtext import KeywordProcessor 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 osc_tools import send_typing, send_message
from window_config import ToplevelWindowConfig from window_config import ToplevelWindowConfig
from window_information import ToplevelWindowInformation 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_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_recorder import SelectedMicRecorder, SelectedSpeakerRecorder
from audio_transcriber import AudioTranscriber from audio_transcriber import AudioTranscriber
@@ -39,6 +39,7 @@ class App(CTk):
self.APPEARANCE_THEME = "System" self.APPEARANCE_THEME = "System"
self.UI_SCALING = "100%" self.UI_SCALING = "100%"
self.FONT_FAMILY = "Yu Gothic UI" self.FONT_FAMILY = "Yu Gothic UI"
self.UI_LANGUAGE = "en"
## Translation ## Translation
self.CHOICE_TRANSLATOR = translators[0] self.CHOICE_TRANSLATOR = translators[0]
self.INPUT_SOURCE_LANG = list(translation_lang[self.CHOICE_TRANSLATOR].keys())[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 "FONT_FAMILY" in config.keys():
if config["FONT_FAMILY"] in list(tk.font.families()): if config["FONT_FAMILY"] in list(tk.font.families()):
self.FONT_FAMILY = config["FONT_FAMILY"] 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 # translation
if "CHOICE_TRANSLATOR" in config.keys(): if "CHOICE_TRANSLATOR" in config.keys():
@@ -208,6 +212,7 @@ class App(CTk):
"TRANSPARENCY": self.TRANSPARENCY, "TRANSPARENCY": self.TRANSPARENCY,
"APPEARANCE_THEME": self.APPEARANCE_THEME, "APPEARANCE_THEME": self.APPEARANCE_THEME,
"UI_SCALING": self.UI_SCALING, "UI_SCALING": self.UI_SCALING,
"UI_LANGUAGE": self.UI_LANGUAGE,
"FONT_FAMILY": self.FONT_FAMILY, "FONT_FAMILY": self.FONT_FAMILY,
"CHOICE_TRANSLATOR": self.CHOICE_TRANSLATOR, "CHOICE_TRANSLATOR": self.CHOICE_TRANSLATOR,
"INPUT_SOURCE_LANG": self.INPUT_SOURCE_LANG, "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(row=0, column=0, rowspan=4, sticky="nsw")
self.sidebar_frame.grid_rowconfigure(5, weight=1) self.sidebar_frame.grid_rowconfigure(5, weight=1)
init_lang_text = "Loading..."
# add checkbox translation # add checkbox translation
self.checkbox_translation = CTkCheckBox( self.checkbox_translation = CTkCheckBox(
self.sidebar_frame, self.sidebar_frame,
text="translation", text=init_lang_text,
onvalue=True, onvalue=True,
offvalue=False, offvalue=False,
command=self.checkbox_translation_callback, command=self.checkbox_translation_callback,
@@ -269,7 +276,7 @@ class App(CTk):
# add checkbox transcription send # add checkbox transcription send
self.checkbox_transcription_send = CTkCheckBox( self.checkbox_transcription_send = CTkCheckBox(
self.sidebar_frame, self.sidebar_frame,
text="voice2chatbox", text=init_lang_text,
onvalue=True, onvalue=True,
offvalue=False, offvalue=False,
command=self.checkbox_transcription_send_callback, command=self.checkbox_transcription_send_callback,
@@ -280,7 +287,7 @@ class App(CTk):
# add checkbox transcription receive # add checkbox transcription receive
self.checkbox_transcription_receive = CTkCheckBox( self.checkbox_transcription_receive = CTkCheckBox(
self.sidebar_frame, self.sidebar_frame,
text="speaker2log", text=init_lang_text,
onvalue=True, onvalue=True,
offvalue=False, offvalue=False,
command=self.checkbox_transcription_receive_callback, command=self.checkbox_transcription_receive_callback,
@@ -291,7 +298,7 @@ class App(CTk):
# add checkbox foreground # add checkbox foreground
self.checkbox_foreground = CTkCheckBox( self.checkbox_foreground = CTkCheckBox(
self.sidebar_frame, self.sidebar_frame,
text="foreground", text=init_lang_text,
onvalue=True, onvalue=True,
offvalue=False, offvalue=False,
command=self.checkbox_foreground_callback, 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.button_config.grid(row=5, column=1, padx=(5, 10), pady=(5, 5), sticky="wse")
self.config_window = None self.config_window = None
# load ui language data
language_yaml_data = get_localized_text(f"{self.UI_LANGUAGE}")
# add tabview textbox # add tabview textbox
self.tabview_logs = CTkTabview(master=self) self.add_tabview_logs(language_yaml_data)
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')
# add entry message box # add entry message box
self.entry_message_box = CTkEntry( self.entry_message_box = CTkEntry(
@@ -667,6 +628,71 @@ class App(CTk):
self.quit() self.quit()
self.destroy() 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__": if __name__ == "__main__":
try: try:
app = App() app = App()

View File

@@ -278,4 +278,10 @@ translation_lang["Bing(web)"] = {
"telugu":"te", "telugu":"te",
"punjabi":"pa", "punjabi":"pa",
"irish":"ga" "irish":"ga"
}
selectable_languages = {
"en": "English",
"ja": "日本語",
# 新しい言語とキーを追加する場合はここに追記してください
} }

125
locales.yml Normal file
View 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: "送信後はチャットボックスを空にする"

View File

@@ -3,4 +3,5 @@ PyAudioWPatch
python-osc python-osc
customtkinter customtkinter
deepl deepl
flashtext flashtext
pyyaml

View File

@@ -1,4 +1,6 @@
from json import load, dump from json import load, dump
from os import path as os_path
import yaml
from datetime import datetime from datetime import datetime
from threading import Thread, Event from threading import Thread, Event
@@ -38,4 +40,91 @@ class thread_fnc(Thread):
while True: while True:
if self.stopped(): if self.stopped():
return return
self.fnc(*self._args, **self._kwargs) 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)

File diff suppressed because it is too large Load Diff