feat(desktop): add language switcher to onboarding setup screen

Add centered language toggle (EN/VI/中文) at top of setup wizard.
Default language changed from English to Vietnamese.
This commit is contained in:
viettranx committed 2026-03-27 23:53:17 +07:00
1 parent b373561f72
commit 8beb72039c
3 files changed
+35 -4

No files matched your search

@@ -1,17 +1,28 @@
import { useState, useEffect } from 'react'
import { useTranslation } from 'react-i18next'
import { useBootstrapStatus, type SetupStep } from '../../hooks/use-bootstrap-status'
import { useUiStore } from '../../stores/ui-store'
import { SetupStepper } from './SetupStepper'
import { ProviderStep } from './ProviderStep'
import { ModelVerifyStep } from './ModelVerifyStep'
import { AgentStep } from './AgentStep'
import type { ProviderData } from '../../types/provider'
const LANGUAGES = [
{ value: 'en', label: 'EN' },
{ value: 'vi', label: 'VI' },
{ value: 'zh', label: '中文' },
] as const
interface OnboardingWizardProps {
onComplete: () => void
}
export function OnboardingWizard({ onComplete }: OnboardingWizardProps) {
const { currentStep, loading, providers } = useBootstrapStatus()
const locale = useUiStore((s) => s.locale)
const setLocale = useUiStore((s) => s.setLocale)
const { t, i18n } = useTranslation('desktop')
const [step, setStep] = useState<1 | 2 | 3>(1)
const [createdProvider, setCreatedProvider] = useState<ProviderData | null>(null)
const [selectedModel, setSelectedModel] = useState<string | null>(null)
@@ -46,12 +57,32 @@ export function OnboardingWizard({ onComplete }: OnboardingWizardProps) {
return (
<div className="h-dvh flex items-center justify-center bg-surface-primary px-4 py-8">
<div className="w-full max-w-2xl space-y-6">
{/* Language switcher */}
<div className="flex justify-center">
<div className="flex gap-1 rounded-lg border border-border p-0.5">
{LANGUAGES.map((lang) => (
<button
key={lang.value}
onClick={() => { setLocale(lang.value); i18n.changeLanguage(lang.value) }}
className={[
'rounded-md px-2.5 py-1 text-xs font-medium transition-colors cursor-pointer',
locale === lang.value
? 'bg-accent text-white'
: 'text-text-secondary hover:bg-surface-tertiary',
].join(' ')}
>
{lang.label}
</button>
))}
</div>
</div>
{/* Header */}
<div className="text-center">
<img src="/goclaw-icon.svg" alt="GoClaw" className="mx-auto mb-4 h-16 w-16" />
<h1 className="text-4xl font-bold tracking-tight text-text-primary">GoClaw Setup</h1>
<h1 className="text-4xl font-bold tracking-tight text-text-primary">{t('onboarding.welcome')}</h1>
<p className="mt-2 text-sm text-text-muted">
Let's get your gateway up and running
{t('onboarding.welcomeDesc')}
</p>
</div>
+1 -1
View File
@@ -60,7 +60,7 @@ function getInitialLanguage(): string {
const lang = navigator.language.toLowerCase()
if (lang.startsWith('vi')) return 'vi'
if (lang.startsWith('zh')) return 'zh'
return 'en'
return 'vi'
}
i18n.use(initReactI18next).init({
+1 -1
View File
@@ -32,7 +32,7 @@ export const useUiStore = create<UiState>()(
persist(
(set) => ({
theme: 'light',
locale: 'en',
locale: 'vi',
timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
sidebarOpen: true,
sidebarWidth: 260,