db7cef5f17
Replace all user-visible hardcoded Chinese strings in Vue/TS source files
with proper i18n function calls and add corresponding translation keys
to all 4 locale files (zh-CN, en-US, ko-KR, ru-RU).
Changes:
- Replace 80+ hardcoded Chinese strings across 30+ source files
- Add ~450 new translation keys per locale file
- Cover components, views, utils, hooks, and API modules
- Remove Chinese fallback patterns (|| '中文') from existing t() calls
- Add mermaid toolbar and ollama date format translations
Intentionally preserved (backend API values / backward compatibility):
- FAQ CSV column headers and parsing constants
- RelevanceLevel type and Record key mappings
- Graph database engine status comparison ('未启用')
- Language name labels ('简体中文')
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import i18n from '@/i18n';
|
|
|
|
const STREAMING_IMAGE_PLACEHOLDER = '<span class="streaming-image-loading"><span class="streaming-image-loading__skeleton"></span></span>';
|
|
|
|
export const replaceIncompleteImageWithPlaceholder = (content: string): string => {
|
|
if (!content) return '';
|
|
|
|
const lastImgStart = content.lastIndexOf('![');
|
|
if (lastImgStart < 0) return content;
|
|
|
|
const tail = content.slice(lastImgStart);
|
|
const hasImageOpen = tail.startsWith('![');
|
|
const hasBracketClose = tail.includes(']');
|
|
const hasParenOpen = tail.includes('(');
|
|
const hasParenClose = tail.includes(')');
|
|
if (!hasImageOpen) return content;
|
|
|
|
// Incomplete image syntax at stream tail, e.g. ) {
|
|
return content.slice(0, lastImgStart) + STREAMING_IMAGE_PLACEHOLDER;
|
|
}
|
|
|
|
return content;
|
|
};
|
|
|
|
export const formatManualTitle = (question?: string): string => {
|
|
if (!question) {
|
|
return i18n.global.t('chat.sessionExcerpt');
|
|
}
|
|
const condensed = question.replace(/\s+/g, ' ').trim();
|
|
if (!condensed) {
|
|
return i18n.global.t('chat.sessionExcerpt');
|
|
}
|
|
return condensed.length > 40 ? `${condensed.slice(0, 40)}...` : condensed;
|
|
};
|
|
|
|
export const buildManualMarkdown = (_question: string, answer: string): string => {
|
|
const safeAnswer = answer?.trim() || i18n.global.t('chat.noAnswerContent');
|
|
return `${safeAnswer}`;
|
|
};
|
|
|
|
export const copyTextToClipboard = async (content: string): Promise<void> => {
|
|
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
await navigator.clipboard.writeText(content);
|
|
return;
|
|
}
|
|
|
|
const textArea = document.createElement('textarea');
|
|
textArea.value = content;
|
|
textArea.style.position = 'fixed';
|
|
textArea.style.opacity = '0';
|
|
document.body.appendChild(textArea);
|
|
textArea.select();
|
|
document.execCommand('copy');
|
|
document.body.removeChild(textArea);
|
|
};
|