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