diff --git a/gui/scripts/i18n-backend.ts b/gui/scripts/i18n-backend.ts index 4471c51..d6584a2 100644 --- a/gui/scripts/i18n-backend.ts +++ b/gui/scripts/i18n-backend.ts @@ -10,7 +10,7 @@ const keys: Set = new Set(); async function updateFile() { delayId = null; - for (const lng of ["en", "zh-CN"]) { + for (const lng of ["en", 'ja', "zh-CN"]) { const translationPath = path.join( __dirname, `../src/i18n/translation/${lng}.json`, diff --git a/gui/src-tauri/src/main.rs b/gui/src-tauri/src/main.rs index 22e50d3..9424797 100644 --- a/gui/src-tauri/src/main.rs +++ b/gui/src-tauri/src/main.rs @@ -36,11 +36,12 @@ detectAndInject(); "#; #[tauri::command] -async fn open_splatnet(app: tauri::AppHandle, gtoken: String) -> Option<()> { +async fn open_splatnet(app: tauri::AppHandle, gtoken: String, lang: Option) -> Option<()> { + let ui_lang = lang.unwrap_or_else(|| "en-US".to_string()); let _window = WindowBuilder::new( &app, "splatnet3", - tauri::WindowUrl::App("https://api.lp1.av5ja.srv.nintendo.net/".into()), + tauri::WindowUrl::App(format!("https://api.lp1.av5ja.srv.nintendo.net/?lang={ui_lang}").into()), ) .title("Splatnet3") .center() diff --git a/gui/src/components/OpenSplatnet.tsx b/gui/src/components/OpenSplatnet.tsx index 89c999a..5155e0e 100644 --- a/gui/src/components/OpenSplatnet.tsx +++ b/gui/src/components/OpenSplatnet.tsx @@ -35,6 +35,7 @@ export const OpenSplatnet: React.FC = ({ children }) => { const gtoken = newState.loginState?.gToken; await invoke('open_splatnet', { gtoken, + lang: result.profile.state.userLang, }); } catch (e) { setError(e); diff --git a/gui/src/i18n/config.ts b/gui/src/i18n/config.ts index e574100..ea430c1 100644 --- a/gui/src/i18n/config.ts +++ b/gui/src/i18n/config.ts @@ -3,6 +3,7 @@ import LanguageDetector from 'i18next-browser-languagedetector'; import { initReactI18next } from 'react-i18next'; import en from './translation/en.json'; import zhCN from './translation/zh-CN.json'; +import ja from './translation/ja.json'; import HttpBackend from 'i18next-http-backend' export const resources = { @@ -11,6 +12,9 @@ export const resources = { }, 'zh-CN': { translation: zhCN, + }, + ja: { + translation: ja, } }; @@ -25,5 +29,6 @@ if (import.meta.env.DEV) { instance.init({ debug: import.meta.env.DEV, resources, + fallbackLng: 'en', // saveMissing: true, }); diff --git a/gui/src/i18n/translation/en.json b/gui/src/i18n/translation/en.json index 9e26dfe..a0cabf2 100644 --- a/gui/src/i18n/translation/en.json +++ b/gui/src/i18n/translation/en.json @@ -1 +1,23 @@ -{} \ No newline at end of file +{ + "保存": "Save", + "查看API密钥": "View API Key", + "打开 stat.ink": "Open stat.ink", + "打开鱿鱼圈3": "Open Splatnet3", + "导出": "Export", + "导出打工数据": "Export Salmon Run", + "导出对战数据": "Export VS", + "欢迎! 请点击\"导出\"按钮开始使用.": "Welcome! Please click \"Export\" button to start using.", + "界面语言": "Interface Language", + "没有更改": "No changes made", + "密钥的长度应该为{{length}}, 请检查": "The length of the key should be {{length}}, please check", + "前往 stat.ink": "Go to stat.ink", + "请从stat.ink中获取API密钥": "Please obtain the API key from stat.ink", + "请点击右上角的登录填入": "Please click the top right corner to log in", + "请先在设置中完成Nintendo Account登录和stat.ink的API密钥": "Please complete Nintendo Account login and stat.ink API key setup in settings first", + "设置": "Settings", + "网页登录": "Web Login", + "鱿鱼圈3语言偏好": "Splatnet3 Language", + "重置": "Reset", + "Nintendo Account 会话令牌": "Nintendo Account Session Token", + "stat.ink API密钥": "stat.ink API Key" +} \ No newline at end of file diff --git a/gui/src/i18n/translation/ja.json b/gui/src/i18n/translation/ja.json new file mode 100644 index 0000000..fbd8142 --- /dev/null +++ b/gui/src/i18n/translation/ja.json @@ -0,0 +1,23 @@ +{ + "保存": "保存", + "查看API密钥": "APIキーを表示する", + "打开 stat.ink": "stat.inkを開く", + "打开鱿鱼圈3": "イカリング3を開く", + "导出": "エクスポートする", + "导出打工数据": "勤務データをエクスポートする", + "导出对战数据": "対戦データをエクスポートする", + "欢迎! 请点击\"导出\"按钮开始使用.": "ようこそ!「エクスポート」ボタンをクリックして使い始めてください。", + "界面语言": "インターフェース言語", + "没有更改": "変更はありません", + "密钥的长度应该为{{length}}, 请检查": "キーの長さは{{length}}でなければなりません。確認してください。", + "前往 stat.ink": "stat.inkに移動する", + "请从stat.ink中获取API密钥": "stat.inkからAPIキーを取得してください", + "请点击右上角的登录填入": "右上隅のログインをクリックして入力してください", + "请先在设置中完成Nintendo Account登录和stat.ink的API密钥": "Nintendoアカウントのログインとstat.inkのAPIキー設定を先に設定してください", + "设置": "設定", + "网页登录": "ウェブサイトにログインする", + "鱿鱼圈3语言偏好": "イカリング3言語設定", + "重置": "リセット", + "Nintendo Account 会话令牌": "Nintendo Accountセッショントークン", + "stat.ink API密钥": "stat.ink APIキー" +} \ No newline at end of file diff --git a/gui/src/i18n/translation/zh-CN.json b/gui/src/i18n/translation/zh-CN.json index 9e26dfe..cb57b2b 100644 --- a/gui/src/i18n/translation/zh-CN.json +++ b/gui/src/i18n/translation/zh-CN.json @@ -1 +1,23 @@ -{} \ No newline at end of file +{ + "保存": "保存", + "查看API密钥": "查看API密钥", + "打开 stat.ink": "打开 stat.ink", + "打开鱿鱼圈3": "打开鱿鱼圈3", + "导出": "导出", + "导出打工数据": "导出打工数据", + "导出对战数据": "导出对战数据", + "欢迎! 请点击\"导出\"按钮开始使用.": "欢迎! 请点击\"导出\"按钮开始使用.", + "界面语言": "界面语言", + "没有更改": "没有更改", + "密钥的长度应该为{{length}}, 请检查": "密钥的长度应该为{{length}}, 请检查", + "前往 stat.ink": "前往 stat.ink", + "请从stat.ink中获取API密钥": "请从stat.ink中获取API密钥", + "请点击右上角的登录填入": "请点击右上角的登录填入", + "请先在设置中完成Nintendo Account登录和stat.ink的API密钥": "请先在设置中完成Nintendo Account登录和stat.ink的API密钥", + "设置": "设置", + "网页登录": "网页登录", + "鱿鱼圈3语言偏好": "鱿鱼圈3语言偏好", + "重置": "重置", + "Nintendo Account 会话令牌": "Nintendo Account 会话令牌", + "stat.ink API密钥": "stat.ink API密钥" +} \ No newline at end of file diff --git a/gui/src/pages/Settings.tsx b/gui/src/pages/Settings.tsx index 379e656..2c94cbe 100644 --- a/gui/src/pages/Settings.tsx +++ b/gui/src/pages/Settings.tsx @@ -27,12 +27,34 @@ type FormData = { profile: Profile, } +const SPLATNET3_LANGS = { + "de-DE": "German", + "en-GB": "English (UK/Australia)", + "en-US": "English (US)", + "es-ES": "Spanish (Spain)", + "es-MX": "Spanish (Latin America)", + "fr-CA": "French (Canada)", + "fr-FR": "French (France)", + "it-IT": "Italian", + "ja-JP": "Japanese", + "ko-KR": "Korean", + "nl-NL": "Dutch", + "ru-RU": "Russian", + "zh-CN": "Chinese (China)", + "zh-TW": "Chinese (Taiwan)" +} +const UI_LANGS = { + "en": "English", + "zh-CN": "简体中文", + "ja": "日本語", +}; + const Form: React.FC<{ oldValue: FormData, onSaved?: () => void, }> = ({ oldValue, onSaved }) => { const { login } = useLogin(); - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); const [value, setValue] = useState(oldValue); const { subField } = useSubField({ value, onChange: setValue }); @@ -40,6 +62,7 @@ const Form: React.FC<{ const sessionToken = subField('profile.state.loginState.sessionToken') const statInkApiKey = subField('profile.state.statInkApiKey') + const splatnet3Lang = subField('profile.state.userLang') const [onSave, { loading, error }] = usePromiseLazy(async () => { await setProfile(0, value.profile); @@ -100,6 +123,28 @@ const Form: React.FC<{ /> +
+ + +
+
+ + +