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,7 +1,6 @@
import { Loader2, Pencil, QrCode } from 'lucide-react';
import TextInputArea from '@/components/TextInputArea';
import QrCodePreview from './QrCodePreview';
import { useI18n } from '@/utils/chromeI18n';
import { useQrCodeContext } from '../contexts/QrCodeContext';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
@@ -11,7 +10,6 @@ import { cn } from '@/lib/utils';
const TEXT_PREVIEW_MAX_LENGTH = 80;
export default function GeneratePanel() {
const { t } = useI18n('qrCode');
const {
generatorState,
setTextToEncode,
@@ -42,13 +40,13 @@ export default function GeneratePanel() {
>
<div className="flex flex-col space-y-2.5">
<Label className="text-[10px] font-bold text-muted-foreground/90 uppercase tracking-wider select-none pl-0.5">
{t('qrCode:urlInputLabel')}
{'输入 URL 或文本'}
</Label>
<TextInputArea
value={generatorState.textToEncode}
onChange={setTextToEncode}
placeholder={t('qrCode:urlInputPlaceholder')}
placeholder={'请输入 URL 或文本内容,将自动生成二维码'}
showCount={true}
showClear={true}
allowCopy={false}
@@ -66,12 +64,12 @@ export default function GeneratePanel() {
{generatorState.generating ? (
<>
<Loader2 className="w-4 h-4 mr-2 animate-spin" />
{t('qrCode:generating')}
{'生成中...'}
</>
) : (
<>
<QrCode className="w-4 h-4 mr-2" />
{t('qrCode:generateButton')}
{'生成二维码'}
</>
)}
</Button>
@@ -88,11 +86,11 @@ export default function GeneratePanel() {
<div className="border border-border rounded-xl bg-card text-card-foreground shadow-sm p-3 mb-3">
<div className="flex items-center justify-between mb-1.5">
<Label className="text-[10px] font-bold text-muted-foreground/90 uppercase tracking-wider select-none pl-0.5">
{t('qrCode:textPreviewLabel')}
{'原始文本'}
</Label>
<Button variant="ghost" size="sm" onClick={backToEdit} className="h-6 px-2 text-xs">
<Pencil className="w-3 h-3 mr-1" />
{t('qrCode:editButton')}
{'编辑'}
</Button>
</div>
<div
+8 -10
View File
@@ -3,7 +3,6 @@ import { Image, X } from 'lucide-react';
import { toast } from 'sonner';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { useI18n } from '@/utils/chromeI18n';
interface ImageUploaderProps {
/** 选中的文件 */
@@ -31,7 +30,6 @@ const ImageUploader = ({
dragging,
onDraggingChange,
}: ImageUploaderProps) => {
const { t } = useI18n('qrCode');
const fileInputRef = useRef<HTMLInputElement>(null);
const handleFileChange = useCallback(
@@ -47,8 +45,8 @@ const ImageUploader = ({
URL.revokeObjectURL(previewUrl);
}
onClearFile();
toast.success(t('qrCode:imageCleared'));
}, [previewUrl, onClearFile, t]);
toast.success('图片已清除');
}, [previewUrl, onClearFile]);
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
if (e.target.files && e.target.files.length > 0) {
@@ -88,10 +86,10 @@ const ImageUploader = ({
if (file) {
try {
handleFileChange(file);
toast.success(t('qrCode:imagePasted'));
toast.success('图片粘贴成功,正在解析...');
} catch (error) {
console.error('处理粘贴图片失败:', error);
toast.error(t('qrCode:imagePasteError'));
toast.error('粘贴图片失败,请重试');
}
}
break;
@@ -104,7 +102,7 @@ const ImageUploader = ({
return () => {
document.removeEventListener('paste', handlePaste);
};
}, [handleFileChange, t]);
}, [handleFileChange]);
return (
<div
@@ -151,7 +149,7 @@ const ImageUploader = ({
</Button>
</div>
<span className="block text-sm text-muted-foreground mt-2">{selectedFile.name}</span>
<span className="block text-xs text-muted-foreground">{t('qrCode:clickToChange')}</span>
<span className="block text-xs text-muted-foreground">{'点击更换图片'}</span>
</div>
) : (
<>
@@ -160,10 +158,10 @@ const ImageUploader = ({
className="w-12 h-12 text-muted-foreground mx-auto mb-2"
/>
<span className="block text-sm text-muted-foreground mb-1">
{t('qrCode:clickToUpload')}
{'点击、拖拽或粘贴上传二维码图片'}
</span>
<span className="block text-xs text-muted-foreground">
{t('qrCode:supportFormats')}
{'支持 PNG、JPG、WEBP、Base64 格式'}
</span>
</>
)}
+9 -11
View File
@@ -3,14 +3,12 @@ import { RefreshCw } from 'lucide-react';
import { toast } from 'sonner';
import TextInputArea from '@/components/TextInputArea';
import ImageUploader from './ImageUploader';
import { useI18n } from '@/utils/chromeI18n';
import { useQrCodeContext } from '../contexts/QrCodeContext';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { cn } from '@/lib/utils';
export default function ParsePanel() {
const { t } = useI18n('qrCode');
const { parserState, setParserState, handleFileChange, handleClearFile } = useQrCodeContext();
const hasFile = parserState.selectedFile !== null;
@@ -27,7 +25,7 @@ export default function ParsePanel() {
const file = items[i].getAsFile();
if (file) {
handleFileChange(file);
toast.success(t('qrCode:imagePasted'));
toast.success('图片粘贴成功,正在解析...');
}
return;
}
@@ -41,14 +39,14 @@ export default function ParsePanel() {
const blob = await response.blob();
const file = new File([blob], 'pasted-image.png', { type: blob.type });
handleFileChange(file);
toast.success(t('qrCode:imagePasted'));
toast.success('图片粘贴成功,正在解析...');
} catch (error) {
console.error('处理 Base64 图片失败:', error);
toast.error(t('qrCode:imagePasteError'));
toast.error('粘贴图片失败,请重试');
}
}
},
[handleFileChange, t],
[handleFileChange],
);
useEffect(() => {
@@ -82,11 +80,11 @@ export default function ParsePanel() {
<div className="border border-border rounded-xl bg-card text-card-foreground shadow-sm p-3 mb-3">
<div className="flex items-center justify-between mb-1.5">
<Label className="text-[10px] font-bold text-muted-foreground/90 uppercase tracking-wider select-none pl-0.5">
{t('qrCode:uploadedImage')}
{'已上传图片'}
</Label>
<Button variant="ghost" size="sm" onClick={handleClearFile} className="h-6 px-2 text-xs">
<RefreshCw className="w-3 h-3 mr-1" />
{t('qrCode:reuploadButton')}
{'重新上传'}
</Button>
</div>
<div className="flex items-center gap-3 bg-muted/50 rounded-md p-2">
@@ -98,7 +96,7 @@ export default function ParsePanel() {
<div className="flex-1 min-w-0">
<p className="text-sm text-foreground truncate">{parserState.selectedFile?.name}</p>
{parserState.parsing && (
<p className="text-xs text-primary animate-pulse mt-1">{t('qrCode:parsing')}</p>
<p className="text-xs text-primary animate-pulse mt-1">{'解析中...'}</p>
)}
</div>
</div>
@@ -113,7 +111,7 @@ export default function ParsePanel() {
>
<div className="flex flex-col space-y-2.5">
<Label className="text-[10px] font-bold text-muted-foreground/90 uppercase tracking-wider pl-0.5">
{t('qrCode:resultLabel')}
{'解析结果'}
</Label>
<TextInputArea
@@ -121,7 +119,7 @@ export default function ParsePanel() {
readOnly={true}
showClear={false}
allowCopy={true}
placeholder={parserState.parsing ? '' : t('qrCode:resultPlaceholder')}
placeholder={parserState.parsing ? '' : '解析结果将显示在此处'}
minRows={4}
maxRows={8}
externalError={parserState.parseError || undefined}
@@ -1,6 +1,5 @@
import React from 'react';
import { Copy, Download } from 'lucide-react';
import { useI18n } from '@/utils/chromeI18n';
import { cn } from '@/lib/utils';
import { Button } from '@/components/ui/button';
@@ -24,8 +23,6 @@ const QrCodePreview = ({
className,
...props
}: QrCodePreviewProps) => {
const { t } = useI18n('qrCode');
// 空状态下的虚线骨架屏
if (!qrCodeDataUrl) {
return (
@@ -37,7 +34,7 @@ const QrCodePreview = ({
{...props}
>
<p className="text-sm text-muted-foreground text-center">
{placeholderText || t('qrCode:qrCodeWillShow')}
{placeholderText || '二维码将显示在这里'}
</p>
</div>
);
@@ -68,12 +65,12 @@ const QrCodePreview = ({
<div className="flex w-full gap-2 mt-3">
<Button variant="outline" size="sm" onClick={onDownload} className="flex-1 h-8">
<Download className="w-3.5 h-3.5 text-muted-foreground" />
<span className="truncate text-xs">{t('qrCode:downloadButton')}</span>
<span className="truncate text-xs">{'下载二维码'}</span>
</Button>
<Button variant="default" size="sm" onClick={onCopy} className="flex-1 h-8">
<Copy className="w-3.5 h-3.5" />
<span className="truncate text-xs">{t('qrCode:copyQrButton')}</span>
<span className="truncate text-xs">{'复制二维码'}</span>
</Button>
</div>
</div>