feat: support placeholder selection

This commit is contained in:
Gabe
2025-10-01 13:22:22 +08:00
parent d563521eb1
commit 96a7a41759
4 changed files with 86 additions and 30 deletions

View File

@@ -138,8 +138,8 @@ export const BUILTIN_STONES = [
"machine-like", // 机器风格
"concise", // 简明风格
];
export const BUILTIN_PLACEHOULDERS = ["{ }", "{{ }}", "[ ]", "[[ ]]"];
export const BUILTIN_TAG_NAMES = ["i", "a", "span"];
export const BUILTIN_PLACEHOLDERS = ["{ }", "{{ }}", "[ ]", "[[ ]]"];
export const BUILTIN_PLACETAGS = ["i", "a", "x", "span"];
export const OPT_LANGS_TO = [
["en", "English - English"],
@@ -357,10 +357,10 @@ const defaultApi = {
model: "", // 模型名称
systemPrompt: defaultSystemPrompt,
userPrompt: "",
tone: "neutral", // 翻译风格
placeholder: "{ }", // 占位符todo: 备用)
tagName: "i", // 标签符 todo: 备用)
aiTerms: false, // AI智能专业术语 todo: 备用)
tone: BUILTIN_STONES[0], // 翻译风格
placeholder: BUILTIN_PLACEHOLDERS[0], // 占位符
placetag: [BUILTIN_PLACETAGS[0]], // 占位标签
// aiTerms: false, // AI智能专业术语 todo: 备用)
customHeader: "",
customBody: "",
reqHook: "", // request 钩子函数

View File

@@ -1493,4 +1493,14 @@ export const I18N = {
en: `Mini/Regular Mode`,
zh_TW: `迷你/常規模式`,
},
api_placeholder: {
zh: `占位符`,
en: `Placeholder`,
zh_TW: `佔位符`,
},
api_placetag: {
zh: `占位标签`,
en: `Placeholder tags`,
zh_TW: `佔位標`,
},
};

View File

@@ -209,13 +209,6 @@ export class Translator {
/^\d{1,2}:\d{2}(:\d{2})?$/,
];
// 占位符
static PLACEHOLDER = {
startDelimiter: "{",
endDelimiter: "}",
tagName: "i",
};
static DEFAULT_OPTIONS = DEFAULT_SETTING; // 默认配置
static DEFAULT_RULE = GLOBLA_RULE; // 默认规则
@@ -280,6 +273,12 @@ export class Translator {
#docInfo = {}; // 网页信息
#textClass = {}; // 译文样式class
#textSheet = ""; // 译文样式字典
#apiSetting = null;
#placeholder = {
startDelimiter: "{",
endDelimiter: "}",
tagName: "i",
};
#isUserscript = false;
#transboxManager = null; // 划词翻译
@@ -312,6 +311,18 @@ export class Translator {
constructor(rule = {}, setting = {}, isUserscript) {
this.#setting = { ...Translator.DEFAULT_OPTIONS, ...setting };
this.#rule = { ...Translator.DEFAULT_RULE, ...rule };
this.#apiSetting =
this.#setting.transApis.find(
(api) => api.apiSlug === this.#rule.apiSlug
) || DEFAULT_API_SETTING;
const [startDelimiter, endDelimiter] =
this.#apiSetting.placeholder.split(" ");
this.#placeholder = {
startDelimiter,
endDelimiter,
tagName: this.#apiSetting.placetag,
};
this.#isUserscript = isUserscript;
this.#eventName = genEventName();
this.#docInfo = {
@@ -437,11 +448,9 @@ export class Translator {
#createPlaceholderRegex() {
const escapedStart = Translator.escapeRegex(
Translator.PLACEHOLDER.startDelimiter
);
const escapedEnd = Translator.escapeRegex(
Translator.PLACEHOLDER.endDelimiter
this.#placeholder.startDelimiter
);
const escapedEnd = Translator.escapeRegex(this.#placeholder.endDelimiter);
const patternString = `(${escapedStart}\\d+${escapedEnd}|<\\/?\\w+\\d+>)`;
const flags = "g";
return new RegExp(patternString, flags);
@@ -1031,10 +1040,11 @@ export class Translator {
let replaceCounter = 0; // {{n}}
let wrapCounter = 0; // <tagn>
const placeholderMap = new Map();
const { startDelimiter, endDelimiter } = this.#placeholder;
const pushReplace = (html) => {
replaceCounter++;
const placeholder = `${Translator.PLACEHOLDER.startDelimiter}${replaceCounter}${Translator.PLACEHOLDER.endDelimiter}`;
const placeholder = `${startDelimiter}${replaceCounter}${endDelimiter}`;
placeholderMap.set(placeholder, html);
return placeholder;
};
@@ -1095,8 +1105,8 @@ export class Translator {
if (Translator.TAGS.WARP.has(node.tagName)) {
wrapCounter++;
const startPlaceholder = `<${Translator.PLACEHOLDER.tagName}${wrapCounter}>`;
const endPlaceholder = `</${Translator.PLACEHOLDER.tagName}${wrapCounter}>`;
const startPlaceholder = `<${this.#placeholder.tagName}${wrapCounter}>`;
const endPlaceholder = `</${this.#placeholder.tagName}${wrapCounter}>`;
placeholderMap.set(startPlaceholder, buildOpeningTag(node));
placeholderMap.set(endPlaceholder, `</${node.localName}>`);
return `${startPlaceholder}${innerContent}${endPlaceholder}`;
@@ -1139,16 +1149,13 @@ export class Translator {
// 发起翻译请求
#translateFetch(text, deLang = "") {
const { apiSlug, fromLang, toLang } = this.#rule;
const apiSetting =
this.#setting.transApis.find((api) => api.apiSlug === apiSlug) ||
DEFAULT_API_SETTING;
const { fromLang, toLang } = this.#rule;
return apiTranslate({
text,
fromLang: deLang || fromLang,
toLang,
apiSetting,
apiSetting: this.#apiSetting,
docInfo: this.#docInfo,
});
}

View File

@@ -40,8 +40,8 @@ import {
OPT_ALL_TYPES,
API_SPE_TYPES,
BUILTIN_STONES,
// BUILTIN_PLACEHOULDERS,
// BUILTIN_TAG_NAMES,
BUILTIN_PLACEHOLDERS,
BUILTIN_PLACETAGS,
} from "../../config";
function TestButton({ apiSlug, api }) {
@@ -233,8 +233,8 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
useContext = false,
contextSize = DEFAULT_CONTEXT_SIZE,
tone = "neutral",
// placeholder = "{ }",
// tagName = "i",
placeholder = BUILTIN_PLACEHOLDERS[0],
placetag = BUILTIN_PLACETAGS[0],
// aiTerms = false,
} = formData;
@@ -360,7 +360,7 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
freeSolo
size="small"
fullWidth
options={BUILTIN_PLACEHOULDERS}
options={BUILTIN_PLACEHOLDERS}
name="placeholder"
label={i18n("placeholder")}
value={placeholder}
@@ -610,6 +610,45 @@ function ApiFields({ apiSlug, isUserApi, deleteApi }) {
{showMore && (
<>
<Box>
<Grid container spacing={2} columns={12}>
<Grid item xs={12} sm={12} md={6} lg={3}>
<TextField
select
fullWidth
size="small"
name="placeholder"
value={placeholder}
label={i18n("api_placeholder")}
onChange={handleChange}
>
{BUILTIN_PLACEHOLDERS.map((item) => (
<MenuItem key={item} value={item}>
{item}
</MenuItem>
))}
</TextField>
</Grid>
<Grid item xs={12} sm={12} md={6} lg={3}>
<TextField
select
fullWidth
size="small"
name="placetag"
value={placetag}
label={i18n("api_placetag")}
onChange={handleChange}
>
{BUILTIN_PLACETAGS.map((item) => (
<MenuItem key={item} value={item}>
{`<${item}N>`}
</MenuItem>
))}
</TextField>
</Grid>
</Grid>
</Box>
<TextField
size="small"
label={i18n("custom_header")}