jacobinwwey_obsidian-NotEMD/scripts/translate-readme-settings-guide.cjs
aliyun1121003339 bac0fb8dc1 feat(diagrams): add managed CircuitikZ runtime and fix history scrolling
Add an optional ownership-scoped Tectonic environment with secure installation, native compile verification, and topology-preserving repair support. Harden CircuitikZ generation and preview routing, fix the history drawer scroll model, and synchronize bilingual architecture, user guidance, and localized README documentation.
2026-07-20 03:49:24 +08:00

71 lines
3.6 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const endpoint = 'http://100.80.17.113:301/v1/chat/completions';
const model = 'hy-mt2-7b';
const marker = '<!-- notemd-settings-discovery-guide -->';
const source = `${marker}
## Settings discovery, diagram history, CircuitikZ, and safe batch folders
The Notemd settings page provides fuzzy search, large category navigation, and per-setting favorites stored for the current Vault.
- Diagram history is stored at Vault scope, ordered newest first, searchable and paginated in groups of 20. Removing a history record does not delete generated files.
- Diagram preview export PPI controls PNG and PDF clarity. SVG remains vector-based.
- Preferred diagram type and preferred source format are separate choices.
- Desktop users can open the optional CircuitikZ native compile environment to reuse system Tectonic/pdflatex, select a custom compiler, or explicitly install the pinned managed Tectonic runtime. Preview, SVG, PNG, and preview PDF exports do not require LaTeX.
- Advanced batch file selection enables saved selection profiles and rule previews.
- A missing batch target folder can be created after confirmation, with an option to remember automatic creation for future missing folders.
- An existing non-empty folder requires one confirmation before the whole batch, never one confirmation per generated file.
- Developer mode reveals provider diagnostics and advanced troubleshooting controls.
`;
const languageNames = {
ar: 'Arabic', bn: 'Bengali', cs: 'Czech', da: 'Danish', de: 'German', el: 'Greek', es: 'Spanish',
fi: 'Finnish', fr: 'French', he: 'Hebrew', hi: 'Hindi', hu: 'Hungarian', id: 'Indonesian', it: 'Italian',
ja: 'Japanese', ko: 'Korean', ms: 'Malay', nl: 'Dutch', no: 'Norwegian', pl: 'Polish', pt: 'Portuguese',
ro: 'Romanian', ru: 'Russian', sv: 'Swedish', th: 'Thai', tr: 'Turkish', uk: 'Ukrainian', vi: 'Vietnamese',
zh_Hant: 'Traditional Chinese'
};
async function translate(locale) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10 * 60 * 1000);
try {
const response = await fetch(endpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
signal: controller.signal,
body: JSON.stringify({
model,
temperature: 0.1,
max_tokens: 1800,
messages: [
{ role: 'system', content: `Translate Markdown into ${languageNames[locale]}. Preserve the HTML marker, headings, bullets, technical names, and Markdown structure. Return only translated Markdown.` },
{ role: 'user', content: source }
]
})
});
if (!response.ok) throw new Error(`${locale}: HTTP ${response.status}`);
const payload = await response.json();
const content = payload.choices?.[0]?.message?.content?.trim();
if (!content || !content.includes(marker)) throw new Error(`${locale}: invalid translation response`);
return `${content}\n`;
} finally {
clearTimeout(timeout);
}
}
async function main() {
const root = path.resolve(__dirname, '..');
for (const locale of Object.keys(languageNames)) {
const file = path.join(root, `README_${locale}.md`);
const current = fs.readFileSync(file, 'utf8');
const translated = await translate(locale);
const markerOffset = current.indexOf(marker);
const base = markerOffset >= 0 ? current.slice(0, markerOffset).trimEnd() : current.trimEnd();
fs.writeFileSync(file, `${base}\n\n${translated}`, 'utf8');
process.stdout.write(`${locale}\n`);
}
}
main().catch(error => { console.error(error); process.exit(1); });