From 0acfad6dcdf934cefcb4241e87f638d05fe140f2 Mon Sep 17 00:00:00 2001 From: myhloli Date: Mon, 14 Sep 2026 17:21:20 +0800 Subject: [PATCH] Update tier terminology and localization for improved clarity in UI --- mineru/kit/gradio/app.py | 2 +- mineru/kit/gradio/i18n.py | 8 ++++++-- mineru/resources/gradio_app.css | 2 +- mineru/resources/gradio_i18n.js | 9 +++++++-- mineru/resources/gradio_page_range.js | 5 ++--- tests/unittest/test_kit_gradio.py | 8 +++++++- tests/unittest/test_kit_gradio_i18n.cjs | 13 ++++++++++++- tests/unittest/test_kit_gradio_page_range.cjs | 6 +++--- 8 files changed, 39 insertions(+), 14 deletions(-) diff --git a/mineru/kit/gradio/app.py b/mineru/kit/gradio/app.py index ffde428f..0652e1de 100644 --- a/mineru/kit/gradio/app.py +++ b/mineru/kit/gradio/app.py @@ -342,7 +342,7 @@ def build_gradio_app( ) with gr.Group(): tier_label = gr.Markdown( - value=f"解析 tier:{preferred_tier}", + value=MESSAGES["tier_value"][1].format(tier=MESSAGES[f"tier_{preferred_tier}"][1], notice=""), padding=True, elem_classes=["mineru-tier-label"], ) diff --git a/mineru/kit/gradio/i18n.py b/mineru/kit/gradio/i18n.py index b039391f..f7dbd907 100644 --- a/mineru/kit/gradio/i18n.py +++ b/mineru/kit/gradio/i18n.py @@ -24,8 +24,12 @@ MESSAGES: dict[str, tuple[str, str]] = { "homepage": ("Homepage", "主页"), "download": ("Download", "下载"), "upload": ("Select a document to parse", "请选择要解析的文件"), - "tier": ("Parsing tier", "解析 tier"), - "tier_value": ("Parsing tier: {tier}{notice}", "解析 tier:{tier}{notice}"), + "tier": ("Parsing tier", "解析等级"), + "tier_value": ("Parsing tier: {tier}{notice}", "解析等级:{tier}{notice}"), + "tier_flash": ("flash", "flash(极速)"), + "tier_basic": ("basic (medium)", "basic(中)"), + "tier_standard": ("standard (high)", "standard(高)"), + "tier_advanced": ("advanced (xhigh)", "advanced(极高)"), "tier_unavailable_suffix": (" (unavailable on this server)", "(当前服务不可用)"), "force_ocr": ("Force OCR", "强制 OCR"), "force_ocr_info": ("Ignore the PDF text layer and perform OCR", "忽略 PDF 文本层并进行 OCR"), diff --git a/mineru/resources/gradio_app.css b/mineru/resources/gradio_app.css index 7c3515d7..ecaae082 100644 --- a/mineru/resources/gradio_app.css +++ b/mineru/resources/gradio_app.css @@ -61,7 +61,7 @@ body.dark .gradio-container { .mineru-kit-page-range:has([data-range-visible="true"]) { display: flex !important; } .mineru-page-summary, .mineru-page-summary .html-container { padding: 0 !important; } .mineru-page-values, .mineru-page-axis { display: flex; justify-content: space-between; align-items: center; gap: 6px; } -.mineru-page-values { font-size: 12px; } +.mineru-page-values { font-size: 12px; justify-content: center; } .mineru-page-selection { font-weight: 600; color: var(--mineru-accent); } .mineru-page-axis { position: absolute; bottom: 0; left: 0; right: 0; font-size: 12px; opacity: .7; } .mineru-page-summary { position: static !important; } diff --git a/mineru/resources/gradio_i18n.js b/mineru/resources/gradio_i18n.js index 6348c1c3..28380168 100644 --- a/mineru/resources/gradio_i18n.js +++ b/mineru/resources/gradio_i18n.js @@ -29,8 +29,13 @@ while ((node = walker.nextNode())) { const original = node.textContent.trim(); let translated = message(original); - const tier = /^(?:解析 tier:|Parsing tier: )(\w+)$/.exec(original); - if (tier) translated = text("tier_value", { tier: tier[1], notice: "" }); + const tier = /^(?:解析等级:|Parsing tier: )(flash|basic|standard|advanced)(?:([^)]*)| \([^)]*\))*$/.exec(original); + if (tier) { + const unavailable = messages.tier_unavailable_suffix.some((suffix) => original.endsWith(suffix)); + translated = text("tier_value", { + tier: text(`tier_${tier[1]}`), notice: unavailable ? text("tier_unavailable_suffix") : "", + }); + } if (translated !== original) node.textContent = node.textContent.replace(original, () => translated); } }); diff --git a/mineru/resources/gradio_page_range.js b/mineru/resources/gradio_page_range.js index 741ee602..f100aad2 100644 --- a/mineru/resources/gradio_page_range.js +++ b/mineru/resources/gradio_page_range.js @@ -68,9 +68,8 @@ const selected = end - start + 1; const limitText = maxPages === null ? text("page_unlimited") : text("page_limit", { count: maxPages }); const summary = `
` - + `${text("start_page")} ${start}` + `[${start}-${end}] · ${text("page_count", { count: selected })}` - + `${text("end_page")} ${end}
` + + `` + `
1${limitText}${count}
`; const notice = flashUnavailable ? text("flash_unavailable") : needsRange && !count ? (message(state.error) || text("reading_pages")) : ""; @@ -85,7 +84,7 @@ update({ value: escapeHtml(notice), visible: Boolean(notice) }), // 同一事件同时更新值、标签和页码,程序赋值无需再触发 tier.input。 update({ value: effectivePosition, interactive: !flashOnly && tiers.length > 1 }), - text("tier_value", { tier: selectedTier, notice: flashUnavailable ? text("tier_unavailable_suffix") : "" }), + text("tier_value", { tier: text(`tier_${selectedTier}`), notice: flashUnavailable ? text("tier_unavailable_suffix") : "" }), JSON.stringify(tierSelection), ]; } diff --git a/tests/unittest/test_kit_gradio.py b/tests/unittest/test_kit_gradio.py index acec15eb..66aee85b 100644 --- a/tests/unittest/test_kit_gradio.py +++ b/tests/unittest/test_kit_gradio.py @@ -1127,7 +1127,13 @@ def test_gradio_tier_slider_uses_available_tiers_and_preserves_selection( assert (slider.minimum, slider.maximum, slider.step, slider.precision) == (0, maximum, 1, 0) assert slider.value == default_position assert slider.interactive is (len(tiers) > 1) - assert label.value == f"解析 tier:{default_tier}" + assert ( + label.value + == "解析等级:" + + {"flash": "flash(极速)", "basic": "basic(中)", "standard": "standard(高)", "advanced": "advanced(极高)"}[ + default_tier + ] + ) assert not any(block.__class__.__name__ == "Dropdown" for block in demo.blocks.values()) label_events = [event for event in demo.config["dependencies"] if (slider._id, "input") in event["targets"]] assert len(label_events) == 1 diff --git a/tests/unittest/test_kit_gradio_i18n.cjs b/tests/unittest/test_kit_gradio_i18n.cjs index 4f81438b..a67b52a3 100644 --- a/tests/unittest/test_kit_gradio_i18n.cjs +++ b/tests/unittest/test_kit_gradio_i18n.cjs @@ -22,7 +22,18 @@ for (const [languages, language, expected] of [ assert.equal(out[0].label, i18n.text("start_page")); assert.equal(out[3], "1-10"); assert.ok(out[2].includes(i18n.text("page_limit", { count: 20 }))); - assert.equal(out[8], i18n.text("tier_value", { tier: "standard", notice: "" })); + assert.equal(out[8], i18n.text("tier_value", { tier: i18n.text("tier_standard"), notice: "" })); + assert.ok(!out[2].includes("")); + assert.ok(!out[2].includes(i18n.text("start_page"))); + assert.ok(!out[2].includes(i18n.text("end_page"))); + for (const [position, tier] of ["flash", "basic", "standard", "advanced"].entries()) { + const labels = expected === "zh" + ? ["解析等级:flash(极速)", "解析等级:basic(中)", "解析等级:standard(高)", "解析等级:advanced(极高)"] + : ["Parsing tier: flash", "Parsing tier: basic (medium)", "Parsing tier: standard (high)", "Parsing tier: advanced (xhigh)"]; + const result = range(["flash", "basic", "standard", "advanced"], ["csv"], null, null, position, + "{}", "{}", 1, 1, JSON.stringify({ tier, locked: false })); + assert.equal(result[8], labels[position]); + } const download = vm.runInContext(resource("gradio_download.js"), context); const formats = [["html", "HTML"]]; download("activate", formats, "", "", "run"); diff --git a/tests/unittest/test_kit_gradio_page_range.cjs b/tests/unittest/test_kit_gradio_page_range.cjs index 7aa6457f..2ee01654 100644 --- a/tests/unittest/test_kit_gradio_page_range.cjs +++ b/tests/unittest/test_kit_gradio_page_range.cjs @@ -53,7 +53,7 @@ for (const extension of flashOnlyExtensions.flatMap((extension) => [extension, e const out = ui.step("file", { file: { path: `/source.${extension}` } }); assert.equal(out[7].value, 0); assert.equal(out[7].interactive, false); - assert.equal(out[8], "解析 tier:flash"); + assert.equal(out[8], "解析等级:flash(极速)"); assert.equal(out[5].interactive, true); assert.equal(out[3], ""); assert.match(out[2], /data-range-visible="false"/); @@ -65,7 +65,7 @@ for (const extension of flashOnlyExtensions.flatMap((extension) => [extension, e const cleared = ui.step("clear"); assert.equal(cleared[7].value, 3); assert.equal(cleared[7].interactive, true); - assert.equal(cleared[8], "解析 tier:advanced"); + assert.equal(cleared[8], "解析等级:advanced(极高)"); assert.equal(cleared[5].interactive, false); } @@ -76,7 +76,7 @@ for (const extension of tieredExtensions.flatMap((extension) => [extension, exte const out = ui.step("file", { file: { path: `/source.${extension}` } }); assert.equal(out[7].value, 2); assert.equal(out[7].interactive, true); - assert.equal(out[8], "解析 tier:standard"); + assert.equal(out[8], "解析等级:standard(高)"); assert.equal(out[5].interactive, extension.toLowerCase() !== "pdf"); assert.deepEqual(ui.state.tierSelection, { tier: "standard", locked: false }); }