diff --git a/locales/en.yml b/locales/en.yml index 1faf9639..5dabb4b2 100644 --- a/locales/en.yml +++ b/locales/en.yml @@ -250,6 +250,13 @@ config_page: received_message_format: label: "Message Format (Speaker2Chatbox)" desc: "Currently, it is used in Speaker2Chatbox." + convert_message_to_romaji: + label: Show Romaji + desc: Supported only when Japanese is selected as the translation language. When enabled along with '{{convert_message_to_hiragana}}', romaji will be shown on mouse hover. + convert_message_to_hiragana: + label: Show Hiragana + desc: Supported only when Japanese is selected as the translation language. + hotkeys: toggle_vrct_visibility: diff --git a/locales/ja.yml b/locales/ja.yml index d3da554e..b4097a9a 100644 --- a/locales/ja.yml +++ b/locales/ja.yml @@ -250,6 +250,12 @@ config_page: received_message_format: label: メッセージフォーマット(Speaker2Chatbox) desc: 今のところ、Speaker2Chatboxで送信した時の表示に使われます。 + convert_message_to_romaji: + label: ローマ字を表示 + desc: 翻訳言語として日本語を選択した時のみサポート。「{{convert_message_to_hiragana}}」と同時に有効にした場合は、マウスホバーで表示されます。 + convert_message_to_hiragana: + label: ひらがなを表示 + desc: 翻訳言語として日本語を選択した時のみサポート。 hotkeys: toggle_vrct_visibility: diff --git a/src-ui/app/config_page/setting_section/setting_box/others/Others.jsx b/src-ui/app/config_page/setting_section/setting_box/others/Others.jsx index 65027ef3..5ef39ce0 100644 --- a/src-ui/app/config_page/setting_section/setting_box/others/Others.jsx +++ b/src-ui/app/config_page/setting_section/setting_box/others/Others.jsx @@ -45,6 +45,10 @@ export const Others = () => { +
+ + +
); }; @@ -201,4 +205,35 @@ const ReceivedMessageFormatPartsContainer = () => { format_id="received" /> ); +}; + +const ConvertMessageToRomajiContainer = () => { + const { t } = useI18n(); + const { currentConvertMessageToRomaji, toggleConvertMessageToRomaji } = useOthers(); + + return ( + + ); +}; + +const ConvertMessageToHiraganaContainer = () => { + const { t } = useI18n(); + const { currentConvertMessageToHiragana, toggleConvertMessageToHiragana } = useOthers(); + + return ( + + ); }; \ No newline at end of file diff --git a/src-ui/app/main_page/main_section/message_container/log_box/message_container/MessageContainer.jsx b/src-ui/app/main_page/main_section/message_container/log_box/message_container/MessageContainer.jsx index d982f27c..cd36754d 100644 --- a/src-ui/app/main_page/main_section/message_container/log_box/message_container/MessageContainer.jsx +++ b/src-ui/app/main_page/main_section/message_container/log_box/message_container/MessageContainer.jsx @@ -39,7 +39,7 @@ export const MessageContainer = ({ messages, status, category, created_at }) => setIsLocked(true); }; - const is_translated_exist = messages.translated?.length >= 1; + const is_translation_exist = messages.translations?.length > 0; const is_pending = status === "pending"; const is_sent_message = category === "sent"; const is_system_message = category === "system"; @@ -69,11 +69,11 @@ export const MessageContainer = ({ messages, status, category, created_at }) =>
{is_system_message ? ( -

{messages.message}

- ) : is_translated_exist ? ( +

{messages.original.message}

+ ) : is_translation_exist ? ( ) : ( -

{messages.original}

+ )}
@@ -88,13 +88,74 @@ export const MessageContainer = ({ messages, status, category, created_at }) => ); }; -const WithTranslatedMessages = ({ messages }) => { - const translated_data = Array.isArray(messages.translated) ? messages.translated : [messages.translated]; +const MessageWithTransliteration = ({ item }) => { + const renderTokenNode = (token, key) => { + const orig = token.orig ?? ""; + const hira = token.hira ?? ""; + const hepburn = token.hepburn ?? ""; + + if ((hira && orig === hira) || (hepburn && orig === hepburn) || (!hira && !hepburn)) { + return ( + + {orig} + + ); + } + + if (hira && hira !== orig) { + const needHepburn = hepburn && hepburn !== orig; + const titleAttr = needHepburn ? hepburn : undefined; + return ( + + {orig} + {hira} + + ); + } + + if (hepburn && hepburn !== orig) { + return ( + + {orig} + {hepburn} + + ); + } + + return ( + + {orig} + + ); + }; + + if (!item.transliteration.length) { + return

{item.message}

; + } + + return ( +

+ {item.transliteration.map((token, idx) => renderTokenNode(token, idx))} +

+ ); +}; + +const OriginalMessage = ({ messages }) => { return ( <> -

{messages.original}

- {translated_data.map((message, index) => ( -

{message}

+ + + ); +}; + +const WithTranslatedMessages = ({ messages }) => { + return ( + <> +

{messages.original.message}

+ {messages.translations.map((item, idx) => ( +
+ +
))} ); diff --git a/src-ui/logics/common/useMessage.js b/src-ui/logics/common/useMessage.js index 78986b55..1b50bbbd 100644 --- a/src-ui/logics/common/useMessage.js +++ b/src-ui/logics/common/useMessage.js @@ -24,8 +24,8 @@ export const useMessage = () => { status: "pending", created_at: generateTimeData(), messages: { - original: message, - translated: [], + original: { message: message, transliteration: [] }, + translations: [], }, }); }; @@ -39,20 +39,26 @@ export const useMessage = () => { category: "system", status: "system", created_at: date, - messages: {message: message}, + messages: { + original: { message: message, transliteration: [] }, + translations: [], + }, }); }; + const addSystemMessageLog_FromBackend = (payload) => { addSystemMessageLog(payload.message); }; const updateSentMessageLogById = (payload) => { - updateMessageLogs(updateItemById(payload.id, payload.translation)); + updateMessageLogs(updateItemById(payload.id, payload)); }; + const addSentMessageLog = (payload) => { const message_object = generateMessageObject(payload, "sent"); addMessageLogs(message_object); }; + const addReceivedMessageLog = (payload) => { const message_object = generateMessageObject(payload, "received"); addMessageLogs(message_object); @@ -61,6 +67,7 @@ export const useMessage = () => { const startTyping = () => { asyncStdoutToPython("/run/typing_message_box"); }; + const stopTyping = () => { asyncStdoutToPython("/run/stop_typing_message_box"); }; @@ -83,11 +90,10 @@ export const useMessage = () => { }; const generateTimeData = () => { - const data = new Date().toLocaleTimeString( + return new Date().toLocaleTimeString( "ja-JP", - { hour12: false, hour: "2-digit", minute: "2-digit" }, + { hour12: false, hour: "2-digit", minute: "2-digit" } ); - return data; }; const generateMessageObject = (data, category) => { @@ -97,17 +103,17 @@ const generateMessageObject = (data, category) => { category: category, status: "ok", messages: { - original: data.message, - translated: data.translation, + original: data.original, + translations: data.translations ?? [], }, }; }; -const updateItemById = (id, translated_data) => (current_items) => { +const updateItemById = (id, updated_data) => (current_items) => { return current_items.data.map(item => { if (item.id === id) { item.status = "ok"; - item.messages.translated = translated_data; + if (updated_data.translations) item.messages.translations = updated_data.translations; } return item; }); diff --git a/src-ui/logics/configs/others/useOthers.js b/src-ui/logics/configs/others/useOthers.js index c2b0179f..855ab24e 100644 --- a/src-ui/logics/configs/others/useOthers.js +++ b/src-ui/logics/configs/others/useOthers.js @@ -9,6 +9,8 @@ import { useStore_MessageFormat_ExampleViewFilter, useStore_SendMessageFormatParts, useStore_ReceivedMessageFormatParts, + useStore_ConvertMessageToRomaji, + useStore_ConvertMessageToHiragana, } from "@store"; import { useStdoutToPython } from "@useStdoutToPython"; import { useNotificationStatus } from "@logics_common"; @@ -39,6 +41,11 @@ export const useOthers = () => { // Received const { currentReceivedMessageFormatParts, updateReceivedMessageFormatParts, pendingReceivedMessageFormatParts } = useStore_ReceivedMessageFormatParts(); + // Convert Message To Romaji + const { currentConvertMessageToRomaji, updateConvertMessageToRomaji, pendingConvertMessageToRomaji } = useStore_ConvertMessageToRomaji(); + // Convert Message To Hiragana + const { currentConvertMessageToHiragana, updateConvertMessageToHiragana, pendingConvertMessageToHiragana } = useStore_ConvertMessageToHiragana(); + const { showNotification_SaveSuccess } = useNotificationStatus(); // Auto Clear Message Input Box @@ -233,6 +240,45 @@ export const useOthers = () => { }); }; + // Convert Message To Romaji + const getConvertMessageToRomaji = () => { + pendingConvertMessageToRomaji(); + asyncStdoutToPython("/get/data/convert_message_to_romaji"); + }; + + const toggleConvertMessageToRomaji = () => { + pendingConvertMessageToRomaji(); + if (currentConvertMessageToRomaji.data) { + asyncStdoutToPython("/set/disable/convert_message_to_romaji"); + } else { + asyncStdoutToPython("/set/enable/convert_message_to_romaji"); + } + }; + + const setSuccessConvertMessageToRomaji = (enabled) => { + updateConvertMessageToRomaji(enabled); + showNotification_SaveSuccess(); + }; + + // Convert Message To Hiragana + const getConvertMessageToHiragana = () => { + pendingConvertMessageToHiragana(); + asyncStdoutToPython("/get/data/convert_message_to_hiragana"); + }; + + const toggleConvertMessageToHiragana = () => { + pendingConvertMessageToHiragana(); + if (currentConvertMessageToHiragana.data) { + asyncStdoutToPython("/set/disable/convert_message_to_hiragana"); + } else { + asyncStdoutToPython("/set/enable/convert_message_to_hiragana"); + } + }; + + const setSuccessConvertMessageToHiragana = (enabled) => { + updateConvertMessageToHiragana(enabled); + showNotification_SaveSuccess(); + }; return { // Auto Clear Message Input Box @@ -303,5 +349,19 @@ export const useOthers = () => { getReceivedMessageFormatParts, setReceivedMessageFormatParts, setSuccessReceivedMessageFormatParts, + + // Convert Message To Romaji + currentConvertMessageToRomaji, + getConvertMessageToRomaji, + toggleConvertMessageToRomaji, + updateConvertMessageToRomaji, + setSuccessConvertMessageToRomaji, + + // Convert Message To Hiragana + currentConvertMessageToHiragana, + getConvertMessageToHiragana, + toggleConvertMessageToHiragana, + updateConvertMessageToHiragana, + setSuccessConvertMessageToHiragana, }; }; \ No newline at end of file diff --git a/src-ui/logics/useReceiveRoutes.js b/src-ui/logics/useReceiveRoutes.js index c36b5fa7..a5e6d8ed 100644 --- a/src-ui/logics/useReceiveRoutes.js +++ b/src-ui/logics/useReceiveRoutes.js @@ -292,6 +292,14 @@ export const ROUTE_META_LIST = [ { endpoint: "/get/data/received_message_format_parts", ns: configs, hook_name: "useOthers", method_name: "updateReceivedMessageFormatParts" }, { endpoint: "/set/data/received_message_format_parts", ns: configs, hook_name: "useOthers", method_name: "setSuccessReceivedMessageFormatParts" }, + { endpoint: "/get/data/convert_message_to_romaji", ns: configs, hook_name: "useOthers", method_name: "updateConvertMessageToRomaji" }, + { endpoint: "/set/enable/convert_message_to_romaji", ns: configs, hook_name: "useOthers", method_name: "setSuccessConvertMessageToRomaji" }, + { endpoint: "/set/disable/convert_message_to_romaji", ns: configs, hook_name: "useOthers", method_name: "setSuccessConvertMessageToRomaji" }, + + { endpoint: "/get/data/convert_message_to_hiragana", ns: configs, hook_name: "useOthers", method_name: "updateConvertMessageToHiragana" }, + { endpoint: "/set/enable/convert_message_to_hiragana", ns: configs, hook_name: "useOthers", method_name: "setSuccessConvertMessageToHiragana" }, + { endpoint: "/set/disable/convert_message_to_hiragana", ns: configs, hook_name: "useOthers", method_name: "setSuccessConvertMessageToHiragana" }, + // Hotkeys { endpoint: "/get/data/hotkeys", ns: configs, hook_name: "useHotkeys", method_name: "updateHotkeys" }, { endpoint: "/set/data/hotkeys", ns: configs, hook_name: "useHotkeys", method_name: "setSuccessHotkeys" }, @@ -323,8 +331,6 @@ export const ROUTE_META_LIST = [ { endpoint: "/get/data/mic_no_speech_prob", ns: null, hook_name: null, method_name: null }, // Not implemented on UI yet { endpoint: "/get/data/speaker_avg_logprob", ns: null, hook_name: null, method_name: null }, // Not implemented on UI yet { endpoint: "/get/data/speaker_no_speech_prob", ns: null, hook_name: null, method_name: null }, // Not implemented on UI yet - { endpoint: "/get/data/convert_message_to_romaji", ns: null, hook_name: null, method_name: null }, // Not implemented on UI yet - { endpoint: "/get/data/convert_message_to_hiragana", ns: null, hook_name: null, method_name: null }, // Not implemented on UI yet { endpoint: "/get/data/transcription_engines", ns: null, hook_name: null, method_name: null }, // Not implemented on UI yet. (if ai_models has not been detected, this will be blank array[]. if the ai_models are ok but just network has not connected, it'l be only ["Whisper"]) ]; diff --git a/src-ui/store.js b/src-ui/store.js index e36aad46..6c31e87f 100644 --- a/src-ui/store.js +++ b/src-ui/store.js @@ -309,6 +309,8 @@ export const { atomInstance: Atom_ReceivedMessageFormatParts, useHook: useStore_ }, translation_first: false, }, "ReceivedMessageFormatParts"); +export const { atomInstance: Atom_ConvertMessageToRomaji, useHook: useStore_ConvertMessageToRomaji } = createAtomWithHook(false, "ConvertMessageToRomaji"); +export const { atomInstance: Atom_ConvertMessageToHiragana, useHook: useStore_ConvertMessageToHiragana } = createAtomWithHook(false, "ConvertMessageToHiragana"); // Hotkeys