refactor(i18n): 移除 chrome.i18n 国际化,统一使用中文硬编码

移除 chromeI18n 工具、_locales 翻译文件和 manifest default_locale 配置,
将所有 UI 文案改为直接硬编码中文,并更新相关测试与文档。
This commit is contained in:
雨霖铃
2026-06-18 14:22:14 +00:00
parent 618f3c36f2
commit ec92afa294
68 changed files with 531 additions and 2148 deletions
@@ -1,6 +1,5 @@
import React from 'react';
import { ChevronLeft, ChevronRight } from 'lucide-react';
import { useI18n } from '@/utils/chromeI18n';
import { cn } from '@/lib/utils';
export interface DiffNavigatorProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -19,8 +18,6 @@ export default function DiffNavigator({
className,
...props
}: DiffNavigatorProps) {
const { t } = useI18n('jsonDiff');
const isFirst = currentIndex <= 0;
const isLast = currentIndex >= total - 1;
@@ -33,9 +30,7 @@ export default function DiffNavigator({
)}
{...props}
>
<span className="text-xs font-semibold text-muted-foreground/90">
{t('jsonDiff:noDiffs')}
</span>
<span className="text-xs font-semibold text-muted-foreground/90">{'无差异'}</span>
</div>
);
}
@@ -52,7 +47,7 @@ export default function DiffNavigator({
<button
type="button"
disabled={isFirst}
aria-label={t('jsonDiff:previousDiff')}
aria-label={'上一个'}
onClick={onPrev}
className={cn(
'p-1 rounded-md text-muted-foreground hover:bg-accent hover:text-foreground',
@@ -72,7 +67,7 @@ export default function DiffNavigator({
<button
type="button"
disabled={isLast}
aria-label={t('jsonDiff:nextDiff')}
aria-label={'下一个'}
onClick={onNext}
className={cn(
'p-1 rounded-md text-muted-foreground hover:bg-accent hover:text-foreground',
@@ -1,5 +1,4 @@
import React from 'react';
import { useI18n } from '@/utils/chromeI18n';
import { cn } from '@/lib/utils';
import JsonTree from './JsonTree';
import type { DiffNode, DiffResult as DiffResultType, DiffType, ViewMode } from '../types';
@@ -17,8 +16,6 @@ export default function DiffResult({
className,
...props
}: DiffResultProps) {
const { t } = useI18n('jsonDiff');
if (viewMode === 'sideBySide') {
return (
<div
@@ -26,11 +23,11 @@ export default function DiffResult({
{...props}
>
<div className="flex-1 min-w-0">
<SectionLabel text={t('jsonDiff:leftLabel')} />
<SectionLabel text={'原始 JSON'} />
<JsonTree node={result.root} side="left" activePath={activePath} />
</div>
<div className="flex-1 min-w-0">
<SectionLabel text={t('jsonDiff:rightLabel')} />
<SectionLabel text={'目标 JSON'} />
<JsonTree node={result.root} side="right" activePath={activePath} />
</div>
</div>
@@ -1,5 +1,4 @@
import React, { useEffect, useMemo, useState } from 'react';
import { useI18n } from '@/utils/chromeI18n';
import { formatBytes } from '@/utils/format';
import { CopyButton } from '@/components/CopyButton';
import TextInputArea from '@/components/TextInputArea';
@@ -7,6 +6,27 @@ import { validateJson } from '@/utils/jsonFormatter';
import { cn } from '@/lib/utils';
import type { ConvertFunction, ConvertResult } from '../types';
const CONVERT_LABELS: Record<
string,
{ inputPlaceholder: string; outputLabel: string; emptyHint: string }
> = {
yaml: {
inputPlaceholder: '输入需要转换的 JSON...',
outputLabel: 'YAML 结果',
emptyHint: '输入 JSON 后点击转换',
},
toml: {
inputPlaceholder: '输入需要转换的 JSON...',
outputLabel: 'TOML 结果',
emptyHint: '输入 JSON 后点击转换',
},
minify: {
inputPlaceholder: '输入需要压缩的 JSON...',
outputLabel: '压缩结果',
emptyHint: '输入 JSON 后点击压缩',
},
};
interface JsonConvertSectionProps extends React.HTMLAttributes<HTMLDivElement> {
translationPrefix: string;
convertFunction: ConvertFunction;
@@ -18,12 +38,11 @@ export default function JsonConvertSection({
className,
...props
}: JsonConvertSectionProps) {
const { t } = useI18n('jsonFormat');
const [input, setInput] = useState('');
const [debouncedInput, setDebouncedInput] = useState('');
const pk = translationPrefix;
const labels = CONVERT_LABELS[pk] || CONVERT_LABELS.yaml;
// Debounce input
useEffect(() => {
@@ -65,7 +84,7 @@ export default function JsonConvertSection({
<div className={cn('w-full flex flex-col gap-4', className)} {...props}>
{/* 输入区 */}
<TextInputArea
placeholder={t(`jsonFormat:${pk}InputPlaceholder`)}
placeholder={labels.inputPlaceholder}
value={input}
onChange={setInput}
externalError={error || runtimeError || undefined}
@@ -82,19 +101,19 @@ export default function JsonConvertSection({
<div className="flex h-9 items-center justify-between px-4 border-b border-border bg-muted/50 select-none">
<div className="flex gap-4 items-center">
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground/90">
{t(`jsonFormat:${pk}OutputLabel`)}
{labels.outputLabel}
</span>
<div className="hidden sm:flex gap-3 items-center font-mono text-[10px] text-muted-foreground/70 tabular-nums">
<span>
{t('jsonFormat:originalSize')}:{' '}
{'原始大小'}:{' '}
<span className="font-semibold text-foreground/80">
{formatBytes(result.originalBytes)}
</span>
</span>
<span className="text-border/60">|</span>
<span>
{t('jsonFormat:formattedSize')}:{' '}
{'格式化后大小'}:{' '}
<span className="font-semibold text-foreground/80">
{formatBytes(result.outputBytes)}
</span>
@@ -115,7 +134,7 @@ export default function JsonConvertSection({
) : (
<div className="p-8 rounded-xl bg-muted/30 border border-dashed border-border/80 text-center flex flex-col items-center justify-center min-h-[120px] select-none">
<p className="text-xs font-semibold text-muted-foreground/80 tracking-wide max-w-[240px] leading-relaxed">
{error ? t('jsonFormat:fixErrorHint') : t(`jsonFormat:${pk}EmptyHint`)}
{error ? '请修正上方 JSON 的语法错误以开启实时流式格式化' : labels.emptyHint}
</p>
</div>
)}
@@ -1,5 +1,4 @@
import { useEffect, useMemo, useState } from 'react';
import { useI18n } from '@/utils/chromeI18n';
import {
formatJson,
type JsonFormatOptions,
@@ -14,8 +13,6 @@ import { Checkbox } from '@/components/ui/checkbox';
import { Label } from '@/components/ui/label';
export default function JsonFormatSection() {
const { t } = useI18n('jsonFormat');
const [input, setInput] = useState('');
const [debouncedInput, setDebouncedInput] = useState('');
const [indentSize, setIndentSize] = useState<number>(2);
@@ -66,7 +63,7 @@ export default function JsonFormatSection() {
{/* 缩进配置区 */}
<div className="flex gap-2 items-center shrink-0 select-none">
<span className="text-[10px] font-bold text-muted-foreground/90 uppercase tracking-wider">
{t('jsonFormat:indentSize')}
{'缩进'}
</span>
<SwitchButtonGroup
value={indentSize}
@@ -94,7 +91,7 @@ export default function JsonFormatSection() {
htmlFor="sort-keys-checkbox"
className="text-xs font-bold text-foreground/80 cursor-pointer tracking-tight group-hover:text-foreground"
>
{t('jsonFormat:sortKeys')}
{'键名排序'}
</Label>
</div>
</div>
@@ -102,7 +99,7 @@ export default function JsonFormatSection() {
{/* 满血版输入终端 */}
<TextInputArea
placeholder={t('jsonFormat:inputPlaceholder')}
placeholder={'输入需要格式化的 JSON...'}
value={input}
onChange={setInput}
externalError={error || runtimeError || undefined}
@@ -120,19 +117,19 @@ export default function JsonFormatSection() {
<div className="flex h-9 items-center justify-between px-4 border-b border-border bg-muted/50 select-none">
<div className="flex gap-4 items-center">
<span className="text-[10px] font-bold uppercase tracking-wider text-muted-foreground/90">
{t('jsonFormat:outputLabel')}
{'格式化结果'}
</span>
<div className="hidden sm:flex gap-3 items-center font-mono text-[10px] text-muted-foreground/70 tabular-nums">
<span>
{t('jsonFormat:originalSize')}:{' '}
{'原始大小'}:{' '}
<span className="font-semibold text-foreground/80">
{formatBytes(result.originalBytes)}
</span>
</span>
<span className="text-border/60">|</span>
<span>
{t('jsonFormat:formattedSize')}:{' '}
{'格式化后大小'}:{' '}
<span className="font-semibold text-foreground/80">
{formatBytes(result.formattedBytes)}
</span>
@@ -154,7 +151,7 @@ export default function JsonFormatSection() {
/* 空状态指示引导区 */
<div className="p-8 rounded-xl bg-muted/30 border border-dashed border-border/80 text-center flex flex-col items-center justify-center min-h-[120px] select-none">
<p className="text-xs font-semibold text-muted-foreground/80 tracking-wide max-w-[240px] leading-relaxed">
{error ? t('jsonFormat:fixErrorHint') : t('jsonFormat:emptyHint')}
{error ? '请修正上方 JSON 的语法错误以开启实时流式格式化' : '输入 JSON 后点击格式化'}
</p>
</div>
)}