mirror of
https://github.com/w-okada/voice-changer.git
synced 2025-01-23 13:35:12 +03:00
WIP: multi lang
This commit is contained in:
parent
e6b58a8613
commit
52a954ebaa
11
client/demo/dist/index.html
vendored
11
client/demo/dist/index.html
vendored
@ -1,10 +1 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="width: 100%; height: 100%; overflow: hidden">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<title>Voice Changer Client Demo</title>
|
||||
<script defer src="index.js"></script></head>
|
||||
<body style="width: 100%; height: 100%; margin: 0px">
|
||||
<div id="app" style="width: 100%; height: 100%"></div>
|
||||
</body>
|
||||
</html>
|
||||
<!doctype html><html style="width:100%;height:100%;overflow:hidden"><head><meta charset="utf-8"/><title>Voice Changer Client Demo</title><script defer="defer" src="index.js"></script></head><body style="width:100%;height:100%;margin:0"><div id="app" style="width:100%;height:100%"></div></body></html>
|
1904
client/demo/dist/index.js
vendored
1904
client/demo/dist/index.js
vendored
File diff suppressed because one or more lines are too long
31
client/demo/dist/index.js.LICENSE.txt
vendored
Normal file
31
client/demo/dist/index.js.LICENSE.txt
vendored
Normal file
@ -0,0 +1,31 @@
|
||||
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react-dom.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* react.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @license React
|
||||
* scheduler.production.min.js
|
||||
*
|
||||
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
56
client/demo/package-lock.json
generated
56
client/demo/package-lock.json
generated
@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@dannadori/voice-changer-client-js": "^1.0.143",
|
||||
"@dannadori/voice-changer-client-js": "^1.0.144",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||
@ -24,8 +24,8 @@
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@types/node": "^20.2.6",
|
||||
"@types/react": "^18.2.9",
|
||||
"@types/node": "^20.3.0",
|
||||
"@types/react": "^18.2.11",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"babel-loader": "^9.1.2",
|
||||
@ -37,7 +37,7 @@
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-webpack-plugin": "^4.0.1",
|
||||
"html-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^5.5.2",
|
||||
"html-webpack-plugin": "^5.5.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-loader": "^7.3.3",
|
||||
"postcss-nested": "^6.0.1",
|
||||
@ -3290,9 +3290,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@dannadori/voice-changer-client-js": {
|
||||
"version": "1.0.143",
|
||||
"resolved": "https://registry.npmjs.org/@dannadori/voice-changer-client-js/-/voice-changer-client-js-1.0.143.tgz",
|
||||
"integrity": "sha512-rMmqpzUx6Rc0IDDpSMwZXLsHN1LibX79PjpgWiM5RTzyVLMg3wwlrZKdDeh1h0uJ+aKcFhqr1HNQSL3PXpzucw==",
|
||||
"version": "1.0.144",
|
||||
"resolved": "https://registry.npmjs.org/@dannadori/voice-changer-client-js/-/voice-changer-client-js-1.0.144.tgz",
|
||||
"integrity": "sha512-gxavGAXgxNbCIkGUrezvfs9WXykSwTdQSsig+i6OGRSxD+9eM70jFmhMuwxqjeYjJRc5zUtVw9OzCEXPIupZhA==",
|
||||
"dependencies": {
|
||||
"@types/readable-stream": "^2.3.15",
|
||||
"amazon-chime-sdk-js": "^3.14.1",
|
||||
@ -3986,9 +3986,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.6.tgz",
|
||||
"integrity": "sha512-GQBWUtGoefMEOx/vu+emHEHU5aw6JdDoEtZhoBrHFPZbA/YNRFfN996XbBASEWdvmLSLyv9FKYppYGyZjCaq/g=="
|
||||
"version": "20.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz",
|
||||
"integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ=="
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
@ -4009,9 +4009,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.9.tgz",
|
||||
"integrity": "sha512-pL3JAesUkF7PEQGxh5XOwdXGV907te6m1/Qe1ERJLgomojS6Ne790QiA7GUl434JEkFA2aAaB6qJ5z4e1zJn/w==",
|
||||
"version": "18.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.11.tgz",
|
||||
"integrity": "sha512-+hsJr9hmwyDecSMQAmX7drgbDpyE+EgSF6t7+5QEBAn1tQK7kl1vWZ4iRf6SjQ8lk7dyEULxUmZOIpN0W5baZA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
@ -7048,9 +7048,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/html-webpack-plugin": {
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.2.tgz",
|
||||
"integrity": "sha512-2KsxTJQmtqsT1JGaZJmoMW25wpC0HM9gpW3jH/UMH62To0UKlzRUbJ/FtQNhZ0gd4gWMoetEYkyG8FMNqEO66Q==",
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz",
|
||||
"integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/html-minifier-terser": "^6.0.0",
|
||||
@ -14233,9 +14233,9 @@
|
||||
}
|
||||
},
|
||||
"@dannadori/voice-changer-client-js": {
|
||||
"version": "1.0.143",
|
||||
"resolved": "https://registry.npmjs.org/@dannadori/voice-changer-client-js/-/voice-changer-client-js-1.0.143.tgz",
|
||||
"integrity": "sha512-rMmqpzUx6Rc0IDDpSMwZXLsHN1LibX79PjpgWiM5RTzyVLMg3wwlrZKdDeh1h0uJ+aKcFhqr1HNQSL3PXpzucw==",
|
||||
"version": "1.0.144",
|
||||
"resolved": "https://registry.npmjs.org/@dannadori/voice-changer-client-js/-/voice-changer-client-js-1.0.144.tgz",
|
||||
"integrity": "sha512-gxavGAXgxNbCIkGUrezvfs9WXykSwTdQSsig+i6OGRSxD+9eM70jFmhMuwxqjeYjJRc5zUtVw9OzCEXPIupZhA==",
|
||||
"requires": {
|
||||
"@types/readable-stream": "^2.3.15",
|
||||
"amazon-chime-sdk-js": "^3.14.1",
|
||||
@ -14811,9 +14811,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "20.2.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.2.6.tgz",
|
||||
"integrity": "sha512-GQBWUtGoefMEOx/vu+emHEHU5aw6JdDoEtZhoBrHFPZbA/YNRFfN996XbBASEWdvmLSLyv9FKYppYGyZjCaq/g=="
|
||||
"version": "20.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz",
|
||||
"integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ=="
|
||||
},
|
||||
"@types/prop-types": {
|
||||
"version": "15.7.5",
|
||||
@ -14834,9 +14834,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/react": {
|
||||
"version": "18.2.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.9.tgz",
|
||||
"integrity": "sha512-pL3JAesUkF7PEQGxh5XOwdXGV907te6m1/Qe1ERJLgomojS6Ne790QiA7GUl434JEkFA2aAaB6qJ5z4e1zJn/w==",
|
||||
"version": "18.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.11.tgz",
|
||||
"integrity": "sha512-+hsJr9hmwyDecSMQAmX7drgbDpyE+EgSF6t7+5QEBAn1tQK7kl1vWZ4iRf6SjQ8lk7dyEULxUmZOIpN0W5baZA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/prop-types": "*",
|
||||
@ -17113,9 +17113,9 @@
|
||||
}
|
||||
},
|
||||
"html-webpack-plugin": {
|
||||
"version": "5.5.2",
|
||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.2.tgz",
|
||||
"integrity": "sha512-2KsxTJQmtqsT1JGaZJmoMW25wpC0HM9gpW3jH/UMH62To0UKlzRUbJ/FtQNhZ0gd4gWMoetEYkyG8FMNqEO66Q==",
|
||||
"version": "5.5.3",
|
||||
"resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.3.tgz",
|
||||
"integrity": "sha512-6YrDKTuqaP/TquFH7h4srYWsZx+x6k6+FbsTm0ziCwGHDP78Unr1r9F/H4+sGmMbX08GQcJ+K64x55b+7VM/jg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/html-minifier-terser": "^6.0.0",
|
||||
|
@ -24,8 +24,8 @@
|
||||
"@babel/preset-env": "^7.22.5",
|
||||
"@babel/preset-react": "^7.22.5",
|
||||
"@babel/preset-typescript": "^7.22.5",
|
||||
"@types/node": "^20.2.6",
|
||||
"@types/react": "^18.2.9",
|
||||
"@types/node": "^20.3.0",
|
||||
"@types/react": "^18.2.11",
|
||||
"@types/react-dom": "^18.2.4",
|
||||
"autoprefixer": "^10.4.14",
|
||||
"babel-loader": "^9.1.2",
|
||||
@ -37,7 +37,7 @@
|
||||
"eslint-plugin-react": "^7.32.2",
|
||||
"eslint-webpack-plugin": "^4.0.1",
|
||||
"html-loader": "^4.2.0",
|
||||
"html-webpack-plugin": "^5.5.2",
|
||||
"html-webpack-plugin": "^5.5.3",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"postcss-loader": "^7.3.3",
|
||||
"postcss-nested": "^6.0.1",
|
||||
@ -52,7 +52,7 @@
|
||||
"webpack-dev-server": "^4.15.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@dannadori/voice-changer-client-js": "^1.0.143",
|
||||
"@dannadori/voice-changer-client-js": "^1.0.144",
|
||||
"@fortawesome/fontawesome-svg-core": "^6.4.0",
|
||||
"@fortawesome/free-brands-svg-icons": "^6.4.0",
|
||||
"@fortawesome/free-regular-svg-icons": "^6.4.0",
|
||||
|
@ -14,6 +14,7 @@ import { ClientType, useIndexedDB } from "@dannadori/voice-changer-client-js";
|
||||
import { INDEXEDDB_KEY_DEFAULT_MODEL_TYPE } from "./const";
|
||||
import { Demo } from "./components/demo/010_Demo";
|
||||
import { ClientSelector } from "./001_ClientSelector";
|
||||
import { useMessageBuilder } from "./hooks/useMessageBuilder";
|
||||
|
||||
library.add(fas, far, fab);
|
||||
|
||||
@ -40,9 +41,21 @@ const App = () => {
|
||||
|
||||
const AppStateWrapper = () => {
|
||||
const { appGuiSettingState, clientType, setClientType } = useAppRoot()
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
// エラーメッセージ登録
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "Problem", { "ja": "ちょっと問題が起きたみたいです。", "en": "Looks like there's a bit of a problem." })
|
||||
messageBuilderState.setMessage(__filename, "Problem-sub1", { "ja": "このアプリで管理している情報をクリアすると回復する場合があります。", "en": "" })
|
||||
messageBuilderState.setMessage(__filename, "Problem-sub2", { "ja": "下記のボタンを押して情報をクリアします。", "en": "If you clear the information being managed by this app, it may be recoverable." })
|
||||
messageBuilderState.setMessage(__filename, "Problem-action1", { "ja": "アプリを初期化", "en": "Initialize" })
|
||||
messageBuilderState.setMessage(__filename, "Problem-action2", { "ja": "初期化せずリロード", "en": "Reload without initialize" })
|
||||
}, [])
|
||||
|
||||
// エラーバウンダリー設定
|
||||
const [error, setError] = useState<{ error: Error, errorInfo: ErrorInfo }>()
|
||||
const { getItem, removeDB } = useIndexedDB({ clientType: null })
|
||||
|
||||
|
||||
const errorComponent = useMemo(() => {
|
||||
const errorName = error?.error.name || "no error name"
|
||||
const errorMessage = error?.error.message || "no error message"
|
||||
@ -58,13 +71,13 @@ const AppStateWrapper = () => {
|
||||
return (
|
||||
<div className="error-container">
|
||||
<div className="top-error-message">
|
||||
ちょっと問題が起きたみたいです。
|
||||
{messageBuilderState.getMessage(__filename, "Problem")}
|
||||
</div>
|
||||
<div className="top-error-description">
|
||||
<p>このアプリで管理している情報をクリアすると回復する場合があります。</p>
|
||||
<p>下記のボタンを押して情報をクリアします。</p>
|
||||
<p><button onClick={onClearCacheClicked}>アプリを初期化</button></p>
|
||||
<p><button onClick={onReloadClicked}>初期化せずリロード</button></p>
|
||||
<p> {messageBuilderState.getMessage(__filename, "Problem-sub1")}</p>
|
||||
<p> {messageBuilderState.getMessage(__filename, "Problem-sub2")}</p>
|
||||
<p><button onClick={onClearCacheClicked}>{messageBuilderState.getMessage(__filename, "Problem-action1")}</button></p>
|
||||
<p><button onClick={onReloadClicked}>{messageBuilderState.getMessage(__filename, "Problem-action2")}</button></p>
|
||||
</div>
|
||||
<div className="error-detail">
|
||||
<div className="error-name">
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { isDesktopApp } from "./const";
|
||||
import { useAppRoot } from "./001_provider/001_AppRootProvider";
|
||||
import { useMessageBuilder } from "./hooks/useMessageBuilder";
|
||||
|
||||
|
||||
export type TitleProps = {
|
||||
@ -9,6 +11,13 @@ export type TitleProps = {
|
||||
}
|
||||
|
||||
export const Title = (props: TitleProps) => {
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "github", { "ja": "github", "en": "github" })
|
||||
messageBuilderState.setMessage(__filename, "manual", { "ja": "マニュアル", "en": "manual" })
|
||||
messageBuilderState.setMessage(__filename, "screenCapture", { "ja": "録画ツール", "en": "Record Screen" })
|
||||
messageBuilderState.setMessage(__filename, "support", { "ja": "支援", "en": "Donation" })
|
||||
}, [])
|
||||
|
||||
const githubLink = useMemo(() => {
|
||||
return isDesktopApp() ?
|
||||
@ -16,14 +25,14 @@ export const Title = (props: TitleProps) => {
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer") }}>
|
||||
<img src="./assets/icons/github.svg" />
|
||||
<div className="tooltip-text">github</div>
|
||||
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
|
||||
</span>
|
||||
)
|
||||
:
|
||||
(
|
||||
<a className="link tooltip" href="https://github.com/w-okada/voice-changer" target="_blank" rel="noopener noreferrer">
|
||||
<img src="./assets/icons/github.svg" />
|
||||
<div className="tooltip-text">github</div>
|
||||
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
|
||||
</a>
|
||||
)
|
||||
}, [])
|
||||
@ -33,16 +42,16 @@ export const Title = (props: TitleProps) => {
|
||||
return isDesktopApp() ?
|
||||
(
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://zenn.dev/wok/books/0004_vc-client-v_1_5_1_x") }}>
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md") }}>
|
||||
<img src="./assets/icons/help-circle.svg" />
|
||||
<div className="tooltip-text">manual</div>
|
||||
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
|
||||
</span>
|
||||
)
|
||||
:
|
||||
(
|
||||
<a className="link tooltip" href="https://zenn.dev/wok/books/0004_vc-client-v_1_5_1_x" target="_blank" rel="noopener noreferrer">
|
||||
<a className="link tooltip" href="https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md" target="_blank" rel="noopener noreferrer">
|
||||
<img src="./assets/icons/help-circle.svg" />
|
||||
<div className="tooltip-text">manual</div>
|
||||
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
|
||||
</a>
|
||||
)
|
||||
}, [])
|
||||
@ -58,7 +67,7 @@ export const Title = (props: TitleProps) => {
|
||||
// @ts-ignore
|
||||
window.electronAPI.openBrowser("https://w-okada.github.io/screen-recorder-ts/")
|
||||
}}>
|
||||
screen capture
|
||||
{messageBuilderState.getMessage(__filename, "screenCapture")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -71,7 +80,7 @@ export const Title = (props: TitleProps) => {
|
||||
<p onClick={() => {
|
||||
window.open("https://w-okada.github.io/screen-recorder-ts/", '_blank', "noreferrer")
|
||||
}}>
|
||||
screen capture
|
||||
{messageBuilderState.getMessage(__filename, "screenCapture")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -85,7 +94,7 @@ export const Title = (props: TitleProps) => {
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://www.buymeacoffee.com/wokad") }}>
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" />
|
||||
<div className="tooltip-text tooltip-text-100px">donate(寄付)</div>
|
||||
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "support")}</div>
|
||||
</span>
|
||||
)
|
||||
:
|
||||
@ -93,7 +102,7 @@ export const Title = (props: TitleProps) => {
|
||||
<a className="link tooltip" href="https://www.buymeacoffee.com/wokad" target="_blank" rel="noopener noreferrer">
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" />
|
||||
<div className="tooltip-text tooltip-text-100px">
|
||||
donate(寄付)
|
||||
{messageBuilderState.getMessage(__filename, "support")}
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
|
@ -12,8 +12,6 @@ export const ClientSelector = () => {
|
||||
setItem(INDEXEDDB_KEY_DEFAULT_MODEL_TYPE, clientType)
|
||||
}
|
||||
|
||||
|
||||
|
||||
const selectableClientTypes = useMemo(() => {
|
||||
const ua = window.navigator.userAgent.toLowerCase();
|
||||
if (ua.indexOf("mac os x") !== -1) {
|
||||
|
37
client/demo/src/001_globalHooks/010_useMessageBuilder.ts
Normal file
37
client/demo/src/001_globalHooks/010_useMessageBuilder.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { useRef } from "react"
|
||||
|
||||
export type Message = {
|
||||
file: string,
|
||||
id: string,
|
||||
message: { [lang: string]: string }
|
||||
}
|
||||
|
||||
export type MessageBuilderStateAndMethod = {
|
||||
setMessage: (file: string, id: string, message: { [lang: string]: string }) => void
|
||||
getMessage: (file: string, id: string) => string
|
||||
}
|
||||
|
||||
export const useMessageBuilder_old = (): MessageBuilderStateAndMethod => {
|
||||
const messagesRef = useRef<Message[]>([])
|
||||
|
||||
const setMessage = (file: string, id: string, message: { [lang: string]: string }) => {
|
||||
if (messagesRef.current.find(x => { return x.file == file && x.id == id })) {
|
||||
console.warn("duplicate message is registerd", file, id, message)
|
||||
} else {
|
||||
messagesRef.current.push({ file, id, message })
|
||||
}
|
||||
}
|
||||
const getMessage = (file: string, id: string) => {
|
||||
let lang = window.navigator.language
|
||||
if (lang != "ja") {
|
||||
lang = "en"
|
||||
}
|
||||
|
||||
console.log(messagesRef.current)
|
||||
return messagesRef.current.find(x => { return x.file == file && x.id == id })?.message[lang] || "unknwon message"
|
||||
}
|
||||
return {
|
||||
setMessage,
|
||||
getMessage
|
||||
}
|
||||
}
|
@ -27,8 +27,10 @@ export const useAppRoot = (): AppRootValue => {
|
||||
export const AppRootProvider = ({ children }: Props) => {
|
||||
const audioContextState = useAudioConfig()
|
||||
const appGuiSettingState = useAppGuiSetting()
|
||||
|
||||
const [clientType, setClientType] = useState<ClientType | null>(null)
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!clientType) {
|
||||
return
|
||||
|
@ -3,6 +3,7 @@ import React, { useContext, useEffect, useRef } from "react";
|
||||
import { ReactNode } from "react";
|
||||
import { useVCClient } from "../001_globalHooks/001_useVCClient";
|
||||
import { useAppRoot } from "./001_AppRootProvider";
|
||||
import { useMessageBuilder } from "../hooks/useMessageBuilder";
|
||||
|
||||
type Props = {
|
||||
children: ReactNode;
|
||||
@ -25,7 +26,14 @@ export const useAppState = (): AppStateValue => {
|
||||
export const AppStateProvider = ({ children }: Props) => {
|
||||
const appRoot = useAppRoot()
|
||||
const clientState = useVCClient({ audioContext: appRoot.audioContextState.audioContext, clientType: appRoot.clientType })
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
|
||||
useEffect(() => {
|
||||
messageBuilderState.setMessage(__filename, "ioError", {
|
||||
"ja": "エラーが頻発しています。対象としているフレームワークのモデルがロードされているか確認してください。",
|
||||
"en": "Frequent errors occur. Please check if the model of the framework being targeted is loaded."
|
||||
})
|
||||
}, [])
|
||||
|
||||
const initializedRef = useRef<boolean>(false)
|
||||
useEffect(() => {
|
||||
@ -60,7 +68,7 @@ export const AppStateProvider = ({ children }: Props) => {
|
||||
|
||||
useEffect(() => {
|
||||
if (clientState.clientState.ioErrorCount > 100) {
|
||||
alert("エラーが頻発しています。対象としているフレームワークのモデルがロードされているか確認してください。")
|
||||
alert(messageBuilderState.getMessage(__filename, "ioError"))
|
||||
clientState.clientState.resetIoErrorCount()
|
||||
}
|
||||
|
||||
|
@ -1,9 +1,15 @@
|
||||
import React, { useMemo } from "react";
|
||||
// import { useGuiState } from "./001_GuiStateProvider";
|
||||
import { useMessageBuilder } from "../../hooks/useMessageBuilder";
|
||||
|
||||
|
||||
export const WaitingDialog = () => {
|
||||
// const guiState = useGuiState()
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "wait", { "ja": "しばらくお待ちください", "en": "please wait..." })
|
||||
messageBuilderState.setMessage(__filename, "wait_sub1", { "ja": "ONNXファイルを生成しています。", "en": "generating ONNX file." })
|
||||
messageBuilderState.setMessage(__filename, "wait_sub2", { "ja": "しばらくお待ちください(1分程度)。", "en": "please wait... (about 1 min)." })
|
||||
}, [])
|
||||
|
||||
const dialog = useMemo(() => {
|
||||
// const closeButtonRow = (
|
||||
@ -17,19 +23,21 @@ export const WaitingDialog = () => {
|
||||
// </div>
|
||||
// )
|
||||
const content = (
|
||||
<div className="body-row split-3-4-3 left-padding-1">
|
||||
<div className="body-row left-padding-1">
|
||||
<div className="body-item-text">
|
||||
</div>
|
||||
<div className="body-item-text">
|
||||
please wait... (about 1 min)
|
||||
{messageBuilderState.getMessage(__filename, "wait_sub1")}
|
||||
</div>
|
||||
<div className="body-item-text">
|
||||
{messageBuilderState.getMessage(__filename, "wait_sub2")}
|
||||
</div>
|
||||
<div className="body-item-text"></div>
|
||||
</div>
|
||||
)
|
||||
|
||||
return (
|
||||
<div className="dialog-frame">
|
||||
<div className="dialog-title">export onnx file</div>
|
||||
<div className="dialog-title">{messageBuilderState.getMessage(__filename, "wait")}</div>
|
||||
<div className="dialog-content">
|
||||
{content}
|
||||
{/* {closeButtonRow} */}
|
||||
|
@ -1,30 +1,42 @@
|
||||
import React, { useMemo } from "react";
|
||||
import { useGuiState } from "./001_GuiStateProvider";
|
||||
import { getMessage } from "./messages/MessageBuilder";
|
||||
// import { getMessage } from "./messages/MessageBuilder";
|
||||
import { isDesktopApp } from "../../const";
|
||||
import { useAppRoot } from "../../001_provider/001_AppRootProvider";
|
||||
import { useMessageBuilder } from "../../hooks/useMessageBuilder";
|
||||
|
||||
|
||||
export const StartingNoticeDialog = () => {
|
||||
const guiState = useGuiState()
|
||||
const { appGuiSettingState } = useAppRoot()
|
||||
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "support", { "ja": "支援", "en": "Donation" })
|
||||
messageBuilderState.setMessage(__filename, "support_message_1", { "ja": "このソフトウェアを気に入ったら開発者にコーヒーをご馳走してあげよう。黄色いアイコンから。", "en": "This software is supported by donations. Thank you for your support!" })
|
||||
messageBuilderState.setMessage(__filename, "support_message_2", { "ja": "コーヒーをご馳走する。", "en": "I will support a developer by buying coffee." })
|
||||
|
||||
messageBuilderState.setMessage(__filename, "directml_1", { "ja": "directML版は実験的バージョンです。以下の既知の問題があります。", "en": "DirectML version is an experimental version. There are the known issues as follows." })
|
||||
messageBuilderState.setMessage(__filename, "directml_2", { "ja": "(1) 一部の設定変更を行うとgpuを使用していても変換処理が遅くなることが発生します。もしこの現象が発生したらGPUの値を-1にしてから再度0に戻してください。", "en": "(1) When some settings are changed, conversion process becomes slow even when using GPU. If this occurs, reset the GPU value to -1 and then back to 0." })
|
||||
messageBuilderState.setMessage(__filename, "click_to_start", { "ja": "スタートボタンを押してください。", "en": "Click to start" })
|
||||
messageBuilderState.setMessage(__filename, "start", { "ja": "スタート", "en": "start" })
|
||||
|
||||
}, [])
|
||||
|
||||
|
||||
|
||||
const coffeeLink = useMemo(() => {
|
||||
return isDesktopApp() ?
|
||||
(
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://www.buymeacoffee.com/wokad") }}>
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" /> donate
|
||||
<div className="tooltip-text tooltip-text-100px">donate(寄付)</div>
|
||||
<span className="link" onClick={() => { window.electronAPI.openBrowser("https://www.buymeacoffee.com/wokad") }}>
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" /> {messageBuilderState.getMessage(__filename, "support_message_2")}
|
||||
</span>
|
||||
)
|
||||
:
|
||||
(
|
||||
<a className="link tooltip" href="https://www.buymeacoffee.com/wokad" target="_blank" rel="noopener noreferrer">
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" /> Donate
|
||||
<div className="tooltip-text tooltip-text-100px">
|
||||
donate(寄付)
|
||||
</div>
|
||||
<a className="link" href="https://www.buymeacoffee.com/wokad" target="_blank" rel="noopener noreferrer">
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" /> {messageBuilderState.getMessage(__filename, "support_message_2")}
|
||||
</a>
|
||||
)
|
||||
}, [])
|
||||
@ -38,7 +50,9 @@ export const StartingNoticeDialog = () => {
|
||||
<div className="body-item-text">
|
||||
</div>
|
||||
<div className="body-button-container body-button-container-space-around">
|
||||
<div className="body-button" onClick={() => { guiState.stateControls.showStartingNoticeCheckbox.updateState(false) }} >start</div>
|
||||
<div className="body-button" onClick={() => { guiState.stateControls.showStartingNoticeCheckbox.updateState(false) }} >
|
||||
{messageBuilderState.getMessage(__filename, "start")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="body-item-text"></div>
|
||||
</div>
|
||||
@ -47,7 +61,7 @@ export const StartingNoticeDialog = () => {
|
||||
const donationMessage = (
|
||||
<div className="dialog-content-part">
|
||||
<div>
|
||||
{getMessage("donate_1")}
|
||||
{messageBuilderState.getMessage(__filename, "support_message_1")}
|
||||
</div>
|
||||
<div>
|
||||
{coffeeLink}
|
||||
@ -58,25 +72,24 @@ export const StartingNoticeDialog = () => {
|
||||
const directMLMessage = (
|
||||
<div className="dialog-content-part">
|
||||
<div>
|
||||
{getMessage("notice_1")}
|
||||
{messageBuilderState.getMessage(__filename, "directml_1")}
|
||||
</div>
|
||||
<div className="left-padding-1">
|
||||
{getMessage("notice_2")}
|
||||
{messageBuilderState.getMessage(__filename, "directml_2")}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
const clickToStartMessage = (
|
||||
<div className="dialog-content-part">
|
||||
<div>
|
||||
{getMessage("click_to_start_1")}
|
||||
{messageBuilderState.getMessage(__filename, "click_to_start")}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
const lang = window.navigator.language
|
||||
const edition = appGuiSettingState.edition
|
||||
const content = (
|
||||
<div className="body-row">
|
||||
{lang != "ja" || edition.indexOf("onnxdirectML-cuda") >= 0 ? donationMessage : <></>}
|
||||
{donationMessage}
|
||||
{edition.indexOf("onnxdirectML-cuda") >= 0 ? directMLMessage : <></>}
|
||||
{clickToStartMessage}
|
||||
</div>
|
||||
|
@ -2,6 +2,7 @@ import React, { useMemo, useState } from "react";
|
||||
import { useGuiState } from "./001_GuiStateProvider";
|
||||
import { useAppState } from "../../001_provider/001_AppStateProvider";
|
||||
import { InitialFileUploadSetting, fileSelector } from "@dannadori/voice-changer-client-js";
|
||||
import { useMessageBuilder } from "../../hooks/useMessageBuilder";
|
||||
|
||||
|
||||
export type uploadData = {
|
||||
@ -23,8 +24,14 @@ export const ModelSlotManagerDialog = () => {
|
||||
const [mode, setMode] = useState<Mode>("localFile")
|
||||
const [fromNetTargetIndex, setFromNetTargetIndex] = useState<number>(0)
|
||||
const [lang, setLang] = useState<string>("All")
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
|
||||
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "change_icon", { "ja": "アイコン変更", "en": "chage icon" })
|
||||
messageBuilderState.setMessage(__filename, "rename", { "ja": "リネーム", "en": "rename" })
|
||||
messageBuilderState.setMessage(__filename, "download", { "ja": "ダウンロード", "en": "download" })
|
||||
messageBuilderState.setMessage(__filename, "terms_of_use", { "ja": "利用規約", "en": "terms of use" })
|
||||
}, [])
|
||||
/////////////////////////////////////////
|
||||
// Slot Manager
|
||||
/////////////////////////////////////////
|
||||
@ -130,7 +137,7 @@ export const ModelSlotManagerDialog = () => {
|
||||
|
||||
const isRegisterd = modelFileName.length > 0 ? true : false
|
||||
const name = x.name && x.name.length > 0 ? x.name : isRegisterd ? modelFileName : "blank"
|
||||
const termOfUseUrlLink = x.termsOfUseUrl && x.termsOfUseUrl.length > 0 ? <a href={x.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="body-item-text-small">[terms of use]</a> : <></>
|
||||
const termOfUseUrlLink = x.termsOfUseUrl && x.termsOfUseUrl.length > 0 ? <a href={x.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="body-item-text-small">[{messageBuilderState.getMessage(__filename, "terms_of_use")}]</a> : <></>
|
||||
|
||||
const nameValueClass = isRegisterd ? "model-slot-detail-row-value-pointable" : "model-slot-detail-row-value"
|
||||
const nameValueAction = isRegisterd ? async (index: number) => {
|
||||
@ -168,21 +175,41 @@ export const ModelSlotManagerDialog = () => {
|
||||
|
||||
return (
|
||||
<div key={index} className="model-slot">
|
||||
<img src={iconUrl} className={iconClass} onClick={() => { iconAction(index) }}></img>
|
||||
<div className="tooltip">
|
||||
<img src={iconUrl} className={iconClass} onClick={() => { iconAction(index) }} />
|
||||
<div className="tooltip-text tooltip-text-thin tooltip-text-lower">
|
||||
{messageBuilderState.getMessage(__filename, "change_icon")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="model-slot-detail">
|
||||
<div className="model-slot-detail-row">
|
||||
<div className="model-slot-detail-row-label">[{index}]</div>
|
||||
<div className={nameValueClass} onClick={() => { nameValueAction(index) }}>{name}</div>
|
||||
<div className={nameValueClass + " tooltip"} onClick={() => { nameValueAction(index) }}>
|
||||
{name}
|
||||
<div className="tooltip-text tooltip-text-thin">
|
||||
{messageBuilderState.getMessage(__filename, "rename")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="">{termOfUseUrlLink}</div>
|
||||
</div>
|
||||
<div className="model-slot-detail-row">
|
||||
<div className="model-slot-detail-row-label">model:</div>
|
||||
<div className={fileValueClass} onClick={() => { fileValueAction(x.modelFile) }}>{modelFileName}</div>
|
||||
<div className={fileValueClass + " tooltip"} onClick={() => { fileValueAction(x.modelFile) }}>
|
||||
{modelFileName}
|
||||
<div className="tooltip-text tooltip-text-thin">
|
||||
{messageBuilderState.getMessage(__filename, "download")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="model-slot-button model-slot-detail-row-button" onClick={() => { onRVCModelLoadClicked(index) }}>select</div>
|
||||
</div>
|
||||
<div className="model-slot-detail-row">
|
||||
<div className="model-slot-detail-row-label">index:</div>
|
||||
<div className={fileValueClass} onClick={() => { fileValueAction(x.indexFile) }}>{indexFileName}</div>
|
||||
<div className={fileValueClass + " tooltip"} onClick={() => { fileValueAction(x.indexFile) }}>
|
||||
{indexFileName}
|
||||
<div className="tooltip-text tooltip-text-thin">
|
||||
{messageBuilderState.getMessage(__filename, "download")}
|
||||
</div>
|
||||
</div>
|
||||
<div className="model-slot-button model-slot-detail-row-button" onClick={() => { onRVCIndexLoadClicked(index) }}>select</div>
|
||||
</div>
|
||||
<div className="model-slot-detail-row">
|
||||
@ -209,7 +236,7 @@ export const ModelSlotManagerDialog = () => {
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div >
|
||||
)
|
||||
})
|
||||
|
||||
@ -267,7 +294,7 @@ export const ModelSlotManagerDialog = () => {
|
||||
}
|
||||
const options = (
|
||||
serverSetting.serverSetting.sampleModels.filter(x => { return lang == "All" ? true : x.lang == lang }).map((x, index) => {
|
||||
const termOfUseUrlLink = x.termsOfUseUrl && x.termsOfUseUrl.length > 0 ? <a href={x.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="body-item-text-small">[terms of use]</a> : <></>
|
||||
const termOfUseUrlLink = x.termsOfUseUrl && x.termsOfUseUrl.length > 0 ? <a href={x.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="body-item-text-small">[{messageBuilderState.getMessage(__filename, "terms_of_use")}]</a> : <></>
|
||||
|
||||
return (
|
||||
<div key={index} className="model-slot">
|
||||
|
@ -4,6 +4,7 @@ import { useGuiState } from "../001_GuiStateProvider";
|
||||
import { useAppRoot } from "../../../001_provider/001_AppRootProvider";
|
||||
import { useAppState } from "../../../001_provider/001_AppStateProvider";
|
||||
import { useIndexedDB } from "@dannadori/voice-changer-client-js";
|
||||
import { useMessageBuilder } from "../../../hooks/useMessageBuilder";
|
||||
|
||||
|
||||
export type HeaderAreaProps = {
|
||||
@ -13,6 +14,7 @@ export type HeaderAreaProps = {
|
||||
|
||||
export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
const { appGuiSettingState, setClientType } = useAppRoot()
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
const { clientSetting, clearSetting } = useAppState()
|
||||
const { setIsConverting, isConverting } = useGuiState()
|
||||
|
||||
@ -20,6 +22,13 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
const { removeItem } = useIndexedDB({ clientType: clientType })
|
||||
const { setItem } = useIndexedDB({ clientType: null })
|
||||
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "github", { "ja": "github", "en": "github" })
|
||||
messageBuilderState.setMessage(__filename, "manual", { "ja": "マニュアル", "en": "manual" })
|
||||
messageBuilderState.setMessage(__filename, "screenCapture", { "ja": "録画ツール", "en": "Record Screen" })
|
||||
messageBuilderState.setMessage(__filename, "support", { "ja": "支援", "en": "Donation" })
|
||||
}, [])
|
||||
|
||||
|
||||
const githubLink = useMemo(() => {
|
||||
return isDesktopApp() ?
|
||||
@ -27,14 +36,14 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer") }}>
|
||||
<img src="./assets/icons/github.svg" />
|
||||
<div className="tooltip-text">github</div>
|
||||
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
|
||||
</span>
|
||||
)
|
||||
:
|
||||
(
|
||||
<a className="link tooltip" href="https://github.com/w-okada/voice-changer" target="_blank" rel="noopener noreferrer">
|
||||
<img src="./assets/icons/github.svg" />
|
||||
<div className="tooltip-text">github</div>
|
||||
<div className="tooltip-text">{messageBuilderState.getMessage(__filename, "github")}</div>
|
||||
</a>
|
||||
)
|
||||
}, [])
|
||||
@ -46,14 +55,14 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md") }}>
|
||||
<img src="./assets/icons/help-circle.svg" />
|
||||
<div className="tooltip-text">manual</div>
|
||||
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
|
||||
</span>
|
||||
)
|
||||
:
|
||||
(
|
||||
<a className="link tooltip" href="https://github.com/w-okada/voice-changer/blob/master/tutorials/tutorial_rvc_ja_latest.md" target="_blank" rel="noopener noreferrer">
|
||||
<img src="./assets/icons/help-circle.svg" />
|
||||
<div className="tooltip-text">manual</div>
|
||||
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "manual")}</div>
|
||||
</a>
|
||||
)
|
||||
}, [])
|
||||
@ -69,7 +78,7 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
// @ts-ignore
|
||||
window.electronAPI.openBrowser("https://w-okada.github.io/screen-recorder-ts/")
|
||||
}}>
|
||||
screen capture
|
||||
{messageBuilderState.getMessage(__filename, "screenCapture")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -82,7 +91,7 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
<p onClick={() => {
|
||||
window.open("https://w-okada.github.io/screen-recorder-ts/", '_blank', "noreferrer")
|
||||
}}>
|
||||
screen capture
|
||||
{messageBuilderState.getMessage(__filename, "screenCapture")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@ -96,7 +105,7 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
// @ts-ignore
|
||||
<span className="link tooltip" onClick={() => { window.electronAPI.openBrowser("https://www.buymeacoffee.com/wokad") }}>
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" />
|
||||
<div className="tooltip-text tooltip-text-100px">donate(寄付)</div>
|
||||
<div className="tooltip-text tooltip-text-100px">{messageBuilderState.getMessage(__filename, "support")}</div>
|
||||
</span>
|
||||
)
|
||||
:
|
||||
@ -104,7 +113,7 @@ export const HeaderArea = (props: HeaderAreaProps) => {
|
||||
<a className="link tooltip" href="https://www.buymeacoffee.com/wokad" target="_blank" rel="noopener noreferrer">
|
||||
<img className="donate-img" src="./assets/buymeacoffee.png" />
|
||||
<div className="tooltip-text tooltip-text-100px">
|
||||
donate(寄付)
|
||||
{messageBuilderState.getMessage(__filename, "support")}
|
||||
</div>
|
||||
</a>
|
||||
)
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useMemo } from "react"
|
||||
import { useAppState } from "../../../001_provider/001_AppStateProvider"
|
||||
import { useGuiState } from "../001_GuiStateProvider"
|
||||
import { useMessageBuilder } from "../../../hooks/useMessageBuilder"
|
||||
|
||||
export type ModelSlotAreaProps = {
|
||||
}
|
||||
@ -9,6 +10,13 @@ export type ModelSlotAreaProps = {
|
||||
export const ModelSlotArea = (_props: ModelSlotAreaProps) => {
|
||||
const { serverSetting, getInfo } = useAppState()
|
||||
const guiState = useGuiState()
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "edit", { "ja": "編集", "en": "edit" })
|
||||
}, [])
|
||||
|
||||
|
||||
const modelTiles = useMemo(() => {
|
||||
if (!serverSetting.serverSetting.modelSlots) {
|
||||
return []
|
||||
@ -21,7 +29,7 @@ export const ModelSlotArea = (_props: ModelSlotAreaProps) => {
|
||||
const name = x.name.length > 8 ? x.name.substring(0, 7) + "..." : x.name
|
||||
const iconElem = x.iconFile.length > 0 ?
|
||||
<img className="model-slot-tile-icon" src={x.iconFile} alt={x.name} /> :
|
||||
<div className="model-slot-tile-icon-no-entry">no entry.</div>
|
||||
<div className="model-slot-tile-icon-no-entry">no image</div>
|
||||
|
||||
const clickAction = async () => {
|
||||
const dummyModelSlotIndex = (Math.floor(Date.now() / 1000)) * 1000 + index
|
||||
@ -55,7 +63,7 @@ export const ModelSlotArea = (_props: ModelSlotAreaProps) => {
|
||||
<div className="model-slot-tiles-container">{modelTiles}</div>
|
||||
<div className="model-slot-buttons">
|
||||
<div className="model-slot-button" onClick={onModelSlotEditClicked}>
|
||||
edit
|
||||
{messageBuilderState.getMessage(__filename, "edit")}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -2,6 +2,7 @@ import React, { useEffect, useMemo, useState } from "react"
|
||||
import { useAppState } from "../../../001_provider/001_AppStateProvider"
|
||||
import { useGuiState } from "../001_GuiStateProvider"
|
||||
import { OnnxExporterInfo } from "@dannadori/voice-changer-client-js"
|
||||
import { useMessageBuilder } from "../../../hooks/useMessageBuilder"
|
||||
|
||||
export type CharacterAreaProps = {
|
||||
}
|
||||
@ -10,6 +11,14 @@ export type CharacterAreaProps = {
|
||||
export const CharacterArea = (_props: CharacterAreaProps) => {
|
||||
const { serverSetting, clientSetting, initializedRef, volume, bufferingTime, performance } = useAppState()
|
||||
const guiState = useGuiState()
|
||||
const messageBuilderState = useMessageBuilder()
|
||||
|
||||
useMemo(() => {
|
||||
messageBuilderState.setMessage(__filename, "terms_of_use", { "ja": "利用規約", "en": "terms of use" })
|
||||
messageBuilderState.setMessage(__filename, "export_to_onnx", { "ja": "onnx出力", "en": "export to onnx" })
|
||||
messageBuilderState.setMessage(__filename, "save_default", { "ja": "設定保存", "en": "save setting" })
|
||||
messageBuilderState.setMessage(__filename, "alert_onnx", { "ja": "ボイチェン中はonnx出力できません", "en": "cannot export onnx when voice conversion is enabled" })
|
||||
}, [])
|
||||
|
||||
const selected = useMemo(() => {
|
||||
if (serverSetting.serverSetting.modelSlotIndex == undefined) {
|
||||
@ -38,7 +47,7 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
|
||||
}
|
||||
|
||||
const icon = selected.iconFile.length > 0 ? selected.iconFile : "./assets/icons/human.png"
|
||||
const selectedTermOfUseUrlLink = selected.termsOfUseUrl ? <a href={selected.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="portrait-area-terms-of-use-link">[terms of use]</a> : <></>
|
||||
const selectedTermOfUseUrlLink = selected.termsOfUseUrl ? <a href={selected.termsOfUseUrl} target="_blank" rel="noopener noreferrer" className="portrait-area-terms-of-use-link">[{messageBuilderState.getMessage(__filename, "terms_of_use")}]</a> : <></>
|
||||
|
||||
|
||||
return (
|
||||
@ -235,7 +244,7 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
|
||||
|
||||
const onnxExportButtonAction = async () => {
|
||||
if (guiState.isConverting) {
|
||||
alert("cannot export onnx when voice conversion is enabled")
|
||||
alert(messageBuilderState.getMessage(__filename, "alert_onnx"))
|
||||
return
|
||||
}
|
||||
|
||||
@ -253,7 +262,7 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
|
||||
}
|
||||
|
||||
const exportOnnx = selected.modelFile.endsWith("pth") ? (
|
||||
<div className="character-area-button" onClick={onnxExportButtonAction}>export onnx</div>
|
||||
<div className="character-area-button" onClick={onnxExportButtonAction}>{messageBuilderState.getMessage(__filename, "export_to_onnx")}</div>
|
||||
) : <></>
|
||||
return (
|
||||
<div className="character-area-control">
|
||||
@ -262,7 +271,7 @@ export const CharacterArea = (_props: CharacterAreaProps) => {
|
||||
</div>
|
||||
<div className="character-area-control-field">
|
||||
<div className="character-area-buttons">
|
||||
<div className="character-area-button" onClick={onUpdateDefaultClicked}>save default</div>
|
||||
<div className="character-area-button" onClick={onUpdateDefaultClicked}>{messageBuilderState.getMessage(__filename, "save_default")}</div>
|
||||
{exportOnnx}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -57,7 +57,7 @@ export const RecorderArea = (_props: RecorderAreaProps) => {
|
||||
|
||||
|
||||
<div className="config-sub-area-control left-padding-1">
|
||||
<div className="config-sub-area-control-title">dev</div>
|
||||
<div className="config-sub-area-control-title">output</div>
|
||||
<div className="config-sub-area-control-field">
|
||||
<div className="config-sub-area-control-field-auido-io">
|
||||
<select className="body-select" value={audioOutputForAnalyzer} onChange={(e) => {
|
||||
|
@ -1,5 +1,5 @@
|
||||
|
||||
const messages: {
|
||||
const messages_: {
|
||||
[id: string]: {
|
||||
[lang: string]: string
|
||||
}
|
||||
@ -23,15 +23,15 @@ const messages: {
|
||||
|
||||
}
|
||||
|
||||
export const getMessage = (id: string) => {
|
||||
export const getMessage_ = (id: string) => {
|
||||
let lang = window.navigator.language
|
||||
if (lang != "ja") {
|
||||
lang = "en"
|
||||
}
|
||||
|
||||
if (!messages[id]) {
|
||||
if (!messages_[id]) {
|
||||
return "undefined message."
|
||||
}
|
||||
|
||||
return messages[id][lang]
|
||||
return messages_[id][lang]
|
||||
}
|
@ -974,7 +974,12 @@ body {
|
||||
.tooltip-text-100px {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.tooltip-text-thin {
|
||||
line-height: 1rem;
|
||||
}
|
||||
.tooltip-text-right {
|
||||
line-height: 1rem;
|
||||
}
|
||||
.tooltip-text:before {
|
||||
content: "";
|
||||
position: absolute;
|
||||
@ -989,6 +994,11 @@ body {
|
||||
top: 30px;
|
||||
left: 0px;
|
||||
}
|
||||
.tooltip:hover .tooltip-text-lower {
|
||||
display: inline-block;
|
||||
top: 60px;
|
||||
left: 0px;
|
||||
}
|
||||
|
||||
.tooltip {
|
||||
position: relative;
|
||||
|
37
client/demo/src/hooks/useMessageBuilder.ts
Normal file
37
client/demo/src/hooks/useMessageBuilder.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import { useRef } from "react"
|
||||
|
||||
export type Message = {
|
||||
file: string,
|
||||
id: string,
|
||||
message: { [lang: string]: string }
|
||||
}
|
||||
|
||||
export type MessageBuilderStateAndMethod = {
|
||||
setMessage: (file: string, id: string, message: { [lang: string]: string }) => void
|
||||
getMessage: (file: string, id: string) => string
|
||||
}
|
||||
|
||||
export const useMessageBuilder = (): MessageBuilderStateAndMethod => {
|
||||
const messagesRef = useRef<Message[]>([])
|
||||
|
||||
const setMessage = (file: string, id: string, message: { [lang: string]: string }) => {
|
||||
if (messagesRef.current.find(x => { return x.file == file && x.id == id })) {
|
||||
console.warn("duplicate message is registerd", file, id, message)
|
||||
} else {
|
||||
messagesRef.current.push({ file, id, message })
|
||||
}
|
||||
}
|
||||
const getMessage = (file: string, id: string) => {
|
||||
let lang = window.navigator.language
|
||||
if (lang != "ja") {
|
||||
lang = "en"
|
||||
}
|
||||
|
||||
console.log(messagesRef.current)
|
||||
return messagesRef.current.find(x => { return x.file == file && x.id == id })?.message[lang] || "unknwon message"
|
||||
}
|
||||
return {
|
||||
setMessage,
|
||||
getMessage
|
||||
}
|
||||
}
|
4
client/lib/package-lock.json
generated
4
client/lib/package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@dannadori/voice-changer-client-js",
|
||||
"version": "1.0.143",
|
||||
"version": "1.0.144",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@dannadori/voice-changer-client-js",
|
||||
"version": "1.0.143",
|
||||
"version": "1.0.144",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@types/readable-stream": "^2.3.15",
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@dannadori/voice-changer-client-js",
|
||||
"version": "1.0.143",
|
||||
"version": "1.0.144",
|
||||
"description": "",
|
||||
"main": "dist/index.js",
|
||||
"directories": {
|
||||
|
Loading…
Reference in New Issue
Block a user