diff options
Diffstat (limited to 'src/components')
| -rw-r--r-- | src/components/ConfigurationSection.tsx | 53 | ||||
| -rw-r--r-- | src/components/Content.tsx | 7 | ||||
| -rw-r--r-- | src/components/FgmodClipboardButton.tsx | 3 | ||||
| -rw-r--r-- | src/components/FlatpaksModal.tsx | 91 | ||||
| -rw-r--r-- | src/components/FpsMultiplierControl.tsx | 3 | ||||
| -rw-r--r-- | src/components/InstallationButton.tsx | 9 | ||||
| -rw-r--r-- | src/components/NerdStuffModal.tsx | 31 | ||||
| -rw-r--r-- | src/components/ProfileManagement.tsx | 41 | ||||
| -rw-r--r-- | src/components/SmartClipboardButton.tsx | 3 | ||||
| -rw-r--r-- | src/components/UsageInstructions.tsx | 7 |
10 files changed, 129 insertions, 119 deletions
diff --git a/src/components/ConfigurationSection.tsx b/src/components/ConfigurationSection.tsx index 344481e..a10aab2 100644 --- a/src/components/ConfigurationSection.tsx +++ b/src/components/ConfigurationSection.tsx @@ -7,6 +7,7 @@ import { EXPERIMENTAL_PRESENT_MODE, DXVK_FRAME_RATE, DISABLE_STEAMDECK_MODE, MANGOHUD_WORKAROUND, DISABLE_VKBASALT, FORCE_ENABLE_VKBASALT, ENABLE_WSI, ENABLE_ZINK } from "../config/generatedConfigSchema"; +import t from '../i18n/i18n'; interface ConfigurationSectionProps { config: ConfigurationData; @@ -84,7 +85,7 @@ export function ConfigurationSection({ color: "white" }} > - Config + {t('CONFIG_SECTION_TITLE', 'Config')} </div> </PanelSectionRow> @@ -115,8 +116,8 @@ export function ConfigurationSection({ <> <PanelSectionRow> <SliderField - label={`Flow Scale (${Math.round(config.flow_scale * 100)}%)`} - description="Lowers internal motion estimation resolution, improving performance slightly" + label={`${t('CONFIG_FLOW_SCALE', 'Flow Scale')} (${Math.round(config.flow_scale * 100)}%)`} + description={t('CONFIG_FLOW_SCALE_DESC', 'Lowers internal motion estimation resolution, improving performance slightly')} value={config.flow_scale} min={0.25} max={1.0} @@ -136,8 +137,8 @@ export function ConfigurationSection({ <PanelSectionRow> <SliderField - label={`Base FPS Cap${config.dxvk_frame_rate > 0 ? ` (${config.dxvk_frame_rate} FPS)` : " (Off)"}`} - description="Base framerate cap for DirectX games, before frame multiplier. (Requires game restart to apply)" + label={`${t('CONFIG_BASE_FPS_CAP', 'Base FPS Cap')}${config.dxvk_frame_rate > 0 ? ` (${config.dxvk_frame_rate} FPS)` : ` (${t('CONFIG_BASE_FPS_CAP_OFF', 'Off')})`}`} + description={t('CONFIG_BASE_FPS_CAP_DESC', 'Base framerate cap for DirectX games, before frame multiplier. (Requires game restart to apply)')} value={config.dxvk_frame_rate} min={0} max={60} @@ -148,8 +149,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label={`Present Mode (${(config.experimental_present_mode || "fifo") === "fifo" ? "FIFO - VSync" : "Mailbox"})`} - description="Toggle between FIFO - VSync (default) and Mailbox presentation modes for better performance or compatibility" + label={`${t('CONFIG_PRESENT_MODE', 'Present Mode')} (${(config.experimental_present_mode || "fifo") === "fifo" ? t('CONFIG_PRESENT_MODE_FIFO', 'FIFO - VSync') : t('CONFIG_PRESENT_MODE_MAILBOX', 'Mailbox')})`} + description={t('CONFIG_PRESENT_MODE_DESC', 'Toggle between FIFO - VSync (default) and Mailbox presentation modes for better performance or compatibility')} checked={(config.experimental_present_mode || "fifo") === "fifo"} onChange={(value) => onConfigChange(EXPERIMENTAL_PRESENT_MODE, value ? "fifo" : "mailbox")} /> @@ -157,8 +158,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="Performance Mode" - description="Uses a lighter model for FG (Recommended for most games)" + label={t('CONFIG_PERFORMANCE_MODE', 'Performance Mode')} + description={t('CONFIG_PERFORMANCE_MODE_DESC', 'Uses a lighter model for FG (Recommended for most games)')} checked={config.performance_mode} onChange={(value) => onConfigChange(PERFORMANCE_MODE, value)} /> @@ -166,8 +167,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="HDR Mode" - description="Enables HDR mode (only for games that support HDR)" + label={t('CONFIG_HDR_MODE', 'HDR Mode')} + description={t('CONFIG_HDR_MODE_DESC', 'Enables HDR mode (only for games that support HDR)')} checked={config.hdr_mode} onChange={(value) => onConfigChange(HDR_MODE, value)} /> @@ -188,7 +189,7 @@ export function ConfigurationSection({ color: "white" }} > - Workarounds + {t('CONFIG_WORKAROUNDS_TITLE', 'Workarounds')} </div> </PanelSectionRow> @@ -219,8 +220,8 @@ export function ConfigurationSection({ <> <PanelSectionRow> <ToggleField - label="Enable WSI" - description="Re-Enable Gamescope WSI Layer. Requires game restart to apply." + label={t('CONFIG_ENABLE_WSI', 'Enable WSI')} + description={t('CONFIG_ENABLE_WSI_DESC', 'Re-Enable Gamescope WSI Layer. Requires game restart to apply.')} checked={config.enable_wsi} onChange={(value) => onConfigChange(ENABLE_WSI, value)} /> @@ -228,8 +229,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="Enable WOW64 for 32-bit games" - description="Enables PROTON_USE_WOW64=1 for 32-bit games (Use with ProtonGE to fix crashing)" + label={t('CONFIG_ENABLE_WOW64', 'Enable WOW64 for 32-bit games')} + description={t('CONFIG_ENABLE_WOW64_DESC', 'Enables PROTON_USE_WOW64=1 for 32-bit games (Use with ProtonGE to fix crashing)')} checked={config.enable_wow64} onChange={(value) => onConfigChange('enable_wow64', value)} /> @@ -237,8 +238,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="Disable Steam Deck Mode" - description="Disables Steam Deck mode (Unlocks hidden settings in some games)" + label={t('CONFIG_DISABLE_STEAMDECK_MODE', 'Disable Steam Deck Mode')} + description={t('CONFIG_DISABLE_STEAMDECK_MODE_DESC', 'Disables Steam Deck mode (Unlocks hidden settings in some games)')} checked={config.disable_steamdeck_mode} onChange={(value) => onConfigChange(DISABLE_STEAMDECK_MODE, value)} /> @@ -246,8 +247,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="MangoHud Workaround" - description="Enables a transparent mangohud overlay, sometimes fixes issues with 2X multiplier in game mode" + label={t('CONFIG_MANGOHUD_WORKAROUND', 'MangoHud Workaround')} + description={t('CONFIG_MANGOHUD_WORKAROUND_DESC', 'Enables a transparent mangohud overlay, sometimes fixes issues with 2X multiplier in game mode')} checked={config.mangohud_workaround} onChange={(value) => onConfigChange(MANGOHUD_WORKAROUND, value)} /> @@ -255,8 +256,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="Disable vkBasalt" - description="Disables vkBasalt layer which can conflict with LSFG (Reshade, some Decky plugins)" + label={t('CONFIG_DISABLE_VKBASALT', 'Disable vkBasalt')} + description={t('CONFIG_DISABLE_VKBASALT_DESC', 'Disables vkBasalt layer which can conflict with LSFG (Reshade, some Decky plugins)')} checked={config.disable_vkbasalt} disabled={config.force_enable_vkbasalt} onChange={(value) => { @@ -271,8 +272,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="Force Enable vkBasalt" - description="Force vkBasalt to engage to fix framepacing issues in gamemode" + label={t('CONFIG_FORCE_ENABLE_VKBASALT', 'Force Enable vkBasalt')} + description={t('CONFIG_FORCE_ENABLE_VKBASALT_DESC', 'Force vkBasalt to engage to fix framepacing issues in gamemode')} checked={config.force_enable_vkbasalt} disabled={config.disable_vkbasalt} onChange={(value) => { @@ -287,8 +288,8 @@ export function ConfigurationSection({ <PanelSectionRow> <ToggleField - label="Enable Zink for OpenGL Games" - description="Use Vulkan-based OpenGL implementation for OpenGL games (may cause crashes or freezes with some games)" + label={t('CONFIG_ENABLE_ZINK', 'Enable Zink for OpenGL Games')} + description={t('CONFIG_ENABLE_ZINK_DESC', 'Use Vulkan-based OpenGL implementation for OpenGL games (may cause crashes or freezes with some games)')} checked={config.enable_zink} onChange={(value) => onConfigChange(ENABLE_ZINK, value)} /> diff --git a/src/components/Content.tsx b/src/components/Content.tsx index 3f94745..5988e79 100644 --- a/src/components/Content.tsx +++ b/src/components/Content.tsx @@ -14,6 +14,7 @@ import { FpsMultiplierControl } from "./FpsMultiplierControl"; import { NerdStuffModal } from "./NerdStuffModal"; import { FlatpaksModal } from "./FlatpaksModal"; import { ConfigurationData } from "../config/configSchema"; +import t from '../i18n/i18n'; export function Content() { const { @@ -108,7 +109,7 @@ export function Content() { color: "white" }} > - FPS Multiplier + {t('CONTENT_FPS_MULTIPLIER', 'FPS Multiplier')} </div> </PanelSectionRow> @@ -150,7 +151,7 @@ export function Content() { layout="below" onClick={handleShowNerdStuff} > - Nerd Stuff + {t('CONTENT_NERD_STUFF', 'Nerd Stuff')} </ButtonItem> </PanelSectionRow> @@ -159,7 +160,7 @@ export function Content() { layout="below" onClick={handleShowFlatpaks} > - Flatpak Setup + {t('CONTENT_FLATPAK_SETUP', 'Flatpak Setup')} </ButtonItem> </PanelSectionRow> diff --git a/src/components/FgmodClipboardButton.tsx b/src/components/FgmodClipboardButton.tsx index 6f65955..efc5490 100644 --- a/src/components/FgmodClipboardButton.tsx +++ b/src/components/FgmodClipboardButton.tsx @@ -4,6 +4,7 @@ import { FaClipboard, FaCheck } from "react-icons/fa"; import { checkFgmodDirectory } from "../api/lsfgApi"; import { showClipboardErrorToast } from "../utils/toastUtils"; import { copyWithVerification } from "../utils/clipboardUtils"; +import t from '../i18n/i18n'; export function FgmodClipboardButton() { const [isLoading, setIsLoading] = useState(false); @@ -93,7 +94,7 @@ export function FgmodClipboardButton() { color: showSuccess ? "#4CAF50" : "inherit", fontWeight: showSuccess ? "bold" : "normal" }}> - {showSuccess ? "Copied to clipboard" : isLoading ? "Copying..." : "LSFG + DeckyFG"} + {showSuccess ? t('CLIPBOARD_COPIED', 'Copied to clipboard') : isLoading ? t('CLIPBOARD_COPYING', 'Copying...') : t('CLIPBOARD_LSFG_FGMOD', 'LSFG + DeckyFG')} </div> </div> </ButtonItem> diff --git a/src/components/FlatpaksModal.tsx b/src/components/FlatpaksModal.tsx index a80fff0..16d0369 100644 --- a/src/components/FlatpaksModal.tsx +++ b/src/components/FlatpaksModal.tsx @@ -27,6 +27,7 @@ import { FlatpakApp, FlatpakAppInfo } from '../api/lsfgApi'; +import t from '../i18n/i18n'; interface FlatpaksModalProps { closeModal?: () => void; @@ -116,7 +117,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { if (loading) { return ( <ModalRoot closeModal={closeModal}> - <DialogHeader>Flatpak Extensions</DialogHeader> + <DialogHeader>{t('FLATPAK_MODAL_TITLE', 'Flatpak Extensions')}</DialogHeader> <DialogBody> <div style={{ display: 'flex', justifyContent: 'center', padding: '20px' }}> <Spinner /> @@ -129,17 +130,17 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { const instructionSteps = [ { id: 'try-first', - title: 'Try first:', + title: t('FLATPAK_STEP_TRY_FIRST', 'Try first:'), command: '~/lsfg' }, { id: 'try-full-path', - title: "If that doesn't work, try full path:", + title: t('FLATPAK_STEP_TRY_FULL_PATH', "If that doesn't work, try full path:"), command: '/home/(username)/lsfg' }, { id: 'final-result', - title: 'Final result should look like:', + title: t('FLATPAK_STEP_FINAL', 'Final result should look like:'), command: '~/lsfg "usr/bin/flatpak"' } ]; @@ -162,20 +163,20 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { return ( <ModalRoot closeModal={closeModal}> - <DialogHeader>Flatpak Extensions</DialogHeader> + <DialogHeader>{t('FLATPAK_MODAL_TITLE', 'Flatpak Extensions')}</DialogHeader> <DialogBody> <Focusable> {/* Extension Status Section */} <DialogControlsSection> - <DialogControlsSectionHeader>Runtime Extension Installer</DialogControlsSectionHeader> + <DialogControlsSectionHeader>{t('FLATPAK_RUNTIME_INSTALLER', 'Runtime Extension Installer')}</DialogControlsSectionHeader> {extensionStatus && extensionStatus.success ? ( <> {/* 23.08 Runtime */} <PanelSectionRow> - <Field - label="Runtime 23.08" - description={extensionStatus.installed_23_08 ? "Installed" : "Not installed"} + <Field + label={t('FLATPAK_RUNTIME_23', 'Runtime 23.08')} + description={extensionStatus.installed_23_08 ? t('FLATPAK_INSTALLED', 'Installed') : t('FLATPAK_NOT_INSTALLED', 'Not installed')} icon={extensionStatus.installed_23_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />} > <ButtonItem @@ -187,8 +188,8 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { if (operation === 'uninstall') { confirmOperation( action, - 'Uninstall Runtime Extension', - 'Are you sure you want to uninstall the 23.08 runtime extension?' + t('FLATPAK_UNINSTALL_TITLE', 'Uninstall Runtime Extension'), + `${t('FLATPAK_UNINSTALL_CONFIRM_PREFIX', 'Are you sure you want to uninstall the')} 23.08 ${t('FLATPAK_UNINSTALL_CONFIRM_SUFFIX', 'runtime extension?')}` ); } else { action(); @@ -200,11 +201,11 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { <Spinner /> ) : extensionStatus.installed_23_08 ? ( <> - <FaTrash /> Uninstall + <FaTrash /> {t('FLATPAK_UNINSTALL_BTN', 'Uninstall')} </> ) : ( <> - <FaDownload /> Install + <FaDownload /> {t('FLATPAK_INSTALL_BTN', 'Install')} </> )} </ButtonItem> @@ -213,9 +214,9 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { {/* 24.08 Runtime */} <PanelSectionRow> - <Field - label="Runtime 24.08" - description={extensionStatus.installed_24_08 ? "Installed" : "Not installed"} + <Field + label={t('FLATPAK_RUNTIME_24', 'Runtime 24.08')} + description={extensionStatus.installed_24_08 ? t('FLATPAK_INSTALLED', 'Installed') : t('FLATPAK_NOT_INSTALLED', 'Not installed')} icon={extensionStatus.installed_24_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />} > <ButtonItem @@ -227,8 +228,8 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { if (operation === 'uninstall') { confirmOperation( action, - 'Uninstall Runtime Extension', - 'Are you sure you want to uninstall the 24.08 runtime extension?' + t('FLATPAK_UNINSTALL_TITLE', 'Uninstall Runtime Extension'), + `${t('FLATPAK_UNINSTALL_CONFIRM_PREFIX', 'Are you sure you want to uninstall the')} 24.08 ${t('FLATPAK_UNINSTALL_CONFIRM_SUFFIX', 'runtime extension?')}` ); } else { action(); @@ -240,11 +241,11 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { <Spinner /> ) : extensionStatus.installed_24_08 ? ( <> - <FaTrash /> Uninstall + <FaTrash /> {t('FLATPAK_UNINSTALL_BTN', 'Uninstall')} </> ) : ( <> - <FaDownload /> Install + <FaDownload /> {t('FLATPAK_INSTALL_BTN', 'Install')} </> )} </ButtonItem> @@ -253,9 +254,9 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { {/* 25.08 Runtime */} <PanelSectionRow> - <Field - label="Runtime 25.08" - description={extensionStatus.installed_25_08 ? "Installed" : "Not installed"} + <Field + label={t('FLATPAK_RUNTIME_25', 'Runtime 25.08')} + description={extensionStatus.installed_25_08 ? t('FLATPAK_INSTALLED', 'Installed') : t('FLATPAK_NOT_INSTALLED', 'Not installed')} icon={extensionStatus.installed_25_08 ? <FaCheck style={{color: 'green'}} /> : <FaTimes style={{color: 'red'}} />} > <ButtonItem @@ -267,8 +268,8 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { if (operation === 'uninstall') { confirmOperation( action, - 'Uninstall Runtime Extension', - 'Are you sure you want to uninstall the 25.08 runtime extension?' + t('FLATPAK_UNINSTALL_TITLE', 'Uninstall Runtime Extension'), + `${t('FLATPAK_UNINSTALL_CONFIRM_PREFIX', 'Are you sure you want to uninstall the')} 25.08 ${t('FLATPAK_UNINSTALL_CONFIRM_SUFFIX', 'runtime extension?')}` ); } else { action(); @@ -280,11 +281,11 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { <Spinner /> ) : extensionStatus.installed_25_08 ? ( <> - <FaTrash /> Uninstall + <FaTrash /> {t('FLATPAK_UNINSTALL_BTN', 'Uninstall')} </> ) : ( <> - <FaDownload /> Install + <FaDownload /> {t('FLATPAK_INSTALL_BTN', 'Install')} </> )} </ButtonItem> @@ -293,9 +294,9 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { </> ) : ( <PanelSectionRow> - <Field - label="Error" - description={extensionStatus?.error || 'Failed to check extension status'} + <Field + label={t('FLATPAK_ERROR', 'Error')} + description={extensionStatus?.error || t('FLATPAK_ERROR_STATUS', 'Failed to check extension status')} icon={<FaTimes style={{color: 'red'}} />} /> </PanelSectionRow> @@ -304,7 +305,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { {/* Flatpak Apps Section */} <DialogControlsSection> - <DialogControlsSectionHeader>Flatpak Applications</DialogControlsSectionHeader> + <DialogControlsSectionHeader>{t('FLATPAK_APPS_TITLE', 'Flatpak Applications')}</DialogControlsSectionHeader> {flatpakApps && flatpakApps.success ? ( flatpakApps.apps.length > 0 ? ( @@ -313,14 +314,14 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { const partialOverrides = app.has_filesystem_override || app.has_env_override; let statusColor = 'red'; - let statusText = 'No overrides'; + let statusText = t('FLATPAK_STATUS_NO_OVERRIDES', 'No overrides'); if (hasOverrides) { statusColor = 'green'; - statusText = 'Configured'; + statusText = t('FLATPAK_STATUS_CONFIGURED', 'Configured'); } else if (partialOverrides) { statusColor = 'orange'; - statusText = 'Partial'; + statusText = t('FLATPAK_STATUS_PARTIAL', 'Partial'); } return ( @@ -341,17 +342,17 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { }) ) : ( <PanelSectionRow> - <Field - label="No Flatpak Apps Found" - description="No Flatpak applications are currently installed" + <Field + label={t('FLATPAK_NO_APPS', 'No Flatpak Apps Found')} + description={t('FLATPAK_NO_APPS_DESC', 'No Flatpak applications are currently installed')} /> </PanelSectionRow> ) ) : ( <PanelSectionRow> - <Field - label="Error" - description={flatpakApps?.error || 'Failed to load Flatpak applications'} + <Field + label={t('FLATPAK_ERROR', 'Error')} + description={flatpakApps?.error || t('FLATPAK_ERROR_APPS', 'Failed to load Flatpak applications')} icon={<FaTimes style={{color: 'red'}} />} /> </PanelSectionRow> @@ -360,7 +361,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { {/* Steam Configuration Instructions */} <DialogControlsSection> - <DialogControlsSectionHeader>Steam Configuration</DialogControlsSectionHeader> + <DialogControlsSectionHeader>{t('FLATPAK_STEAM_CONFIG_TITLE', 'Steam Configuration')}</DialogControlsSectionHeader> <div style={{ padding: '12px', @@ -372,13 +373,13 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { }} > <div style={{ fontWeight: 'bold', marginBottom: '8px', color: '#fff' }}> - Configure Steam Flatpak Shortcuts + {t('FLATPAK_STEAM_CONFIG_HEADER', 'Configure Steam Flatpak Shortcuts')} </div> <div style={{ fontSize: '0.9em', lineHeight: '1.4', marginBottom: '8px' }}> - In Steam, open your flatpak game and click the cog wheel. + {t('FLATPAK_STEAM_CONFIG_DESC', 'In Steam, open your flatpak game and click the cog wheel.')} </div> <div style={{ fontSize: '0.9em', lineHeight: '1.4', marginBottom: '12px', color: '#ffa500' }}> - <strong>IMPORTANT:</strong> Set this in TARGET (NOT LAUNCH OPTIONS) + <strong>IMPORTANT:</strong> {t('FLATPAK_STEAM_CONFIG_IMPORTANT', 'Set this in TARGET (NOT LAUNCH OPTIONS)')} </div> {instructionSteps.map((step) => ( @@ -421,7 +422,7 @@ export const FlatpaksModal: FC<FlatpaksModalProps> = ({ closeModal }) => { layout="below" onClick={closeModal} > - Close + {t('FLATPAK_CLOSE', 'Close')} </ButtonItem> </PanelSectionRow> </DialogControlsSection> diff --git a/src/components/FpsMultiplierControl.tsx b/src/components/FpsMultiplierControl.tsx index 5ac31bb..206643e 100644 --- a/src/components/FpsMultiplierControl.tsx +++ b/src/components/FpsMultiplierControl.tsx @@ -1,6 +1,7 @@ import { PanelSectionRow, DialogButton, Focusable } from "@decky/ui"; import { ConfigurationData } from "../config/configSchema"; import { MULTIPLIER } from "../config/generatedConfigSchema"; +import t from '../i18n/i18n'; interface FpsMultiplierControlProps { config: ConfigurationData; @@ -49,7 +50,7 @@ export function FpsMultiplierControl({ textAlign: "center" }} > - {config.multiplier < 2 ? "OFF" : `${config.multiplier}X`} + {config.multiplier < 2 ? t('MULTIPLIER_OFF', 'OFF') : `${config.multiplier}X`} </div> <DialogButton style={{ diff --git a/src/components/InstallationButton.tsx b/src/components/InstallationButton.tsx index d0f2ce5..7f0ac96 100644 --- a/src/components/InstallationButton.tsx +++ b/src/components/InstallationButton.tsx @@ -1,5 +1,6 @@ import { ButtonItem, PanelSectionRow } from "@decky/ui"; import { FaDownload, FaTrash } from "react-icons/fa"; +import t from '../i18n/i18n'; interface InstallationButtonProps { isInstalled: boolean; @@ -20,7 +21,7 @@ export function InstallationButton({ if (isInstalling) { return ( <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> - <div>Installing...</div> + <div>{t('INSTALL_INSTALLING', 'Installing...')}</div> </div> ); } @@ -28,7 +29,7 @@ export function InstallationButton({ if (isUninstalling) { return ( <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> - <div>Uninstalling...</div> + <div>{t('INSTALL_UNINSTALLING', 'Uninstalling...')}</div> </div> ); } @@ -37,7 +38,7 @@ export function InstallationButton({ return ( <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> <FaTrash /> - <div>Uninstall LSFG-VK</div> + <div>{t('INSTALL_UNINSTALL_BTN', 'Uninstall LSFG-VK')}</div> </div> ); } @@ -45,7 +46,7 @@ export function InstallationButton({ return ( <div style={{ display: "flex", alignItems: "center", gap: "8px" }}> <FaDownload /> - <div>Install LSFG-VK</div> + <div>{t('INSTALL_INSTALL_BTN', 'Install LSFG-VK')}</div> </div> ); }; diff --git a/src/components/NerdStuffModal.tsx b/src/components/NerdStuffModal.tsx index b4a79a2..8a79b67 100644 --- a/src/components/NerdStuffModal.tsx +++ b/src/components/NerdStuffModal.tsx @@ -8,6 +8,7 @@ import { ButtonItem } from "@decky/ui"; import { getDllStats, DllStatsResult, getConfigFileContent, getLaunchScriptContent, FileContentResult } from "../api/lsfgApi"; +import t from '../i18n/i18n'; interface NerdStuffModalProps { closeModal?: () => void; @@ -63,7 +64,7 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { return ( <ModalRoot onCancel={closeModal} onOK={closeModal}> {loading && ( - <div>Loading information...</div> + <div>{t('NERD_LOADING', 'Loading information...')}</div> )} {error && ( @@ -79,26 +80,26 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { <div>{dllStats.error || "Failed to get DLL stats"}</div> ) : ( <div> - <Field label="DLL Path"> + <Field label={t('NERD_DLL_PATH', 'DLL Path')}> <Focusable onClick={() => dllStats.dll_path && copyToClipboard(dllStats.dll_path)} onActivate={() => dllStats.dll_path && copyToClipboard(dllStats.dll_path)} > - {dllStats.dll_path || "Not available"} + {dllStats.dll_path || t('NERD_NOT_AVAILABLE', 'Not available')} </Focusable> </Field> - <Field label="DLL SHA256 Hash"> + <Field label={t('NERD_DLL_HASH', 'DLL SHA256 Hash')}> <Focusable onClick={() => dllStats.dll_sha256 && copyToClipboard(dllStats.dll_sha256)} onActivate={() => dllStats.dll_sha256 && copyToClipboard(dllStats.dll_sha256)} > - {dllStats.dll_sha256 ? formatSHA256(dllStats.dll_sha256) : "Not available"} + {dllStats.dll_sha256 ? formatSHA256(dllStats.dll_sha256) : t('NERD_NOT_AVAILABLE', 'Not available')} </Focusable> </Field> {dllStats.dll_source && ( - <Field label="Detection Source"> + <Field label={t('NERD_DETECTION_SOURCE', 'Detection Source')}> <div>{dllStats.dll_source}</div> </Field> )} @@ -109,13 +110,13 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { {/* Launch Script Section */} {scriptContent && ( - <Field label="Launch Script"> + <Field label={t('NERD_LAUNCH_SCRIPT', 'Launch Script')}> {!scriptContent.success ? ( - <div>Script not found: {scriptContent.error}</div> + <div>{t('NERD_SCRIPT_NOT_FOUND_PREFIX', 'Script not found:')} {scriptContent.error}</div> ) : ( <div> <div style={{ marginBottom: "8px", fontSize: "0.9em", opacity: 0.8 }}> - Path: {scriptContent.path} + {t('NERD_PATH_PREFIX', 'Path:')} {scriptContent.path} </div> <Focusable onClick={() => scriptContent.content && copyToClipboard(scriptContent.content)} @@ -130,7 +131,7 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { overflow: "auto", maxHeight: "150px" }}> - {scriptContent.content || "No content"} + {scriptContent.content || t('NERD_NO_CONTENT', 'No content')} </pre> </Focusable> </div> @@ -140,13 +141,13 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { {/* Config File Section */} {configContent && ( - <Field label="Configuration File"> + <Field label={t('NERD_CONFIG_FILE', 'Configuration File')}> {!configContent.success ? ( - <div>Config not found: {configContent.error}</div> + <div>{t('NERD_CONFIG_NOT_FOUND_PREFIX', 'Config not found:')} {configContent.error}</div> ) : ( <div> <div style={{ marginBottom: "8px", fontSize: "0.9em", opacity: 0.8 }}> - Path: {configContent.path} + {t('NERD_PATH_PREFIX', 'Path:')} {configContent.path} </div> <Focusable onClick={() => configContent.content && copyToClipboard(configContent.content)} @@ -160,7 +161,7 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { whiteSpace: "pre-wrap", overflow: "auto" }}> - {configContent.content || "No content"} + {configContent.content || t('NERD_NO_CONTENT', 'No content')} </pre> </Focusable> </div> @@ -175,7 +176,7 @@ export function NerdStuffModal({ closeModal }: NerdStuffModalProps) { layout="below" onClick={closeModal} > - Close + {t('NERD_CLOSE', 'Close')} </ButtonItem> </PanelSectionRow> </DialogControlsSection> diff --git a/src/components/ProfileManagement.tsx b/src/components/ProfileManagement.tsx index 73a40c7..626d54c 100644 --- a/src/components/ProfileManagement.tsx +++ b/src/components/ProfileManagement.tsx @@ -25,6 +25,7 @@ import { ProfileResult } from "../api/lsfgApi"; import { showSuccessToast, showErrorToast } from "../utils/toastUtils"; +import t from '../i18n/i18n'; const PROFILES_COLLAPSED_KEY = 'lsfg-profiles-collapsed'; @@ -63,8 +64,8 @@ function TextInputModal({ <p style={{ marginBottom: "24px" }}>{description}</p> <div style={{ marginBottom: "24px" }}> - <Field - label="Name" + <Field + label={t('PROFILE_NAME_LABEL', 'Name')} childrenLayout="below" childrenContainerWidth="max" > @@ -199,10 +200,10 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa const handleCreateProfile = () => { showModal( <TextInputModal - title="Create New Profile" - description="Enter a name for the new profile. The current profile's settings will be copied." - okText="Create" - cancelText="Cancel" + title={t('PROFILE_CREATE_TITLE', 'Create New Profile')} + description={t('PROFILE_CREATE_DESC', "Enter a name for the new profile. The current profile's settings will be copied.")} + okText={t('PROFILE_CREATE_BTN', 'Create')} + cancelText={t('PROFILE_CANCEL_BTN', 'Cancel')} onOK={(name: string) => { if (name.trim()) { createNewProfile(name.trim()); @@ -237,16 +238,16 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa const handleDeleteProfile = () => { if (selectedProfile === "decky-lsfg-vk") { - showErrorToast("Cannot delete default profile", "The default profile cannot be deleted"); + showErrorToast(t('PROFILE_CANNOT_DELETE_TITLE', 'Cannot delete default profile'), t('PROFILE_CANNOT_DELETE_MSG', 'The default profile cannot be deleted')); return; } showModal( <ConfirmModal - strTitle="Delete Profile" - strDescription={`Are you sure you want to delete the profile "${selectedProfile}"? This action cannot be undone.`} - strOKButtonText="Delete" - strCancelButtonText="Cancel" + strTitle={t('PROFILE_DELETE_TITLE', 'Delete Profile')} + strDescription={`${t('PROFILE_DELETE_DESC_PREFIX', 'Are you sure you want to delete the profile')} "${selectedProfile}"${t('PROFILE_DELETE_DESC_SUFFIX', '? This action cannot be undone.')}`} + strOKButtonText={t('PROFILE_DELETE_BTN', 'Delete')} + strCancelButtonText={t('PROFILE_CANCEL_BTN', 'Cancel')} onOK={() => deleteSelectedProfile()} /> ); @@ -284,17 +285,17 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa const handleRenameProfile = () => { if (selectedProfile === "decky-lsfg-vk") { - showErrorToast("Cannot rename default profile", "The default profile cannot be renamed"); + showErrorToast(t('PROFILE_CANNOT_RENAME_TITLE', 'Cannot rename default profile'), t('PROFILE_CANNOT_RENAME_MSG', 'The default profile cannot be renamed')); return; } showModal( <TextInputModal - title="Rename Profile" - description={`Enter a new name for the profile "${selectedProfile}".`} + title={t('PROFILE_RENAME_TITLE', 'Rename Profile')} + description={`${t('PROFILE_RENAME_DESC_PREFIX', 'Enter a new name for the profile')} "${selectedProfile}".`} defaultValue={selectedProfile} - okText="Rename" - cancelText="Cancel" + okText={t('PROFILE_RENAME_BTN', 'Rename')} + cancelText={t('PROFILE_CANCEL_BTN', 'Cancel')} onOK={(newName: string) => { if (newName.trim() && newName.trim() !== selectedProfile) { renameSelectedProfile(newName.trim()); @@ -330,11 +331,11 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa const profileOptions: DropdownOption[] = [ ...profiles.map((profile: string) => ({ data: profile, - label: profile === "decky-lsfg-vk" ? "Default" : profile + label: profile === "decky-lsfg-vk" ? t('PROFILE_DEFAULT', 'Default') : profile })), { data: "__NEW_PROFILE__", - label: "New Profile" + label: t('PROFILE_NEW', 'New Profile') } ]; @@ -361,7 +362,7 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa border: "1px solid rgba(0, 255, 0, 0.3)", fontSize: "13px" }}> - <strong>{mainRunningApp.display_name}</strong> running. Close game to change profile. + <strong>{mainRunningApp.display_name}</strong> running. {t('PROFILE_CLOSE_GAME', 'Close game to change profile.')} </div> </PanelSectionRow> )} @@ -378,7 +379,7 @@ export function ProfileManagement({ currentProfile, onProfileChange }: ProfileMa color: "white" }} > - Profile: {selectedProfile === "decky-lsfg-vk" ? "Default" : selectedProfile} + {t('PROFILE_SECTION_TITLE', 'Profile:')} {selectedProfile === "decky-lsfg-vk" ? t('PROFILE_DEFAULT', 'Default') : selectedProfile} </div> </PanelSectionRow> diff --git a/src/components/SmartClipboardButton.tsx b/src/components/SmartClipboardButton.tsx index c90515a..8da239a 100644 --- a/src/components/SmartClipboardButton.tsx +++ b/src/components/SmartClipboardButton.tsx @@ -4,6 +4,7 @@ import { FaClipboard, FaCheck } from "react-icons/fa"; import { getLaunchOption } from "../api/lsfgApi"; import { showClipboardErrorToast } from "../utils/toastUtils"; import { copyWithVerification } from "../utils/clipboardUtils"; +import t from '../i18n/i18n'; export function SmartClipboardButton() { const [isLoading, setIsLoading] = useState(false); @@ -74,7 +75,7 @@ export function SmartClipboardButton() { color: showSuccess ? "#4CAF50" : "inherit", fontWeight: showSuccess ? "bold" : "normal" }}> - {showSuccess ? "Copied to clipboard" : isLoading ? "Copying..." : "Copy Launch Option"} + {showSuccess ? t('CLIPBOARD_COPIED', 'Copied to clipboard') : isLoading ? t('CLIPBOARD_COPYING', 'Copying...') : t('CLIPBOARD_COPY_LAUNCH', 'Copy Launch Option')} </div> </div> </ButtonItem> diff --git a/src/components/UsageInstructions.tsx b/src/components/UsageInstructions.tsx index 5f032b8..36e31cf 100644 --- a/src/components/UsageInstructions.tsx +++ b/src/components/UsageInstructions.tsx @@ -1,4 +1,5 @@ import { PanelSectionRow } from "@decky/ui"; +import t from '../i18n/i18n'; export function UsageInstructions() { return ( @@ -15,7 +16,7 @@ export function UsageInstructions() { color: "white" }} > - Usage Instructions + {t('USAGE_TITLE', 'Usage Instructions')} </div> </PanelSectionRow> @@ -28,7 +29,7 @@ export function UsageInstructions() { whiteSpace: "pre-wrap" }} > - Click "Copy Launch Option" button, then paste it into your Steam game's launch options to enable frame generation. + {t('USAGE_DESC', 'Click "Copy Launch Option" button, then paste it into your Steam game\'s launch options to enable frame generation.')} </div> </PanelSectionRow> @@ -60,7 +61,7 @@ export function UsageInstructions() { marginTop: "8px" }} > -The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running. + {t('USAGE_CONFIG_NOTE', 'The configuration is stored in ~/.config/lsfg-vk/conf.toml and hot-reloads while games are running.')} </div> </PanelSectionRow> </> |
