From c62c9b1c788bf5aff4290805710296722d00f628 Mon Sep 17 00:00:00 2001 From: Shantur Rathore Date: Mon, 26 Jan 2026 13:11:05 +0000 Subject: [PATCH] feat(ui): add language selector Adds a language dropdown to the folder picker using the shared selector UI and persists selection to preferences.locale. --- .../src/components/folder-selection-view.tsx | 66 +++++++++++++++++-- .../lib/i18n/messages/en/folderSelection.ts | 2 + .../lib/i18n/messages/es/folderSelection.ts | 2 + .../lib/i18n/messages/fr/folderSelection.ts | 2 + .../lib/i18n/messages/ja/folderSelection.ts | 2 + .../lib/i18n/messages/ru/folderSelection.ts | 2 + .../i18n/messages/zh-Hans/folderSelection.ts | 2 + 7 files changed, 74 insertions(+), 4 deletions(-) diff --git a/packages/ui/src/components/folder-selection-view.tsx b/packages/ui/src/components/folder-selection-view.tsx index 0ffb20d5..fef0c1f3 100644 --- a/packages/ui/src/components/folder-selection-view.tsx +++ b/packages/ui/src/components/folder-selection-view.tsx @@ -1,5 +1,6 @@ +import { Select } from "@kobalte/core/select" import { Component, createSignal, Show, For, onMount, onCleanup, createEffect } from "solid-js" -import { Folder, Clock, Trash2, FolderPlus, Settings, ChevronRight, MonitorUp, Star } from "lucide-solid" +import { Folder, Clock, Trash2, FolderPlus, Settings, ChevronRight, MonitorUp, Star, Languages, ChevronDown } from "lucide-solid" import { useConfig } from "../stores/preferences" import AdvancedSettingsModal from "./advanced-settings-modal" import DirectoryBrowserDialog from "./directory-browser-dialog" @@ -9,7 +10,7 @@ import VersionPill from "./version-pill" import { DiscordSymbolIcon, GitHubMarkIcon } from "./brand-icons" import { githubStars } from "../stores/github-stars" import { formatCompactCount } from "../lib/formatters" -import { useI18n } from "../lib/i18n" +import { useI18n, type Locale } from "../lib/i18n" const codeNomadLogo = new URL("../images/CodeNomad-Icon.png", import.meta.url).href @@ -24,14 +25,27 @@ interface FolderSelectionViewProps { } const FolderSelectionView: Component = (props) => { - const { recentFolders, removeRecentFolder, preferences } = useConfig() - const { t } = useI18n() + const { recentFolders, removeRecentFolder, preferences, updatePreferences } = useConfig() + const { t, locale } = useI18n() const [selectedIndex, setSelectedIndex] = createSignal(0) const [focusMode, setFocusMode] = createSignal<"recent" | "new" | null>("recent") const [selectedBinary, setSelectedBinary] = createSignal(preferences().lastUsedBinary || "opencode") const [isFolderBrowserOpen, setIsFolderBrowserOpen] = createSignal(false) const nativeDialogsAvailable = supportsNativeDialogs() let recentListRef: HTMLDivElement | undefined + + type LanguageOption = { value: Locale; label: string } + + const languageOptions: LanguageOption[] = [ + { value: "en", label: "English" }, + { value: "es", label: "Español" }, + { value: "fr", label: "Français" }, + { value: "ru", label: "Русский" }, + { value: "ja", label: "日本語" }, + { value: "zh-Hans", label: "简体中文" }, + ] + + const selectedLanguageOption = () => languageOptions.find((opt) => opt.value === locale()) ?? languageOptions[0] const folders = () => recentFolders() const isLoading = () => Boolean(props.isLoading) @@ -255,6 +269,50 @@ const FolderSelectionView: Component = (props) => { class="w-full max-w-5xl h-full px-4 sm:px-8 pb-2 flex flex-col overflow-hidden" aria-busy={isLoading() ? "true" : "false"} > +
+ + value={selectedLanguageOption()} + onChange={(value) => { + if (!value) return + if (value.value === locale()) return + updatePreferences({ locale: value.value }) + }} + options={languageOptions} + optionValue="value" + optionTextValue="label" + itemComponent={(itemProps) => ( + + {itemProps.item.rawValue.label} + + )} + > + + + + + + + + + +