From 60e3234cf2bc8a4db065c39dea893e9a15bdd197 Mon Sep 17 00:00:00 2001 From: SheffeyG <57262511+SheffeyG@users.noreply.github.com> Date: Sat, 9 Nov 2024 20:43:41 +0800 Subject: [PATCH] feat: add multilingual support (#39) * move default.json to data * initial translate code * simplify code * rename zh-cn json * closure! no useMemo * initial translate strings * update en.json * update zh-cn.json * more languages * update default strings * add translator credit * setup languages --- src/{ => data}/default.json | 0 src/data/i18n/de.json | 40 ++++++++++++++++++++++++++++++ src/data/i18n/en.json | 40 ++++++++++++++++++++++++++++++ src/data/i18n/fr.json | 40 ++++++++++++++++++++++++++++++ src/data/i18n/ja.json | 40 ++++++++++++++++++++++++++++++ src/data/i18n/ko.json | 40 ++++++++++++++++++++++++++++++ src/data/i18n/ru.json | 41 +++++++++++++++++++++++++++++++ src/data/i18n/zh-cn.json | 40 ++++++++++++++++++++++++++++++ src/data/i18n/zh-tw.json | 40 ++++++++++++++++++++++++++++++ src/utils/options.ts | 8 ++++-- src/utils/translate.ts | 45 ++++++++++++++++++++++++++++++++++ src/views/Advanced.tsx | 20 +++++++++++---- src/views/Content.tsx | 31 ++++++++++++++++------- src/views/Custom/ModalEdit.tsx | 11 +++++---- src/views/Custom/ModalNew.tsx | 11 +++++---- src/views/Custom/index.tsx | 3 ++- src/views/Normal.tsx | 19 +++++++------- src/views/PageRouter.tsx | 7 +++--- 18 files changed, 437 insertions(+), 39 deletions(-) rename src/{ => data}/default.json (100%) create mode 100644 src/data/i18n/de.json create mode 100644 src/data/i18n/en.json create mode 100644 src/data/i18n/fr.json create mode 100644 src/data/i18n/ja.json create mode 100644 src/data/i18n/ko.json create mode 100644 src/data/i18n/ru.json create mode 100644 src/data/i18n/zh-cn.json create mode 100644 src/data/i18n/zh-tw.json create mode 100644 src/utils/translate.ts diff --git a/src/default.json b/src/data/default.json similarity index 100% rename from src/default.json rename to src/data/default.json diff --git a/src/data/i18n/de.json b/src/data/i18n/de.json new file mode 100644 index 0000000..cfe9928 --- /dev/null +++ b/src/data/i18n/de.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "Deutsch", + "CREDIT": "", + + "SAVE": "Speichern", + "DELETE": "Löschen", + "CANCEL": "Abbrechen", + "MESSAGE_SAVED": "Spielstartoptionen wurden gespeichert.", + "MESSAGE_NON_STEAM": "Warnung: Dies ist KEIN Steam-Spiel! Einstellungen werden niemals gespeichert.", + + "CONTENT_TITLE": "Informationen", + "CONTENT_NOTE0": "CheatDeck unterstützt derzeit nur den normalen Steam-Launcher.", + "CONTENT_NOTE1": "Bitte aktivieren Sie den Entwicklermodus in den SteamOS-Einstellungen;", + "CONTENT_NOTE2": "Sie finden die CheatDeck-Einstellung im Detailmenü des Spiels;", + "CONTENT_NOTE3": "Verwenden Sie die STEAM-Taste, um zwischen Spiel- und Cheat-Fenstern zu wechseln;", + "CONTENT_NOTE4": "Wenn Sie nicht auf das ausgewählte Cheat-Panel klicken können, schalten Sie das Spiel bitte in den Fenstermodus.", + "CONTENT_GH_DESC": "Besuchen Sie die GitHub-Seite für weitere Informationen und Hilfe bei der Übersetzung.", + "CONTENT_QR_DESC": "Link-QR anzeigen", + + "NORMAL_TITLE": "Normal", + "NORMAL_CHEAT_TOGGLE_LABEL": "Cheat aktivieren", + "NORMAL_CHEAT_TOGGLE_DESC": "Wählen Sie die Cheat- oder Trainer-Exe-Datei aus dem Speicher aus", + "NORMAL_CHEAT_LABEL": "EXE-Pfad", + "NORMAL_LANG_TOGGLE_LABEL": "Sprache", + "NORMAL_LANG_TOGGLE_DESC": "Legen Sie die Spielumgebungssprache fest", + "NORMAL_LANG_LABEL": "Sprachcode", + "NORMAL_LANG_DEFAULT": "Standard", + + "ADVANCED_TITLE": "Erweitert", + "ADVANCED_DXVK_ASYNC_DESC": "Optimieren Sie die ProtonGE-Kompatibilitätsschicht, um die Framezeit und die Eingabeverzögerung zu reduzieren", + "ADVANCED_RADV_PERFTEST_DESC": "Optimieren Sie das Shader-Cache-Verhalten der ProtonGE-Kompatibilitätsschicht", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "Geben Sie den Speicherpfad für Spieldaten an", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "Präfix-Ordner", + + "CUSTOM_TITLE": "Benutzerdefiniert", + "CUSTOM_OPTION_LABEL": "Bezeichnung", + "CUSTOM_OPTION_Fields": "Feld & Wert", + "CUSTOM_EDIT_TITLE": "Option bearbeiten", + "CUSTOM_NEW_TITLE": "Neue Option hinzufügen" +} diff --git a/src/data/i18n/en.json b/src/data/i18n/en.json new file mode 100644 index 0000000..5f320da --- /dev/null +++ b/src/data/i18n/en.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "Translator", + "CREDIT": "", + + "SAVE": "Save", + "DELETE": "Delete", + "CANCEL": "Cancel", + "MESSAGE_SAVED": "Game launch options have been saved.", + "MESSAGE_NON_STEAM": "Warning: This is NOT a Steam game! Settings will never be saved.", + + "CONTENT_TITLE": "Information", + "CONTENT_NOTE0": "CheatDeck only support the normal Steam launcher for now.", + "CONTENT_NOTE1": "Please enable developer mode in the SteamOS settings;", + "CONTENT_NOTE2": "You can find the CheatDeck setting in the game details menu;", + "CONTENT_NOTE3": "Use the STEAM key to switch between game and cheat windows;", + "CONTENT_NOTE4": "If you are unable to click the selected cheat panel, please turn the game to window mode.", + "CONTENT_GH_DESC": "Check the GitHub page for more information and help translation.", + "CONTENT_QR_DESC": "Show Link QR", + + "NORMAL_TITLE": "Normal", + "NORMAL_CHEAT_TOGGLE_LABEL": "Enable Cheat", + "NORMAL_CHEAT_TOGGLE_DESC": "Select the cheat or trainer exe file from storage", + "NORMAL_CHEAT_LABEL": "EXE Path", + "NORMAL_LANG_TOGGLE_LABEL": "Language", + "NORMAL_LANG_TOGGLE_DESC": "Set the game enviroment language", + "NORMAL_LANG_LABEL": "Language Code", + "NORMAL_LANG_DEFAULT": "Default", + + "ADVANCED_TITLE": "Advanced", + "ADVANCED_DXVK_ASYNC_DESC": "Optimize the ProtonGE compatibility layer to reduce frame time and input lag", + "ADVANCED_RADV_PERFTEST_DESC": "Optimize the shader cache behavior of the ProtonGE compatibility layer", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "Specify the game data save path", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "Prefix Folder", + + "CUSTOM_TITLE": "Custom", + "CUSTOM_OPTION_LABEL": "Label", + "CUSTOM_OPTION_Fields": "Field & Value", + "CUSTOM_EDIT_TITLE": "Edit Option", + "CUSTOM_NEW_TITLE": "Add a New Option" +} \ No newline at end of file diff --git a/src/data/i18n/fr.json b/src/data/i18n/fr.json new file mode 100644 index 0000000..97de768 --- /dev/null +++ b/src/data/i18n/fr.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "Traduction française", + "CREDIT": "", + + "SAVE": "Enregistrer", + "DELETE": "Supprimer", + "CANCEL": "Annuler", + "MESSAGE_SAVED": "Les options de lancement du jeu ont été enregistrées.", + "MESSAGE_NON_STEAM": "Attention : Ceci n'est PAS un jeu Steam ! Les paramètres ne seront jamais enregistrés.", + + "CONTENT_TITLE": "Informations", + "CONTENT_NOTE0": "CheatDeck ne prend en charge que le lanceur Steam normal pour le moment.", + "CONTENT_NOTE1": "Veuillez activer le mode développeur dans les paramètres SteamOS ;", + "CONTENT_NOTE2": "Vous pouvez trouver le paramètre CheatDeck dans le menu des détails du jeu ;", + "CONTENT_NOTE3": "Utilisez la touche STEAM pour basculer entre le jeu et les fenêtres de triche ;", + "CONTENT_NOTE4": "Si vous ne parvenez pas à cliquer sur le panneau de triche sélectionné, veuillez passer le jeu en mode fenêtré.", + "CONTENT_GH_DESC": "Consultez la page GitHub pour plus d'informations et pour aider à la traduction.", + "CONTENT_QR_DESC": "Afficher le QR Code du lien", + + "NORMAL_TITLE": "Normal", + "NORMAL_CHEAT_TOGGLE_LABEL": "Activer la triche", + "NORMAL_CHEAT_TOGGLE_DESC": "Sélectionnez le fichier exe de triche ou d'entraîneur dans le stockage", + "NORMAL_CHEAT_LABEL": "Chemin EXE", + "NORMAL_LANG_TOGGLE_LABEL": "Langue", + "NORMAL_LANG_TOGGLE_DESC": "Définir la langue de l'environnement du jeu", + "NORMAL_LANG_LABEL": "Code de langue", + "NORMAL_LANG_DEFAULT": "Par défaut", + + "ADVANCED_TITLE": "Avancé", + "ADVANCED_DXVK_ASYNC_DESC": "Optimiser la couche de compatibilité ProtonGE pour réduire le temps d'image et le décalage d'entrée", + "ADVANCED_RADV_PERFTEST_DESC": "Optimiser le comportement du cache de shader de la couche de compatibilité ProtonGE", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "Spécifier le chemin de sauvegarde des données de jeu", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "Dossier préfixe", + + "CUSTOM_TITLE": "Personnalisé", + "CUSTOM_OPTION_LABEL": "Étiquette", + "CUSTOM_OPTION_Fields": "Champ & Valeur", + "CUSTOM_EDIT_TITLE": "Modifier l'option", + "CUSTOM_NEW_TITLE": "Ajouter une nouvelle option" +} diff --git a/src/data/i18n/ja.json b/src/data/i18n/ja.json new file mode 100644 index 0000000..4a765f3 --- /dev/null +++ b/src/data/i18n/ja.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "日本語翻訳", + "CREDIT": "", + + "SAVE": "保存", + "DELETE": "削除", + "CANCEL": "キャンセル", + "MESSAGE_SAVED": "ゲームの起動オプションが保存されました。", + "MESSAGE_NON_STEAM": "警告: これはSteamゲームではありません!設定は保存されません。", + + "CONTENT_TITLE": "情報", + "CONTENT_NOTE0": "CheatDeckは現在、通常のSteamランチャーのみをサポートしています。", + "CONTENT_NOTE1": "SteamOSの設定で開発者モードを有効にしてください。", + "CONTENT_NOTE2": "ゲームの詳細メニューでCheatDeckの設定を見つけることができます。", + "CONTENT_NOTE3": "STEAMキーを使用して、ゲームウィンドウとチートウィンドウを切り替えます。", + "CONTENT_NOTE4": "選択したチートパネルをクリックできない場合は、ゲームをウィンドウモードにしてください。", + "CONTENT_GH_DESC": "詳細情報と翻訳のヘルプについては、GitHubページをご覧ください。", + "CONTENT_QR_DESC": "リンクQRを表示", + + "NORMAL_TITLE": "標準", + "NORMAL_CHEAT_TOGGLE_LABEL": "チートを有効にする", + "NORMAL_CHEAT_TOGGLE_DESC": "ストレージからチートまたはトレーナーexeファイルを選択します", + "NORMAL_CHEAT_LABEL": "EXEパス", + "NORMAL_LANG_TOGGLE_LABEL": "言語", + "NORMAL_LANG_TOGGLE_DESC": "ゲーム環境の言語を設定します", + "NORMAL_LANG_LABEL": "言語コード", + "NORMAL_LANG_DEFAULT": "デフォルト", + + "ADVANCED_TITLE": "詳細設定", + "ADVANCED_DXVK_ASYNC_DESC": "ProtonGE互換性レイヤーを最適化して、フレーム時間と入力ラグを短縮します", + "ADVANCED_RADV_PERFTEST_DESC": "ProtonGE互換性レイヤーのシェーダーキャッシュ動作を最適化します", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "ゲームデータの保存パスを指定します", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "プレフィックスフォルダー", + + "CUSTOM_TITLE": "カスタム", + "CUSTOM_OPTION_LABEL": "ラベル", + "CUSTOM_OPTION_Fields": "フィールドと値", + "CUSTOM_EDIT_TITLE": "オプションを編集", + "CUSTOM_NEW_TITLE": "新しいオプションを追加" +} diff --git a/src/data/i18n/ko.json b/src/data/i18n/ko.json new file mode 100644 index 0000000..7fb8805 --- /dev/null +++ b/src/data/i18n/ko.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "한국어 번역", + "CREDIT": "", + + "SAVE": "저장", + "DELETE": "삭제", + "CANCEL": "취소", + "MESSAGE_SAVED": "게임 실행 옵션이 저장되었습니다.", + "MESSAGE_NON_STEAM": "경고: 스팀 게임이 아닙니다! 설정이 저장되지 않습니다.", + + "CONTENT_TITLE": "정보", + "CONTENT_NOTE0": "CheatDeck은 현재 일반 스팀 런처만 지원합니다.", + "CONTENT_NOTE1": "SteamOS 설정에서 개발자 모드를 활성화하십시오.", + "CONTENT_NOTE2": "게임 세부 정보 메뉴에서 CheatDeck 설정을 찾을 수 있습니다.", + "CONTENT_NOTE3": "STEAM 키를 사용하여 게임 및 치트 창 사이를 전환하십시오.", + "CONTENT_NOTE4": "선택한 치트 패널을 클릭할 수 없는 경우 게임을 창 모드로 전환하십시오.", + "CONTENT_GH_DESC": "자세한 정보 및 번역 지원은 GitHub 페이지를 확인하십시오.", + "CONTENT_QR_DESC": "링크 QR 표시", + + "NORMAL_TITLE": "일반", + "NORMAL_CHEAT_TOGGLE_LABEL": "치트 활성화", + "NORMAL_CHEAT_TOGGLE_DESC": "저장소에서 치트 또는 트레이너 exe 파일을 선택하십시오.", + "NORMAL_CHEAT_LABEL": "EXE 경로", + "NORMAL_LANG_TOGGLE_LABEL": "언어", + "NORMAL_LANG_TOGGLE_DESC": "게임 환경 언어를 설정하십시오.", + "NORMAL_LANG_LABEL": "언어 코드", + "NORMAL_LANG_DEFAULT": "기본값", + + "ADVANCED_TITLE": "고급", + "ADVANCED_DXVK_ASYNC_DESC": "프레임 시간 및 입력 지연을 줄이기 위해 ProtonGE 호환성 레이어를 최적화합니다.", + "ADVANCED_RADV_PERFTEST_DESC": "ProtonGE 호환성 레이어의 셰이더 캐시 동작을 최적화합니다.", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "게임 데이터 저장 경로를 지정하십시오.", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "접두사 폴더", + + "CUSTOM_TITLE": "사용자 지정", + "CUSTOM_OPTION_LABEL": "레이블", + "CUSTOM_OPTION_Fields": "필드 및 값", + "CUSTOM_EDIT_TITLE": "옵션 편집", + "CUSTOM_NEW_TITLE": "새 옵션 추가" +} diff --git a/src/data/i18n/ru.json b/src/data/i18n/ru.json new file mode 100644 index 0000000..32e53c0 --- /dev/null +++ b/src/data/i18n/ru.json @@ -0,0 +1,41 @@ +{ + "TRANSLATION": "Русский перевод", + "CREDIT": "", + + "SAVE": "Сохранить", + "DELETE": "Удалить", + "CANCEL": "Отмена", + "MESSAGE_SAVED": "Параметры запуска игры сохранены.", + "MESSAGE_NON_STEAM": "Внимание: это НЕ игра Steam! Настройки не будут сохранены.", + + "CONTENT_TITLE": "Информация", + "CONTENT_NOTE0": "CheatDeck пока поддерживает только обычный лаунчер Steam.", + "CONTENT_NOTE1": "Включите режим разработчика в настройках SteamOS;", + "CONTENT_NOTE2": "Настройки CheatDeck можно найти в меню подробной информации об игре;", + "CONTENT_NOTE3": "Используйте клавишу STEAM для переключения между окнами игры и читов;", + "CONTENT_NOTE4": "Если вы не можете щелкнуть выбранную панель читов, переключите игру в оконный режим.", + "CONTENT_GH_DESC": "Посетите страницу GitHub для получения дополнительной информации и помощи с переводом.", + "CONTENT_QR_DESC": "Показать QR-код ссылки", + + "NORMAL_TITLE": "Обычные", + "NORMAL_CHEAT_TOGGLE_LABEL": "Включить читы", + "NORMAL_CHEAT_TOGGLE_DESC": "Выберите файл с читами или трейнером (exe) из хранилища", + "NORMAL_CHEAT_LABEL": "Путь к EXE-файлу", + "NORMAL_LANG_TOGGLE_LABEL": "Язык", + "NORMAL_LANG_TOGGLE_DESC": "Установить язык игровой среды", + "NORMAL_LANG_LABEL": "Код языка", + "NORMAL_LANG_DEFAULT": "По умолчанию", + + "ADVANCED_TITLE": "Дополнительные", + "ADVANCED_DXVK_ASYNC_DESC": "Оптимизировать слой совместимости ProtonGE для уменьшения времени кадра и задержки ввода", + "ADVANCED_RADV_PERFTEST_DESC": "Оптимизировать поведение кэша шейдеров слоя совместимости ProtonGE", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "Указать путь сохранения данных игры", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "Папка префикса", + + "CUSTOM_TITLE": "Пользовательские", + "CUSTOM_OPTION_LABEL": "Метка", + "CUSTOM_OPTION_Fields": "Поле и значение", + "CUSTOM_EDIT_TITLE": "Редактировать параметр", + "CUSTOM_NEW_TITLE": "Добавить новый параметр" +} + diff --git a/src/data/i18n/zh-cn.json b/src/data/i18n/zh-cn.json new file mode 100644 index 0000000..3dcb5fc --- /dev/null +++ b/src/data/i18n/zh-cn.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "简体中文翻译", + "CREDIT": "sheffey", + + "SAVE": "保存", + "DELETE": "删除", + "CANCEL": "取消", + "MESSAGE_SAVED": "游戏启动项已保存。", + "MESSAGE_NON_STEAM": "警告: 非 Steam 游戏! 设置将不会被保存。", + + "CONTENT_TITLE": "说明", + "CONTENT_NOTE0": "CheatDeck 目前仅支持原生 Steam 游戏启动器。", + "CONTENT_NOTE1": "请在 SteamOS 设置中启用开发者模式;", + "CONTENT_NOTE2": "你可以在游戏详情菜单中找到 CheatDeck 设置;", + "CONTENT_NOTE3": "使用 STEAM 键来切换游戏窗口和修改器窗口;", + "CONTENT_NOTE4": "如无法点击修改器窗口,请在游戏中启用窗口模式。", + "CONTENT_GH_DESC": "查看 GitHub 页面以获取更多信息或帮助我们翻译该软件", + "CONTENT_QR_DESC": "显示链接二维码", + + "NORMAL_TITLE": "常规", + "NORMAL_CHEAT_TOGGLE_LABEL": "启用修改器", + "NORMAL_CHEAT_TOGGLE_DESC": "从系统存储中选择需要启用的游戏修改器", + "NORMAL_CHEAT_LABEL": "EXE 路径", + "NORMAL_LANG_TOGGLE_LABEL": "语言", + "NORMAL_LANG_TOGGLE_DESC": "设置游戏环境语言", + "NORMAL_LANG_LABEL": "语言编码", + "NORMAL_LANG_DEFAULT": "默认", + + "ADVANCED_TITLE": "高级", + "ADVANCED_DXVK_ASYNC_DESC": "优化 ProtonGE 兼容层减少帧时间和输入延迟", + "ADVANCED_RADV_PERFTEST_DESC": "优化 ProtonGE 兼容层着色器缓存行为", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "指定游戏数据保存路径", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "Prefix 路径", + + "CUSTOM_TITLE": "自定义", + "CUSTOM_OPTION_LABEL": "标签", + "CUSTOM_OPTION_Fields": "字段 & 值", + "CUSTOM_EDIT_TITLE": "编辑启动项", + "CUSTOM_NEW_TITLE": "新建启动项" +} \ No newline at end of file diff --git a/src/data/i18n/zh-tw.json b/src/data/i18n/zh-tw.json new file mode 100644 index 0000000..6d4b3b0 --- /dev/null +++ b/src/data/i18n/zh-tw.json @@ -0,0 +1,40 @@ +{ + "TRANSLATION": "繁體中文翻譯", + "CREDIT": "sheffey", + + "SAVE": "儲存", + "DELETE": "刪除", + "CANCEL": "取消", + "MESSAGE_SAVED": "遊戲啟動項已儲存。", + "MESSAGE_NON_STEAM": "警告: 非 Steam 遊戲! 設定將不會被儲存。", + + "CONTENT_TITLE": "說明", + "CONTENT_NOTE0": "CheatDeck 目前僅支援原生 Steam 遊戲啟動器。", + "CONTENT_NOTE1": "請在 SteamOS 設定中啟用開發者模式;", + "CONTENT_NOTE2": "您可以在遊戲詳情選單中找到 CheatDeck 設定;", + "CONTENT_NOTE3": "使用 STEAM 鍵來切換遊戲視窗和修改器視窗;", + "CONTENT_NOTE4": "如無法點擊修改器視窗,請在遊戲中啟用視窗模式。", + "CONTENT_GH_DESC": "檢視 GitHub 頁面以取得更多資訊或協助我們翻譯該軟體", + "CONTENT_QR_DESC": "顯示連結 QR Code", + + "NORMAL_TITLE": "一般", + "NORMAL_CHEAT_TOGGLE_LABEL": "啟用修改器", + "NORMAL_CHEAT_TOGGLE_DESC": "從系統儲存中選擇需要啟用的遊戲修改器", + "NORMAL_CHEAT_LABEL": "EXE 路徑", + "NORMAL_LANG_TOGGLE_LABEL": "語言", + "NORMAL_LANG_TOGGLE_DESC": "設定遊戲環境語言", + "NORMAL_LANG_LABEL": "語言編碼", + "NORMAL_LANG_DEFAULT": "預設", + + "ADVANCED_TITLE": "進階", + "ADVANCED_DXVK_ASYNC_DESC": "最佳化 ProtonGE 相容層減少幀時間和輸入延遲", + "ADVANCED_RADV_PERFTEST_DESC": "最佳化 ProtonGE 相容層著色器快取行為", + "ADVANCED_STEAM_COMPAT_DATA_PATH_DESC": "指定遊戲資料儲存路徑", + "ADVANCED_STEAM_COMPAT_DATA_PATH_LABEL": "Prefix 路徑", + + "CUSTOM_TITLE": "自訂", + "CUSTOM_OPTION_LABEL": "標籤", + "CUSTOM_OPTION_Fields": "欄位 & 值", + "CUSTOM_EDIT_TITLE": "編輯啟動項", + "CUSTOM_NEW_TITLE": "新增啟動項" +} diff --git a/src/utils/options.ts b/src/utils/options.ts index 9b15b2c..7c7a0ac 100644 --- a/src/utils/options.ts +++ b/src/utils/options.ts @@ -1,4 +1,5 @@ import { Backend } from "./backend"; +import t from "./translate"; export class Options { #options: { [key: string]: string }; @@ -71,11 +72,14 @@ export class Options { saveOptions(appid: number) { if (this.#isSteam) { SteamClient.Apps.SetAppLaunchOptions(appid, this.getOptionsString()); - Backend.sendNotice("Launch Options Saved."); + Backend.sendNotice(t("MESSAGE_SAVED", "Game launch options have been saved.")); } else { // Never change anything for non-steam games - Backend.sendNotice("Warning: This is not a steam game! settings will not be saved."); + Backend.sendNotice(t( + "MESSAGE_NON_STEAM", + "Warning: This is NOT a steam game! Settings will never be saved.", + )); } }; } diff --git a/src/utils/translate.ts b/src/utils/translate.ts new file mode 100644 index 0000000..ba2ee75 --- /dev/null +++ b/src/utils/translate.ts @@ -0,0 +1,45 @@ +import logger from "./logger"; + +import * as de from "../data/i18n/de.json"; +import * as en from "../data/i18n/en.json"; +import * as fr from "../data/i18n/fr.json"; +import * as ja from "../data/i18n/ja.json"; +import * as ko from "../data/i18n/ko.json"; +import * as ru from "../data/i18n/ru.json"; +import * as zhCn from "../data/i18n/zh-cn.json"; +import * as zhTw from "../data/i18n/zh-tw.json"; + +type Language = { [key: string]: string }; +type Languages = { [key: string]: Language }; + +const languages: Languages = { + de, + en, + fr, + ja, + ko, + ru, + zhCn, + zhTw, +}; + +function getCurrentLangCode(): string { + const steamLang = window.LocalizationManager.m_rgLocalesToUse[0]; + const langCode = steamLang.replace( + /-([a-z])/g, (_, letter: string) => letter.toUpperCase(), + ); + logger.info(`LanguageCode: ${langCode}`); + return langCode; +} + +function translate() { + const langCode: string = getCurrentLangCode(); + const lang: Language = languages[langCode] ?? languages.en; + return function (label: string, defaultString: string): string { + return lang[label] ?? defaultString; + }; +} + +const t = translate(); + +export default t; diff --git a/src/views/Advanced.tsx b/src/views/Advanced.tsx index b051dac..6a048cf 100644 --- a/src/views/Advanced.tsx +++ b/src/views/Advanced.tsx @@ -12,6 +12,7 @@ import { FC, useEffect, useState } from "react"; import { Backend } from "../utils/backend"; import { Options } from "../utils/options"; import { FaFolderOpen } from "react-icons/fa"; +import t from "../utils/translate"; const Advanced: FC<{ appid: number }> = ({ appid }) => { const [options, setOptions] = useState(new Options("")); @@ -44,7 +45,10 @@ const Advanced: FC<{ appid: number }> = ({ appid }) => { { @@ -56,7 +60,10 @@ const Advanced: FC<{ appid: number }> = ({ appid }) => { { @@ -68,7 +75,10 @@ const Advanced: FC<{ appid: number }> = ({ appid }) => { { @@ -83,7 +93,7 @@ const Advanced: FC<{ appid: number }> = ({ appid }) => { {showPrefix && ( @@ -133,7 +143,7 @@ const Advanced: FC<{ appid: number }> = ({ appid }) => { width: "80%", }} > - Save Settings + {t("SAVE", "Save")} ); diff --git a/src/views/Content.tsx b/src/views/Content.tsx index e83d60c..fabe701 100644 --- a/src/views/Content.tsx +++ b/src/views/Content.tsx @@ -12,7 +12,11 @@ import { import { HiQrCode } from "react-icons/hi2"; import { QRCodeSVG } from "qrcode.react"; +import t from "../utils/translate"; + const Content = () => { + const translator = t("CREDIT", ""); + const navLink = (url: string) => { Navigation.CloseSideMenus(); Navigation.NavigateToExternalWeb(url); @@ -34,7 +38,7 @@ const Content = () => { }; return ( - + {}} @@ -45,14 +49,23 @@ const Content = () => { }} > -

CheatDeck only support the normal steam launcher for now.

-
  • Please enable developer mode in the steam system settings.
  • -
  • You can find the cheat settings in the game details menu.
  • -
  • Use the steam key to switch between game and cheat windows.
  • -
  • If you are unable to click the selected cheat panel, please turn the game to window mode.
  • +

    {t("CONTENT_NOTE0", "CheatDeck only support the normal steam launcher for now.")}

    +
  • {t("CONTENT_NOTE1", "Please enable developer mode in the steam system settings.")}
  • +
  • {t("CONTENT_NOTE2", "You can find the cheat settings in the game details menu.")}
  • +
  • {t("CONTENT_NOTE3", "Use the steam key to switch between game and cheat windows.")}
  • +
  • {t("CONTENT_NOTE4", "If you are unable to click the selected cheat panel, please turn the game to window mode.")}
  • + {translator.length > 0 && ( + +

    + {t("TRANSLATION", "Translator") + ": "} + {translator} +

    +
    + )} + { padding="none" spacingBetweenLabelAndChild="none" childrenContainerWidth="max" - description="For more information, check the GitHub page." + description={t("CONTENT_GH_DESC", "For more information, check the GitHub page.")} > navLink("https://github.com/SheffeyG/CheatDeck")} onSecondaryButton={() => showQrModal("https://github.com/SheffeyG/CheatDeck")} - onSecondaryActionDescription="Show Link QR" + onSecondaryActionDescription={t("CONTENT_QR_DESC", "Show Link QR")} style={{ padding: "10px", fontSize: "14px", @@ -78,7 +91,7 @@ const Content = () => { GitHub showQrModal("https://github.com/SheffeyG/CheatDeck")} style={{ display: "flex", diff --git a/src/views/Custom/ModalEdit.tsx b/src/views/Custom/ModalEdit.tsx index 85663cb..30b3d0d 100644 --- a/src/views/Custom/ModalEdit.tsx +++ b/src/views/Custom/ModalEdit.tsx @@ -9,6 +9,7 @@ import { import { FC, useState } from "react"; import { CustomOption, setCustomOptions } from "../../utils/custom"; +import t from "../../utils/translate"; export const ModalEdit: FC<{ closeModal?: () => void; @@ -38,9 +39,9 @@ export const ModalEdit: FC<{ return (
    - Edit Option + {t("CUSTOM_EDIT_TITLE", "Edit Option")} @@ -60,7 +61,7 @@ export const ModalEdit: FC<{ @@ -97,13 +98,13 @@ export const ModalEdit: FC<{ onClick={() => handleSave("Save")} style={{ alignSelf: "center", marginTop: "20px", fontSize: "14px", textAlign: "center", width: "200px" }} > - Save + {t("SAVE", "Save")} handleSave("Delete")} style={{ alignSelf: "center", marginTop: "20px", fontSize: "14px", textAlign: "center", width: "200px" }} > - Delete + {t("DELETE", "Delete")}
    diff --git a/src/views/Custom/ModalNew.tsx b/src/views/Custom/ModalNew.tsx index d439720..8d89ca1 100644 --- a/src/views/Custom/ModalNew.tsx +++ b/src/views/Custom/ModalNew.tsx @@ -9,6 +9,7 @@ import { import { FC, useState } from "react"; import { CustomOption, getEmptyCusOpt, setCustomOptions } from "../../utils/custom"; +import t from "../../utils/translate"; export const ModalNew: FC<{ closeModal?: () => void; @@ -32,9 +33,9 @@ export const ModalNew: FC<{ return (
    - Add a New Option + {t("CUSTOM_NEW_TITLE", "Add a New Option")} @@ -54,7 +55,7 @@ export const ModalNew: FC<{ @@ -91,13 +92,13 @@ export const ModalNew: FC<{ onClick={() => handleSave()} style={{ alignSelf: "center", marginTop: "20px", fontSize: "14px", textAlign: "center", width: "200px" }} > - Save + {t("SAVE", "Save")} - Cancel + {t("CANCEL", "Cancel")}
    diff --git a/src/views/Custom/index.tsx b/src/views/Custom/index.tsx index e3e8164..3a4c409 100644 --- a/src/views/Custom/index.tsx +++ b/src/views/Custom/index.tsx @@ -13,6 +13,7 @@ import { CustomOption, getCustomOptions } from "../../utils/custom"; import { ModalEdit } from "./ModalEdit"; import { ModalNew } from "./ModalNew"; import { Options } from "../../utils/options"; +import t from "../../utils/translate"; const Custom: FC<{ appid: number }> = ({ appid }) => { // Custom Options from user's saved settings @@ -139,7 +140,7 @@ const Custom: FC<{ appid: number }> = ({ appid }) => { className="CD_SaveButton" onClick={() => options.saveOptions(appid)} > - Save Settings + {t("SAVE", "Save")}
    )} diff --git a/src/views/Normal.tsx b/src/views/Normal.tsx index dbc6875..3016d10 100644 --- a/src/views/Normal.tsx +++ b/src/views/Normal.tsx @@ -14,7 +14,8 @@ import { FaGamepad, FaLanguage, FaFolderOpen } from "react-icons/fa"; // import logger from "../utils/logger" import { Backend } from "../utils/backend"; import { Options } from "../utils/options"; -import { LangCodes } from "../default.json"; +import { LangCodes } from "../data/default.json"; +import t from "../utils/translate"; const Normal: FC<{ appid: number }> = ({ appid }) => { const [options, setOptions] = useState(new Options("")); @@ -52,8 +53,8 @@ const Normal: FC<{ appid: number }> = ({ appid }) => { } bottomSeparator="none" checked={showCheat} @@ -70,7 +71,7 @@ const Normal: FC<{ appid: number }> = ({ appid }) => { {showCheat && ( @@ -110,8 +111,8 @@ const Normal: FC<{ appid: number }> = ({ appid }) => { )} } checked={showLang} bottomSeparator="none" @@ -126,7 +127,7 @@ const Normal: FC<{ appid: number }> = ({ appid }) => { /> {showLang && ( @@ -162,7 +163,7 @@ const Normal: FC<{ appid: number }> = ({ appid }) => { updatedOptions.setFieldValue("LANG", `"${v.data}"`); setOptions(updatedOptions); }} - strDefaultLabel="Default" + strDefaultLabel={t("NORMAL_LANG_DEFAULT", "Default")} />
    @@ -179,7 +180,7 @@ const Normal: FC<{ appid: number }> = ({ appid }) => { width: "80%", }} > - Save Settings + {t("SAVE", "Save")} ); diff --git a/src/views/PageRouter.tsx b/src/views/PageRouter.tsx index a954935..d6ea6a7 100644 --- a/src/views/PageRouter.tsx +++ b/src/views/PageRouter.tsx @@ -9,6 +9,7 @@ import { import Normal from "./Normal"; import Advanced from "./Advanced"; import Custom from "./Custom"; +import t from "../utils/translate"; const PageRouter: FC = () => { let { appid } = useParams<{ appid: number }>(); @@ -17,19 +18,19 @@ const PageRouter: FC = () => { } const pages = [ { - title: "Normal", + title: t("NORMAL_TITLE", "Normal"), content: , icon: , hideTitle: false, }, { - title: "Advanced", + title: t("ADVANCED_TITLE", "Advanced"), content: , icon: , hideTitle: false, }, { - title: "Custom", + title: t("CUSTOM_TITLE", "Custom"), content: , icon: , hideTitle: false,