Commit 3932f929 authored by wuzekai's avatar wuzekai

feat: 界面汉化 + OMAP 品牌化 + AI 读取历史数据集能力

- 汉化 /chatgxy、/upload 等路由界面
- 前端/后端提示词 OMAP 品牌化
- AI 问答新增读取当前历史数据集的能力(list_history_datasets / read_history_dataset)
- 新增 AI 读取历史数据设计文档
parent 5b5387d2
...@@ -194,3 +194,9 @@ involucro ...@@ -194,3 +194,9 @@ involucro
.DS_Store .DS_Store
*.rej *.rej
*~ *~
# build artifacts
client/dist_new/
# temporary scripts
client/src/translate_rare.py
...@@ -8284,6 +8284,11 @@ export interface components { ...@@ -8284,6 +8284,11 @@ export interface components {
* @description The ID of an existing chat exchange to continue. * @description The ID of an existing chat exchange to continue.
*/ */
exchange_id?: string | null; exchange_id?: string | null;
/**
* History ID
* @description The (encoded) ID of the current history, used by the AI to read datasets for analysis.
*/
history_id?: string | null;
/** /**
* Query * Query
* @description The query to be sent to the chatbot. * @description The query to be sent to the chatbot.
...@@ -30,12 +30,12 @@ const versionUserDocumentationUrl = computed(() => { ...@@ -30,12 +30,12 @@ const versionUserDocumentationUrl = computed(() => {
<template> <template>
<div v-if="isConfigLoaded" class="about-galaxy"> <div v-if="isConfigLoaded" class="about-galaxy">
<Heading h1 :icon="galaxyLogo" size="lg">Help and Support</Heading> <Heading h1 :icon="galaxyLogo" size="lg">帮助与支持</Heading>
<div class="p-2"> <div class="p-2">
<Heading h2 separator size="md">Support</Heading> <Heading h2 separator size="md">支持</Heading>
<div v-if="config.wiki_url"> <div v-if="config.wiki_url">
<ExternalLink :href="config.wiki_url"> <ExternalLink :href="config.wiki_url">
<strong v-localize>Community Hub</strong> <strong v-localize>社区中心</strong>
</ExternalLink> </ExternalLink>
<p v-localize>Join our community and explore tutorials on using Galaxy and enhance your skills.</p> <p v-localize>Join our community and explore tutorials on using Galaxy and enhance your skills.</p>
</div> </div>
...@@ -49,34 +49,34 @@ const versionUserDocumentationUrl = computed(() => { ...@@ -49,34 +49,34 @@ const versionUserDocumentationUrl = computed(() => {
</div> </div>
<div v-if="config.support_url"> <div v-if="config.support_url">
<ExternalLink :href="config.support_url"> <ExternalLink :href="config.support_url">
<strong v-localize>Reach Out</strong> <strong v-localize>联系我们</strong>
</ExternalLink> </ExternalLink>
<p v-localize>Need help or want to teach and learn more about Galaxy? Feel free to reach out to us.</p> <p v-localize>Need help or want to teach and learn more about Galaxy? Feel free to reach out to us.</p>
</div> </div>
<Heading v-localize h2 separator size="md">Help</Heading> <Heading v-localize h2 separator size="md">Help</Heading>
<div> <div>
<RouterLink to="tours"> <RouterLink to="tours">
<strong v-localize>Interactive Tours</strong> <strong v-localize>交互式教程</strong>
</RouterLink> </RouterLink>
<p v-localize>Discover and learn about Galaxy with our interactive tours.</p> <p v-localize>通过交互式教程发现和学习 Galaxy。</p>
</div> </div>
<div v-if="config.screencasts_url"> <div v-if="config.screencasts_url">
<ExternalLink :href="config.screencasts_url"> <ExternalLink :href="config.screencasts_url">
<strong v-localize>Videos and Screencasts</strong> <strong v-localize>视频和屏幕录像</strong>
</ExternalLink> </ExternalLink>
<p v-localize>Learn more about Galaxy by watching videos and screencasts.</p> <p v-localize>通过观看视频和屏幕录像了解更多关于 Galaxy 的信息。</p>
</div> </div>
<div v-if="config.citation_url"> <div v-if="config.citation_url">
<ExternalLink :href="config.citation_url"> <ExternalLink :href="config.citation_url">
<strong v-localize>How to Cite Us</strong> <strong v-localize>如何引用我们</strong>
</ExternalLink> </ExternalLink>
<p v-localize>View details on how to properly cite Galaxy.</p> <p v-localize>查看如何正确引用 Galaxy 的详情。</p>
</div> </div>
<Heading h2 separator size="md">Technical Details</Heading> <Heading h2 separator size="md">技术详情</Heading>
<div> <div>
<!-- Galaxy version (detailed), with a link to the release notes --> <!-- Galaxy version (detailed), with a link to the release notes -->
<ExternalLink :href="versionUserDocumentationUrl"> <ExternalLink :href="versionUserDocumentationUrl">
<strong v-localize>Release Notes</strong> <strong v-localize>发行说明</strong>
</ExternalLink> </ExternalLink>
<p v-localize> <p v-localize>
This Galaxy server version is <strong>{{ config.version_major }}.{{ config.version_minor }}</strong This Galaxy server version is <strong>{{ config.version_major }}.{{ config.version_minor }}</strong
...@@ -95,18 +95,18 @@ const versionUserDocumentationUrl = computed(() => { ...@@ -95,18 +95,18 @@ const versionUserDocumentationUrl = computed(() => {
</div> </div>
<div> <div>
<ExternalLink :href="apiDocsLink"> <ExternalLink :href="apiDocsLink">
<strong v-localize>API Documentation</strong> <strong v-localize>API 文档</strong>
</ExternalLink> </ExternalLink>
<p v-localize>Explore the Galaxy API.</p> <p v-localize>探索 Galaxy API。</p>
</div> </div>
<div> <div>
<License class="font-weight-bold" :license-id="galaxyLicense" /> <License class="font-weight-bold" :license-id="galaxyLicense" />
<p v-localize>The Galaxy Software is licensed under the MIT License.</p> <p v-localize>Galaxy 软件在 MIT 许可证下授权。</p>
</div> </div>
<div v-if="config.terms_url"> <div v-if="config.terms_url">
<!-- Terms, if available.--> <!-- Terms, if available.-->
<ExternalLink :href="config.terms_url"> <ExternalLink :href="config.terms_url">
<strong v-localize>Terms and Conditions</strong> <strong v-localize>条款和条件</strong>
</ExternalLink> </ExternalLink>
<p v-localize> <p v-localize>
This Galaxy Server has specified Terms and Conditions that apply to use of the service. This Galaxy Server has specified Terms and Conditions that apply to use of the service.
......
...@@ -122,7 +122,7 @@ const meta = computed(() => store.metaForId(props.id)); ...@@ -122,7 +122,7 @@ const meta = computed(() => store.metaForId(props.id));
</template> </template>
<div class="text-center px-2 py-1"> <div class="text-center px-2 py-1">
<small v-if="tooltip">{{ localize(tooltip) }}</small> <small v-if="tooltip">{{ localize(tooltip) }}</small>
<small v-else>No tooltip available for this item</small> <small v-else>此项目没有可用的提示</small>
<div v-if="options" class="nav-options p-1"> <div v-if="options" class="nav-options p-1">
<router-link v-for="(option, index) in options" :key="index" :to="option.value"> <router-link v-for="(option, index) in options" :key="index" :to="option.value">
<GButton size="small" outline color="blue" class="w-100 my-1 text-break text-light"> <GButton size="small" outline color="blue" class="w-100 my-1 text-break text-light">
......
...@@ -42,7 +42,7 @@ const edamLink = (edamIRI: string) => `https://edamontology.github.io/edam-brows ...@@ -42,7 +42,7 @@ const edamLink = (edamIRI: string) => `https://edamontology.github.io/edam-brows
<template> <template>
<div> <div>
<h1>Datatypes</h1> <h1>数据类型</h1>
<p> <p>
All Datatypes supported by this Galaxy instance. Hover over an item for more information. These extensions All Datatypes supported by this Galaxy instance. Hover over an item for more information. These extensions
can be filtered by in the History, by expanding "search datasets". can be filtered by in the History, by expanding "search datasets".
......
...@@ -70,7 +70,7 @@ onUnmounted(() => { ...@@ -70,7 +70,7 @@ onUnmounted(() => {
<div v-if="tipList.length > 0" class="g-tip" :class="variantClass"> <div v-if="tipList.length > 0" class="g-tip" :class="variantClass">
<small class="text-muted tip-content" :class="{ 'has-controls': hasMultipleTips }"> <small class="text-muted tip-content" :class="{ 'has-controls': hasMultipleTips }">
<span class="tip-item"> <span class="tip-item">
<strong>Tip:</strong> <strong>提示:</strong>
<!-- eslint-disable-next-line vue/no-v-html --> <!-- eslint-disable-next-line vue/no-v-html -->
<span v-html="tipList[currentIndex]"></span> <span v-html="tipList[currentIndex]"></span>
</span> </span>
......
...@@ -8,6 +8,7 @@ import { GalaxyApi } from "@/api"; ...@@ -8,6 +8,7 @@ import { GalaxyApi } from "@/api";
import { getGalaxyInstance } from "@/app"; import { getGalaxyInstance } from "@/app";
import { type AgentResponse, useAgentActions } from "@/composables/agentActions"; import { type AgentResponse, useAgentActions } from "@/composables/agentActions";
import { useMarkdown } from "@/composables/markdown"; import { useMarkdown } from "@/composables/markdown";
import { useHistoryStore } from "@/stores/historyStore";
import { errorMessageAsString } from "@/utils/simple-error"; import { errorMessageAsString } from "@/utils/simple-error";
import { getAgentIcon } from "./ChatGXY/agentTypes"; import { getAgentIcon } from "./ChatGXY/agentTypes";
...@@ -71,8 +72,8 @@ function showWelcome() { ...@@ -71,8 +72,8 @@ function showWelcome() {
id: generateId(), id: generateId(),
role: "assistant", role: "assistant",
content: content:
"Welcome to ChatGXY. Ask about tools, workflows, errors, or data quality " + "欢迎使用 ChatGXY。你可以询问关于工具、工作流、错误或数据质量的问题," +
"and your question will be routed to the appropriate specialist agent.", "你的问题会被路由到相应的专家智能体。",
timestamp: new Date(), timestamp: new Date(),
agentType: "router", agentType: "router",
confidence: "high", confidence: "high",
...@@ -104,6 +105,9 @@ async function submitQuery() { ...@@ -104,6 +105,9 @@ async function submitQuery() {
busy.value = true; busy.value = true;
try { try {
const historyStore = useHistoryStore();
const currentHistoryId = historyStore.currentHistoryId ?? null;
const { data, error } = await GalaxyApi().POST("/api/chat", { const { data, error } = await GalaxyApi().POST("/api/chat", {
params: { params: {
query: { query: {
...@@ -114,15 +118,16 @@ async function submitQuery() { ...@@ -114,15 +118,16 @@ async function submitQuery() {
query: currentQuery, query: currentQuery,
context: null, context: null,
exchange_id: currentChatId.value, exchange_id: currentChatId.value,
history_id: currentHistoryId,
}, },
}); });
if (error) { if (error) {
const errorText = errorMessageAsString(error, "Failed to get response from ChatGXY."); const errorText = errorMessageAsString(error, "无法从 ChatGXY 获取响应。");
const errorMsg: ChatMessage = { const errorMsg: ChatMessage = {
id: generateId(), id: generateId(),
role: "assistant", role: "assistant",
content: `Error: ${errorText}`, content: `错误:${errorText}`,
timestamp: new Date(), timestamp: new Date(),
agentType: selectedAgentType.value, agentType: selectedAgentType.value,
confidence: "low", confidence: "low",
...@@ -134,7 +139,7 @@ async function submitQuery() { ...@@ -134,7 +139,7 @@ async function submitQuery() {
scrollToBottom(chatContainer.value); scrollToBottom(chatContainer.value);
} else if (data) { } else if (data) {
const agentResponse = data.agent_response as AgentResponse | undefined; const agentResponse = data.agent_response as AgentResponse | undefined;
const content = data.response || "No response received"; const content = data.response || "未收到响应";
if (data.exchange_id) { if (data.exchange_id) {
currentChatId.value = data.exchange_id; currentChatId.value = data.exchange_id;
...@@ -163,7 +168,7 @@ async function submitQuery() { ...@@ -163,7 +168,7 @@ async function submitQuery() {
const errorMsg: ChatMessage = { const errorMsg: ChatMessage = {
id: generateId(), id: generateId(),
role: "assistant", role: "assistant",
content: "Unexpected error occurred. Please try again.", content: "发生意外错误,请重试。",
timestamp: new Date(), timestamp: new Date(),
agentType: selectedAgentType.value, agentType: selectedAgentType.value,
confidence: "low", confidence: "low",
...@@ -292,7 +297,7 @@ function startNewChat() { ...@@ -292,7 +297,7 @@ function startNewChat() {
{ {
id: generateId(), id: generateId(),
role: "assistant", role: "assistant",
content: "New conversation started. How can I help?", content: "已开始新对话。有什么可以帮你?",
timestamp: new Date(), timestamp: new Date(),
agentType: "router", agentType: "router",
confidence: "high", confidence: "high",
...@@ -335,20 +340,20 @@ function popOutToScratchbook() { ...@@ -335,20 +340,20 @@ function popOutToScratchbook() {
<span>ChatGXY</span> <span>ChatGXY</span>
</Heading> </Heading>
<div class="header-actions"> <div class="header-actions">
<button class="btn btn-sm btn-outline-primary" title="Start New Chat" @click="startNewChat"> <button class="btn btn-sm btn-outline-primary" title="开始新对话" @click="startNewChat">
<FontAwesomeIcon :icon="faPlus" fixed-width /> <FontAwesomeIcon :icon="faPlus" fixed-width />
New 新建
</button> </button>
<button <button
v-if="currentChatId" v-if="currentChatId"
class="btn btn-sm btn-outline-danger" class="btn btn-sm btn-outline-danger"
title="Delete this conversation" title="删除此对话"
@click="deleteCurrentChat"> @click="deleteCurrentChat">
<FontAwesomeIcon :icon="faTrash" fixed-width /> <FontAwesomeIcon :icon="faTrash" fixed-width />
</button> </button>
<button <button
class="btn btn-sm btn-outline-primary" class="btn btn-sm btn-outline-primary"
title="Open in floating window" title="在浮窗中打开"
@click="popOutToScratchbook"> @click="popOutToScratchbook">
<FontAwesomeIcon :icon="faExternalLinkAlt" fixed-width /> <FontAwesomeIcon :icon="faExternalLinkAlt" fixed-width />
</button> </button>
......
<template> <template>
<div v-if="suggestions.length > 0" class="action-card"> <div v-if="suggestions.length > 0" class="action-card">
<div class="action-header">Quick Actions</div> <div class="action-header">快速操作</div>
<div class="action-list"> <div class="action-list">
<GButton <GButton
v-for="action in sortedSuggestions" v-for="action in sortedSuggestions"
......
...@@ -94,15 +94,15 @@ async function deleteSelected() { ...@@ -94,15 +94,15 @@ async function deleteSelected() {
</script> </script>
<template> <template>
<ActivityPanel title="ChatGXY" go-to-all-title="Open ChatGXY" href="/chatgxy"> <ActivityPanel title="ChatGXY" go-to-all-title="打开 ChatGXY" href="/chatgxy">
<template v-slot:header-buttons> <template v-slot:header-buttons>
<button class="btn btn-sm btn-outline-primary" title="New Chat" @click="startNewChat"> <button class="btn btn-sm btn-outline-primary" title="新对话" @click="startNewChat">
<FontAwesomeIcon :icon="faPlus" fixed-width /> <FontAwesomeIcon :icon="faPlus" fixed-width />
</button> </button>
<button <button
class="btn btn-sm" class="btn btn-sm"
:class="selectionMode ? 'btn-outline-secondary' : 'btn-outline-danger'" :class="selectionMode ? 'btn-outline-secondary' : 'btn-outline-danger'"
:title="selectionMode ? 'Cancel selection' : 'Select chats to delete'" :title="selectionMode ? '取消选择' : '选择要删除的对话'"
@click="toggleSelectionMode"> @click="toggleSelectionMode">
<FontAwesomeIcon :icon="selectionMode ? faTimes : faTrash" fixed-width /> <FontAwesomeIcon :icon="selectionMode ? faTimes : faTrash" fixed-width />
</button> </button>
...@@ -112,7 +112,7 @@ async function deleteSelected() { ...@@ -112,7 +112,7 @@ async function deleteSelected() {
<!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events vuejs-accessibility/no-static-element-interactions --> <!-- eslint-disable-next-line vuejs-accessibility/click-events-have-key-events vuejs-accessibility/no-static-element-interactions -->
<span class="select-all-toggle" @click="toggleSelectAll"> <span class="select-all-toggle" @click="toggleSelectAll">
<FontAwesomeIcon :icon="allSelected ? faCheckSquare : faSquare" fixed-width /> <FontAwesomeIcon :icon="allSelected ? faCheckSquare : faSquare" fixed-width />
{{ allSelected ? "Deselect all" : "Select all" }} {{ allSelected ? "取消全选" : "全选" }}
</span> </span>
<button class="btn btn-sm btn-danger" :disabled="selectedIds.size === 0" @click="deleteSelected"> <button class="btn btn-sm btn-danger" :disabled="selectedIds.size === 0" @click="deleteSelected">
Delete {{ selectedIds.size > 0 ? selectedIds.size : "" }} Delete {{ selectedIds.size > 0 ? selectedIds.size : "" }}
...@@ -124,8 +124,8 @@ async function deleteSelected() { ...@@ -124,8 +124,8 @@ async function deleteSelected() {
:is-loading="loading" :is-loading="loading"
:item-key="(item) => item.id" :item-key="(item) => item.id"
:item-class="(item) => ({ selected: selectedIds.has(item.id) })" :item-class="(item) => ({ selected: selectedIds.has(item.id) })"
loading-message="Loading history..." loading-message="正在加载历史记录……"
empty-message="No chat history yet" empty-message="暂无对话历史"
@select="handleItemClick"> @select="handleItemClick">
<template v-slot:item="{ item }"> <template v-slot:item="{ item }">
<span v-if="selectionMode" class="history-checkbox"> <span v-if="selectionMode" class="history-checkbox">
......
...@@ -28,7 +28,7 @@ describe("ChatInput", () => { ...@@ -28,7 +28,7 @@ describe("ChatInput", () => {
it("renders with default placeholder", () => { it("renders with default placeholder", () => {
const wrapper = mountInput(); const wrapper = mountInput();
const textarea = wrapper.find("textarea"); const textarea = wrapper.find("textarea");
expect(textarea.attributes("placeholder")).toContain("Ask about tools"); expect(textarea.attributes("placeholder")).toContain("询问关于工具、工作流、错误或数据质量的问题");
}); });
it("renders with custom placeholder", () => { it("renders with custom placeholder", () => {
......
...@@ -12,7 +12,7 @@ const props = withDefaults( ...@@ -12,7 +12,7 @@ const props = withDefaults(
disabled?: boolean; disabled?: boolean;
}>(), }>(),
{ {
placeholder: "Ask about tools, workflows, errors, or anything Galaxy...", placeholder: "询问关于工具、工作流、错误或数据质量的问题……",
disabled: false, disabled: false,
}, },
); );
...@@ -29,7 +29,7 @@ function onInput(event: Event) { ...@@ -29,7 +29,7 @@ function onInput(event: Event) {
<template> <template>
<div class="chat-input-container"> <div class="chat-input-container">
<label for="chat-input" class="sr-only">Chat message</label> <label for="chat-input" class="sr-only">聊天消息</label>
<textarea <textarea
id="chat-input" id="chat-input"
:value="props.value" :value="props.value"
......
...@@ -79,7 +79,7 @@ describe("ChatMessageCell", () => { ...@@ -79,7 +79,7 @@ describe("ChatMessageCell", () => {
const wrapper = mountCell(makeAssistantMessage({ agentType: "error_analysis" })); const wrapper = mountCell(makeAssistantMessage({ agentType: "error_analysis" }));
const tags = wrapper.findAll(".meta-tag"); const tags = wrapper.findAll(".meta-tag");
const labels = tags.wrappers.map((w) => w.text()); const labels = tags.wrappers.map((w) => w.text());
expect(labels.some((l) => l.includes("Error Analysis"))).toBe(true); expect(labels.some((l) => l.includes("错误分析"))).toBe(true);
}); });
}); });
...@@ -125,7 +125,7 @@ describe("ChatMessageCell", () => { ...@@ -125,7 +125,7 @@ describe("ChatMessageCell", () => {
it("shows thanks text after feedback", () => { it("shows thanks text after feedback", () => {
const wrapper = mountCell(makeAssistantMessage({ feedback: "up" })); const wrapper = mountCell(makeAssistantMessage({ feedback: "up" }));
expect(wrapper.find(".feedback-ack").text()).toBe("Thanks!"); expect(wrapper.find(".feedback-ack").text()).toBe("谢谢反馈!");
}); });
it("hides meta for error messages", () => { it("hides meta for error messages", () => {
......
...@@ -67,7 +67,7 @@ const emit = defineEmits<{ ...@@ -67,7 +67,7 @@ const emit = defineEmits<{
class="feedback-btn" class="feedback-btn"
:disabled="props.message.feedback !== null" :disabled="props.message.feedback !== null"
:class="{ active: props.message.feedback === 'up' }" :class="{ active: props.message.feedback === 'up' }"
title="Helpful" title="有帮助"
@click="emit('feedback', props.message.id, 'up')"> @click="emit('feedback', props.message.id, 'up')">
<FontAwesomeIcon :icon="faThumbsUp" fixed-width /> <FontAwesomeIcon :icon="faThumbsUp" fixed-width />
</button> </button>
...@@ -75,11 +75,11 @@ const emit = defineEmits<{ ...@@ -75,11 +75,11 @@ const emit = defineEmits<{
class="feedback-btn" class="feedback-btn"
:disabled="props.message.feedback !== null" :disabled="props.message.feedback !== null"
:class="{ active: props.message.feedback === 'down' }" :class="{ active: props.message.feedback === 'down' }"
title="Not helpful" title="没有帮助"
@click="emit('feedback', props.message.id, 'down')"> @click="emit('feedback', props.message.id, 'down')">
<FontAwesomeIcon :icon="faThumbsDown" fixed-width /> <FontAwesomeIcon :icon="faThumbsDown" fixed-width />
</button> </button>
<span v-if="props.message.feedback" class="feedback-ack">Thanks!</span> <span v-if="props.message.feedback" class="feedback-ack">谢谢反馈!</span>
</div> </div>
<div class="meta-right"> <div class="meta-right">
<span class="meta-tag">{{ getAgentLabel(props.message.agentType) }}</span> <span class="meta-tag">{{ getAgentLabel(props.message.agentType) }}</span>
......
...@@ -24,21 +24,21 @@ describe("agentTypes", () => { ...@@ -24,21 +24,21 @@ describe("agentTypes", () => {
describe("getAgentLabel", () => { describe("getAgentLabel", () => {
it("returns label for known agent types", () => { it("returns label for known agent types", () => {
expect(getAgentLabel("auto")).toBe("Auto (Router)"); expect(getAgentLabel("auto")).toBe("自动(路由)");
expect(getAgentLabel("error_analysis")).toBe("Error Analysis"); expect(getAgentLabel("error_analysis")).toBe("错误分析");
expect(getAgentLabel("gtn_training")).toBe("GTN Training"); expect(getAgentLabel("gtn_training")).toBe("GTN 培训");
}); });
it("returns raw value for unknown agent type", () => { it("returns raw value for unknown agent type", () => {
expect(getAgentLabel("my_custom_agent")).toBe("my_custom_agent"); expect(getAgentLabel("my_custom_agent")).toBe("my_custom_agent");
}); });
it("returns 'AI Assistant' for undefined", () => { it("returns 'AI 助手' for undefined", () => {
expect(getAgentLabel(undefined)).toBe("AI Assistant"); expect(getAgentLabel(undefined)).toBe("AI 助手");
}); });
it("returns 'AI Assistant' for empty string", () => { it("returns 'AI 助手' for empty string", () => {
expect(getAgentLabel("")).toBe("AI Assistant"); expect(getAgentLabel("")).toBe("AI 助手");
}); });
}); });
......
...@@ -19,12 +19,12 @@ export interface AgentType { ...@@ -19,12 +19,12 @@ export interface AgentType {
} }
export const agentTypes: AgentType[] = [ export const agentTypes: AgentType[] = [
{ value: "auto", label: "Auto (Router)", icon: faMagic, description: "Intelligent routing" }, { value: "auto", label: "自动(路由)", icon: faMagic, description: "智能路由" },
{ value: "router", label: "Router", icon: faRoute, description: "Query router" }, { value: "router", label: "路由", icon: faRoute, description: "查询路由" },
{ value: "error_analysis", label: "Error Analysis", icon: faBug, description: "Debug tool errors" }, { value: "error_analysis", label: "错误分析", icon: faBug, description: "调试工具错误" },
{ value: "custom_tool", label: "Custom Tool", icon: faPlus, description: "Create custom tools" }, { value: "custom_tool", label: "自定义工具", icon: faPlus, description: "创建自定义工具" },
{ value: "dataset_analyzer", label: "Dataset Analyzer", icon: faChartBar, description: "Analyze datasets" }, { value: "dataset_analyzer", label: "数据集分析", icon: faChartBar, description: "分析数据集" },
{ value: "gtn_training", label: "GTN Training", icon: faGraduationCap, description: "Find tutorials" }, { value: "gtn_training", label: "GTN 培训", icon: faGraduationCap, description: "查找教程" },
]; ];
export function getAgentIcon(agentType?: string): IconDefinition { export function getAgentIcon(agentType?: string): IconDefinition {
...@@ -33,7 +33,7 @@ export function getAgentIcon(agentType?: string): IconDefinition { ...@@ -33,7 +33,7 @@ export function getAgentIcon(agentType?: string): IconDefinition {
export function getAgentLabel(agentType?: string): string { export function getAgentLabel(agentType?: string): string {
const agent = agentTypes.find((a) => a.value === agentType); const agent = agentTypes.find((a) => a.value === agentType);
return agent?.label || agentType || "AI Assistant"; return agent?.label || agentType || "AI 助手";
} }
export function formatModelName(model?: string): string { export function formatModelName(model?: string): string {
......
...@@ -131,7 +131,7 @@ function citationsToBibtexAsText() { ...@@ -131,7 +131,7 @@ function citationsToBibtexAsText() {
<div v-if="isLoading" class="text-center"> <div v-if="isLoading" class="text-center">
<BSpinner /> <BSpinner />
<p class="ml-2">Loading references...</p> <p class="ml-2">正在加载参考文献...</p>
</div> </div>
<div v-else> <div v-else>
<BCard v-if="!simple" class="citation-card" header-tag="nav"> <BCard v-if="!simple" class="citation-card" header-tag="nav">
...@@ -201,7 +201,7 @@ function citationsToBibtexAsText() { ...@@ -201,7 +201,7 @@ function citationsToBibtexAsText() {
</div> </div>
</BCard> </BCard>
<div v-else-if="citations.length"> <div v-else-if="citations.length">
<BButton v-b-toggle="id" variant="primary">References</BButton> <BButton v-b-toggle="id" variant="primary">{{ localize("References") }}</BButton>
<BCollapse <BCollapse
:id="id.replace(/ /g, '_')" :id="id.replace(/ /g, '_')"
......
...@@ -67,7 +67,7 @@ watch( ...@@ -67,7 +67,7 @@ watch(
<i v-if="!selected" class="mr-2"> <i v-if="!selected" class="mr-2">
<FontAwesomeIcon :icon="faCheck" class="text-success" /> Added to collection <FontAwesomeIcon :icon="faCheck" class="text-success" /> Added to collection
</i> </i>
<i v-else class="text-secondary">Selected</i> <i v-else class="text-secondary">{{ localize("Selected") }}</i>
<button class="btn-sm" :title="localize('Remove this dataset from the list')" @click="clickDiscard"> <button class="btn-sm" :title="localize('Remove this dataset from the list')" @click="clickDiscard">
<FontAwesomeIcon :icon="faMinus" fixed-width /> <FontAwesomeIcon :icon="faMinus" fixed-width />
{{ localize("Remove") }} {{ localize("Remove") }}
......
...@@ -31,7 +31,7 @@ function toggleAdvanced() { ...@@ -31,7 +31,7 @@ function toggleAdvanced() {
:border-variant="borderVariant(value === 'list')" :border-variant="borderVariant(value === 'list')"
@click="emit('onChange', 'list')"> @click="emit('onChange', 'list')">
<BCardTitle> <BCardTitle>
<b>Flat List</b> <b>{{ localize("Flat List") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
This option creates a simple flat list of files. If your data isn't nested and does not contained This option creates a simple flat list of files. If your data isn't nested and does not contained
...@@ -44,7 +44,7 @@ function toggleAdvanced() { ...@@ -44,7 +44,7 @@ function toggleAdvanced() {
:border-variant="borderVariant(value === 'list:paired')" :border-variant="borderVariant(value === 'list:paired')"
@click="emit('onChange', 'list:paired')"> @click="emit('onChange', 'list:paired')">
<BCardTitle> <BCardTitle>
<b>List of Paired Datasets</b> <b>{{ localize("List of Paired Datasets") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
This option creates a uniform list of paired datasets, use this option if all of your data should be This option creates a uniform list of paired datasets, use this option if all of your data should be
...@@ -57,7 +57,7 @@ function toggleAdvanced() { ...@@ -57,7 +57,7 @@ function toggleAdvanced() {
:border-variant="borderVariant(value === 'rules')" :border-variant="borderVariant(value === 'rules')"
@click="emit('onChange', 'rules')"> @click="emit('onChange', 'rules')">
<BCardTitle> <BCardTitle>
<b>Rule Builder</b> <b>规则构建器</b>
</BCardTitle> </BCardTitle>
<div> <div>
The rule builder allows building arbitrarily nested collections of data with reproducible metadata The rule builder allows building arbitrarily nested collections of data with reproducible metadata
...@@ -67,7 +67,7 @@ function toggleAdvanced() { ...@@ -67,7 +67,7 @@ function toggleAdvanced() {
</BCardGroup> </BCardGroup>
<span> <span>
<div v-if="!advanced" class="m-3"> <div v-if="!advanced" class="m-3">
<BButton variant="primary" @click="toggleAdvanced">Advanced Options</BButton> <BButton variant="primary" @click="toggleAdvanced">高级选项</BButton>
</div> </div>
<BCardGroup v-else deck class="mt-3"> <BCardGroup v-else deck class="mt-3">
<BCard <BCard
...@@ -76,7 +76,7 @@ function toggleAdvanced() { ...@@ -76,7 +76,7 @@ function toggleAdvanced() {
:border-variant="borderVariant(value === 'list:paired_or_unpaired')" :border-variant="borderVariant(value === 'list:paired_or_unpaired')"
@click="emit('onChange', 'list:paired_or_unpaired')"> @click="emit('onChange', 'list:paired_or_unpaired')">
<BCardTitle> <BCardTitle>
<b>Mixed List of Paired and Unpaired Datasets</b> <b>{{ localize("Mixed List of Paired and Unpaired Datasets") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
For studies that have a mix of paired and unpaired data, this may be the right choice. Existing For studies that have a mix of paired and unpaired data, this may be the right choice. Existing
...@@ -89,7 +89,7 @@ function toggleAdvanced() { ...@@ -89,7 +89,7 @@ function toggleAdvanced() {
:border-variant="borderVariant(value === 'list:list')" :border-variant="borderVariant(value === 'list:list')"
@click="emit('onChange', 'list:list')"> @click="emit('onChange', 'list:list')">
<BCardTitle> <BCardTitle>
<b>Nested List of Datasets</b> <b>{{ localize("Nested List of Datasets") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
A nested list of datasets. This type of collection is a list where each element is in turn a A nested list of datasets. This type of collection is a list where each element is in turn a
...@@ -103,7 +103,7 @@ function toggleAdvanced() { ...@@ -103,7 +103,7 @@ function toggleAdvanced() {
:border-variant="borderVariant(value === 'list:list:paired')" :border-variant="borderVariant(value === 'list:list:paired')"
@click="emit('onChange', 'list:list:paired')"> @click="emit('onChange', 'list:list:paired')">
<BCardTitle> <BCardTitle>
<b>Nested List of Dataset Pairs</b> <b>{{ localize("Nested List of Dataset Pairs") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
A nested list of datasets. This type of collection is a list where each element is in turn a A nested list of datasets. This type of collection is a list where each element is in turn a
......
...@@ -772,7 +772,7 @@ export default { ...@@ -772,7 +772,7 @@ export default {
style="font-weight: bold" style="font-weight: bold"
data-description="dismiss unmatched datasets" data-description="dismiss unmatched datasets"
@click="dismissUnmatchedDatasets" @click="dismissUnmatchedDatasets"
>Click here to discard all remaining unpaired datasets.</BLink >点击此处丢弃所有剩余未配对的数据集。</BLink
> >
</BAlert> </BAlert>
</BCol> </BCol>
......
...@@ -91,7 +91,7 @@ function onApply() { ...@@ -91,7 +91,7 @@ function onApply() {
<div class="summary-text mt-2"> <div class="summary-text mt-2">
{{ summaryText }} {{ summaryText }}
</div> </div>
<div class="summary-list-header mt-2">Auto-matched Pairs</div> <div class="summary-list-header mt-2">自动匹配的对</div>
<div class="summary-list-description"> <div class="summary-list-description">
These pairs of datasets have been auto-matched up using the filters above. The will be included as These pairs of datasets have been auto-matched up using the filters above. The will be included as
dataset pairs in the final list without additional action. dataset pairs in the final list without additional action.
...@@ -99,16 +99,16 @@ function onApply() { ...@@ -99,16 +99,16 @@ function onApply() {
<ol class="summary-list"> <ol class="summary-list">
<li v-for="(pair, index) of currentSummary?.pairs" :key="`paired_${index}`"> <li v-for="(pair, index) of currentSummary?.pairs" :key="`paired_${index}`">
<span v-if="index > 0">,</span> <span v-if="index > 0">,</span>
<span class="pair-name">{{ pair.name }}</span> (<span class="direction">FORWARD</span <span class="pair-name">{{ pair.name }}</span> (<span class="direction">{{ localize("FORWARD") }}</span
><span v-if="showHid" class="dataset-hid">{{ getHid(pair.forward) }}: </span ><span v-if="showHid" class="dataset-hid">{{ getHid(pair.forward) }}: </span
><span class="dataset-name">{{ pair.forward.name }}</span> | <span class="direction">REVERSE</span ><span class="dataset-name">{{ pair.forward.name }}</span> | <span class="direction">{{ localize("REVERSE") }}</span
><span v-if="showHid" class="dataset-hid">{{ getHid(pair.reverse) }}: </span ><span v-if="showHid" class="dataset-hid">{{ getHid(pair.reverse) }}: </span
><span class="dataset-name">{{ pair.reverse.name }}</span ><span class="dataset-name">{{ pair.reverse.name }}</span
>) >)
</li> </li>
</ol> </ol>
<span v-if="hasUnmatchedDatasets"> <span v-if="hasUnmatchedDatasets">
<div class="summary-list-header mt-2">Un-matched Datasets</div> <div class="summary-list-header mt-2">未配对的数据集</div>
<div class="summary-list-description"> <div class="summary-list-description">
These datasets were not paired automatically. This builder will allow you to match any of pairs of These datasets were not paired automatically. This builder will allow you to match any of pairs of
these manually {{ whereIsTheBuilder }}. these manually {{ whereIsTheBuilder }}.
...@@ -139,7 +139,7 @@ function onApply() { ...@@ -139,7 +139,7 @@ function onApply() {
</ol> </ol>
</span> </span>
<span v-else> <span v-else>
<div class="summary-list-header mt-2">No Un-matched Datasets</div> <div class="summary-list-header mt-2">没有未配对的数据集</div>
<div class="summary-list-description"> <div class="summary-list-description">
All datasets successfully auto-paired, this is generally a good sign Galaxy was able to correctly All datasets successfully auto-paired, this is generally a good sign Galaxy was able to correctly
pair off all supplied datasets using their names. pair off all supplied datasets using their names.
......
...@@ -37,7 +37,7 @@ function clickedSave() { ...@@ -37,7 +37,7 @@ function clickedSave() {
<template> <template>
<div> <div>
<div> <div>
<span class="float-left h-sm">Change Datatype/Extension of all elements in collection</span> <span class="float-left h-sm">更改集合中所有元素的数据类型/扩展名</span>
<div class="text-right"> <div class="text-right">
<button class="save-datatype-edit btn btn-primary" :disabled="!enableSave" @click="clickedSave"> <button class="save-datatype-edit btn btn-primary" :disabled="!enableSave" @click="clickedSave">
......
...@@ -29,7 +29,7 @@ onMounted(() => { ...@@ -29,7 +29,7 @@ onMounted(() => {
<template> <template>
<div> <div>
<div> <div>
<span class="float-left h-sm">Change Database/Build of all elements in collection</span> <span class="float-left h-sm">更改集合中所有元素的数据库/构建</span>
<div class="text-right"> <div class="text-right">
<button <button
......
...@@ -101,12 +101,12 @@ export default defineComponent({ ...@@ -101,12 +101,12 @@ export default defineComponent({
<FontAwesomeIcon size="2x" :icon="faUnlink" class="paired-action-icon" @click="onUnpair" /> <FontAwesomeIcon size="2x" :icon="faUnlink" class="paired-action-icon" @click="onUnpair" />
<div class="text-container"> <div class="text-container">
<span> <span>
<span class="direction">FORWARD</span> <span class="direction">{{ localize("FORWARD") }}</span>
<span v-if="showHid" class="dataset-hid">{{ params.value.forward.hid }}: </span> <span v-if="showHid" class="dataset-hid">{{ params.value.forward.hid }}: </span>
<span class="dataset-name">{{ params.value.forward.name }}</span> <span class="dataset-name">{{ params.value.forward.name }}</span>
</span> </span>
<span> <span>
<span class="direction">REVERSE</span> <span class="direction">{{ localize("REVERSE") }}</span>
<span v-if="showHid" class="dataset-hid">{{ params.value.reverse.hid }}: </span> <span v-if="showHid" class="dataset-hid">{{ params.value.reverse.hid }}: </span>
<span class="dataset-name">{{ params.value.reverse.name }}</span> <span class="dataset-name">{{ params.value.reverse.name }}</span>
</span> </span>
...@@ -131,7 +131,7 @@ export default defineComponent({ ...@@ -131,7 +131,7 @@ export default defineComponent({
:class="{ dragging: dragging, 'active-target': isUnpairedTarget, 'fa-beat': isUnpairedTarget }" /> :class="{ dragging: dragging, 'active-target': isUnpairedTarget, 'fa-beat': isUnpairedTarget }" />
</div> </div>
<div class="text-container"> <div class="text-container">
<div><span class="direction">UNPAIRED</span></div> <div><span class="direction">未配对</span></div>
<div> <div>
<span v-if="showHid" class="dataset-hid">{{ params.value.unpaired.hid }}: </span> <span v-if="showHid" class="dataset-hid">{{ params.value.unpaired.hid }}: </span>
<span class="dataset-name">{{ params.value.unpaired.name }}</span> <span class="dataset-name">{{ params.value.unpaired.name }}</span>
......
...@@ -54,7 +54,7 @@ watch(currentReverseFilter, resync); ...@@ -54,7 +54,7 @@ watch(currentReverseFilter, resync);
{{ forward }} / {{ reverse }} {{ forward }} / {{ reverse }}
</BDropdownItem> </BDropdownItem>
<BDropdownItem @click="update('', '')"> <BDropdownItem @click="update('', '')">
<i>Clear All Filtering</i> <i>清除所有筛选</i>
</BDropdownItem> </BDropdownItem>
</BDropdown> </BDropdown>
</template> </template>
......
<template> <template>
<div> <div>
<div> <div>
<span class="float-left h-sm">Convert all datasets to new format</span> <span class="float-left h-sm">将所有数据集转换为新格式</span>
<div class="text-right"> <div class="text-right">
<button <button
class="run-tool-collection-edit btn btn-primary" class="run-tool-collection-edit btn btn-primary"
......
...@@ -597,7 +597,7 @@ defineExpose({ attemptCreate }); ...@@ -597,7 +597,7 @@ defineExpose({ attemptCreate });
@gridReady="onGridReady" /> @gridReady="onGridReady" />
<BRow align-h="center" style="margin-top: 10px"> <BRow align-h="center" style="margin-top: 10px">
<BCol v-if="showExtension" cols="4"> <BCol v-if="showExtension" cols="4">
<span class="upload-footer-title">Type</span> <span class="upload-footer-title">{{ localize("Type") }}</span>
<UploadSelectExtension <UploadSelectExtension
class="upload-footer-extension" class="upload-footer-extension"
:value="extension" :value="extension"
...@@ -607,7 +607,7 @@ defineExpose({ attemptCreate }); ...@@ -607,7 +607,7 @@ defineExpose({ attemptCreate });
</UploadSelectExtension> </UploadSelectExtension>
</BCol> </BCol>
<BCol v-if="showDbKey" cols="4"> <BCol v-if="showDbKey" cols="4">
<span class="upload-footer-title">Reference</span> <span class="upload-footer-title">{{ localize("Reference") }}</span>
<UploadSelect <UploadSelect
class="upload-footer-genome" class="upload-footer-genome"
:value="dbKey" :value="dbKey"
......
...@@ -19,7 +19,7 @@ const emit = defineEmits(["download"]); ...@@ -19,7 +19,7 @@ const emit = defineEmits(["download"]);
<template> <template>
<BCard> <BCard>
<BCardTitle> <BCardTitle>
<b>Step 1: Download</b> <b>步骤 1:下载</b>
</BCardTitle> </BCardTitle>
<BLink :href="generateWorkbookLink" @click="emit('download')" <BLink :href="generateWorkbookLink" @click="emit('download')"
><FontAwesomeIcon size="xl" :icon="faDownload" /> Download workbook.</BLink ><FontAwesomeIcon size="xl" :icon="faDownload" /> Download workbook.</BLink
......
...@@ -7,7 +7,7 @@ import { BCard, BCardTitle } from "bootstrap-vue"; ...@@ -7,7 +7,7 @@ import { BCard, BCardTitle } from "bootstrap-vue";
<template> <template>
<BCard> <BCard>
<BCardTitle> <BCardTitle>
<b>Step 2: Fill Out</b> <b>步骤 2:填写</b>
</BCardTitle> </BCardTitle>
<FontAwesomeIcon size="xl" :icon="faEdit" />Fill out the workbook with your favorite spreadsheet application and <FontAwesomeIcon size="xl" :icon="faEdit" />Fill out the workbook with your favorite spreadsheet application and
save it to your local disk. save it to your local disk.
......
...@@ -30,7 +30,7 @@ const emit = defineEmits(["workbookContents"]); ...@@ -30,7 +30,7 @@ const emit = defineEmits(["workbookContents"]);
@dragover.prevent="isDragging = true" @dragover.prevent="isDragging = true"
@dragleave.prevent="isDragging = false"> @dragleave.prevent="isDragging = false">
<BCardTitle> <BCardTitle>
<b>Step 3: Upload</b> <b>步骤 3:上传</b>
</BCardTitle> </BCardTitle>
<div v-if="uploadErrorMessage"> <div v-if="uploadErrorMessage">
<BAlert variant="danger" show> <BAlert variant="danger" show>
......
...@@ -22,7 +22,7 @@ defineProps<Props>(); ...@@ -22,7 +22,7 @@ defineProps<Props>();
:border-variant="borderVariant(creatingWhat === 'datasets')" :border-variant="borderVariant(creatingWhat === 'datasets')"
@click="emit('onChange', 'datasets')"> @click="emit('onChange', 'datasets')">
<BCardTitle> <BCardTitle>
<b>Datasets</b> <b>数据集</b>
</BCardTitle> </BCardTitle>
<div> <div>
This option lets you import any number of individual Galaxy datasets. These will be unique items in your This option lets you import any number of individual Galaxy datasets. These will be unique items in your
...@@ -35,7 +35,7 @@ defineProps<Props>(); ...@@ -35,7 +35,7 @@ defineProps<Props>();
:border-variant="borderVariant(creatingWhat === 'collections')" :border-variant="borderVariant(creatingWhat === 'collections')"
@click="emit('onChange', 'collections')"> @click="emit('onChange', 'collections')">
<BCardTitle> <BCardTitle>
<b>Collections</b> <b>集合</b>
</BCardTitle> </BCardTitle>
<div>This option lets you create or more Galaxy dataset collections.</div> <div>This option lets you create or more Galaxy dataset collections.</div>
</BCard> </BCard>
......
...@@ -68,7 +68,7 @@ onMounted(() => { ...@@ -68,7 +68,7 @@ onMounted(() => {
border-variant="primary" border-variant="primary"
@click="inputDialog"> @click="inputDialog">
<BCardTitle> <BCardTitle>
<b>Select collection</b> <b>选择集合</b>
</BCardTitle> </BCardTitle>
<div> <div>
<BAlert v-if="errorMessage" show variant="danger">{{ errorMessage }}</BAlert> <BAlert v-if="errorMessage" show variant="danger">{{ errorMessage }}</BAlert>
......
...@@ -54,7 +54,7 @@ watch(table, (newValue: string[][]) => { ...@@ -54,7 +54,7 @@ watch(table, (newValue: string[][]) => {
<template> <template>
<BCard class="wizard-selection-card" border-variant="primary" @click="inputDialog"> <BCard class="wizard-selection-card" border-variant="primary" @click="inputDialog">
<BCardTitle> <BCardTitle>
<b>Select dataset</b> <b>选择数据集</b>
</BCardTitle> </BCardTitle>
<div> <div>
<BAlert v-if="errorMessage" show variant="danger">{{ errorMessage }}</BAlert> <BAlert v-if="errorMessage" show variant="danger">{{ errorMessage }}</BAlert>
......
...@@ -19,7 +19,7 @@ const emit = defineEmits(["select"]); ...@@ -19,7 +19,7 @@ const emit = defineEmits(["select"]);
:border-variant="borderVariant(selected)" :border-variant="borderVariant(selected)"
@click="emit('select', 'collection')"> @click="emit('select', 'collection')">
<BCardTitle> <BCardTitle>
<b>An Existing Collection</b> <b>{{ localize("An Existing Collection") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
<!-- TODO: replace collection with an english expression --> <!-- TODO: replace collection with an english expression -->
......
...@@ -19,7 +19,7 @@ const emit = defineEmits(["select"]); ...@@ -19,7 +19,7 @@ const emit = defineEmits(["select"]);
:border-variant="borderVariant(selected)" :border-variant="borderVariant(selected)"
@click="emit('select', 'collection')"> @click="emit('select', 'collection')">
<BCardTitle> <BCardTitle>
<b>An Existing Collection</b> <b>{{ localize("An Existing Collection") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
The "Apply Rules" tool allows you to transform an existing collection using the same set of rules as can be The "Apply Rules" tool allows you to transform an existing collection using the same set of rules as can be
......
...@@ -22,12 +22,12 @@ const emit = defineEmits(["select"]); ...@@ -22,12 +22,12 @@ const emit = defineEmits(["select"]);
:border-variant="borderVariant(selected)" :border-variant="borderVariant(selected)"
@click="emit('select', 'dataset_as_table')"> @click="emit('select', 'dataset_as_table')">
<BCardTitle> <BCardTitle>
<b>Dataset As Table</b> <b>表格数据集</b>
</BCardTitle> </BCardTitle>
<div v-if="forWhat === 'rule_builder'"> <div v-if="forWhat === 'rule_builder'">
This option lets you load a list of URIs or any sort of tabular data that can be transformed into a list of This option lets you load a list of URIs or any sort of tabular data that can be transformed into a list of
URIs to describe the datasets and metadata to import from an existing Galaxy dataset. URIs to describe the datasets and metadata to import from an existing Galaxy dataset.
</div> </div>
<div v-else>Load a list of URIs from an existing Galaxy tabular dataset.</div> <div v-else>从现有的 Galaxy 表格数据集加载 URI 列表。</div>
</BCard> </BCard>
</template> </template>
...@@ -22,12 +22,12 @@ const emit = defineEmits(["select"]); ...@@ -22,12 +22,12 @@ const emit = defineEmits(["select"]);
:border-variant="borderVariant(selected)" :border-variant="borderVariant(selected)"
@click="emit('select', 'pasted_table')"> @click="emit('select', 'pasted_table')">
<BCardTitle> <BCardTitle>
<b>Pasted Table</b> <b>粘贴的表格</b>
</BCardTitle> </BCardTitle>
<div v-if="forWhat === 'rule_builder'"> <div v-if="forWhat === 'rule_builder'">
This option lets you just paste in a list of URLs/URIs or any sort of tabular data that can be transformed This option lets you just paste in a list of URLs/URIs or any sort of tabular data that can be transformed
into a list of URIs to describe the datasets and metadata to import. into a list of URIs to describe the datasets and metadata to import.
</div> </div>
<div v-else>Paste in or upload a plain list of URIs/URLs.</div> <div v-else>粘贴或上传 URI/URL 的纯文本列表。</div>
</BCard> </BCard>
</template> </template>
...@@ -22,7 +22,7 @@ const emit = defineEmits(["select"]); ...@@ -22,7 +22,7 @@ const emit = defineEmits(["select"]);
:border-variant="borderVariant(selected)" :border-variant="borderVariant(selected)"
@click="emit('select', 'remote_files')"> @click="emit('select', 'remote_files')">
<BCardTitle> <BCardTitle>
<b>Remote Files</b> <b>远程文件</b>
</BCardTitle> </BCardTitle>
<div v-if="forWhat === 'rule_builder'"> <div v-if="forWhat === 'rule_builder'">
This option lets you select a folder of file URIs from Galaxy's configured "remote file" repositories. This option lets you select a folder of file URIs from Galaxy's configured "remote file" repositories.
......
...@@ -22,7 +22,7 @@ const emit = defineEmits(["select"]); ...@@ -22,7 +22,7 @@ const emit = defineEmits(["select"]);
:border-variant="borderVariant(selected)" :border-variant="borderVariant(selected)"
@click="emit('select', 'workbook')"> @click="emit('select', 'workbook')">
<BCardTitle> <BCardTitle>
<b>External Workbook</b> <b>外部工作簿</b>
</BCardTitle> </BCardTitle>
<div> <div>
Fill in URLs/URIs as well as sample sheet in an external workbook using tools like Excel or Google Sheets. Fill in URLs/URIs as well as sample sheet in an external workbook using tools like Excel or Google Sheets.
......
...@@ -23,7 +23,7 @@ defineProps<Props>(); ...@@ -23,7 +23,7 @@ defineProps<Props>();
:border-variant="borderVariant(value === 'list')" :border-variant="borderVariant(value === 'list')"
@click="emit('onChange', 'list')"> @click="emit('onChange', 'list')">
<BCardTitle> <BCardTitle>
<b>Flat List</b> <b>{{ localize("Flat List") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
This option creates a simple flat list of files. If your data isn't nested and does not contained This option creates a simple flat list of files. If your data isn't nested and does not contained
...@@ -36,7 +36,7 @@ defineProps<Props>(); ...@@ -36,7 +36,7 @@ defineProps<Props>();
:border-variant="borderVariant(value === 'list:paired')" :border-variant="borderVariant(value === 'list:paired')"
@click="emit('onChange', 'list:paired')"> @click="emit('onChange', 'list:paired')">
<BCardTitle> <BCardTitle>
<b>List of Paired Datasets</b> <b>{{ localize("List of Paired Datasets") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
This option creates a uniform list of paired datasets, use this option if all of your data should be This option creates a uniform list of paired datasets, use this option if all of your data should be
...@@ -52,7 +52,7 @@ defineProps<Props>(); ...@@ -52,7 +52,7 @@ defineProps<Props>();
:border-variant="borderVariant(value === 'list:paired_or_unpaired')" :border-variant="borderVariant(value === 'list:paired_or_unpaired')"
@click="emit('onChange', 'list:paired_or_unpaired')"> @click="emit('onChange', 'list:paired_or_unpaired')">
<BCardTitle> <BCardTitle>
<b>Mixed List of Paired and Unpaired Datasets</b> <b>{{ localize("Mixed List of Paired and Unpaired Datasets") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
For studies that have a mix of paired and unpaired data, this may be the right choice. Existing For studies that have a mix of paired and unpaired data, this may be the right choice. Existing
...@@ -65,7 +65,7 @@ defineProps<Props>(); ...@@ -65,7 +65,7 @@ defineProps<Props>();
:border-variant="borderVariant(value === 'list:list')" :border-variant="borderVariant(value === 'list:list')"
@click="emit('onChange', 'list:list')"> @click="emit('onChange', 'list:list')">
<BCardTitle> <BCardTitle>
<b>Nested List of Datasets</b> <b>{{ localize("Nested List of Datasets") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
A nested list of datasets. This type of collection is a list where each element is in turn a A nested list of datasets. This type of collection is a list where each element is in turn a
...@@ -79,7 +79,7 @@ defineProps<Props>(); ...@@ -79,7 +79,7 @@ defineProps<Props>();
:border-variant="borderVariant(value === 'list:list:paired')" :border-variant="borderVariant(value === 'list:list:paired')"
@click="emit('onChange', 'list:list:paired')"> @click="emit('onChange', 'list:list:paired')">
<BCardTitle> <BCardTitle>
<b>Nested List of Dataset Pairs</b> <b>{{ localize("Nested List of Dataset Pairs") }}</b>
</BCardTitle> </BCardTitle>
<div> <div>
A nested list of datasets. This type of collection is a list where each element is in turn a A nested list of datasets. This type of collection is a list where each element is in turn a
......
...@@ -57,7 +57,7 @@ async function submitEmail() { ...@@ -57,7 +57,7 @@ async function submitEmail() {
<template> <template>
<div> <div>
<h4 class="mb-3 h-md">Issue Report</h4> <h4 class="mb-3 h-md">问题报告</h4>
<BAlert v-if="props.requireLogin && !userEmail" variant="info" show> <BAlert v-if="props.requireLogin && !userEmail" variant="info" show>
<span v-localize> You must be logged in to submit a report. </span> <span v-localize> You must be logged in to submit a report. </span>
<GLink to="/login/start"> Please log in to continue. </GLink> <GLink to="/login/start"> Please log in to continue. </GLink>
......
...@@ -45,7 +45,7 @@ function isSelected(plugin: ExportPlugin): boolean { ...@@ -45,7 +45,7 @@ function isSelected(plugin: ExportPlugin): boolean {
<BCardImg :src="plugin.img" :alt="plugin.title" class="export-format-img" /> <BCardImg :src="plugin.img" :alt="plugin.title" class="export-format-img" />
<br /> <br />
<ExternalLink v-if="plugin.url" :href="plugin.url"> <ExternalLink v-if="plugin.url" :href="plugin.url">
<b>Learn more</b> <b>了解更多</b>
</ExternalLink> </ExternalLink>
</div> </div>
<div v-else v-html="renderMarkdown(plugin.markdownDescription)" /> <div v-else v-html="renderMarkdown(plugin.markdownDescription)" />
......
...@@ -61,7 +61,7 @@ function copyDownloadLink(record: ExportRecord) { ...@@ -61,7 +61,7 @@ function copyDownloadLink(record: ExportRecord) {
</template> </template>
<template v-slot:cell(expires)="row"> <template v-slot:cell(expires)="row">
<span v-if="row.item.hasExpired">Expired</span> <span v-if="row.item.hasExpired">已过期</span>
<span v-else-if="row.item.expirationDate" :title="row.item.expirationDate.toLocaleString()"> <span v-else-if="row.item.expirationDate" :title="row.item.expirationDate.toLocaleString()">
{{ row.item.expirationElapsedTime }} {{ row.item.expirationElapsedTime }}
......
...@@ -334,7 +334,7 @@ function updateFilterText(newFilterText: string) { ...@@ -334,7 +334,7 @@ function updateFilterText(newFilterText: string) {
@click="onSearch"> @click="onSearch">
<FontAwesomeIcon :icon="faSearch" /> <FontAwesomeIcon :icon="faSearch" />
<span v-localize>Search</span> <span v-localize>搜索</span>
</GButton> </GButton>
<GButton v-if="props.hasHelp" title="Search Help" size="small" @click="showHelp = true"> <GButton v-if="props.hasHelp" title="Search Help" size="small" @click="showHelp = true">
......
...@@ -48,7 +48,7 @@ function onChange(value: FilterType) { ...@@ -48,7 +48,7 @@ function onChange(value: FilterType) {
<template> <template>
<div v-if="hasSelectableObjectStores"> <div v-if="hasSelectableObjectStores">
<small>Filter by storage source:</small> <small>按存储源筛选:</small>
<FilterObjectStoreLink :object-stores="selectableObjectStores || []" :value="localValue" @change="onChange" /> <FilterObjectStoreLink :object-stores="selectableObjectStores || []" :value="localValue" @change="onChange" />
</div> </div>
</template> </template>
...@@ -723,7 +723,7 @@ defineExpose({ ...@@ -723,7 +723,7 @@ defineExpose({
</th> </th>
<th v-if="props.actions" class="g-table-actions-column"> <th v-if="props.actions" class="g-table-actions-column">
<slot name="head-actions">Actions</slot> <slot name="head-actions">操作</slot>
</th> </th>
</tr> </tr>
</thead> </thead>
......
...@@ -123,8 +123,8 @@ function resetForm() { ...@@ -123,8 +123,8 @@ function resetForm() {
<div class="spacer"></div> <div class="spacer"></div>
<div v-if="currentItemError" class="error">{{ currentItemError }}</div> <div v-if="currentItemError" class="error">{{ currentItemError }}</div>
<div v-if="props.description" v-html="description"></div> <div v-if="props.description" v-html="description"></div>
<b-button variant="primary" @click="onSave">Save</b-button> <b-button variant="primary" @click="onSave">{{ localize("Save") }}</b-button>
<b-button variant="danger" @click="onReset">Cancel</b-button> <b-button variant="danger" @click="onReset">{{ localize("Cancel") }}</b-button>
</div> </div>
<div v-else> <div v-else>
<div v-if="itemsCurrent.length > 0"> <div v-if="itemsCurrent.length > 0">
......
...@@ -19,7 +19,7 @@ const toWhat = "Datasets will be filtered to those stored in"; ...@@ -19,7 +19,7 @@ const toWhat = "Datasets will be filtered to those stored in";
<template> <template>
<div> <div>
<p>Select a storage source to filter by</p> <p>选择存储源进行筛选</p>
<b-button-group vertical size="lg" class="select-button-group"> <b-button-group vertical size="lg" class="select-button-group">
<ObjectStoreSelectButton <ObjectStoreSelectButton
v-for="objectStore in objectStores" v-for="objectStore in objectStores"
......
...@@ -132,7 +132,7 @@ function dismissAlert() { ...@@ -132,7 +132,7 @@ function dismissAlert() {
<span>{{ completedMessage }}</span> <span>{{ completedMessage }}</span>
<BLink v-if="downloadUrl" class="download-link" :href="downloadUrl"> <BLink v-if="downloadUrl" class="download-link" :href="downloadUrl">
<b>Download here</b> <b>在此下载</b>
</BLink> </BLink>
<span v-if="remoteUri"> <span v-if="remoteUri">
......
...@@ -62,13 +62,13 @@ const urlAll = computed(() => `/${pluralPath.value}/list_published`); ...@@ -62,13 +62,13 @@ const urlAll = computed(() => `/${pluralPath.value}/list_published`);
<br /> <br />
<h2 class="h-sm">Author</h2> <h2 class="h-sm">{{ localize("Author") }}</h2>
<div>{{ owner }}</div> <div>{{ owner }}</div>
<hr /> <hr />
<h2 class="h-sm">Related Pages</h2> <h2 class="h-sm">相关页面</h2>
<div> <div>
<router-link :to="urlAll">All published {{ plural }}</router-link> <router-link :to="urlAll">All published {{ plural }}</router-link>
......
...@@ -56,8 +56,8 @@ const textTooLong = computed(() => { ...@@ -56,8 +56,8 @@ const textTooLong = computed(() => {
@keyup.enter="showDetails = !showDetails" @keyup.enter="showDetails = !showDetails"
@click.prevent.stop="showDetails = !showDetails"> @click.prevent.stop="showDetails = !showDetails">
<template v-if="showExpandText"> <template v-if="showExpandText">
<template v-if="showDetails">Show less</template> <template v-if="showDetails">{{ localize("Show less") }}</template>
<template v-else>Show more</template> <template v-else>{{ localize("Show more") }}</template>
</template> </template>
<FontAwesomeIcon :icon="showDetails ? faChevronUp : faChevronDown" /> <FontAwesomeIcon :icon="showDetails ? faChevronUp : faChevronDown" />
......
...@@ -23,7 +23,7 @@ defineProps<Props>(); ...@@ -23,7 +23,7 @@ defineProps<Props>();
<span :data-description="errorDataDescription"> <span :data-description="errorDataDescription">
{{ error }} {{ error }}
</span> </span>
<BButton variant="link" @click="showTestResults = true">View configuration test status.</BButton> <BButton variant="link" @click="showTestResults = true">查看配置测试状态。</BButton>
</BAlert> </BAlert>
</div> </div>
</template> </template>
...@@ -41,7 +41,7 @@ const emit = defineEmits<{ ...@@ -41,7 +41,7 @@ const emit = defineEmits<{
@keypress="router.push(routeUpgrade)" @keypress="router.push(routeUpgrade)"
@click.prevent="router.push(routeUpgrade)"> @click.prevent="router.push(routeUpgrade)">
<FontAwesomeIcon :icon="faArrowUp" /> <FontAwesomeIcon :icon="faArrowUp" />
<span v-localize>Upgrade</span> <span v-localize>升级</span>
</button> </button>
<button <button
class="dropdown-item" class="dropdown-item"
...@@ -49,15 +49,15 @@ const emit = defineEmits<{ ...@@ -49,15 +49,15 @@ const emit = defineEmits<{
@keypress="router.push(routeEdit)" @keypress="router.push(routeEdit)"
@click.prevent="router.push(routeEdit)"> @click.prevent="router.push(routeEdit)">
<FontAwesomeIcon :icon="faEdit" /> <FontAwesomeIcon :icon="faEdit" />
<span v-localize>Edit configuration</span> <span v-localize>编辑配置</span>
</button> </button>
<button class="dropdown-item" @keypress="emit('test')" @click.prevent="emit('test')"> <button class="dropdown-item" @keypress="emit('test')" @click.prevent="emit('test')">
<FontAwesomeIcon :icon="faStethoscope" /> <FontAwesomeIcon :icon="faStethoscope" />
<span v-localize>Test instance</span> <span v-localize>测试实例</span>
</button> </button>
<button class="dropdown-item" @keypress="emit('remove')" @click.prevent="emit('remove')"> <button class="dropdown-item" @keypress="emit('remove')" @click.prevent="emit('remove')">
<FontAwesomeIcon :icon="faTrash" /> <FontAwesomeIcon :icon="faTrash" />
<span v-localize>Remove instance</span> <span v-localize>移除实例</span>
</button> </button>
</div> </div>
</div> </div>
......
...@@ -179,7 +179,7 @@ defineExpose({ ...@@ -179,7 +179,7 @@ defineExpose({
</span> </span>
</span> </span>
</BAlert> </BAlert>
<Heading h1 separator size="lg">Copy Datasets and Collections</Heading> <Heading h1 separator size="lg">复制数据集和集合</Heading>
</div> </div>
<div class="dataset-copy-columns d-flex flex-grow-1"> <div class="dataset-copy-columns d-flex flex-grow-1">
...@@ -187,9 +187,9 @@ defineExpose({ ...@@ -187,9 +187,9 @@ defineExpose({
<div class="d-flex flex-column flex-grow-1 w-50 pr-1"> <div class="d-flex flex-column flex-grow-1 w-50 pr-1">
<Heading h2 size="sm"> <Heading h2 size="sm">
<FontAwesomeIcon :icon="faCopy" /> <FontAwesomeIcon :icon="faCopy" />
<span>From History</span> <span>来自历史</span>
</Heading> </Heading>
<span class="text-sm mt-1">Select a Source History:</span> <span class="text-sm mt-1">选择源历史:</span>
<Multiselect <Multiselect
v-model="sourceHistory" v-model="sourceHistory"
:options="histories" :options="histories"
...@@ -198,10 +198,10 @@ defineExpose({ ...@@ -198,10 +198,10 @@ defineExpose({
deselect-label="" deselect-label=""
select-label="" select-label=""
@input="loadContents" /> @input="loadContents" />
<span class="text-sm mt-1">Select Datasets and Collections:</span> <span class="text-sm mt-1">选择数据集和集合:</span>
<div class="dataset-copy-contents flex-grow-1 overflow-auto border rounded p-2"> <div class="dataset-copy-contents flex-grow-1 overflow-auto border rounded p-2">
<LoadingSpan v-if="loading" /> <LoadingSpan v-if="loading" />
<div v-else-if="sourceContents.length === 0" class="text-muted">This history has no datasets.</div> <div v-else-if="sourceContents.length === 0" class="text-muted">此历史没有数据集。</div>
<div v-else> <div v-else>
<div v-for="item in sourceContents" :key="item.id" class="d-flex align-items-center mb-1"> <div v-for="item in sourceContents" :key="item.id" class="d-flex align-items-center mb-1">
<BFormCheckbox <BFormCheckbox
...@@ -224,9 +224,9 @@ defineExpose({ ...@@ -224,9 +224,9 @@ defineExpose({
<div class="d-flex flex-column flex-grow-1 w-50 pl-1"> <div class="d-flex flex-column flex-grow-1 w-50 pl-1">
<Heading h2 size="sm"> <Heading h2 size="sm">
<FontAwesomeIcon :icon="faArrowRight" /> <FontAwesomeIcon :icon="faArrowRight" />
<span>To History</span> <span>到历史</span>
</Heading> </Heading>
<span class="text-sm mt-1">Select a Target History:</span> <span class="text-sm mt-1">选择目标历史:</span>
<Multiselect <Multiselect
v-model="targetSingleHistory" v-model="targetSingleHistory"
:allow-empty="true" :allow-empty="true"
...@@ -241,7 +241,7 @@ defineExpose({ ...@@ -241,7 +241,7 @@ defineExpose({
" /> " />
<span class="text-sm mt-1"><b>OR</b> Select Multiple Target Histories:</span> <span class="text-sm mt-1"><b>OR</b> Select Multiple Target Histories:</span>
<div class="dataset-copy-contents flex-grow-1 overflow-auto border rounded p-2"> <div class="dataset-copy-contents flex-grow-1 overflow-auto border rounded p-2">
<div v-if="histories.length === 0" class="text-muted">There are no histories.</div> <div v-if="histories.length === 0" class="text-muted">没有历史。</div>
<div v-for="h in histories" :key="h.id" class="d-flex align-items-center mb-1"> <div v-for="h in histories" :key="h.id" class="d-flex align-items-center mb-1">
<BFormCheckbox <BFormCheckbox
v-model="targetMultiSelections[h.id]" v-model="targetMultiSelections[h.id]"
...@@ -269,7 +269,7 @@ defineExpose({ ...@@ -269,7 +269,7 @@ defineExpose({
data-description="copy button" data-description="copy button"
@click="onCopy"> @click="onCopy">
<FontAwesomeIcon :icon="faCopy" class="mr-1" /> <FontAwesomeIcon :icon="faCopy" class="mr-1" />
<span v-localize>Copy Selected Items</span> <span v-localize>复制所选项目</span>
</BButton> </BButton>
</div> </div>
</div> </div>
......
...@@ -91,7 +91,7 @@ watch( ...@@ -91,7 +91,7 @@ watch(
{{ sanitizedMessage }} {{ sanitizedMessage }}
<span v-if="isAdmin && sanitizedToolId"> <span v-if="isAdmin && sanitizedToolId">
<br /> <br />
<router-link data-description="allowlist link" to="/admin/sanitize_allow">Review Allowlist</router-link> <router-link data-description="allowlist link" to="/admin/sanitize_allow">查看白名单</router-link>
if outputs of {{ sanitizedToolId }} are trusted and should be shown as HTML. if outputs of {{ sanitizedToolId }} are trusted and should be shown as HTML.
</span> </span>
</Alert> </Alert>
...@@ -108,7 +108,7 @@ watch( ...@@ -108,7 +108,7 @@ watch(
<div> <div>
This dataset is large and only the first {{ bytesToString(contentTruncated) }} is shown below. This dataset is large and only the first {{ bytesToString(contentTruncated) }} is shown below.
</div> </div>
<a :href="downloadUrl">Download</a> <a :href="downloadUrl">{{ localize("Download") }}</a>
</div> </div>
<CenterFrame :src="previewUrl" @load="emit('load')" /> <CenterFrame :src="previewUrl" @load="emit('load')" />
</div> </div>
......
...@@ -46,7 +46,7 @@ watch(props, () => { ...@@ -46,7 +46,7 @@ watch(props, () => {
</BFormCheckbox> </BFormCheckbox>
</div> </div>
<a href="javascript:void(0)" @click="selectedAdvancedForm = true">Show advanced options.</a> <a href="javascript:void(0)" @click="selectedAdvancedForm = true">显示高级选项。</a>
</PortletSection> </PortletSection>
</div> </div>
<div v-else> <div v-else>
......
...@@ -26,7 +26,7 @@ const toWhat = "This dataset will be relocated to"; ...@@ -26,7 +26,7 @@ const toWhat = "This dataset will be relocated to";
<template> <template>
<div> <div>
<p>Currently the dataset is located in:</p> <p>当前数据集位于:</p>
<b-button-group vertical size="lg" class="select-button-group"> <b-button-group vertical size="lg" class="select-button-group">
<ObjectStoreSelectButton <ObjectStoreSelectButton
:key="fromObjectStore.object_store_id" :key="fromObjectStore.object_store_id"
...@@ -36,7 +36,7 @@ const toWhat = "This dataset will be relocated to"; ...@@ -36,7 +36,7 @@ const toWhat = "This dataset will be relocated to";
:object-store="fromObjectStore" :object-store="fromObjectStore"
@click="emit('closeModal')" /> @click="emit('closeModal')" />
</b-button-group> </b-button-group>
<p class="relocate-to">Select new Galaxy storage for the dataset:</p> <p class="relocate-to">为数据集选择新的 Galaxy 存储:</p>
<b-button-group vertical size="lg" class="select-button-group"> <b-button-group vertical size="lg" class="select-button-group">
<ObjectStoreSelectButton <ObjectStoreSelectButton
v-for="objectStore in targetObjectStores" v-for="objectStore in targetObjectStores"
......
...@@ -99,6 +99,6 @@ async function relocate(objectStoreId: string) { ...@@ -99,6 +99,6 @@ async function relocate(objectStoreId: string) {
@relocate="relocate" @relocate="relocate"
@closeModal="closeModal" /> @closeModal="closeModal" />
</SelectModal> </SelectModal>
<GButton v-if="relocatable" @click="showModal = true">Relocate Dataset</GButton> <GButton v-if="relocatable" @click="showModal = true">重新定位数据集</GButton>
</span> </span>
</template> </template>
...@@ -109,7 +109,7 @@ watch( ...@@ -109,7 +109,7 @@ watch(
<template> <template>
<div v-if="loadError" class="alert alert-danger m-4"> <div v-if="loadError" class="alert alert-danger m-4">
<h4 class="alert-heading">Dataset Not Available</h4> <h4 class="alert-heading">数据集不可用</h4>
<p> <p>
{{ {{
loadError.message || loadError.message ||
...@@ -215,11 +215,11 @@ watch( ...@@ -215,11 +215,11 @@ watch(
@load="iframeLoading = false" /> @load="iframeLoading = false" />
<div v-else-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4"> <div v-else-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4">
<div class="alert alert-info"> <div class="alert alert-info">
<h4>Download Required</h4> <h4>{{ localize("Download Required") }}</h4>
<p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p> <p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p>
<p>File size: <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p> <p>{{ localize("File size:") }} <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p>
<a :href="downloadUrl" class="btn btn-primary mt-2" download> <a :href="downloadUrl" class="btn btn-primary mt-2" download>
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> Download File <FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> {{ localize("Download File") }}
</a> </a>
</div> </div>
</div> </div>
...@@ -233,11 +233,11 @@ watch( ...@@ -233,11 +233,11 @@ watch(
<div v-else-if="tab === 'raw'" class="tab-content-panel"> <div v-else-if="tab === 'raw'" class="tab-content-panel">
<div v-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4"> <div v-if="isAutoDownloadType && !isPdfDataset" class="auto-download-message p-4">
<div class="alert alert-info"> <div class="alert alert-info">
<h4>Download Required</h4> <h4>{{ localize("Download Required") }}</h4>
<p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p> <p>This file type ({{ dataset.file_ext }}) will download automatically when accessed directly.</p>
<p>File size: <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p> <p>{{ localize("File size:") }} <strong v-html="bytesToString(dataset.file_size || 0, false)" /></p>
<a :href="downloadUrl" class="btn btn-primary mt-2" download> <a :href="downloadUrl" class="btn btn-primary mt-2" download>
<FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> Download File <FontAwesomeIcon :icon="faFileAlt" class="mr-1" /> {{ localize("Download File") }}
</a> </a>
</div> </div>
</div> </div>
......
...@@ -90,7 +90,7 @@ onUnmounted(() => { ...@@ -90,7 +90,7 @@ onUnmounted(() => {
<template> <template>
<div aria-labelledby="dataset-details-heading"> <div aria-labelledby="dataset-details-heading">
<h1 id="dataset-details-heading" class="sr-only">Dataset Details</h1> <h1 id="dataset-details-heading" class="sr-only">数据集详情</h1>
<BAlert v-if="loading" variant="info" show> <BAlert v-if="loading" variant="info" show>
<LoadingSpan message="Loading dataset details..." /> <LoadingSpan message="Loading dataset details..." />
...@@ -138,7 +138,7 @@ onUnmounted(() => { ...@@ -138,7 +138,7 @@ onUnmounted(() => {
<DatasetStorage :dataset-id="datasetId" /> <DatasetStorage :dataset-id="datasetId" />
<div> <div>
<h2 class="h-md">Job Not Found</h2> <h2 class="h-md">未找到作业</h2>
<p> <p>
No job associated with this dataset is recorded in Galaxy. Galaxy cannot determine full dataset No job associated with this dataset is recorded in Galaxy. Galaxy cannot determine full dataset
......
...@@ -127,7 +127,7 @@ onMounted(async () => { ...@@ -127,7 +127,7 @@ onMounted(async () => {
<template> <template>
<div> <div>
<BAlert v-if="errorMessage" variant="danger" show> <BAlert v-if="errorMessage" variant="danger" show>
<h2 class="alert-heading h-sm">Failed to access Dataset details.</h2> <h2 class="alert-heading h-sm">无法访问数据集详情。</h2>
{{ errorMessage }} {{ errorMessage }}
</BAlert> </BAlert>
...@@ -140,7 +140,7 @@ onMounted(async () => { ...@@ -140,7 +140,7 @@ onMounted(async () => {
<div class="response-message"></div> <div class="response-message"></div>
</div> </div>
<h3 class="h-lg">Dataset Error Report</h3> <h3 class="h-lg">数据集错误报告</h3>
<p> <p>
An error occurred while running the tool An error occurred while running the tool
...@@ -148,7 +148,7 @@ onMounted(async () => { ...@@ -148,7 +148,7 @@ onMounted(async () => {
>. >.
</p> </p>
<template v-if="showWizard"> <template v-if="showWizard">
<h4 class="mb-3 h-md">Possible Causes</h4> <h4 class="mb-3 h-md">可能的原因</h4>
<p> <p>
<span> <span>
We can use AI to analyze the issue and suggest possible fixes. Please note that the diagnosis We can use AI to analyze the issue and suggest possible fixes. Please note that the diagnosis
...@@ -172,7 +172,7 @@ onMounted(async () => { ...@@ -172,7 +172,7 @@ onMounted(async () => {
</span> </span>
<div v-if="jobProblems && (jobProblems.has_duplicate_inputs || jobProblems.has_empty_inputs)"> <div v-if="jobProblems && (jobProblems.has_duplicate_inputs || jobProblems.has_empty_inputs)">
<h4 class="common_problems mt-3 h-md">Detected Common Potential Problems</h4> <h4 class="common_problems mt-3 h-md">检测到的常见潜在问题</h4>
<p v-if="jobProblems.has_empty_inputs" id="dataset-error-has-empty-inputs"> <p v-if="jobProblems.has_empty_inputs" id="dataset-error-has-empty-inputs">
The tool was started with one or more empty input datasets. This frequently results in tool errors The tool was started with one or more empty input datasets. This frequently results in tool errors
...@@ -185,7 +185,7 @@ onMounted(async () => { ...@@ -185,7 +185,7 @@ onMounted(async () => {
</p> </p>
</div> </div>
<h4 class="mt-3 h-md">Troubleshooting</h4> <h4 class="mt-3 h-md">故障排除</h4>
<p> <p>
There are a number of helpful resources to self diagnose and correct problems. There are a number of helpful resources to self diagnose and correct problems.
......
...@@ -21,10 +21,10 @@ const hasDetails = computed(() => { ...@@ -21,10 +21,10 @@ const hasDetails = computed(() => {
<template> <template>
<div v-if="hasDetails"> <div v-if="hasDetails">
<h4 class="h-md">Details</h4> <h4 class="h-md">详情</h4>
<div v-if="hasMessages" id="dataset-error-job-messages"> <div v-if="hasMessages" id="dataset-error-job-messages">
<p>Execution resulted in the following messages:</p> <p>执行产生以下消息:</p>
<div v-for="(jobMessage, index) in jobMessages" :key="index"> <div v-for="(jobMessage, index) in jobMessages" :key="index">
<pre class="rounded code"> <pre class="rounded code">
...@@ -34,7 +34,7 @@ const hasDetails = computed(() => { ...@@ -34,7 +34,7 @@ const hasDetails = computed(() => {
</div> </div>
<div v-if="toolStderr"> <div v-if="toolStderr">
<p>Tool generated the following standard error:</p> <p>工具生成以下标准错误:</p>
<pre id="dataset-error-tool-stderr" class="rounded code"> <pre id="dataset-error-tool-stderr" class="rounded code">
{{ toolStderr }} {{ toolStderr }}
...@@ -42,7 +42,7 @@ const hasDetails = computed(() => { ...@@ -42,7 +42,7 @@ const hasDetails = computed(() => {
</div> </div>
<div v-if="jobStderr"> <div v-if="jobStderr">
<p>Galaxy job runner generated the following standard error:</p> <p>Galaxy 作业运行器生成以下标准错误:</p>
<pre id="dataset-error-job-stderr" class="rounded code"> <pre id="dataset-error-job-stderr" class="rounded code">
{{ jobStderr }} {{ jobStderr }}
......
...@@ -27,7 +27,7 @@ defineProps<Props>(); ...@@ -27,7 +27,7 @@ defineProps<Props>();
<table id="dataset-details" class="tabletip info_data_table"> <table id="dataset-details" class="tabletip info_data_table">
<tbody> <tbody>
<tr> <tr>
<td>Number</td> <td>编号</td>
<td id="number"> <td id="number">
{{ dataset.hid }} {{ dataset.hid }}
...@@ -35,7 +35,7 @@ defineProps<Props>(); ...@@ -35,7 +35,7 @@ defineProps<Props>();
</tr> </tr>
<tr> <tr>
<td>Name</td> <td>{{ localize("Name") }}</td>
<td id="name"> <td id="name">
{{ dataset.name }} {{ dataset.name }}
...@@ -43,7 +43,7 @@ defineProps<Props>(); ...@@ -43,7 +43,7 @@ defineProps<Props>();
</tr> </tr>
<tr> <tr>
<td>Created</td> <td>{{ localize("Created") }}</td>
<td v-if="dataset.create_time" id="created"> <td v-if="dataset.create_time" id="created">
<UtcDate :date="dataset.create_time" mode="pretty" /> <UtcDate :date="dataset.create_time" mode="pretty" />
...@@ -51,13 +51,13 @@ defineProps<Props>(); ...@@ -51,13 +51,13 @@ defineProps<Props>();
</tr> </tr>
<tr> <tr>
<td>Filesize</td> <td>文件大小</td>
<td id="file-size" v-html="bytesToString(dataset.file_size, false)" /> <td id="file-size" v-html="bytesToString(dataset.file_size, false)" />
</tr> </tr>
<tr v-if="'metadata_dbkey' in dataset"> <tr v-if="'metadata_dbkey' in dataset">
<td>Dbkey</td> <td>数据库键</td>
<td id="dbkey"> <td id="dbkey">
{{ dataset.metadata_dbkey }} {{ dataset.metadata_dbkey }}
...@@ -75,7 +75,7 @@ defineProps<Props>(); ...@@ -75,7 +75,7 @@ defineProps<Props>();
</tr> </tr>
<tr> <tr>
<td>File contents</td> <td>文件内容</td>
<td id="file-contents"> <td id="file-contents">
<a :href="withPrefix(dataset.download_url)">contents</a> <a :href="withPrefix(dataset.download_url)">contents</a>
...@@ -83,7 +83,7 @@ defineProps<Props>(); ...@@ -83,7 +83,7 @@ defineProps<Props>();
</tr> </tr>
<tr v-if="dataset.id"> <tr v-if="dataset.id">
<td>History Content API ID</td> <td>历史内容 API ID</td>
<td> <td>
<div id="dataset-id"> <div id="dataset-id">
...@@ -94,7 +94,7 @@ defineProps<Props>(); ...@@ -94,7 +94,7 @@ defineProps<Props>();
</tr> </tr>
<tr v-if="dataset.history_id"> <tr v-if="dataset.history_id">
<td>History API ID</td> <td>历史 API ID</td>
<td> <td>
<div id="history_id"> <div id="history_id">
...@@ -114,7 +114,7 @@ defineProps<Props>(); ...@@ -114,7 +114,7 @@ defineProps<Props>();
</tr> </tr>
<tr v-if="dataset.file_name"> <tr v-if="dataset.file_name">
<td>Full Path</td> <td>完整路径</td>
<td id="file_name"> <td id="file_name">
{{ dataset.file_name }} {{ dataset.file_name }}
...@@ -122,7 +122,7 @@ defineProps<Props>(); ...@@ -122,7 +122,7 @@ defineProps<Props>();
</tr> </tr>
<tr v-if="dataset.created_from_basename"> <tr v-if="dataset.created_from_basename">
<td>Originally Created From a File Named</td> <td>最初创建自名为</td>
<td id="created_from_basename"> <td id="created_from_basename">
{{ dataset.created_from_basename }} {{ dataset.created_from_basename }}
...@@ -130,7 +130,7 @@ defineProps<Props>(); ...@@ -130,7 +130,7 @@ defineProps<Props>();
</tr> </tr>
<tr v-if="dataset.sources && dataset.sources.length > 0"> <tr v-if="dataset.sources && dataset.sources.length > 0">
<td>Sources</td> <td>来源</td>
<td> <td>
<DatasetSources :sources="dataset.sources" /> <DatasetSources :sources="dataset.sources" />
...@@ -138,7 +138,7 @@ defineProps<Props>(); ...@@ -138,7 +138,7 @@ defineProps<Props>();
</tr> </tr>
<tr v-if="dataset.hashes && dataset.hashes.length > 0"> <tr v-if="dataset.hashes && dataset.hashes.length > 0">
<td>Hashes</td> <td>哈希值</td>
<td> <td>
<DatasetHashes :hashes="dataset.hashes" /> <DatasetHashes :hashes="dataset.hashes" />
......
...@@ -63,7 +63,7 @@ const breadcrumbItems = [{ title: "Recent Exports & Downloads", to: "/downloads" ...@@ -63,7 +63,7 @@ const breadcrumbItems = [{ title: "Recent Exports & Downloads", to: "/downloads"
<!-- Local Downloads Section --> <!-- Local Downloads Section -->
<div v-if="hasLocalDownloads" class="mb-4"> <div v-if="hasLocalDownloads" class="mb-4">
<h4 class="mb-3">Downloads</h4> <h4 class="mb-3">下载</h4>
<div class="d-flex flex-wrap"> <div class="d-flex flex-wrap">
<DownloadItemCard <DownloadItemCard
v-for="download in downloadMonitoringData" v-for="download in downloadMonitoringData"
...@@ -79,7 +79,7 @@ const breadcrumbItems = [{ title: "Recent Exports & Downloads", to: "/downloads" ...@@ -79,7 +79,7 @@ const breadcrumbItems = [{ title: "Recent Exports & Downloads", to: "/downloads"
<!-- Remote Exports Section --> <!-- Remote Exports Section -->
<div v-if="hasRemoteExports" class="mb-4"> <div v-if="hasRemoteExports" class="mb-4">
<h4 class="mb-3">Remote Exports</h4> <h4 class="mb-3">远程导出</h4>
<div class="d-flex flex-wrap"> <div class="d-flex flex-wrap">
<RemoteExportCard <RemoteExportCard
v-for="exportRecord in remoteExports" v-for="exportRecord in remoteExports"
......
...@@ -135,22 +135,22 @@ function onGoToObject() { ...@@ -135,22 +135,22 @@ function onGoToObject() {
title: 'Export to File Source', title: 'Export to File Source',
}"> }">
<template v-slot:description> <template v-slot:description>
<p class="text-muted mb-2"><strong>Destination:</strong> {{ targetUri }}</p> <p class="text-muted mb-2"><strong>{{ localize("Destination:") }}</strong> {{ targetUri }}</p>
<p v-if="exportRecord.modelStoreFormat" class="text-muted mb-2"> <p v-if="exportRecord.modelStoreFormat" class="text-muted mb-2">
<strong>Format:</strong> {{ exportRecord.modelStoreFormat }} <strong>{{ localize("Format:") }}</strong> {{ exportRecord.modelStoreFormat }}
</p> </p>
<BAlert v-if="exportRecord.isPreparing" variant="info" show> <BAlert v-if="exportRecord.isPreparing" variant="info" show>
<FontAwesomeIcon :icon="faSpinner" spin /> <FontAwesomeIcon :icon="faSpinner" spin />
<span>Exporting to remote file source...</span> <span>正在导出到远程文件源...</span>
</BAlert> </BAlert>
<BAlert v-if="exportRecord.isReady" variant="success" show> <BAlert v-if="exportRecord.isReady" variant="success" show>
<FontAwesomeIcon :icon="faCheckCircle" /> <FontAwesomeIcon :icon="faCheckCircle" />
<span>Export completed successfully</span> <span>导出成功完成</span>
</BAlert> </BAlert>
<BAlert v-if="exportRecord.hasFailed" variant="danger" show> <BAlert v-if="exportRecord.hasFailed" variant="danger" show>
<FontAwesomeIcon :icon="faExclamationTriangle" /> <FontAwesomeIcon :icon="faExclamationTriangle" />
<span>Export failed.</span> <span>导出失败。</span>
<span v-if="exportRecord.errorMessage"> <strong>Error:</strong> {{ exportRecord.errorMessage }} </span> <span v-if="exportRecord.errorMessage"> <strong>错误:</strong> {{ exportRecord.errorMessage }} </span>
</BAlert> </BAlert>
</template> </template>
</GCard> </GCard>
......
...@@ -16,7 +16,7 @@ const fileSourceType = computed(() => props.template.type); ...@@ -16,7 +16,7 @@ const fileSourceType = computed(() => props.template.type);
<template> <template>
<div> <div>
<div>This template produces file sources of type <FileSourceTypeSpan :type="fileSourceType" />.</div> <div>此模板生成类型为的文件源<FileSourceTypeSpan :type="fileSourceType" />.</div>
<ConfigurationMarkdown :markdown="template.description || ''" :admin="true" /> <ConfigurationMarkdown :markdown="template.description || ''" :admin="true" />
</div> </div>
</template> </template>
...@@ -30,7 +30,7 @@ const currentValue = computed({ ...@@ -30,7 +30,7 @@ const currentValue = computed({
<b-form-input :id="id" v-model="currentValue" class="cursor-pointer" type="color" size="sm" /> <b-form-input :id="id" v-model="currentValue" class="cursor-pointer" type="color" size="sm" />
</b-col> </b-col>
<b-col class="pl-0"> <b-col class="pl-0">
<label class="pt-1 cursor-pointer" :for="id">Select a color</label> <label class="pt-1 cursor-pointer" :for="id">选择颜色</label>
</b-col> </b-col>
</b-row> </b-row>
</template> </template>
......
...@@ -967,12 +967,12 @@ const noOptionsWarningMessage = computed(() => { ...@@ -967,12 +967,12 @@ const noOptionsWarningMessage = computed(() => {
switch> switch>
<span v-if="currentLinked"> <span v-if="currentLinked">
<FontAwesomeIcon :icon="faLink" /> <FontAwesomeIcon :icon="faLink" />
<b v-localize class="mr-1">Linked:</b> <b v-localize class="mr-1">已链接:</b>
<span v-localize>Datasets will be run in matched order with other datasets.</span> <span v-localize>数据集将与其他数据集按匹配顺序运行。</span>
</span> </span>
<span v-else> <span v-else>
<FontAwesomeIcon :icon="faUnlink" /> <FontAwesomeIcon :icon="faUnlink" />
<b v-localize class="mr-1">Unlinked:</b> <b v-localize class="mr-1">未链接:</b>
<span v-localize>Dataset will be run against *all* other datasets.</span> <span v-localize>Dataset will be run against *all* other datasets.</span>
</span> </span>
</BFormCheckbox> </BFormCheckbox>
......
...@@ -116,7 +116,7 @@ const defaultCollectionBuilderType = computed<CollectionBuilderType>(() => { ...@@ -116,7 +116,7 @@ const defaultCollectionBuilderType = computed<CollectionBuilderType>(() => {
:pressed="props.workflowTab === 'view'" :pressed="props.workflowTab === 'view'"
@click="clickedTab('view')"> @click="clickedTab('view')">
<FontAwesomeIcon :icon="faEye" /> <FontAwesomeIcon :icon="faEye" />
<span v-if="!props.compact" v-localize>View</span> <span v-if="!props.compact" v-localize>查看</span>
</BButton> </BButton>
<!-- three options here - source is a collection that has multiple builders exposed, source is a collection <!-- three options here - source is a collection that has multiple builders exposed, source is a collection
that has a single builder exposed, or source is dataset(s). --> that has a single builder exposed, or source is dataset(s). -->
...@@ -143,7 +143,7 @@ const defaultCollectionBuilderType = computed<CollectionBuilderType>(() => { ...@@ -143,7 +143,7 @@ const defaultCollectionBuilderType = computed<CollectionBuilderType>(() => {
variant="link" variant="link"
@click="emit('update:workflow-tab', '')"> @click="emit('update:workflow-tab', '')">
<FontAwesomeIcon :icon="faTimes" /> <FontAwesomeIcon :icon="faTimes" />
<span class="sr-only">Close Collection Creator</span> <span class="sr-only">关闭集合创建器</span>
</BButton> </BButton>
</template> </template>
<BButton <BButton
...@@ -166,7 +166,7 @@ const defaultCollectionBuilderType = computed<CollectionBuilderType>(() => { ...@@ -166,7 +166,7 @@ const defaultCollectionBuilderType = computed<CollectionBuilderType>(() => {
:pressed="props.workflowTab === 'create'" :pressed="props.workflowTab === 'create'"
@click="clickedTab('create')"> @click="clickedTab('create')">
<FontAwesomeIcon :icon="faUpload" /> <FontAwesomeIcon :icon="faUpload" />
<span v-localize>Upload</span> <span v-localize>上传</span>
</BButton> </BButton>
</BButtonGroup> </BButtonGroup>
</template> </template>
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
</b-breadcrumb> </b-breadcrumb>
<div v-if="value" class="px-2" data-description="directory full path"> <div v-if="value" class="px-2" data-description="directory full path">
<span v-localize>Directory Path:</span> <span v-localize>目录路径:</span>
<code>{{ value }}</code> <code>{{ value }}</code>
</div> </div>
</div> </div>
......
...@@ -74,7 +74,7 @@ function onCancel() { ...@@ -74,7 +74,7 @@ function onCancel() {
<RulesDisplay :input-rules="displayRules" /> <RulesDisplay :input-rules="displayRules" />
<GButton title="Edit Rules" @click="onEdit"> <GButton title="Edit Rules" @click="onEdit">
<FontAwesomeIcon :icon="faEdit" /> <FontAwesomeIcon :icon="faEdit" />
<span>Edit</span> <span>{{ localize("Edit") }}</span>
</GButton> </GButton>
<LoadingSpan v-if="loading" message="Loading collection details"> </LoadingSpan> <LoadingSpan v-if="loading" message="Loading collection details"> </LoadingSpan>
<BAlert v-if="loadError" show variant="danger" dismissible @dismissed="loadError = undefined"> <BAlert v-if="loadError" show variant="danger" dismissible @dismissed="loadError = undefined">
...@@ -82,7 +82,7 @@ function onCancel() { ...@@ -82,7 +82,7 @@ function onCancel() {
</BAlert> </BAlert>
<b-modal ref="modal" modal-class="ui-form-rules-edit-modal" hide-footer> <b-modal ref="modal" modal-class="ui-form-rules-edit-modal" hide-footer>
<template v-slot:modal-title> <template v-slot:modal-title>
<h2 class="mb-0">Build Rules for Applying to Existing Collection</h2> <h2 class="mb-0">构建应用到现有集合的规则</h2>
</template> </template>
<RuleCollectionBuilder <RuleCollectionBuilder
elements-type="collection_contents" elements-type="collection_contents"
......
...@@ -384,7 +384,7 @@ const selectedCount = computed(() => { ...@@ -384,7 +384,7 @@ const selectedCount = computed(() => {
<span v-if="moreUnselected" class="show-more-indicator"> <span v-if="moreUnselected" class="show-more-indicator">
Limited to {{ unselectedDisplayCount }} options. Limited to {{ unselectedDisplayCount }} options.
<button class="show-more-button" @click="unselectedDisplayCount += 500">Show more</button> <button class="show-more-button" @click="unselectedDisplayCount += 500">{{ localize("Show more") }}</button>
</span> </span>
</div> </div>
<div class="selection-heading px-2"> <div class="selection-heading px-2">
...@@ -419,7 +419,7 @@ const selectedCount = computed(() => { ...@@ -419,7 +419,7 @@ const selectedCount = computed(() => {
<span v-if="moreSelected" class="show-more-indicator"> <span v-if="moreSelected" class="show-more-indicator">
Limited to {{ selectedDisplayCount }} options. Limited to {{ selectedDisplayCount }} options.
<button class="show-more-button" @click="selectedDisplayCount += 500">Show more</button> <button class="show-more-button" @click="selectedDisplayCount += 500">{{ localize("Show more") }}</button>
</span> </span>
</div> </div>
</div> </div>
......
...@@ -129,7 +129,7 @@ async function sendFeedback(value: "up" | "down") { ...@@ -129,7 +129,7 @@ async function sendFeedback(value: "up" | "down") {
@click="sendFeedback('down')"> @click="sendFeedback('down')">
<FontAwesomeIcon :icon="faThumbsDown" fixed-width /> <FontAwesomeIcon :icon="faThumbsDown" fixed-width />
</GButton> </GButton>
<i v-if="!feedback">This feedback helps us improve our responses.</i> <i v-if="!feedback">此反馈有助于我们改进回复。</i>
<i v-else>Thank you for your feedback!</i> <i v-else>Thank you for your feedback!</i>
</div> </div>
</div> </div>
......
...@@ -116,7 +116,7 @@ function refreshTable() { ...@@ -116,7 +116,7 @@ function refreshTable() {
<template v-slot:expanded="{ rowData }"> <template v-slot:expanded="{ rowData }">
<span class="mb-2" :data-invocation-id="rowData.id"> <span class="mb-2" :data-invocation-id="rowData.id">
<small> <small>
<b>Last updated: <UtcDate :date="rowData.update_time" mode="elapsed" />; Invocation ID:</b> <b>最后更新:<UtcDate :date="rowData.update_time" mode="elapsed" />; Invocation ID:</b>
</small> </small>
<code>{{ rowData.id }}</code> <code>{{ rowData.id }}</code>
</span> </span>
......
...@@ -361,13 +361,13 @@ watch(operationMessage, () => { ...@@ -361,13 +361,13 @@ watch(operationMessage, () => {
<span v-else-if="!isAvailable || hasInvalidFilters"> <span v-else-if="!isAvailable || hasInvalidFilters">
<BAlert v-if="!hasInvalidFilters" variant="info" show> <BAlert v-if="!hasInvalidFilters" variant="info" show>
<span v-if="filterText"> <span v-if="filterText">
<span v-localize>Nothing found with:</span> <span v-localize>未找到包含以下内容的结果:</span>
<b>{{ filterText }}</b> <b>{{ filterText }}</b>
</span> </span>
<span v-else v-localize>{{ noDataMessage }}</span> <span v-else v-localize>{{ noDataMessage }}</span>
</BAlert> </BAlert>
<BAlert v-else-if="invalidFilters" variant="danger" show> <BAlert v-else-if="invalidFilters" variant="danger" show>
<Heading h4 inline size="sm" class="flex-grow-1 mb-2">Invalid filters in query:</Heading> <Heading h4 inline size="sm" class="flex-grow-1 mb-2">{{ localize("Invalid filters in query:") }}</Heading>
<ul> <ul>
<li v-for="[invalidKey, value] in Object.entries(invalidFilters)" :key="invalidKey"> <li v-for="[invalidKey, value] in Object.entries(invalidFilters)" :key="invalidKey">
<b>{{ invalidKey }}</b <b>{{ invalidKey }}</b
......
...@@ -27,11 +27,11 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -27,11 +27,11 @@ const props = withDefaults(defineProps<Props>(), {
<template> <template>
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div class="d-flex"> <div class="d-flex">
<Heading h1 separator inline size="lg" class="flex-grow-1 mb-2">Pages</Heading> <Heading h1 separator inline size="lg" class="flex-grow-1 mb-2">页面</Heading>
<div v-if="!userStore.isAnonymous"> <div v-if="!userStore.isAnonymous">
<GButton id="page-create" size="small" outline color="blue" to="/pages/create"> <GButton id="page-create" size="small" outline color="blue" to="/pages/create">
<FontAwesomeIcon :icon="faPlus" /> <FontAwesomeIcon :icon="faPlus" />
<span v-localize>Create Page</span> <span v-localize>创建页面</span>
</GButton> </GButton>
</div> </div>
</div> </div>
......
...@@ -26,7 +26,7 @@ const props = withDefaults(defineProps<Props>(), { ...@@ -26,7 +26,7 @@ const props = withDefaults(defineProps<Props>(), {
<template> <template>
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<div class="d-flex"> <div class="d-flex">
<Heading h1 separator inline size="lg" class="flex-grow-1 mb-2">Visualizations</Heading> <Heading h1 separator inline size="lg" class="flex-grow-1 mb-2">可视化</Heading>
</div> </div>
<BNav pills justified class="mb-2"> <BNav pills justified class="mb-2">
<BNavItem <BNavItem
......
...@@ -16,11 +16,11 @@ const props = defineProps<{ ...@@ -16,11 +16,11 @@ const props = defineProps<{
<b>Exported {{ props.exportRecord.elapsedTime }}</b> on {{ props.exportRecord.date }} <b>Exported {{ props.exportRecord.elapsedTime }}</b> on {{ props.exportRecord.date }}
</BCardText> </BCardText>
<BCardText v-if="props.exportRecord.exportParams"> <BCardText v-if="props.exportRecord.exportParams">
<b>Contains datasets:</b> <b>包含数据集:</b>
<IncludedBadge item-name="active" :included="props.exportRecord.exportParams.includeFiles" /> <IncludedBadge item-name="active" :included="props.exportRecord.exportParams.includeFiles" />
<IncludedBadge item-name="hidden" :included="props.exportRecord.exportParams.includeHidden" /> <IncludedBadge item-name="hidden" :included="props.exportRecord.exportParams.includeHidden" />
<IncludedBadge item-name="deleted" :included="props.exportRecord.exportParams.includeDeleted" /> <IncludedBadge item-name="deleted" :included="props.exportRecord.exportParams.includeDeleted" />
</BCardText> </BCardText>
<BCardText> <b>Stored in:</b> {{ props.exportRecord.importUri }} </BCardText> <BCardText> <b>存储于:</b> {{ props.exportRecord.importUri }} </BCardText>
</BCard> </BCard>
</template> </template>
...@@ -149,14 +149,14 @@ function onArchiveHistoryWithExport() { ...@@ -149,14 +149,14 @@ function onArchiveHistoryWithExport() {
</BAlert> </BAlert>
<BAlert v-else-if="exportErrorMessage" show variant="danger"> <BAlert v-else-if="exportErrorMessage" show variant="danger">
<p> <p>
<b>Something went wrong</b> <b>出现问题</b>
</p> </p>
<p>{{ exportErrorMessage }}</p> <p>{{ exportErrorMessage }}</p>
</BAlert> </BAlert>
<div v-else-if="mostUpToDateExport && mostUpToDateExportIsReady"> <div v-else-if="mostUpToDateExport && mostUpToDateExportIsReady">
<BAlert show variant="success"> <BAlert show variant="success">
<p> <p>
<b>There is an up-to-date export record of this history ready.</b> <b>此历史已有最新的导出记录可用。</b>
</p> </p>
<p> <p>
This export record will be associated with your archived history so you can recreate it later by This export record will be associated with your archived history so you can recreate it later by
...@@ -211,7 +211,7 @@ function onArchiveHistoryWithExport() { ...@@ -211,7 +211,7 @@ function onArchiveHistoryWithExport() {
<GTabs card vertical lazy class="export-option-tabs"> <GTabs card vertical lazy class="export-option-tabs">
<GTab id="to-remote-file-tab" title="To Repository" active> <GTab id="to-remote-file-tab" title="To Repository" active>
<p> <p>
<b>Exporting to a repository</b> will create a compressed archive of the history contents, copy <b>正在导出到仓库</b> will create a compressed archive of the history contents, copy
it to a remote location (e.g. an FTP server) and create an export record with this information it to a remote location (e.g. an FTP server) and create an export record with this information
that will be associated with the archived history. You will be able to recreate the history that will be associated with the archived history. You will be able to recreate the history
later by importing it from the export record. later by importing it from the export record.
...@@ -220,7 +220,7 @@ function onArchiveHistoryWithExport() { ...@@ -220,7 +220,7 @@ function onArchiveHistoryWithExport() {
</GTab> </GTab>
<GTab id="to-rdm-repository-tab" title="To RDM Repository"> <GTab id="to-rdm-repository-tab" title="To RDM Repository">
<p> <p>
<b>Exporting to a RDM repository</b> (e.g. any <b>正在导出到 RDM 仓库</b> (e.g. any
<ExternalLink href="https://inveniosoftware.org/products/rdm/"> Invenio RDM </ExternalLink> <ExternalLink href="https://inveniosoftware.org/products/rdm/"> Invenio RDM </ExternalLink>
compatible repository) will require to create or select an existing record in the repository compatible repository) will require to create or select an existing record in the repository
where the history archive will be uploaded. The export record will be associated with the where the history archive will be uploaded. The export record will be associated with the
......
...@@ -12,7 +12,7 @@ function onArchiveHistory() { ...@@ -12,7 +12,7 @@ function onArchiveHistory() {
<div> <div>
<p> <p>
If you want to remove the history from your <i>active</i> histories but keep it around for reference, you If you want to remove the history from your <i>active</i> histories but keep it around for reference, you
can move it to the <b>Archived Histories</b> section, by clicking the button below. can move it to the <b>{{ localize("Archived Histories") }}</b> section, by clicking the button below.
</p> </p>
<p> <p>
This is particularly useful if you have a lot of histories and want to keep the list of This is particularly useful if you have a lot of histories and want to keep the list of
......
...@@ -86,12 +86,12 @@ const breadcrumbItems = computed(() => [ ...@@ -86,12 +86,12 @@ const breadcrumbItems = computed(() => [
<BAlert v-if="isHistoryAlreadyArchived" id="history-archived-alert" show variant="success"> <BAlert v-if="isHistoryAlreadyArchived" id="history-archived-alert" show variant="success">
This history has been archived. You can access it from the This history has been archived. You can access it from the
<RouterLink :to="archivedHistoriesRoute">Archived Histories</RouterLink> section. <RouterLink :to="archivedHistoriesRoute">{{ localize("Archived Histories") }}</RouterLink> section.
</BAlert> </BAlert>
<div v-else-if="history"> <div v-else-if="history">
<BAlert show variant="info"> <BAlert show variant="info">
Archiving a history will remove it from your <i>active histories</i>. You can still access it from the Archiving a history will remove it from your <i>active histories</i>. You can still access it from the
<RouterLink :to="archivedHistoriesRoute">Archived Histories</RouterLink> section. <RouterLink :to="archivedHistoriesRoute">{{ localize("Archived Histories") }}</RouterLink> section.
</BAlert> </BAlert>
<div v-if="canFreeStorage"> <div v-if="canFreeStorage">
......
...@@ -438,7 +438,7 @@ function unexpandedClick(event: Event) { ...@@ -438,7 +438,7 @@ function unexpandedClick(event: Event) {
</span> </span>
<!-- collections are not expandable, so we only need the DatasetDetails component here --> <!-- collections are not expandable, so we only need the DatasetDetails component here -->
<BCollapse :visible="expandDataset" class="px-2 pb-2"> <BCollapse :visible="expandDataset" class="px-2 pb-2">
<div v-if="item.accessible === false">You are not allowed to access this dataset</div> <div v-if="item.accessible === false">您无权访问此数据集</div>
<DatasetDetails <DatasetDetails
v-else-if="expandDataset && item.id" v-else-if="expandDataset && item.id"
:id="item.id" :id="item.id"
......
...@@ -92,7 +92,7 @@ function toggleHighlights() { ...@@ -92,7 +92,7 @@ function toggleHighlights() {
<span class="value">?</span> <span class="value">?</span>
</span> </span>
<div class="info"> <div class="info">
<span class="value">Loading</span> <span class="value">加载中</span>
</div> </div>
</div> </div>
<div class="dataset-actions mb-1"> <div class="dataset-actions mb-1">
...@@ -118,7 +118,7 @@ function toggleHighlights() { ...@@ -118,7 +118,7 @@ function toggleHighlights() {
</div> </div>
<!-- this looks a mess, but whitespace pads the pre and makes it look wonky --> <!-- this looks a mess, but whitespace pads the pre and makes it look wonky -->
<pre <pre
class="dataset-peek p-1"><table cellspacing="0" cellpadding="3"><tbody><tr><td>Dataset peek loading...</td></tr></tbody></table></pre> class="dataset-peek p-1"><table cellspacing="0" cellpadding="3"><tbody><tr><td>数据集预览加载中...</td></tr></tbody></table></pre>
</div> </div>
</div> </div>
</div> </div>
......
...@@ -35,14 +35,14 @@ function onFilter(value: string) { ...@@ -35,14 +35,14 @@ function onFilter(value: string) {
<template> <template>
<div> <div>
<p>Here are all available item states in Galaxy:</p> <p>以下是 Galaxy 中所有可用的项目状态:</p>
<p> <p>
<i> <i>
(Note that the colors for each state correspond to content item state colors in the history, and if it (Note that the colors for each state correspond to content item state colors in the history, and if it
exists, hovering over the icon on a history item will display the state message.) exists, hovering over the icon on a history item will display the state message.)
</i> </i>
<br /> <br />
<b>You cannot filter a history for collections given a state.</b> <b>在给定状态的情况下,您无法按集合筛选历史。</b>
</p> </p>
<dl v-for="(state, key, index) in states" :key="index"> <dl v-for="(state, key, index) in states" :key="index">
<div :class="['alert', 'content-item', 'alert-' + state.status]" :data-state="dataState(key)"> <div :class="['alert', 'content-item', 'alert-' + state.status]" :data-state="dataState(key)">
......
...@@ -47,7 +47,7 @@ function onDownload() { ...@@ -47,7 +47,7 @@ function onDownload() {
:href="downloadUrl" :href="downloadUrl"
@click="onDownload"> @click="onDownload">
<FontAwesomeIcon class="mr-1" :icon="faDownload" /> <FontAwesomeIcon class="mr-1" :icon="faDownload" />
<span>Download</span> <span>{{ localize("Download") }}</span>
</b-button> </b-button>
<b-button <b-button
v-if="showCollectionDetailsUrl" v-if="showCollectionDetailsUrl"
...@@ -58,7 +58,7 @@ function onDownload() { ...@@ -58,7 +58,7 @@ function onDownload() {
:href="showCollectionDetailsUrl" :href="showCollectionDetailsUrl"
@click.prevent.stop="router.push(showCollectionDetailsUrl)"> @click.prevent.stop="router.push(showCollectionDetailsUrl)">
<FontAwesomeIcon class="mr-1" :icon="faInfoCircle" /> <FontAwesomeIcon class="mr-1" :icon="faInfoCircle" />
<span>Show Details</span> <span>显示详情</span>
</b-button> </b-button>
<b-button <b-button
v-if="rerunUrl" v-if="rerunUrl"
...@@ -69,7 +69,7 @@ function onDownload() { ...@@ -69,7 +69,7 @@ function onDownload() {
:href="rerunUrl" :href="rerunUrl"
@click.prevent.stop="router.push(rerunUrl)"> @click.prevent.stop="router.push(rerunUrl)">
<FontAwesomeIcon class="mr-1" :icon="faRedo" /> <FontAwesomeIcon class="mr-1" :icon="faRedo" />
<span>Run Job Again</span> <span>再次运行作业</span>
</b-button> </b-button>
<b-button <b-button
v-if="hasSampleSheet && sheetUrl" v-if="hasSampleSheet && sheetUrl"
...@@ -79,7 +79,7 @@ function onDownload() { ...@@ -79,7 +79,7 @@ function onDownload() {
:href="sheetUrl" :href="sheetUrl"
@click.prevent.stop="router.push(sheetUrl)"> @click.prevent.stop="router.push(sheetUrl)">
<FontAwesomeIcon class="mr-1" :icon="faTable" /> <FontAwesomeIcon class="mr-1" :icon="faTable" />
<span>View Sheet</span> <span>查看工作表</span>
</b-button> </b-button>
</b-button-group> </b-button-group>
</nav> </nav>
......
...@@ -34,7 +34,7 @@ function clickDataLink() { ...@@ -34,7 +34,7 @@ function clickDataLink() {
</h4> </h4>
<p v-if="props.writable"> <p v-if="props.writable">
<a v-localize href="#" @click.prevent="openGlobalUploadModal">You can load your own data</a> <a v-localize href="#" @click.prevent="openGlobalUploadModal">您可以加载自己的数据</a>
<span v-localize>or</span> <span v-localize>or</span>
<a v-localize href="#" @click.prevent="clickDataLink">get data from an external source</a>. <a v-localize href="#" @click.prevent="clickDataLink">get data from an external source</a>.
</p> </p>
......
...@@ -52,7 +52,7 @@ function userTitle(title: string) { ...@@ -52,7 +52,7 @@ function userTitle(title: string) {
aria-label="current history management"> aria-label="current history management">
<GButton v-if="!props.minimal" size="small" transparent @click="emit('show', false)"> <GButton v-if="!props.minimal" size="small" transparent @click="emit('show', false)">
<FontAwesomeIcon fixed-width :icon="faChevronRight" /> <FontAwesomeIcon fixed-width :icon="faChevronRight" />
<span v-localize>History</span> <span v-localize>历史</span>
</GButton> </GButton>
<BButtonGroup> <BButtonGroup>
......
...@@ -53,21 +53,21 @@ async function runOperation(operation: () => Promise<unknown>) { ...@@ -53,21 +53,21 @@ async function runOperation(operation: () => Promise<unknown>) {
toggle-class="text-decoration-none rounded-0" toggle-class="text-decoration-none rounded-0"
data-description="history action menu"> data-description="history action menu">
<template v-slot:button-content> <template v-slot:button-content>
<span class="sr-only">History actions</span> <span class="sr-only">历史操作</span>
<FontAwesomeIcon :icon="faCog" /> <FontAwesomeIcon :icon="faCog" />
</template> </template>
<BDropdownItem v-if="numItemsHidden" v-b-modal:show-all-hidden-content> <BDropdownItem v-if="numItemsHidden" v-b-modal:show-all-hidden-content>
<span v-localize>Unhide All Hidden Content</span> <span v-localize>取消隐藏所有隐藏内容</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem v-if="numItemsHidden" v-b-modal:delete-all-hidden-content> <BDropdownItem v-if="numItemsHidden" v-b-modal:delete-all-hidden-content>
<span v-localize>Delete All Hidden Content</span> <span v-localize>删除所有隐藏内容</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem v-if="numItemsDeleted" v-b-modal:purge-all-deleted-content> <BDropdownItem v-if="numItemsDeleted" v-b-modal:purge-all-deleted-content>
<span v-localize>Purge All Deleted Content</span> <span v-localize>清除所有已删除内容</span>
</BDropdownItem> </BDropdownItem>
</BDropdown> </BDropdown>
......
...@@ -78,7 +78,7 @@ function onHide() { ...@@ -78,7 +78,7 @@ function onHide() {
>- items were processed successfully, unfortunately, -<strong>{{ error_count }}</strong >- items were processed successfully, unfortunately, -<strong>{{ error_count }}</strong
>- items failed because of the following reasons: >- items failed because of the following reasons:
</p> </p>
<p v-else v-localize>The operation failed for the following reasons:</p> <p v-else v-localize>操作因以下原因失败:</p>
<div> <div>
<ul v-if="errorMessage"> <ul v-if="errorMessage">
......
...@@ -45,9 +45,9 @@ watch( ...@@ -45,9 +45,9 @@ watch(
fade fade
@dismissed="onDismissed" @dismissed="onDismissed"
@dismiss-count-down="dismissCountDown = $event"> @dismiss-count-down="dismissCountDown = $event">
<b>Please notice your selection has changed.</b> Manually unselecting items or adding new ones will disable the <b>请注意您的选择已更改。</b> Manually unselecting items or adding new ones will disable the
`select all` status. `select all` status.
<BProgress variant="info" :max="dismissSecs" :value="dismissCountDown" height="4px" /> <BProgress variant="info" :max="dismissSecs" :value="dismissCountDown" height="4px" />
<BLink @click="onDoNotShowAgain">Do not show again</BLink> <BLink @click="onDoNotShowAgain">不再显示</BLink>
</BAlert> </BAlert>
</template> </template>
...@@ -15,25 +15,25 @@ ...@@ -15,25 +15,25 @@
> >
</b-dropdown-text> </b-dropdown-text>
<b-dropdown-item v-if="canUnhideSelection" v-b-modal:show-selected-content data-description="unhide option"> <b-dropdown-item v-if="canUnhideSelection" v-b-modal:show-selected-content data-description="unhide option">
<span v-localize>Unhide</span> <span v-localize>取消隐藏</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-if="canHideSelection" v-b-modal:hide-selected-content data-description="hide option"> <b-dropdown-item v-if="canHideSelection" v-b-modal:hide-selected-content data-description="hide option">
<span v-localize>Hide</span> <span v-localize>隐藏</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item <b-dropdown-item
v-if="canUndeleteSelection" v-if="canUndeleteSelection"
v-b-modal:restore-selected-content v-b-modal:restore-selected-content
data-description="undelete option"> data-description="undelete option">
<span v-localize>Undelete</span> <span v-localize>取消删除</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item <b-dropdown-item
v-if="canDeleteSelection" v-if="canDeleteSelection"
v-b-modal:delete-selected-content v-b-modal:delete-selected-content
data-description="delete option"> data-description="delete option">
<span v-localize>Delete</span> <span v-localize>删除</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-b-modal:purge-selected-content data-description="purge option"> <b-dropdown-item v-b-modal:purge-selected-content data-description="purge option">
<span v-localize>Delete (permanently)</span> <span v-localize>删除(永久)</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-divider v-if="showBuildOptions" /> <b-dropdown-divider v-if="showBuildOptions" />
<b-dropdown-divider v-if="showBuildOptionForAll" /> <b-dropdown-divider v-if="showBuildOptionForAll" />
...@@ -41,30 +41,30 @@ ...@@ -41,30 +41,30 @@
v-if="showBuildOptionForAll" v-if="showBuildOptionForAll"
data-description="build list all" data-description="build list all"
@click="buildDatasetListAll"> @click="buildDatasetListAll">
<span v-localize>Build Dataset List</span> <span v-localize>构建数据集列表</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-divider /> <b-dropdown-divider />
<b-dropdown-item v-b-modal:change-dbkey-of-selected-content data-description="change database build"> <b-dropdown-item v-b-modal:change-dbkey-of-selected-content data-description="change database build">
<span v-localize>Change Database/Build</span> <span v-localize>更改数据库/构建</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item <b-dropdown-item
v-if="isConfigLoaded && config.enable_celery_tasks" v-if="isConfigLoaded && config.enable_celery_tasks"
v-b-modal:change-datatype-of-selected-content v-b-modal:change-datatype-of-selected-content
data-description="change data type"> data-description="change data type">
<span v-localize>Change data type</span> <span v-localize>更改数据类型</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-b-modal:add-tags-to-selected-content data-description="add tags"> <b-dropdown-item v-b-modal:add-tags-to-selected-content data-description="add tags">
<span v-localize>Add tags</span> <span v-localize>添加标签</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-b-modal:remove-tags-from-selected-content data-description="remove tags"> <b-dropdown-item v-b-modal:remove-tags-from-selected-content data-description="remove tags">
<span v-localize>Remove tags</span> <span v-localize>移除标签</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-divider v-if="showBuildOptions" /> <b-dropdown-divider v-if="showBuildOptions" />
<b-dropdown-item v-if="showBuildOptions" data-description="auto build list" @click="listWizard(false)"> <b-dropdown-item v-if="showBuildOptions" data-description="auto build list" @click="listWizard(false)">
<span v-localize>Auto Build List</span> <span v-localize>自动构建列表</span>
</b-dropdown-item> </b-dropdown-item>
<b-dropdown-item v-if="showBuildOptions" data-description="advanced build list" @click="listWizard(true)"> <b-dropdown-item v-if="showBuildOptions" data-description="advanced build list" @click="listWizard(true)">
<span v-localize>Advanced Build List</span> <span v-localize>高级构建列表</span>
</b-dropdown-item> </b-dropdown-item>
</b-dropdown> </b-dropdown>
......
...@@ -37,7 +37,7 @@ function resetSelection() { ...@@ -37,7 +37,7 @@ function resetSelection() {
</BButton> </BButton>
<BButton v-else variant="link" data-test-id="select-all-btn" @click="selectAll"> <BButton v-else variant="link" data-test-id="select-all-btn" @click="selectAll">
<span v-localize>Select All</span> <span v-localize>全选</span>
</BButton> </BButton>
</BButtonGroup> </BButtonGroup>
</template> </template>
...@@ -271,7 +271,7 @@ const breadcrumbItems = computed(() => [ ...@@ -271,7 +271,7 @@ const breadcrumbItems = computed(() => [
@onReimport="reimportFromRecord" @onReimport="reimportFromRecord"
@onActionMessageDismissed="onActionMessageDismissedFromRecord" /> @onActionMessageDismissed="onActionMessageDismissedFromRecord" />
<Heading h2 size="md" class="mt-3">Export your history again</Heading> <Heading h2 size="md" class="mt-3">再次导出历史</Heading>
</div> </div>
<HistoryExportWizard <HistoryExportWizard
......
...@@ -645,7 +645,7 @@ onMounted(async () => { ...@@ -645,7 +645,7 @@ onMounted(async () => {
</BAlert> </BAlert>
<BAlert v-else id="no-history-found-invalid" variant="danger" show> <BAlert v-else id="no-history-found-invalid" variant="danger" show>
<Heading h4 inline size="sm" class="flex-grow-1 mb-2">Invalid filters in query:</Heading> <Heading h4 inline size="sm" class="flex-grow-1 mb-2">{{ localize("Invalid filters in query:") }}</Heading>
<ul> <ul>
<li v-for="[invalidKey, value] in Object.entries(invalidFilters)" :key="invalidKey"> <li v-for="[invalidKey, value] in Object.entries(invalidFilters)" :key="invalidKey">
<b>{{ invalidKey }}</b> <b>{{ invalidKey }}</b>
......
...@@ -117,13 +117,13 @@ function onDelete() { ...@@ -117,13 +117,13 @@ function onDelete() {
data-description="history options"> data-description="history options">
<template v-slot:button-content> <template v-slot:button-content>
<FontAwesomeIcon fixed-width :icon="faBars" /> <FontAwesomeIcon fixed-width :icon="faBars" />
<span class="sr-only">History Options</span> <span class="sr-only">历史选项</span>
</template> </template>
<BDropdownText> <BDropdownText>
<LoadingSpan v-if="historiesLoading" message="Fetching histories from server" /> <LoadingSpan v-if="historiesLoading" message="Fetching histories from server" />
<span v-else-if="!props.minimal">You have {{ totalHistoryCount }} histories.</span> <span v-else-if="!props.minimal">You have {{ totalHistoryCount }} histories.</span>
<span v-else>Manage History</span> <span v-else>管理历史</span>
</BDropdownText> </BDropdownText>
<BDropdownItem <BDropdownItem
...@@ -133,7 +133,7 @@ function onDelete() { ...@@ -133,7 +133,7 @@ function onDelete() {
:title="userTitle('Open History Multiview')" :title="userTitle('Open History Multiview')"
to="/histories/view_multiple"> to="/histories/view_multiple">
<FontAwesomeIcon fixed-width :icon="faColumns" /> <FontAwesomeIcon fixed-width :icon="faColumns" />
<span v-localize>Show Histories Side-by-Side</span> <span v-localize>并排显示历史</span>
</BDropdownItem> </BDropdownItem>
<BDropdownDivider v-if="!props.minimal" /> <BDropdownDivider v-if="!props.minimal" />
...@@ -141,7 +141,7 @@ function onDelete() { ...@@ -141,7 +141,7 @@ function onDelete() {
<BDropdownText v-if="!canEditHistory"> <BDropdownText v-if="!canEditHistory">
This history has been <span class="font-weight-bold">{{ historyState }}</span This history has been <span class="font-weight-bold">{{ historyState }}</span
>. >.
<span v-localize>Some actions might not be available.</span> <span v-localize>某些操作可能不可用。</span>
</BDropdownText> </BDropdownText>
<BDropdownDivider v-if="!canEditHistory" /> <BDropdownDivider v-if="!canEditHistory" />
...@@ -151,7 +151,7 @@ function onDelete() { ...@@ -151,7 +151,7 @@ function onDelete() {
:title="localize('Resume all Paused Jobs in this History')" :title="localize('Resume all Paused Jobs in this History')"
@click="resumePausedJobs()"> @click="resumePausedJobs()">
<FontAwesomeIcon fixed-width :icon="faPlay" /> <FontAwesomeIcon fixed-width :icon="faPlay" />
<span v-localize>Resume Paused Jobs</span> <span v-localize>恢复已暂停的作业</span>
</BDropdownItem> </BDropdownItem>
<BDropdownDivider /> <BDropdownDivider />
...@@ -161,7 +161,7 @@ function onDelete() { ...@@ -161,7 +161,7 @@ function onDelete() {
:title="userTitle('Copy History to a New History')" :title="userTitle('Copy History to a New History')"
@click="showCopyModal = !showCopyModal"> @click="showCopyModal = !showCopyModal">
<FontAwesomeIcon fixed-width :icon="faClone" /> <FontAwesomeIcon fixed-width :icon="faClone" />
<span v-localize>Copy History</span> <span v-localize>复制历史</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
...@@ -170,7 +170,7 @@ function onDelete() { ...@@ -170,7 +170,7 @@ function onDelete() {
:title="userTitle('Copy Datasets to Another History')" :title="userTitle('Copy Datasets to Another History')"
@click="router.push('/datasets/copy')"> @click="router.push('/datasets/copy')">
<FontAwesomeIcon fixed-width :icon="faCopy" /> <FontAwesomeIcon fixed-width :icon="faCopy" />
<span v-localize>Copy Datasets</span> <span v-localize>复制数据集</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
...@@ -178,15 +178,15 @@ function onDelete() { ...@@ -178,15 +178,15 @@ function onDelete() {
:title="localize(isDeletedNotPurged ? 'Permanently Delete History' : 'Delete History')" :title="localize(isDeletedNotPurged ? 'Permanently Delete History' : 'Delete History')"
@click="showDeleteModal = !showDeleteModal"> @click="showDeleteModal = !showDeleteModal">
<FontAwesomeIcon fixed-width :icon="isDeletedNotPurged ? faBurn : faTrash" /> <FontAwesomeIcon fixed-width :icon="isDeletedNotPurged ? faBurn : faTrash" />
<span v-if="isDeletedNotPurged" v-localize>Permanently Delete History</span> <span v-if="isDeletedNotPurged" v-localize>永久删除历史</span>
<span v-else v-localize>Delete History</span> <span v-else v-localize>删除历史</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
:title="localize('Export references for all Tools used in this History')" :title="localize('Export references for all Tools used in this History')"
:to="`/histories/citations?id=${history.id}`"> :to="`/histories/citations?id=${history.id}`">
<FontAwesomeIcon fixed-width :icon="faStream" /> <FontAwesomeIcon fixed-width :icon="faStream" />
<span v-localize>Export Tool References</span> <span v-localize>导出工具引用</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
...@@ -195,7 +195,7 @@ function onDelete() { ...@@ -195,7 +195,7 @@ function onDelete() {
:title="localize('Export and Download History as a File')" :title="localize('Export and Download History as a File')"
:to="`/histories/${history.id}/export`"> :to="`/histories/${history.id}/export`">
<FontAwesomeIcon fixed-width :icon="faFileArchive" /> <FontAwesomeIcon fixed-width :icon="faFileArchive" />
<span v-localize>Export History to File</span> <span v-localize>将历史导出到文件</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
...@@ -204,7 +204,7 @@ function onDelete() { ...@@ -204,7 +204,7 @@ function onDelete() {
:title="userTitle('Archive this History')" :title="userTitle('Archive this History')"
:to="`/histories/${history.id}/archive`"> :to="`/histories/${history.id}/archive`">
<FontAwesomeIcon fixed-width :icon="faArchive" /> <FontAwesomeIcon fixed-width :icon="faArchive" />
<span v-localize>Archive History</span> <span v-localize>归档历史</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
...@@ -214,7 +214,7 @@ function onDelete() { ...@@ -214,7 +214,7 @@ function onDelete() {
:title="userTitle('Convert History to Workflow')" :title="userTitle('Convert History to Workflow')"
@click="iframeRedirect(`/workflow/build_from_current_history?history_id=${history.id}`)"> @click="iframeRedirect(`/workflow/build_from_current_history?history_id=${history.id}`)">
<FontAwesomeIcon fixed-width :icon="faFileExport" /> <FontAwesomeIcon fixed-width :icon="faFileExport" />
<span v-localize>Extract Workflow</span> <span v-localize>提取工作流</span>
</BDropdownItem> </BDropdownItem>
<BDropdownItem <BDropdownItem
...@@ -222,7 +222,7 @@ function onDelete() { ...@@ -222,7 +222,7 @@ function onDelete() {
:title="userTitle('Display Workflow Invocations')" :title="userTitle('Display Workflow Invocations')"
:to="`/histories/${history.id}/invocations`"> :to="`/histories/${history.id}/invocations`">
<FontAwesomeIcon fixed-width :icon="faList" /> <FontAwesomeIcon fixed-width :icon="faList" />
<span v-localize>Show Invocations</span> <span v-localize>显示调用</span>
</BDropdownItem> </BDropdownItem>
<BDropdownDivider /> <BDropdownDivider />
......
...@@ -285,7 +285,7 @@ function getHistoryTitleBadges(history: HistorySummary) { ...@@ -285,7 +285,7 @@ function getHistoryTitleBadges(history: HistorySummary) {
<BBadge v-if="props.filter && !validFilter" class="alert-warning w-100 mb-2"> <BBadge v-if="props.filter && !validFilter" class="alert-warning w-100 mb-2">
Search term is too short Search term is too short
</BBadge> </BBadge>
<BAlert v-else-if="!busy && hasNoResults" class="mb-2" variant="danger" show>No histories found.</BAlert> <BAlert v-else-if="!busy && hasNoResults" class="mb-2" variant="danger" show>未找到历史。</BAlert>
</template> </template>
<template v-slot:item="{ item: history }"> <template v-slot:item="{ item: history }">
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
</BreadcrumbHeading> </BreadcrumbHeading>
<b-alert :show="copySuccess"> <b-alert :show="copySuccess">
History imported and is now your active history. <b-link :to="importedHistoryLink">View here</b-link>. History imported and is now your active history. <b-link :to="importedHistoryLink">在此查看</b-link>.
</b-alert> </b-alert>
<CollectionPanel <CollectionPanel
......
...@@ -52,11 +52,11 @@ function onViewCollection(collection: CollectionEntry, currentOffset?: number) { ...@@ -52,11 +52,11 @@ function onViewCollection(collection: CollectionEntry, currentOffset?: number) {
@view-collection="onViewCollection" /> @view-collection="onViewCollection" />
<div v-else> <div v-else>
<span class="sr-only">Loading...</span> <span class="sr-only">{{ localize("Loading...") }}</span>
</div> </div>
</div> </div>
<div v-else class="flex-grow-1 loadingBackground h-100"> <div v-else class="flex-grow-1 loadingBackground h-100">
<span v-localize class="sr-only">Loading History...</span> <span v-localize class="sr-only">正在加载历史...</span>
</div> </div>
</template> </template>
...@@ -111,7 +111,7 @@ function showRecent() { ...@@ -111,7 +111,7 @@ function showRecent() {
<template> <template>
<div v-if="currentUser" class="d-flex flex-column"> <div v-if="currentUser" class="d-flex flex-column">
<div class="d-flex"> <div class="d-flex">
<Heading h1 separator inline size="lg" class="flex-grow-1 mb-2">History Multiview</Heading> <Heading h1 separator inline size="lg" class="flex-grow-1 mb-2">历史多视图</Heading>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div> <div>
...@@ -124,7 +124,7 @@ function showRecent() { ...@@ -124,7 +124,7 @@ function showRecent() {
@click="showRecent"> @click="showRecent">
<FontAwesomeIcon v-if="hasPinnedHistories" :icon="faUndo" /> <FontAwesomeIcon v-if="hasPinnedHistories" :icon="faUndo" />
<FontAwesomeIcon v-else :icon="faClock" /> <FontAwesomeIcon v-else :icon="faClock" />
<span v-localize>Recent</span> <span v-localize>最近</span>
</BButton> </BButton>
</BButtonGroup> </BButtonGroup>
<BButton <BButton
...@@ -135,7 +135,7 @@ function showRecent() { ...@@ -135,7 +135,7 @@ function showRecent() {
variant="outline-primary" variant="outline-primary"
@click="showSelectModal = true"> @click="showSelectModal = true">
<FontAwesomeIcon :icon="faCheckSquare" /> <FontAwesomeIcon :icon="faCheckSquare" />
<span v-localize>Select</span> <span v-localize>选择</span>
</BButton> </BButton>
</div> </div>
</div> </div>
...@@ -159,7 +159,7 @@ function showRecent() { ...@@ -159,7 +159,7 @@ function showRecent() {
:show-modal.sync="showSelectModal" /> :show-modal.sync="showSelectModal" />
</div> </div>
<BAlert v-else-if="!histories.length" class="m-2" variant="danger" show> <BAlert v-else-if="!histories.length" class="m-2" variant="danger" show>
<span v-localize class="font-weight-bold">No History found.</span> <span v-localize class="font-weight-bold">未找到历史。</span>
</BAlert> </BAlert>
<SelectorModal <SelectorModal
v-show="showSelectModal" v-show="showSelectModal"
......
...@@ -43,6 +43,6 @@ const isCurrentTargetHistory = computed(() => { ...@@ -43,6 +43,6 @@ const isCurrentTargetHistory = computed(() => {
(not current) (not current)
</span> </span>
</span> </span>
<span v-else class="text-muted">Loading...</span> <span v-else class="text-muted">{{ localize("Loading...") }}</span>
</span> </span>
</template> </template>
...@@ -19,7 +19,7 @@ const props = defineProps<ExportHistoryProps>(); ...@@ -19,7 +19,7 @@ const props = defineProps<ExportHistoryProps>();
</script> </script>
<template> <template>
<span class="history-export-component"> <span class="history-export-component">
<h1 class="h-lg">Export history archive</h1> <h1 class="h-lg">导出历史归档</h1>
<span v-if="initializingFileSources"> <span v-if="initializingFileSources">
<LoadingSpan message="Loading file sources configuration from Galaxy server." /> <LoadingSpan message="Loading file sources configuration from Galaxy server." />
</span> </span>
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment