Feat: 增加语言过滤功能,临时性不显示对应语言
This commit is contained in:
parent
83e826e034
commit
2ae98780de
|
|
@ -35,7 +35,7 @@ export async function requestTranslations({
|
||||||
const keysJson = JSON.stringify(items.map((it) => it.key));
|
const keysJson = JSON.stringify(items.map((it) => it.key));
|
||||||
const instruction = [
|
const instruction = [
|
||||||
"你是一个专业的翻译助手。",
|
"你是一个专业的翻译助手。",
|
||||||
`请将多条原文同时翻译为这些目标语言:${targetList},注意英语的首字母务必是大写。`,
|
`请使用当地人的习惯用语,将多条原文同时翻译为这些目标语言:${targetList},注意英语的首字母务必是大写。`,
|
||||||
"翻译偏好:",
|
"翻译偏好:",
|
||||||
prompt,
|
prompt,
|
||||||
"严格要求:",
|
"严格要求:",
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import {
|
||||||
updateProject,
|
updateProject,
|
||||||
deleteProjectDeep,
|
deleteProjectDeep,
|
||||||
} from "@/lib/db";
|
} from "@/lib/db";
|
||||||
import { ArrowBigDownDash, ArrowBigUpDash, ArrowLeft, Brackets, CaseSensitive, Languages, LocateFixed, MoreVertical, PencilLine, Trash2 } from "lucide-react";
|
import { ArrowBigDownDash, ArrowBigUpDash, ArrowLeft, Brackets, CaseSensitive, Filter, Languages, LocateFixed, MoreVertical, PencilLine, Trash2 } from "lucide-react";
|
||||||
import { useTranslationInlineEdit } from "@/hooks/biz/use-translation-inline-edit";
|
import { useTranslationInlineEdit } from "@/hooks/biz/use-translation-inline-edit";
|
||||||
import { flattenEntries, type FlatEntry, insertEntrySibling, removeEntryAtPath, renameEntryAtPath } from "@/lib/i18n-structure";
|
import { flattenEntries, type FlatEntry, insertEntrySibling, removeEntryAtPath, renameEntryAtPath } from "@/lib/i18n-structure";
|
||||||
import { ImportLanguageModal } from "@/components/biz/import-language-modal";
|
import { ImportLanguageModal } from "@/components/biz/import-language-modal";
|
||||||
|
|
@ -31,6 +31,7 @@ import {
|
||||||
DropdownMenuTrigger,
|
DropdownMenuTrigger,
|
||||||
DropdownMenuContent,
|
DropdownMenuContent,
|
||||||
DropdownMenuItem,
|
DropdownMenuItem,
|
||||||
|
DropdownMenuCheckboxItem,
|
||||||
DropdownMenuSeparator,
|
DropdownMenuSeparator,
|
||||||
} from "@/components/ui/dropdown-menu";
|
} from "@/components/ui/dropdown-menu";
|
||||||
import { useClipboard } from "@/hooks/use-clipboard";
|
import { useClipboard } from "@/hooks/use-clipboard";
|
||||||
|
|
@ -59,6 +60,7 @@ export default function Editor() {
|
||||||
const [aiBulkOpen, setAiBulkOpen] = useState(false);
|
const [aiBulkOpen, setAiBulkOpen] = useState(false);
|
||||||
const [settingsOpen, setSettingsOpen] = useState(false);
|
const [settingsOpen, setSettingsOpen] = useState(false);
|
||||||
const [selected, setSelected] = useState<Set<string>>(new Set());
|
const [selected, setSelected] = useState<Set<string>>(new Set());
|
||||||
|
const [visibleLangs, setVisibleLangs] = useState<Set<string>>(new Set());
|
||||||
|
|
||||||
const { copy } = useClipboard();
|
const { copy } = useClipboard();
|
||||||
|
|
||||||
|
|
@ -139,7 +141,14 @@ export default function Editor() {
|
||||||
onError: (m) => setPageError(m),
|
onError: (m) => setPageError(m),
|
||||||
});
|
});
|
||||||
|
|
||||||
const tableWidth = useMemo(() => (languages.length * 200) + 36 + 60 + 300, [languages.length]);
|
// 同步可见语言集合
|
||||||
|
useEffect(() => {
|
||||||
|
setVisibleLangs(new Set(languages));
|
||||||
|
}, [languages]);
|
||||||
|
|
||||||
|
const displayedLanguages = useMemo(() => languages.filter((l) => visibleLangs.has(l)), [languages, visibleLangs]);
|
||||||
|
|
||||||
|
const tableWidth = useMemo(() => (displayedLanguages.length * 200) + 36 + 60 + 300, [displayedLanguages.length]);
|
||||||
|
|
||||||
function computeSuggestedLanguages(pathsInput: string[]): string[] {
|
function computeSuggestedLanguages(pathsInput: string[]): string[] {
|
||||||
if (languages.length === 0 || pathsInput.length === 0) return [];
|
if (languages.length === 0 || pathsInput.length === 0) return [];
|
||||||
|
|
@ -204,12 +213,12 @@ export default function Editor() {
|
||||||
/>
|
/>
|
||||||
</th>
|
</th>
|
||||||
<th style={{ width: 300 }} className="text-left px-3 py-2">翻译条目名称</th>
|
<th style={{ width: 300 }} className="text-left px-3 py-2">翻译条目名称</th>
|
||||||
{languages.map((lang) => (
|
{displayedLanguages.map((lang) => (
|
||||||
<th key={lang} style={{ width: 200 }} className="text-left px-3 py-2">{lang}</th>
|
<th key={lang} style={{ width: 200 }} className="text-left px-3 py-2">{lang}</th>
|
||||||
))}
|
))}
|
||||||
<th style={{ width: 60 }} className="sticky right-0 text-left px-3 py-2 bg-muted">操作</th>
|
<th style={{ width: 60 }} className="sticky right-0 text-left px-3 py-2 bg-muted">操作</th>
|
||||||
</tr>
|
</tr>
|
||||||
), [languages, allSelected, entries]);
|
), [displayedLanguages, allSelected, entries]);
|
||||||
|
|
||||||
const renderItemContent = useCallback((_idx: number, entry: FlatEntry) => {
|
const renderItemContent = useCallback((_idx: number, entry: FlatEntry) => {
|
||||||
const handleCopy = () => {
|
const handleCopy = () => {
|
||||||
|
|
@ -236,7 +245,7 @@ export default function Editor() {
|
||||||
{entry.path}
|
{entry.path}
|
||||||
</button>
|
</button>
|
||||||
</td>
|
</td>
|
||||||
{languages.map((lang) => {
|
{displayedLanguages.map((lang) => {
|
||||||
const isEditing = inline.isEditingCell(entry.path, lang);
|
const isEditing = inline.isEditingCell(entry.path, lang);
|
||||||
const isSaving = inline.isSavingCell(entry.path, lang);
|
const isSaving = inline.isSavingCell(entry.path, lang);
|
||||||
const displayValue = inline.getDisplayValue(entry.path, lang);
|
const displayValue = inline.getDisplayValue(entry.path, lang);
|
||||||
|
|
@ -324,7 +333,7 @@ export default function Editor() {
|
||||||
</td>
|
</td>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}, [languages, inline, projectId, structure, setStructure, setValuesByLang, copy, selected]);
|
}, [displayedLanguages, inline, projectId, structure, setStructure, setValuesByLang, copy, selected]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!projectId || languages.length === 0) return;
|
if (!projectId || languages.length === 0) return;
|
||||||
|
|
@ -414,6 +423,39 @@ export default function Editor() {
|
||||||
</Button>
|
</Button>
|
||||||
</form>
|
</form>
|
||||||
<div className="mb-2 flex items-center gap-2">
|
<div className="mb-2 flex items-center gap-2">
|
||||||
|
<DropdownMenu>
|
||||||
|
<DropdownMenuTrigger asChild>
|
||||||
|
<Button variant="outline" title="过滤显示的语言列">
|
||||||
|
<Filter />
|
||||||
|
语言过滤
|
||||||
|
</Button>
|
||||||
|
</DropdownMenuTrigger>
|
||||||
|
<DropdownMenuContent align="start" className="w-48">
|
||||||
|
<DropdownMenuItem onClick={() => setVisibleLangs(new Set(languages))}>
|
||||||
|
全部显示
|
||||||
|
</DropdownMenuItem>
|
||||||
|
<DropdownMenuSeparator />
|
||||||
|
{languages.map((lang) => {
|
||||||
|
const checked = visibleLangs.has(lang);
|
||||||
|
return (
|
||||||
|
<DropdownMenuCheckboxItem
|
||||||
|
key={lang}
|
||||||
|
onSelect={(e) => e.preventDefault()}
|
||||||
|
checked={checked}
|
||||||
|
onCheckedChange={(v) => {
|
||||||
|
setVisibleLangs((prev) => {
|
||||||
|
const next = new Set(prev);
|
||||||
|
if (v) next.add(lang); else next.delete(lang);
|
||||||
|
return next;
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{lang}
|
||||||
|
</DropdownMenuCheckboxItem>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</DropdownMenuContent>
|
||||||
|
</DropdownMenu>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
disabled={selected.size === 0 || selected.size > MAX_AI_ITEMS}
|
disabled={selected.size === 0 || selected.size > MAX_AI_ITEMS}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue