Provide an entry for setting the Tencent Cloud Translation API key.
This commit is contained in:
1 parent
79b5f6dad2
commit
edcd29d4bb
4 files changed
+198
-1
No files matched your search
@@ -1,6 +1,6 @@
|
||||
import { applyCandidateArrange, applyDropdownValue, applyToggleState } from './shared';
|
||||
import { applyAppearanceConfig, updateCandidatePreviewHelpcode } from './appearance';
|
||||
import { applyFrequencyConfig, applyInputConfig, applyZhEnMixedInputConfig } from './input';
|
||||
import { applyFrequencyConfig, applyInputConfig, applyTencentTmtConfig, applyZhEnMixedInputConfig } from './input';
|
||||
import { applyVoiceConfig } from './voice';
|
||||
import { applyAiConfig } from './ai-settings';
|
||||
import { applyFloatingToolbarAppearanceConfig, applyFloatingToolbarItemsConfig } from './floating-toolbar';
|
||||
@@ -121,8 +121,12 @@ export function setupConfigSync(): void {
|
||||
payload.data?.general?.cn_en_mixed_input,
|
||||
payload.data?.general?.cn_en_mixed_input_min_chars
|
||||
);
|
||||
applyTencentTmtConfig(payload.data?.tencent_tmt);
|
||||
if (typeof payload.data?.general?.candidate_translations === 'boolean') {
|
||||
applyToggleState('candidateTranslationsToggleBtn', payload.data.general.candidate_translations);
|
||||
document.getElementById('candidateTranslationApiOptions')?.classList.toggle(
|
||||
'is-disabled', !payload.data.general.candidate_translations
|
||||
);
|
||||
}
|
||||
if (typeof payload.data?.general?.emoji_mixed_input === 'boolean') {
|
||||
applyToggleState('emojiMixedInputToggleBtn', payload.data.general.emoji_mixed_input);
|
||||
|
||||
@@ -83,6 +83,26 @@ export function applyZhEnMixedInputConfig(enabled?: boolean, minChars?: number):
|
||||
}
|
||||
}
|
||||
|
||||
function syncCandidateTranslationOptions(enabled: boolean): void {
|
||||
document.getElementById('candidateTranslationApiOptions')?.classList.toggle('is-disabled', !enabled);
|
||||
}
|
||||
|
||||
function syncCandidateTranslationWarning(): void {
|
||||
const secretId = (document.getElementById('tencentTmtSecretId') as HTMLInputElement | null)?.value.trim();
|
||||
const secretKey = (document.getElementById('tencentTmtSecretKey') as HTMLInputElement | null)?.value.trim();
|
||||
document.getElementById('candidateTranslationApiWarning')?.classList.toggle(
|
||||
'is-hidden', Boolean(secretId && secretKey)
|
||||
);
|
||||
}
|
||||
|
||||
export function applyTencentTmtConfig(config: Record<string, unknown> | undefined): void {
|
||||
const secretId = document.getElementById('tencentTmtSecretId') as HTMLInputElement | null;
|
||||
const secretKey = document.getElementById('tencentTmtSecretKey') as HTMLInputElement | null;
|
||||
if (secretId && typeof config?.secret_id === 'string') secretId.value = config.secret_id;
|
||||
if (secretKey && typeof config?.secret_key === 'string') secretKey.value = config.secret_key;
|
||||
syncCandidateTranslationWarning();
|
||||
}
|
||||
|
||||
export function setupInput(): void {
|
||||
document.querySelectorAll<HTMLInputElement>('input[name="input-mode"]').forEach((radio) => {
|
||||
radio.addEventListener('change', () => {
|
||||
@@ -145,8 +165,32 @@ export function setupInput(): void {
|
||||
updateConfig('general.cn_en_mixed_input', active);
|
||||
});
|
||||
setupToggleButton('candidateTranslationsToggleBtn', (active) => {
|
||||
syncCandidateTranslationOptions(active);
|
||||
updateConfig('general.candidate_translations', active);
|
||||
});
|
||||
const translationFields: Record<string, string> = {
|
||||
tencentTmtSecretId: 'tencent_tmt.secret_id',
|
||||
tencentTmtSecretKey: 'tencent_tmt.secret_key'
|
||||
};
|
||||
Object.entries(translationFields).forEach(([id, path]) => {
|
||||
const input = document.getElementById(id) as HTMLInputElement | null;
|
||||
input?.addEventListener('change', () => {
|
||||
input.value = input.value.trim();
|
||||
updateConfig(path, input.value);
|
||||
syncCandidateTranslationWarning();
|
||||
});
|
||||
});
|
||||
const secretKey = document.getElementById('tencentTmtSecretKey') as HTMLInputElement | null;
|
||||
const visibility = document.getElementById('tencentTmtSecretKeyVisibility') as HTMLButtonElement | null;
|
||||
visibility?.addEventListener('click', () => {
|
||||
if (!secretKey) return;
|
||||
const show = secretKey.type === 'password';
|
||||
secretKey.type = show ? 'text' : 'password';
|
||||
visibility.setAttribute('aria-pressed', String(show));
|
||||
const label = show ? '隐藏 SecretKey' : '显示 SecretKey';
|
||||
visibility.setAttribute('aria-label', label);
|
||||
visibility.title = label;
|
||||
});
|
||||
setupDropdownMenu(
|
||||
'zhEnTriggerLengthBtn',
|
||||
'zhEnTriggerLengthMenu',
|
||||
|
||||
@@ -125,6 +125,38 @@
|
||||
<div class="ftb-toggle-knob"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="translation-api-options" id="candidateTranslationApiOptions">
|
||||
<div class="input-option-divider"></div>
|
||||
<div class="translation-api-heading">
|
||||
<div class="section-title">腾讯云 API 凭据</div>
|
||||
<div class="input-setting-description">用于本地词库未命中时请求机器翻译,凭据仅保存在本机配置文件中</div>
|
||||
</div>
|
||||
<div class="translation-api-grid">
|
||||
<label class="translation-api-field">
|
||||
<span>SecretId</span>
|
||||
<input id="tencentTmtSecretId" type="text" autocomplete="off" spellcheck="false" placeholder="AKID...">
|
||||
</label>
|
||||
<label class="translation-api-field">
|
||||
<span>SecretKey</span>
|
||||
<span class="translation-secret-input">
|
||||
<input id="tencentTmtSecretKey" type="password" autocomplete="new-password" spellcheck="false" placeholder="SecretKey">
|
||||
<button id="tencentTmtSecretKeyVisibility" class="translation-secret-toggle" type="button"
|
||||
aria-label="显示 SecretKey" aria-pressed="false" title="显示 SecretKey">
|
||||
<svg class="translation-secret-icon translation-secret-icon-show" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M2.5 12s3.5-6 9.5-6 9.5 6 9.5 6-3.5 6-9.5 6-9.5-6-9.5-6Z"></path>
|
||||
<circle cx="12" cy="12" r="2.6"></circle>
|
||||
</svg>
|
||||
<svg class="translation-secret-icon translation-secret-icon-hide" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="m3 3 18 18"></path>
|
||||
<path d="M10.6 6.1A9.6 9.6 0 0 1 12 6c6 0 9.5 6 9.5 6a16 16 0 0 1-2.2 3"></path>
|
||||
<path d="M6.2 6.3C3.8 8.1 2.5 12 2.5 12s3.5 6 9.5 6a9 9 0 0 0 3-.5"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="translation-api-warning" id="candidateTranslationApiWarning" role="status">请填写 SecretId 和 SecretKey 后使用云端翻译</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section">
|
||||
|
||||
@@ -45,6 +45,123 @@
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.translation-api-options {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.translation-api-options.is-disabled {
|
||||
opacity: 0.45;
|
||||
}
|
||||
|
||||
.translation-api-options.is-disabled .translation-api-grid {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.translation-api-heading {
|
||||
padding-top: 14px;
|
||||
}
|
||||
|
||||
.translation-api-grid {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 16px;
|
||||
margin-top: 14px;
|
||||
}
|
||||
|
||||
.translation-api-field {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 7px;
|
||||
color: var(--text-secondary);
|
||||
font-size: 12px;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.translation-api-field input {
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 10px 12px;
|
||||
color: var(--text-color);
|
||||
background: var(--surface-sunken);
|
||||
border: 1px solid var(--control-border);
|
||||
border-radius: 6px;
|
||||
outline: none;
|
||||
font: 13px Consolas, "Cascadia Mono", monospace;
|
||||
}
|
||||
|
||||
.translation-api-field input:focus {
|
||||
border-color: var(--accent-color);
|
||||
background: var(--control-bg);
|
||||
box-shadow: 0 0 0 2px color-mix(in srgb, var(--accent-color) 20%, transparent);
|
||||
}
|
||||
|
||||
.translation-secret-input {
|
||||
position: relative;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.translation-secret-input input {
|
||||
padding-right: 42px;
|
||||
}
|
||||
|
||||
.translation-secret-input input::-ms-reveal,
|
||||
.translation-secret-input input::-ms-clear {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.translation-secret-toggle {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 5px;
|
||||
display: grid;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
padding: 0;
|
||||
color: var(--text-muted);
|
||||
background: transparent;
|
||||
border: 0;
|
||||
border-radius: 5px;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
place-items: center;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
|
||||
.translation-secret-toggle:hover {
|
||||
color: var(--text-color);
|
||||
background: color-mix(in srgb, var(--text-color) 8%, transparent);
|
||||
}
|
||||
|
||||
.translation-secret-icon {
|
||||
grid-area: 1 / 1;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
fill: none;
|
||||
stroke: currentColor;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 1.7;
|
||||
}
|
||||
|
||||
.translation-secret-icon-hide,
|
||||
.translation-secret-toggle[aria-pressed="true"] .translation-secret-icon-show {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.translation-secret-toggle[aria-pressed="true"] .translation-secret-icon-hide {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.translation-api-warning {
|
||||
margin-top: 10px;
|
||||
color: #d7a64a;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.translation-api-warning.is-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* 输入 -> 双拼方案 */
|
||||
.shuangpin-option-content {
|
||||
display: flex;
|
||||
|
||||
Reference in new issue
Block a user