mirror of
https://github.com/tiennm99/ccs.git
synced 2026-09-10 04:19:29 +00:00
feat(i18n): Added support for Chinese language pack
This commit is contained in:
@@ -1,33 +1,7 @@
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { type NoticeProgressState } from '@/lib/updates-notice-state';
|
||||
|
||||
const NOTICE_PROGRESS_META: Record<
|
||||
NoticeProgressState,
|
||||
{ label: string; className: string; showDot?: boolean }
|
||||
> = {
|
||||
new: {
|
||||
label: 'Needs Action',
|
||||
className:
|
||||
'border-amber-300/70 bg-amber-100/70 text-amber-800 dark:border-amber-500/40 dark:bg-amber-500/15 dark:text-amber-300',
|
||||
showDot: true,
|
||||
},
|
||||
seen: {
|
||||
label: 'In Review',
|
||||
className:
|
||||
'border-blue-300/70 bg-blue-100/70 text-blue-800 dark:border-blue-500/40 dark:bg-blue-500/15 dark:text-blue-300',
|
||||
},
|
||||
done: {
|
||||
label: 'Done',
|
||||
className:
|
||||
'border-emerald-300/70 bg-emerald-100/70 text-emerald-800 dark:border-emerald-500/40 dark:bg-emerald-500/15 dark:text-emerald-300',
|
||||
},
|
||||
dismissed: {
|
||||
label: 'Dismissed',
|
||||
className:
|
||||
'border-muted-foreground/20 bg-muted text-muted-foreground dark:border-muted-foreground/30',
|
||||
},
|
||||
};
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function NoticeProgressBadge({
|
||||
state,
|
||||
@@ -36,7 +10,30 @@ export function NoticeProgressBadge({
|
||||
state: NoticeProgressState;
|
||||
className?: string;
|
||||
}) {
|
||||
const meta = NOTICE_PROGRESS_META[state];
|
||||
const { t } = useTranslation();
|
||||
const meta = {
|
||||
new: {
|
||||
label: t('updates.progressNeedsAction'),
|
||||
className:
|
||||
'border-amber-300/70 bg-amber-100/70 text-amber-800 dark:border-amber-500/40 dark:bg-amber-500/15 dark:text-amber-300',
|
||||
showDot: true,
|
||||
},
|
||||
seen: {
|
||||
label: t('updates.progressInReview'),
|
||||
className:
|
||||
'border-blue-300/70 bg-blue-100/70 text-blue-800 dark:border-blue-500/40 dark:bg-blue-500/15 dark:text-blue-300',
|
||||
},
|
||||
done: {
|
||||
label: t('updates.progressDone'),
|
||||
className:
|
||||
'border-emerald-300/70 bg-emerald-100/70 text-emerald-800 dark:border-emerald-500/40 dark:bg-emerald-500/15 dark:text-emerald-300',
|
||||
},
|
||||
dismissed: {
|
||||
label: t('updates.progressDismissed'),
|
||||
className:
|
||||
'border-muted-foreground/20 bg-muted text-muted-foreground dark:border-muted-foreground/30',
|
||||
},
|
||||
}[state] as { label: string; className: string; showDot?: boolean };
|
||||
|
||||
return (
|
||||
<Badge
|
||||
|
||||
@@ -8,12 +8,7 @@ import {
|
||||
type SupportScope,
|
||||
} from '@/lib/support-updates-catalog';
|
||||
import { SupportStatusBadge } from './support-status-badge';
|
||||
|
||||
const PILLAR_LABELS: { key: keyof CliSupportEntry['pillars']; label: string }[] = [
|
||||
{ key: 'baseUrl', label: 'Base URL' },
|
||||
{ key: 'auth', label: 'Auth' },
|
||||
{ key: 'model', label: 'Model' },
|
||||
];
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const SCOPE_STYLES: Record<SupportScope, string> = {
|
||||
target:
|
||||
@@ -27,6 +22,13 @@ const SCOPE_STYLES: Record<SupportScope, string> = {
|
||||
};
|
||||
|
||||
export function SupportEntryCard({ entry }: { entry: CliSupportEntry }) {
|
||||
const { t } = useTranslation();
|
||||
const pillarLabels: { key: keyof CliSupportEntry['pillars']; label: string }[] = [
|
||||
{ key: 'baseUrl', label: 'Base URL' },
|
||||
{ key: 'auth', label: 'Auth' },
|
||||
{ key: 'model', label: 'Model' },
|
||||
];
|
||||
|
||||
return (
|
||||
<Card className="h-full gap-4">
|
||||
<CardHeader className="gap-3">
|
||||
@@ -45,7 +47,7 @@ export function SupportEntryCard({ entry }: { entry: CliSupportEntry }) {
|
||||
|
||||
<CardContent className="space-y-4">
|
||||
<div className="grid gap-2 sm:grid-cols-3">
|
||||
{PILLAR_LABELS.map((pillar) => (
|
||||
{pillarLabels.map((pillar) => (
|
||||
<div key={pillar.key} className="rounded-md border bg-muted/30 p-2">
|
||||
<p className="text-[10px] uppercase tracking-wide text-muted-foreground">
|
||||
{pillar.label}
|
||||
@@ -57,7 +59,7 @@ export function SupportEntryCard({ entry }: { entry: CliSupportEntry }) {
|
||||
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
Dashboard
|
||||
{t('updates.dashboard')}
|
||||
</p>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{entry.routes.map((route) => (
|
||||
@@ -75,7 +77,7 @@ export function SupportEntryCard({ entry }: { entry: CliSupportEntry }) {
|
||||
|
||||
<div className="space-y-1">
|
||||
<p className="text-xs font-medium uppercase tracking-wide text-muted-foreground">
|
||||
CLI Usage
|
||||
{t('updates.cliUsage')}
|
||||
</p>
|
||||
<div className="space-y-1">
|
||||
{entry.commands.slice(0, 2).map((command) => (
|
||||
|
||||
@@ -1,12 +1,7 @@
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { SupportStatus } from '@/lib/support-updates-catalog';
|
||||
|
||||
const STATUS_LABELS: Record<SupportStatus, string> = {
|
||||
new: 'New',
|
||||
stable: 'Stable',
|
||||
planned: 'Planned',
|
||||
};
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
const STATUS_STYLES: Record<SupportStatus, string> = {
|
||||
new: 'border-blue-200 bg-blue-50 text-blue-700 dark:border-blue-900/50 dark:bg-blue-900/20 dark:text-blue-300',
|
||||
@@ -23,9 +18,16 @@ export function SupportStatusBadge({
|
||||
status: SupportStatus;
|
||||
className?: string;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const labels: Record<SupportStatus, string> = {
|
||||
new: t('updates.statusNew'),
|
||||
stable: t('updates.statusStable'),
|
||||
planned: t('updates.statusPlanned'),
|
||||
};
|
||||
|
||||
return (
|
||||
<Badge variant="outline" className={cn('font-medium', STATUS_STYLES[status], className)}>
|
||||
{STATUS_LABELS[status]}
|
||||
{labels[status]}
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
type SupportNotice,
|
||||
} from '@/lib/support-updates-catalog';
|
||||
import { type NoticeProgressState } from '@/lib/updates-notice-state';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
type UpdatableNoticeProgress = 'new' | 'seen' | 'done' | 'dismissed';
|
||||
|
||||
@@ -29,10 +30,11 @@ export function UpdatesDetailsPanel({
|
||||
relatedEntries: CliSupportEntry[];
|
||||
onUpdateProgress: (nextState: UpdatableNoticeProgress) => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
if (!notice) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center rounded-lg border border-dashed bg-muted/20 p-6">
|
||||
<p className="text-sm text-muted-foreground">No updates available.</p>
|
||||
<p className="text-sm text-muted-foreground">{t('updates.noUpdates')}</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -53,21 +55,21 @@ export function UpdatesDetailsPanel({
|
||||
|
||||
<div className="mt-2 flex flex-wrap items-center gap-2 text-xs text-muted-foreground">
|
||||
<CalendarClock className="h-3.5 w-3.5" />
|
||||
<span>Published {formatCatalogDate(notice.publishedAt)}</span>
|
||||
<span>{t('updates.published', { date: formatCatalogDate(notice.publishedAt) })}</span>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 flex flex-wrap gap-2">
|
||||
<Button size="sm" onClick={() => onUpdateProgress('done')}>
|
||||
<CheckCircle2 className="h-4 w-4" />
|
||||
Mark done
|
||||
{t('updates.markDone')}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" onClick={() => onUpdateProgress('dismissed')}>
|
||||
<EyeOff className="h-4 w-4" />
|
||||
Dismiss
|
||||
{t('updates.dismiss')}
|
||||
</Button>
|
||||
<Button size="sm" variant="ghost" onClick={() => onUpdateProgress('new')}>
|
||||
<RotateCcw className="h-4 w-4" />
|
||||
Reopen
|
||||
{t('updates.reopen')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -78,7 +80,7 @@ export function UpdatesDetailsPanel({
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Sparkles className="h-4 w-4 text-primary" />
|
||||
<CardTitle className="text-base">Do Next</CardTitle>
|
||||
<CardTitle className="text-base">{t('updates.doNext')}</CardTitle>
|
||||
</div>
|
||||
<CardDescription>{notice.primaryAction}</CardDescription>
|
||||
</CardHeader>
|
||||
@@ -96,8 +98,8 @@ export function UpdatesDetailsPanel({
|
||||
<div className="grid h-full grid-rows-[minmax(0,1fr)_minmax(0,1fr)] gap-4 overflow-hidden">
|
||||
<Card className="overflow-hidden">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-base">Impacted Integrations</CardTitle>
|
||||
<CardDescription>Related areas based on update scope and routing.</CardDescription>
|
||||
<CardTitle className="text-base">{t('updates.impactedIntegrations')}</CardTitle>
|
||||
<CardDescription>{t('updates.impactedDesc')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="min-h-0">
|
||||
<ScrollArea className="h-full pr-2">
|
||||
@@ -134,10 +136,8 @@ export function UpdatesDetailsPanel({
|
||||
|
||||
<Card className="overflow-hidden">
|
||||
<CardHeader className="pb-3">
|
||||
<CardTitle className="text-base">Why It Matters</CardTitle>
|
||||
<CardDescription>
|
||||
Short context only, no wall-of-text release notes.
|
||||
</CardDescription>
|
||||
<CardTitle className="text-base">{t('updates.whyMatters')}</CardTitle>
|
||||
<CardDescription>{t('updates.whyMattersDesc')}</CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent className="min-h-0">
|
||||
<ScrollArea className="h-full pr-2">
|
||||
|
||||
@@ -3,8 +3,10 @@ import { ArrowUpRight, Terminal } from 'lucide-react';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { CopyButton } from '@/components/ui/copy-button';
|
||||
import { type SupportNoticeAction } from '@/lib/support-updates-catalog';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export function UpdatesNoticeActionRow({ action }: { action: SupportNoticeAction }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div className="rounded-md border bg-muted/20 p-3">
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
@@ -16,7 +18,7 @@ export function UpdatesNoticeActionRow({ action }: { action: SupportNoticeAction
|
||||
{action.type === 'route' && action.path && (
|
||||
<Button size="sm" asChild>
|
||||
<Link to={action.path}>
|
||||
Open
|
||||
{t('updates.open')}
|
||||
<ArrowUpRight className="h-3.5 w-3.5" />
|
||||
</Link>
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user