refactor(i18n): 移除 chrome.i18n 国际化,统一使用中文硬编码
移除 chromeI18n 工具、_locales 翻译文件和 manifest default_locale 配置, 将所有 UI 文案改为直接硬编码中文,并更新相关测试与文档。
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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>
|
||||
</>
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user