From d52f1c088b1e4fa61647b627b8991b51127f3a56 Mon Sep 17 00:00:00 2001 From: Chneemann Date: Fri, 7 Aug 2026 15:47:23 +0200 Subject: [PATCH] feat: completely localize command palette actions, categories, and hooks --- src/components/CommandPalette.tsx | 15 ++++++++------ src/i18n/messages/de.json | 17 ++++++++++++++++ src/i18n/messages/en.json | 17 ++++++++++++++++ src/lib/paletteCommands.ts | 33 ++++++++++++++++--------------- 4 files changed, 60 insertions(+), 22 deletions(-) diff --git a/src/components/CommandPalette.tsx b/src/components/CommandPalette.tsx index 168ce26..5087c6a 100644 --- a/src/components/CommandPalette.tsx +++ b/src/components/CommandPalette.tsx @@ -1,20 +1,23 @@ "use client"; import { useState, useEffect, useRef } from "react"; +import { useTranslations } from "next-intl"; import { getCommands } from "../lib/paletteCommands"; /** * Interactive Cmd+K modal for quick navigation, actions, and social links */ export default function CommandPalette() { + const tCommands = useTranslations("Commands"); + const [isOpen, setIsOpen] = useState(false); const [search, setSearch] = useState(""); const [selectedIndex, setSelectedIndex] = useState(0); const [copied, setCopied] = useState(false); const inputRef = useRef(null); - // Load action definitions from lib helper - const commands = getCommands(copied, setCopied); + // Load action definitions from lib helper safely inside the component + const commands = getCommands(copied, setCopied, tCommands); // Filter commands dynamically by search query or category const filteredCommands = commands.filter( @@ -104,7 +107,7 @@ export default function CommandPalette() { { setSearch(e.target.value); @@ -122,7 +125,7 @@ export default function CommandPalette() {
{filteredCommands.length === 0 ? (

- No matching commands found. + {tCommands("noResults")}

) : ( filteredCommands.map((cmd, index) => { @@ -167,14 +170,14 @@ export default function CommandPalette() { {/* Footer Hint */}
- Use{" "} + {tCommands("navHint1")}{" "} {" "} {" "} - to navigate + {tCommands("navHint2")} diff --git a/src/i18n/messages/de.json b/src/i18n/messages/de.json index 8dad6c5..c432d84 100644 --- a/src/i18n/messages/de.json +++ b/src/i18n/messages/de.json @@ -95,6 +95,23 @@ "timeMinutesAgo": "vor {minutes}m", "timeHoursAgo": "vor {hours}h" }, + "Commands": { + "catQuickActions": "Schnellzugriff", + "catSocial": "Soziale Medien / Links", + "catSystem": "System & Info", + "copyEmail": "E-Mail kopieren (dev@andre-kempf.com)", + "emailCopied": "E-Mail kopiert!", + "downloadCV": "Lebenslauf herunterladen (PDF)", + "openTerminal": "Statistik-Terminal öffnen", + "viewForgejo": "Git-Profil (Self-Hosted) ansehen", + "viewGitHub": "GitHub-Profil (Legacy) ansehen", + "viewLinkedIn": "LinkedIn-Profil ansehen", + "viewSource": "Quellcode ansehen (Self-Hosted Git)", + "searchPlaceholder": "Befehl oder Aktion eingeben...", + "noResults": "Keine passenden Befehle gefunden.", + "navHint1": "Mit", + "navHint2": "navigieren" + }, "Imprint": { "backHome": "Zurück zur Startseite", "section1Title": "Angaben gemäß § 5 DDG", diff --git a/src/i18n/messages/en.json b/src/i18n/messages/en.json index 72caebf..6b34bbf 100644 --- a/src/i18n/messages/en.json +++ b/src/i18n/messages/en.json @@ -96,6 +96,23 @@ "timeMinutesAgo": "{minutes}m ago", "timeHoursAgo": "{hours}h ago" }, + "Commands": { + "catQuickActions": "Quick Actions", + "catSocial": "Social / Links", + "catSystem": "System & Info", + "copyEmail": "Copy Email (dev@andre-kempf.com)", + "emailCopied": "Email Copied!", + "downloadCV": "Download CV (PDF)", + "openTerminal": "Open Analytics Terminal", + "viewForgejo": "View Self-Hosted Git Profile", + "viewGitHub": "View GitHub (Legacy) Profile", + "viewLinkedIn": "View LinkedIn Profile", + "viewSource": "View Site Source Code (Self-Hosted Git)", + "searchPlaceholder": "Type a command or action...", + "noResults": "No matching commands found.", + "navHint1": "Use", + "navHint2": "to navigate" + }, "Imprint": { "section1Title": "Information Pursuant to § 5 DDG", "section1Sub": "Also responsible for content pursuant to § 18 Abs. 2 MStV.", diff --git a/src/lib/paletteCommands.ts b/src/lib/paletteCommands.ts index da47fcd..06becba 100644 --- a/src/lib/paletteCommands.ts +++ b/src/lib/paletteCommands.ts @@ -6,7 +6,7 @@ import { playSudoEasterEgg } from "./playSudoEasterEgg"; export type CommandItem = { id: string; label: string; - category: "Quick Actions" | "System & Info" | "Social / Links"; + category: string; icon?: string; action: () => void; }; @@ -17,11 +17,12 @@ export type CommandItem = { export const getCommands = ( copied: boolean, setCopied: (value: boolean) => void, + tCommands: (key: string) => string, ): CommandItem[] => [ { id: "copy-email", - label: copied ? "Email Copied!" : "Copy Email (dev@andre-kempf.com)", - category: "Quick Actions", + label: copied ? tCommands("emailCopied") : tCommands("copyEmail"), + category: tCommands("catQuickActions"), icon: copied ? "✓" : "✉️", action: () => { navigator.clipboard.writeText("dev@andre-kempf.com"); @@ -31,8 +32,8 @@ export const getCommands = ( }, { id: "download-cv", - label: "Download CV (PDF)", - category: "Quick Actions", + label: tCommands("downloadCV"), + category: tCommands("catQuickActions"), icon: "📄", action: () => { window.open( @@ -44,8 +45,8 @@ export const getCommands = ( }, { id: "terminal", - label: "Open Analytics Terminal", - category: "Quick Actions", + label: tCommands("openTerminal"), + category: tCommands("catQuickActions"), icon: "⚡", action: () => { window.dispatchEvent(new CustomEvent("open-analytics")); @@ -53,8 +54,8 @@ export const getCommands = ( }, { id: "forgejo", - label: "View Self-Hosted Git Profile", - category: "Social / Links", + label: tCommands("viewForgejo"), + category: tCommands("catSocial"), icon: "🔨", action: () => { window.open( @@ -66,8 +67,8 @@ export const getCommands = ( }, { id: "github", - label: "View GitHub (Legacy) Profile", - category: "Social / Links", + label: tCommands("viewGitHub"), + category: tCommands("catSocial"), icon: "🐙", action: () => { window.open( @@ -79,8 +80,8 @@ export const getCommands = ( }, { id: "linkedin", - label: "View LinkedIn Profile", - category: "Social / Links", + label: tCommands("viewLinkedIn"), + category: tCommands("catSocial"), icon: "💼", action: () => { window.open( @@ -92,8 +93,8 @@ export const getCommands = ( }, { id: "source-code", - label: "View Site Source Code (Self-Hosted Git)", - category: "Social / Links", + label: tCommands("viewSource"), + category: tCommands("catSocial"), icon: "💻", action: () => { window.open( @@ -106,7 +107,7 @@ export const getCommands = ( { id: "sudo-egg", label: "sudo rm -rf --no-preserve-root /", - category: "System & Info", + category: tCommands("catSystem"), icon: "💀", action: playSudoEasterEgg, },