Localize hard strings in submission & performer tagger (#2304)

* Localize hard strings in submission & performer tagger
* Localise show/hide configuration

Co-authored-by: WithoutPants <53250216+WithoutPants@users.noreply.github.com>
This commit is contained in:
Still Hsu 2022-02-16 08:41:08 +08:00 committed by GitHub
parent 7336a6cd18
commit da600d19d5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 223 additions and 64 deletions

View file

@ -4,6 +4,7 @@ import { Button, Form } from "react-bootstrap";
import * as GQL from "src/core/generated-graphql"; import * as GQL from "src/core/generated-graphql";
import { Modal } from "src/components/Shared"; import { Modal } from "src/components/Shared";
import { getStashboxBase } from "src/utils"; import { getStashboxBase } from "src/utils";
import { FormattedMessage, useIntl } from "react-intl";
interface IProps { interface IProps {
show: boolean; show: boolean;
@ -42,6 +43,7 @@ export const SubmitStashBoxDraft: React.FC<IProps> = ({
query query
); );
const [selectedBox, setSelectedBox] = useState(0); const [selectedBox, setSelectedBox] = useState(0);
const intl = useIntl();
const handleSubmit = () => { const handleSubmit = () => {
submit({ submit({
@ -62,7 +64,7 @@ export const SubmitStashBoxDraft: React.FC<IProps> = ({
return ( return (
<Modal <Modal
icon="paper-plane" icon="paper-plane"
header="Submit to Stash-Box" header={intl.formatMessage({ id: "actions.submit_stash_box" })}
isRunning={loading} isRunning={loading}
show={show} show={show}
accept={{ accept={{
@ -73,7 +75,7 @@ export const SubmitStashBoxDraft: React.FC<IProps> = ({
<> <>
<Form.Group className="form-row align-items-end"> <Form.Group className="form-row align-items-end">
<Form.Label className="col-6"> <Form.Label className="col-6">
Selected Stash-Box endpoint: <FormattedMessage id="stashbox.selected_stash_box" />:
</Form.Label> </Form.Label>
<Form.Control <Form.Control
as="select" as="select"
@ -88,12 +90,15 @@ export const SubmitStashBoxDraft: React.FC<IProps> = ({
</Form.Control> </Form.Control>
</Form.Group> </Form.Group>
<Button onClick={handleSubmit}> <Button onClick={handleSubmit}>
Submit {`"${entity.name ?? entity.title}"`} <FormattedMessage id="actions.submit" />{" "}
{`"${entity.name ?? entity.title}"`}
</Button> </Button>
</> </>
) : ( ) : (
<> <>
<h6>Submission successful</h6> <h6>
<FormattedMessage id="stashbox.submission_successful" />
</h6>
<div> <div>
<a <a
target="_blank" target="_blank"
@ -102,14 +107,19 @@ export const SubmitStashBoxDraft: React.FC<IProps> = ({
boxes[selectedBox].endpoint boxes[selectedBox].endpoint
)}drafts/${getResponseId(data)}`} )}drafts/${getResponseId(data)}`}
> >
Go to {boxes[selectedBox].name} to review draft. <FormattedMessage
id="stashbox.go_review_draft"
values={{ endpoint_name: boxes[selectedBox].name }}
/>
</a> </a>
</div> </div>
</> </>
)} )}
{error !== undefined && ( {error !== undefined && (
<> <>
<h6 className="mt-2">Submission failed</h6> <h6 className="mt-2">
<FormattedMessage id="stashbox.submission_failed" />
</h6>
<div>{error.message}</div> <div>{error.message}</div>
</> </>
)} )}

View file

@ -1,5 +1,6 @@
import React, { Dispatch, useState } from "react"; import React, { Dispatch, useState } from "react";
import { Badge, Button, Card, Collapse, Form } from "react-bootstrap"; import { Badge, Button, Card, Collapse, Form } from "react-bootstrap";
import { FormattedMessage } from "react-intl";
import { ConfigurationContext } from "src/hooks/Config"; import { ConfigurationContext } from "src/hooks/Config";
import { TextUtils } from "src/utils"; import { TextUtils } from "src/utils";
@ -38,28 +39,34 @@ const Config: React.FC<IConfigProps> = ({ show, config, setConfig }) => {
<Collapse in={show}> <Collapse in={show}>
<Card> <Card>
<div className="row"> <div className="row">
<h4 className="col-12">Configuration</h4> <h4 className="col-12">
<FormattedMessage id="configuration" />
</h4>
<hr className="w-100" /> <hr className="w-100" />
<div className="col-md-6"> <div className="col-md-6">
<Form.Group controlId="excluded-performer-fields"> <Form.Group controlId="excluded-performer-fields">
<h6>Excluded fields:</h6> <h6>
<FormattedMessage id="performer_tagger.config.excluded_fields" />
</h6>
<span> <span>
{excludedFields.length > 0 {excludedFields.length > 0 ? (
? excludedFields.map((f) => ( excludedFields.map((f) => (
<Badge variant="secondary" className="tag-item" key={f}> <Badge variant="secondary" className="tag-item" key={f}>
{TextUtils.capitalize(f)} {TextUtils.capitalize(f)}
</Badge> </Badge>
)) ))
: "No fields are excluded"} ) : (
<FormattedMessage id="performer_tagger.config.no_fields_are_excluded" />
)}
</span> </span>
<Form.Text> <Form.Text>
These fields will not be changed when updating performers. <FormattedMessage id="performer_tagger.config.these_fields_will_not_be_changed_when_updating_performers" />
</Form.Text> </Form.Text>
<Button <Button
onClick={() => setShowExclusionModal(true)} onClick={() => setShowExclusionModal(true)}
className="mt-2" className="mt-2"
> >
Edit Excluded Fields <FormattedMessage id="performer_tagger.config.edit_excluded_fields" />
</Button> </Button>
</Form.Group> </Form.Group>
<Form.Group <Form.Group
@ -67,7 +74,7 @@ const Config: React.FC<IConfigProps> = ({ show, config, setConfig }) => {
className="align-items-center row no-gutters mt-4" className="align-items-center row no-gutters mt-4"
> >
<Form.Label className="mr-4"> <Form.Label className="mr-4">
Active stash-box instance: <FormattedMessage id="performer_tagger.config.active_stash-box_instance" />
</Form.Label> </Form.Label>
<Form.Control <Form.Control
as="select" as="select"
@ -76,7 +83,11 @@ const Config: React.FC<IConfigProps> = ({ show, config, setConfig }) => {
disabled={!stashBoxes.length} disabled={!stashBoxes.length}
onChange={handleInstanceSelect} onChange={handleInstanceSelect}
> >
{!stashBoxes.length && <option>No instances found</option>} {!stashBoxes.length && (
<option>
<FormattedMessage id="performer_tagger.config.no_instances_found" />
</option>
)}
{stashConfig?.general.stashBoxes.map((i) => ( {stashConfig?.general.stashBoxes.map((i) => (
<option value={i.endpoint} key={i.endpoint}> <option value={i.endpoint} key={i.endpoint}>
{i.endpoint} {i.endpoint}

View file

@ -110,7 +110,9 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
setSearchResults(results); setSearchResults(results);
setSearchErrors({ setSearchErrors({
...searchErrors, ...searchErrors,
[performerID]: "Network Error", [performerID]: intl.formatMessage({
id: "performer_tagger.network_error",
}),
}); });
}); });
@ -178,11 +180,16 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
setError({ setError({
...error, ...error,
[performerID]: { [performerID]: {
message: `Failed to save performer "${modalPerformer?.name}"`, message: intl.formatMessage(
{ id: "performer_tagger.failed_to_save_performer" },
{ performer: modalPerformer?.name }
),
details: details:
res?.errors?.[0].message === res?.errors?.[0].message ===
"UNIQUE constraint failed: performers.checksum" "UNIQUE constraint failed: performers.checksum"
? "Name already exists" ? intl.formatMessage({
id: "performer_tagger.name_already_exists",
})
: res?.errors?.[0].message, : res?.errors?.[0].message,
}, },
}); });
@ -198,7 +205,9 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
if (!isTagged && hasStashIDs) { if (!isTagged && hasStashIDs) {
mainContent = ( mainContent = (
<div className="text-left"> <div className="text-left">
<h5 className="text-bold">Performer already tagged</h5> <h5 className="text-bold">
<FormattedMessage id="performer_tagger.performer_already_tagged" />
</h5>
</div> </div>
); );
} else if (!isTagged && !hasStashIDs) { } else if (!isTagged && !hasStashIDs) {
@ -239,7 +248,9 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
} else if (isTagged) { } else if (isTagged) {
mainContent = ( mainContent = (
<div className="d-flex flex-column text-left"> <div className="d-flex flex-column text-left">
<h5>Performer successfully tagged:</h5> <h5>
<FormattedMessage id="performer_tagger.performer_successfully_tagged" />
</h5>
<h6> <h6>
<Link className="bold" to={`/performers/${performer.id}`}> <Link className="bold" to={`/performers/${performer.id}`}>
{taggedPerformers[performer.id].name} {taggedPerformers[performer.id].name}
@ -285,7 +296,7 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
{loadingUpdate === stashID.stash_id ? ( {loadingUpdate === stashID.stash_id ? (
<LoadingIndicator inline small message="" /> <LoadingIndicator inline small message="" />
) : ( ) : (
"Refresh" <FormattedMessage id="actions.refresh" />
)} )}
</Button> </Button>
)} )}
@ -312,7 +323,9 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
); );
} else if (searchResults[performer.id]?.length === 0) { } else if (searchResults[performer.id]?.length === 0) {
subContent = ( subContent = (
<div className="text-danger font-weight-bold">No results found.</div> <div className="text-danger font-weight-bold">
<FormattedMessage id="performer_tagger.no_results_found" />
</div>
); );
} }
@ -340,7 +353,9 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
onSave={handlePerformerUpdate} onSave={handlePerformerUpdate}
excludedPerformerFields={config.excludedPerformerFields} excludedPerformerFields={config.excludedPerformerFields}
icon="tags" icon="tags"
header="Update Performer" header={intl.formatMessage({
id: "performer_tagger.update_performer",
})}
endpoint={selectedEndpoint.endpoint} endpoint={selectedEndpoint.endpoint}
/> />
)} )}
@ -367,8 +382,15 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
<Modal <Modal
show={showBatchUpdate} show={showBatchUpdate}
icon="tags" icon="tags"
header="Update Performers" header={intl.formatMessage({
accept={{ text: "Update Performers", onClick: handleBatchUpdate }} id: "performer_tagger.update_performers",
})}
accept={{
text: intl.formatMessage({
id: "performer_tagger.update_performers",
}),
onClick: handleBatchUpdate,
}}
cancel={{ cancel={{
text: intl.formatMessage({ id: "actions.cancel" }), text: intl.formatMessage({ id: "actions.cancel" }),
variant: "danger", variant: "danger",
@ -378,13 +400,15 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
> >
<Form.Group> <Form.Group>
<Form.Label> <Form.Label>
<h6>Performer selection</h6> <h6>
<FormattedMessage id="performer_tagger.performer_selection" />
</h6>
</Form.Label> </Form.Label>
<Form.Check <Form.Check
id="query-page" id="query-page"
type="radio" type="radio"
name="performer-query" name="performer-query"
label="Current page" label={<FormattedMessage id="performer_tagger.current_page" />}
defaultChecked defaultChecked
onChange={() => setQueryAll(false)} onChange={() => setQueryAll(false)}
/> />
@ -392,53 +416,71 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
id="query-all" id="query-all"
type="radio" type="radio"
name="performer-query" name="performer-query"
label="All performers in the database" label={intl.formatMessage({
id: "performer_tagger.query_all_performers_in_the_database",
})}
defaultChecked={false} defaultChecked={false}
onChange={() => setQueryAll(true)} onChange={() => setQueryAll(true)}
/> />
</Form.Group> </Form.Group>
<Form.Group> <Form.Group>
<Form.Label> <Form.Label>
<h6>Tag Status</h6> <h6>
<FormattedMessage id="performer_tagger.tag_status" />
</h6>
</Form.Label> </Form.Label>
<Form.Check <Form.Check
id="untagged-performers" id="untagged-performers"
type="radio" type="radio"
name="performer-refresh" name="performer-refresh"
label="Untagged performers" label={intl.formatMessage({
id: "performer_tagger.untagged_performers",
})}
defaultChecked defaultChecked
onChange={() => setRefresh(false)} onChange={() => setRefresh(false)}
/> />
<Form.Text> <Form.Text>
Updating untagged performers will try to match any performers that <FormattedMessage id="performer_tagger.updating_untagged_performers_description" />
lack a stashid and update the metadata.
</Form.Text> </Form.Text>
<Form.Check <Form.Check
id="tagged-performers" id="tagged-performers"
type="radio" type="radio"
name="performer-refresh" name="performer-refresh"
label="Refresh tagged performers" label={intl.formatMessage({
id: "performer_tagger.refresh_tagged_performers",
})}
defaultChecked={false} defaultChecked={false}
onChange={() => setRefresh(true)} onChange={() => setRefresh(true)}
/> />
<Form.Text> <Form.Text>
Refreshing will update the data of any tagged performers from the <FormattedMessage id="performer_tagger.refreshing_will_update_the_data" />
stash-box instance.
</Form.Text> </Form.Text>
</Form.Group> </Form.Group>
<b>{`${ <b>
queryAll <FormattedMessage
? allPerformers?.findPerformers.count id="performer_tagger.number_of_performers_will_be_processed"
: performers.filter((p) => values={{
refresh ? p.stash_ids.length > 0 : p.stash_ids.length === 0 performer_count: queryAll
).length ? allPerformers?.findPerformers.count
} performers will be processed`}</b> : performers.filter((p) =>
refresh ? p.stash_ids.length > 0 : p.stash_ids.length === 0
).length,
}}
/>
</b>
</Modal> </Modal>
<Modal <Modal
show={showBatchAdd} show={showBatchAdd}
icon="star" icon="star"
header="Add New Performers" header={intl.formatMessage({
accept={{ text: "Add Performers", onClick: handleBatchAdd }} id: "performer_tagger.add_new_performers",
})}
accept={{
text: intl.formatMessage({
id: "performer_tagger.add_new_performers",
}),
onClick: handleBatchAdd,
}}
cancel={{ cancel={{
text: intl.formatMessage({ id: "actions.cancel" }), text: intl.formatMessage({ id: "actions.cancel" }),
variant: "danger", variant: "danger",
@ -450,20 +492,21 @@ const PerformerTaggerList: React.FC<IPerformerTaggerListProps> = ({
className="text-input" className="text-input"
as="textarea" as="textarea"
ref={performerInput} ref={performerInput}
placeholder="Performer names separated by comma" placeholder={intl.formatMessage({
id: "performer_tagger.performer_names_separated_by_comma",
})}
rows={6} rows={6}
/> />
<Form.Text> <Form.Text>
Any names entered will be queried from the remote Stash-Box instance <FormattedMessage id="performer_tagger.any_names_entered_will_be_queried" />
and added if found. Only exact matches will be considered a match.
</Form.Text> </Form.Text>
</Modal> </Modal>
<div className="ml-auto mb-3"> <div className="ml-auto mb-3">
<Button onClick={() => setShowBatchAdd(true)}> <Button onClick={() => setShowBatchAdd(true)}>
Batch Add Performers <FormattedMessage id="performer_tagger.batch_add_performers" />
</Button> </Button>
<Button className="ml-3" onClick={() => setShowBatchUpdate(true)}> <Button className="ml-3" onClick={() => setShowBatchUpdate(true)}>
Batch Update Performers <FormattedMessage id="performer_tagger.batch_update_performers" />
</Button> </Button>
</div> </div>
<div className={CLASSNAME}>{renderPerformers()}</div> <div className={CLASSNAME}>{renderPerformers()}</div>
@ -477,6 +520,7 @@ interface ITaggerProps {
export const PerformerTagger: React.FC<ITaggerProps> = ({ performers }) => { export const PerformerTagger: React.FC<ITaggerProps> = ({ performers }) => {
const jobsSubscribe = useJobsSubscribe(); const jobsSubscribe = useJobsSubscribe();
const intl = useIntl();
const { configuration: stashConfig } = React.useContext(ConfigurationContext); const { configuration: stashConfig } = React.useContext(ConfigurationContext);
const [{ data: config }, setConfig] = useLocalForage<ITaggerConfig>( const [{ data: config }, setConfig] = useLocalForage<ITaggerConfig>(
LOCAL_FORAGE_KEY, LOCAL_FORAGE_KEY,
@ -567,7 +611,9 @@ export const PerformerTagger: React.FC<ITaggerProps> = ({ performers }) => {
: undefined; : undefined;
return ( return (
<Form.Group className="px-4"> <Form.Group className="px-4">
<h5>Status: Tagging performers</h5> <h5>
<FormattedMessage id="performer_tagger.status_tagging_performers" />
</h5>
{progress !== undefined && ( {progress !== undefined && (
<ProgressBar <ProgressBar
animated animated
@ -582,12 +628,18 @@ export const PerformerTagger: React.FC<ITaggerProps> = ({ performers }) => {
if (batchJobID !== undefined) { if (batchJobID !== undefined) {
return ( return (
<Form.Group className="px-4"> <Form.Group className="px-4">
<h5>Status: Tagging job queued</h5> <h5>
<FormattedMessage id="performer_tagger.status_tagging_job_queued" />
</h5>
</Form.Group> </Form.Group>
); );
} }
} }
const showHideConfigId = showConfig
? "actions.hide_configuration"
: "actions.show_configuration";
return ( return (
<> <>
<Manual <Manual
@ -601,15 +653,15 @@ export const PerformerTagger: React.FC<ITaggerProps> = ({ performers }) => {
<> <>
<div className="row mb-2 no-gutters"> <div className="row mb-2 no-gutters">
<Button onClick={() => setShowConfig(!showConfig)} variant="link"> <Button onClick={() => setShowConfig(!showConfig)} variant="link">
{showConfig ? "Hide" : "Show"} Configuration {intl.formatMessage({ id: showHideConfigId })}
</Button> </Button>
<Button <Button
className="ml-auto" className="ml-auto"
onClick={() => setShowManual(true)} onClick={() => setShowManual(true)}
title="Help" title={intl.formatMessage({ id: "help" })}
variant="link" variant="link"
> >
Help <FormattedMessage id="help" />
</Button> </Button>
</div> </div>
@ -634,8 +686,7 @@ export const PerformerTagger: React.FC<ITaggerProps> = ({ performers }) => {
) : ( ) : (
<div className="my-4"> <div className="my-4">
<h3 className="text-center mt-4"> <h3 className="text-center mt-4">
To use the performer tagger a stash-box instance needs to be <FormattedMessage id="performer_tagger.to_use_the_performer_tagger" />
configured.
</h3> </h3>
<h5 className="text-center"> <h5 className="text-center">
Please see{" "} Please see{" "}

View file

@ -44,6 +44,7 @@
"generate_thumb_from_current": "Generate thumbnail from current", "generate_thumb_from_current": "Generate thumbnail from current",
"hash_migration": "hash migration", "hash_migration": "hash migration",
"hide": "Hide", "hide": "Hide",
"hide_configuration": "Hide Configuration",
"identify": "Identify", "identify": "Identify",
"ignore": "Ignore", "ignore": "Ignore",
"import": "Import…", "import": "Import…",
@ -87,6 +88,7 @@
"set_front_image": "Front image…", "set_front_image": "Front image…",
"set_image": "Set image…", "set_image": "Set image…",
"show": "Show", "show": "Show",
"show_configuration": "Show Configuration",
"skip": "Skip", "skip": "Skip",
"stop": "Stop", "stop": "Stop",
"submit_stash_box": "Submit to Stash-Box", "submit_stash_box": "Submit to Stash-Box",
@ -99,7 +101,8 @@
"temp_enable": "Enable temporarily…", "temp_enable": "Enable temporarily…",
"use_default": "Use default", "use_default": "Use default",
"view_random": "View Random", "view_random": "View Random",
"continue": "Continue" "continue": "Continue",
"submit": "Submit"
}, },
"actions_name": "Actions", "actions_name": "Actions",
"age": "Age", "age": "Age",
@ -909,5 +912,46 @@
"url": "URL", "url": "URL",
"videos": "Videos", "videos": "Videos",
"weight": "Weight", "weight": "Weight",
"years_old": "years old" "years_old": "years old",
"stashbox": {
"selected_stash_box": "Selected Stash-Box endpoint",
"submission_successful": "Submission successful",
"submission_failed": "Submission failed",
"go_review_draft": "Go to {endpoint_name} to review draft."
},
"performer_tagger": {
"network_error": "Network Error",
"failed_to_save_performer": "Failed to save performer \"{performer}\"",
"name_already_exists": "Name already exists",
"performer_already_tagged": "Performer already tagged",
"current_page": "Current page",
"performer_successfully_tagged": "Performer successfully tagged:",
"no_results_found": "No results found.",
"update_performer": "Update Performer",
"update_performers": "Update Performers",
"query_all_performers_in_the_database": "All performers in the database",
"tag_status": "Tag Status",
"untagged_performers": "Untagged performers",
"updating_untagged_performers_description": "Updating untagged performers will try to match any performers that lack a stashid and update the metadata.",
"refresh_tagged_performers": "Refresh tagged performers",
"refreshing_will_update_the_data": "Refreshing will update the data of any tagged performers from the stash-box instance.",
"add_new_performers": "Add New Performers",
"to_use_the_performer_tagger": "To use the performer tagger a stash-box instance needs to be configured.",
"performer_selection": "Performer selection",
"performer_names_separated_by_comma": "Performer names separated by comma",
"any_names_entered_will_be_queried": "Any names entered will be queried from the remote Stash-Box instance and added if found. Only exact matches will be considered a match.",
"batch_add_performers": "Batch Add Performers",
"batch_update_performers": "Batch Update Performers",
"status_tagging_performers": "Status: Tagging performers",
"status_tagging_job_queued": "Status: Tagging job queued",
"number_of_performers_will_be_processed": "{performer_count} performers will be processed",
"config": {
"excluded_fields": "Excluded fields:",
"these_fields_will_not_be_changed_when_updating_performers": "These fields will not be changed when updating performers.",
"edit_excluded_fields": "Edit Excluded Fields",
"no_fields_are_excluded": "No fields are excluded",
"active_stash-box_instance": "Active stash-box instance:",
"no_instances_found": "No instances found"
}
}
} }

View file

@ -97,7 +97,9 @@
"temp_disable": "暫時關閉…", "temp_disable": "暫時關閉…",
"temp_enable": "暫時啟用…", "temp_enable": "暫時啟用…",
"use_default": "使用預設選項", "use_default": "使用預設選項",
"view_random": "隨機開啟" "view_random": "隨機開啟",
"submit": "提交",
"submit_stash_box": "提交至 Stash-Box"
}, },
"actions_name": "動作", "actions_name": "動作",
"age": "年齡", "age": "年齡",
@ -903,5 +905,46 @@
"url": "連結", "url": "連結",
"videos": "影片", "videos": "影片",
"weight": "體重", "weight": "體重",
"years_old": "歲" "years_old": "歲",
"stashbox": {
"go_review_draft": "到 {endpoint_name} 預覽草稿。",
"submission_failed": "提交失敗",
"submission_successful": "提交成功",
"selected_stash_box": "已選擇的 Stash-Box 端點"
},
"performer_tagger": {
"add_new_performers": "新增演員",
"any_names_entered_will_be_queried": "如果輸入的名稱有在設定的 Stash-Box 端點上找到的話,則相對應的結果將會被自動新增。只有完全符合的結果才會被視為匹配。",
"batch_update_performers": "大量更新演員",
"batch_add_performers": "大量新增演員",
"current_page": "目前頁面",
"name_already_exists": "名稱已存在",
"failed_to_save_performer": "無法新增演員「{performer}」",
"no_results_found": "找不到結果。",
"network_error": "網路錯誤",
"performer_names_separated_by_comma": "演員名稱 (以逗號分隔)",
"performer_already_tagged": "演員資料早已新增",
"performer_successfully_tagged": "成功新增演員資料:",
"performer_selection": "選取演員",
"query_all_performers_in_the_database": "查詢所有資料庫中的演員",
"refresh_tagged_performers": "重新整理已新增的演員資料",
"status_tagging_job_queued": "狀態:已排成資料標記",
"refreshing_will_update_the_data": "重新整理資料將會把任何現有的演員資料重新與 Stash-Box 端點上的資料同步。",
"status_tagging_performers": "狀態:新增演員資料中",
"tag_status": "標記狀態",
"to_use_the_performer_tagger": "在使用演員標記工具前,請先設定 Stash-Box 端點。",
"update_performer": "更新演員資料",
"untagged_performers": "未標記的演員",
"update_performers": "更新演員",
"updating_untagged_performers_description": "更新未標記的演員將試著把尚有 stashid 的演員在 Stash-Box 上找尋對應的資料,並將其資料加入至本地的 Metadata 中。",
"number_of_performers_will_be_processed": "將自動處理 {performer_count} 個演員",
"config": {
"active_stash-box_instance": "目前使用的 Stash-box",
"edit_excluded_fields": "編輯排除的種類",
"no_fields_are_excluded": "尚無排除任何種類",
"excluded_fields": "已排除種類:",
"these_fields_will_not_be_changed_when_updating_performers": "以下種類的資訊將不會於更新演員時更動。",
"no_instances_found": "尚未設定端點"
}
}
} }