refactor(i18n): 移除 chrome.i18n 国际化,统一使用中文硬编码
移除 chromeI18n 工具、_locales 翻译文件和 manifest default_locale 配置, 将所有 UI 文案改为直接硬编码中文,并更新相关测试与文档。
This commit is contained in:
@@ -4,7 +4,6 @@ import { toast } from 'sonner';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import type { UnitType } from '../constants';
|
||||
import { msToUnit } from '../constants';
|
||||
import { useI18n } from '@/utils/chromeI18n';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface LiveClockProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
@@ -13,8 +12,6 @@ interface LiveClockProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
}
|
||||
|
||||
export default function LiveClock({ unit, onUseNow, className, ...props }: LiveClockProps) {
|
||||
const { t } = useI18n('timestamp');
|
||||
|
||||
const [rawTime, setRawTime] = useState(() => Date.now());
|
||||
|
||||
useEffect(() => {
|
||||
@@ -36,7 +33,7 @@ export default function LiveClock({ unit, onUseNow, className, ...props }: LiveC
|
||||
{...props}
|
||||
>
|
||||
<span className="text-muted-foreground font-bold text-[10px] uppercase tracking-wider whitespace-nowrap shrink-0 selection:bg-transparent select-none">
|
||||
{t('timestamp:currentTs')}
|
||||
{'当前时间戳'}
|
||||
</span>
|
||||
|
||||
<span className="flex-1 font-mono font-bold text-foreground text-sm tracking-tight leading-none truncate tabular-nums">
|
||||
@@ -47,19 +44,15 @@ export default function LiveClock({ unit, onUseNow, className, ...props }: LiveC
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onUseNow(rawTime);
|
||||
toast.success(t('timestamp:usedSuccess'));
|
||||
toast.success('已使用当前时间戳');
|
||||
}}
|
||||
title={t('timestamp:useNowTooltip')}
|
||||
title={'填充到下方'}
|
||||
className="flex h-7 w-7 items-center justify-center rounded-md border border-input bg-background text-muted-foreground shadow-sm hover:bg-accent hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring"
|
||||
>
|
||||
<Clock className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
|
||||
<CopyButton
|
||||
text={text}
|
||||
tooltip={t('timestamp:copyTsTooltip')}
|
||||
className="h-7 w-7 rounded-md border"
|
||||
/>
|
||||
<CopyButton text={text} tooltip={'复制时间戳'} className="h-7 w-7 rounded-md border" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import React from 'react';
|
||||
import { CopyButton } from '@/components/CopyButton';
|
||||
import { useI18n } from '@/utils/chromeI18n';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
interface ResultViewProps extends React.HTMLAttributes<HTMLDivElement> {
|
||||
@@ -14,8 +13,6 @@ export default function ResultView({
|
||||
className,
|
||||
...props
|
||||
}: ResultViewProps) {
|
||||
const { t } = useI18n('timestamp');
|
||||
|
||||
if (!result) {
|
||||
if (!showEmptyPlaceholder) return null;
|
||||
return (
|
||||
@@ -26,7 +23,7 @@ export default function ResultView({
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{t('timestamp:resultEmpty')}
|
||||
{'请输入并点击转换'}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -34,7 +31,7 @@ export default function ResultView({
|
||||
return (
|
||||
<div className={cn('flex flex-col w-full', className)} {...props}>
|
||||
<span className="block text-muted-foreground/90 mb-2.5 text-xs font-semibold tracking-wider uppercase">
|
||||
{t('timestamp:resultLabel')}
|
||||
{'转换结果'}
|
||||
</span>
|
||||
|
||||
<div className="bg-card text-card-foreground border border-border p-4 sm:p-5 rounded-xl relative shadow-sm flex justify-between items-center gap-4 focus-within:ring-1 focus-within:ring-ring">
|
||||
@@ -43,7 +40,7 @@ export default function ResultView({
|
||||
</span>
|
||||
<CopyButton
|
||||
text={result}
|
||||
tooltip={t('timestamp:copyResultTooltip')}
|
||||
tooltip={'复制结果'}
|
||||
className="h-8 w-8 rounded-md shrink-0 border"
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,6 @@ import type { ModeType, UnitType, ZoneType } from './constants';
|
||||
import LiveClock from './components/LiveClock';
|
||||
import ResultView from './components/ResultView';
|
||||
import { useTimestampConverter } from './useTimestampConverter';
|
||||
import { useI18n } from '@/utils/chromeI18n';
|
||||
import { cn } from '@/lib/utils';
|
||||
|
||||
import { Input } from '@/components/ui/input';
|
||||
@@ -17,18 +16,16 @@ import {
|
||||
} from '@/components/ui/select';
|
||||
|
||||
const MODE_OPTIONS: { value: ModeType; label: string }[] = [
|
||||
{ value: 'ts2dt', label: 'timestamp:tsToDate' },
|
||||
{ value: 'dt2ts', label: 'timestamp:dateToTs' },
|
||||
{ value: 'ts2dt', label: '时间戳转日期' },
|
||||
{ value: 'dt2ts', label: '日期转时间戳' },
|
||||
];
|
||||
|
||||
const UNIT_OPTIONS: { value: UnitType; label: string }[] = [
|
||||
{ value: 'ms', label: 'timestamp:unitMs' },
|
||||
{ value: 's', label: 'timestamp:unitS' },
|
||||
{ value: 'ms', label: '毫秒' },
|
||||
{ value: 's', label: '秒' },
|
||||
];
|
||||
|
||||
export default function Index() {
|
||||
const { t } = useI18n('timestamp');
|
||||
|
||||
const {
|
||||
mode,
|
||||
input,
|
||||
@@ -53,7 +50,7 @@ export default function Index() {
|
||||
<div className="flex flex-col gap-4">
|
||||
<SwitchButtonGroup
|
||||
value={mode}
|
||||
options={MODE_OPTIONS.map((o) => ({ ...o, label: t(o.label) }))}
|
||||
options={MODE_OPTIONS}
|
||||
onChange={setMode}
|
||||
size="small"
|
||||
/>
|
||||
@@ -61,9 +58,7 @@ export default function Index() {
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={
|
||||
mode === 'ts2dt' ? t('timestamp:placeholderTs') : t('timestamp:placeholderDate')
|
||||
}
|
||||
placeholder={mode === 'ts2dt' ? '输入时间戳...' : 'YYYY-MM-DD HH:mm:ss'}
|
||||
value={input}
|
||||
onChange={(e) => setInput(e.target.value)}
|
||||
className={cn(
|
||||
@@ -78,7 +73,7 @@ export default function Index() {
|
||||
<div className="flex flex-col sm:flex-row items-stretch gap-3 w-full">
|
||||
<SwitchButtonGroup
|
||||
value={unit}
|
||||
options={UNIT_OPTIONS.map((o) => ({ ...o, label: t(o.label) }))}
|
||||
options={UNIT_OPTIONS}
|
||||
onChange={setUnit}
|
||||
size="small"
|
||||
className="sm:w-auto shrink-0"
|
||||
|
||||
@@ -2,7 +2,6 @@ import { useMemo, useState } from 'react';
|
||||
import dayjs from '@/utils/dayjs';
|
||||
import type { UnitType, ZoneType, ModeType } from './constants';
|
||||
import { DATE_FORMAT, msToUnit, dayjsFromTimestamp } from './constants';
|
||||
import { useI18n } from '@/utils/chromeI18n';
|
||||
import { useContextMenuData } from '@/utils/useContextMenuData';
|
||||
|
||||
export interface UseTimestampConverterReturn {
|
||||
@@ -29,7 +28,6 @@ function isTimestampLike(input: string): boolean {
|
||||
}
|
||||
|
||||
export function useTimestampConverter(): UseTimestampConverterReturn {
|
||||
const { t } = useI18n('timestamp');
|
||||
const [mode, setMode] = useState<ModeType>('ts2dt');
|
||||
const [unit, setUnit] = useState<UnitType>('ms');
|
||||
const [zone, setZone] = useState<ZoneType>('Asia/Shanghai');
|
||||
@@ -43,22 +41,22 @@ export function useTimestampConverter(): UseTimestampConverterReturn {
|
||||
if (mode === 'ts2dt') {
|
||||
const num = Number(rawInput);
|
||||
if (isNaN(num)) {
|
||||
return { result: '', error: t('timestamp:errors.invalidNumber') };
|
||||
return { result: '', error: '请输入有效数字' };
|
||||
}
|
||||
const d = dayjsFromTimestamp(num, unit);
|
||||
if (!d.isValid()) {
|
||||
return { result: '', error: t('timestamp:errors.invalidTimestamp') };
|
||||
return { result: '', error: '无效时间戳' };
|
||||
}
|
||||
return { result: d.tz(zone).format(DATE_FORMAT), error: '' };
|
||||
} else {
|
||||
const d = dayjs.tz(rawInput, DATE_FORMAT, zone);
|
||||
if (!d.isValid()) {
|
||||
return { result: '', error: t('timestamp:errors.invalidFormat') };
|
||||
return { result: '', error: '无效的日期格式' };
|
||||
}
|
||||
const ms = d.valueOf();
|
||||
return { result: String(msToUnit(ms, unit)), error: '' };
|
||||
}
|
||||
}, [input, mode, unit, zone, t]);
|
||||
}, [input, mode, unit, zone]);
|
||||
|
||||
const handleContextMenuData = (payload: string) => {
|
||||
const trimmed = payload.trim();
|
||||
|
||||
Reference in New Issue
Block a user