fix: add sp with translations

pull/5092/head
Dylan Tientcheu 4 months ago
parent a6b8ccd7fe
commit ce689eacbc

@ -118,13 +118,10 @@ export default defineConfig({
appId: '8J64VVRP8K',
apiKey: '52f578a92b88ad6abde815aae2b0ad7c',
indexName: 'vitepress',
mode: 'modal',
askAi: {
assistantId: 'YaVSonfX5bS8',
sidePanel: {
button: {
variant: 'inline'
}
}
sidePanel: true
}
}
},

@ -180,8 +180,69 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText:
'Las respuestas son generadas por IA y pueden contener errores. Verifica las respuestas.',
relatedSourcesText: 'Fuentes relacionadas',
thinkingText: 'Pensando...',
copyButtonText: 'Copiar',
copyButtonCopiedText: '¡Copiado!',
copyButtonTitle: 'Copiar',
likeButtonTitle: 'Me gusta',
dislikeButtonTitle: 'No me gusta',
thanksForFeedbackText: '¡Gracias por tu opinión!',
preToolCallText: 'Buscando...',
duringToolCallText: 'Buscando ',
afterToolCallText: 'Búsqueda de'
}
return {
placeholder: 'Buscar documentos',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'Asistente de IA',
conversationHistoryTitle: 'Historial de conversaciones',
newConversationText: 'Nueva conversación',
viewConversationHistoryText: 'Ver historial'
},
promptForm: {
promptPlaceholderText: 'Pregunta algo...',
promptAnsweringText: 'Respondiendo...',
promptAskAnotherQuestionText: 'Hacer otra pregunta...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: 'Tu pregunta',
promptAriaLabelText: 'Campo de entrada de pregunta'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: 'Razonando...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: 'Respuesta detenida',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'Asistente de IA',
introductionText: '¿En qué puedo ayudarte hoy?'
},
logo: {
poweredByText: 'Desarrollado por'
}
}
}
}
},
translations: {
button: {
buttonText: 'Buscar',
@ -226,22 +287,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: 'Preguntar a la IA: '
},
askAiScreen: {
disclaimerText:
'Las respuestas son generadas por IA y pueden contener errores. Verifica las respuestas.',
relatedSourcesText: 'Fuentes relacionadas',
thinkingText: 'Pensando...',
copyButtonText: 'Copiar',
copyButtonCopiedText: '¡Copiado!',
copyButtonTitle: 'Copiar',
likeButtonTitle: 'Me gusta',
dislikeButtonTitle: 'No me gusta',
thanksForFeedbackText: '¡Gracias por tu opinión!',
preToolCallText: 'Buscando...',
duringToolCallText: 'Buscando ',
afterToolCallText: 'Búsqueda de',
aggregatedToolCallText: 'Búsqueda de'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: 'Seleccionar',
submitQuestionText: 'Enviar pregunta',

@ -181,8 +181,69 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText:
'پاسخ‌ها توسط هوش مصنوعی تولید می‌شوند و ممکن است خطا داشته باشند. لطفاً بررسی کنید.',
relatedSourcesText: 'منابع مرتبط',
thinkingText: 'در حال پردازش...',
copyButtonText: 'کپی',
copyButtonCopiedText: 'کپی شد!',
copyButtonTitle: 'کپی',
likeButtonTitle: 'پسندیدم',
dislikeButtonTitle: 'نپسندیدم',
thanksForFeedbackText: 'از بازخورد شما سپاسگزاریم!',
preToolCallText: 'در حال جستجو...',
duringToolCallText: 'در حال جستجو برای ',
afterToolCallText: 'جستجو انجام شد'
}
return {
placeholder: 'جستجوی مستندات',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'دستیار هوش مصنوعی',
conversationHistoryTitle: 'تاریخچه گفتگوها',
newConversationText: 'گفتگوی جدید',
viewConversationHistoryText: 'مشاهده تاریخچه'
},
promptForm: {
promptPlaceholderText: 'سوالی بپرسید...',
promptAnsweringText: 'در حال پاسخ...',
promptAskAnotherQuestionText: 'سوال دیگری بپرسید...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: 'سوال شما',
promptAriaLabelText: 'فیلد ورودی سوال'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: 'در حال استدلال...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: 'پاسخ متوقف شد',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'دستیار هوش مصنوعی',
introductionText: 'امروز چگونه می‌توانم کمکتان کنم؟'
},
logo: {
poweredByText: 'توسعه یافته توسط'
}
}
}
}
},
translations: {
button: {
buttonText: 'جستجو',
@ -224,22 +285,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: 'از هوش مصنوعی بپرسید: '
},
askAiScreen: {
disclaimerText:
'پاسخ‌ها توسط هوش مصنوعی تولید می‌شوند و ممکن است خطا داشته باشند. لطفاً بررسی کنید.',
relatedSourcesText: 'منابع مرتبط',
thinkingText: 'در حال پردازش...',
copyButtonText: 'کپی',
copyButtonCopiedText: 'کپی شد!',
copyButtonTitle: 'کپی',
likeButtonTitle: 'پسندیدم',
dislikeButtonTitle: 'نپسندیدم',
thanksForFeedbackText: 'از بازخورد شما سپاسگزاریم!',
preToolCallText: 'در حال جستجو...',
duringToolCallText: 'در حال جستجو برای ',
afterToolCallText: 'جستجو انجام شد',
aggregatedToolCallText: 'جستجو انجام شد'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: 'انتخاب',
submitQuestionText: 'ارسال پرسش',

@ -148,8 +148,69 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText:
'AI が生成した回答には誤りが含まれる可能性があります。必ずご確認ください。',
relatedSourcesText: '関連ソース',
thinkingText: '考え中...',
copyButtonText: 'コピー',
copyButtonCopiedText: 'コピーしました!',
copyButtonTitle: 'コピー',
likeButtonTitle: 'いいね',
dislikeButtonTitle: 'よくない',
thanksForFeedbackText: 'フィードバックありがとうございます!',
preToolCallText: '検索中...',
duringToolCallText: '検索中 ',
afterToolCallText: '検索完了'
}
return {
placeholder: 'ドキュメントを検索',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'AI アシスタント',
conversationHistoryTitle: '会話履歴',
newConversationText: '新しい会話',
viewConversationHistoryText: '履歴を表示'
},
promptForm: {
promptPlaceholderText: '質問してください...',
promptAnsweringText: '回答中...',
promptAskAnotherQuestionText: '別の質問をする...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: 'あなたの質問',
promptAriaLabelText: '質問入力フィールド'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: '推論中...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: '応答が停止されました',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'AI アシスタント',
introductionText: '今日は何をお手伝いできますか?'
},
logo: {
poweredByText: '提供'
}
}
}
}
},
translations: {
button: {
buttonText: '検索',
@ -191,22 +252,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: 'AI に質問: '
},
askAiScreen: {
disclaimerText:
'AI が生成した回答には誤りが含まれる可能性があります。必ずご確認ください。',
relatedSourcesText: '関連ソース',
thinkingText: '考え中...',
copyButtonText: 'コピー',
copyButtonCopiedText: 'コピーしました!',
copyButtonTitle: 'コピー',
likeButtonTitle: 'いいね',
dislikeButtonTitle: 'よくない',
thanksForFeedbackText: 'フィードバックありがとうございます!',
preToolCallText: '検索中...',
duringToolCallText: '検索中 ',
afterToolCallText: '検索完了',
aggregatedToolCallText: '検索完了'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: '選択',
submitQuestionText: '質問を送信',

@ -222,8 +222,69 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText:
'AI가 생성한 답변으로 오류가 있을 수 있습니다. 반드시 확인하세요.',
relatedSourcesText: '관련 소스',
thinkingText: '생각 중...',
copyButtonText: '복사',
copyButtonCopiedText: '복사됨!',
copyButtonTitle: '복사',
likeButtonTitle: '좋아요',
dislikeButtonTitle: '싫어요',
thanksForFeedbackText: '피드백 감사합니다!',
preToolCallText: '검색 중...',
duringToolCallText: '검색 중 ',
afterToolCallText: '검색 완료'
}
return {
placeholder: '문서 검색',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'AI 어시스턴트',
conversationHistoryTitle: '대화 기록',
newConversationText: '새 대화',
viewConversationHistoryText: '기록 보기'
},
promptForm: {
promptPlaceholderText: '질문하세요...',
promptAnsweringText: '답변 작성 중...',
promptAskAnotherQuestionText: '다른 질문하기...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: '질문',
promptAriaLabelText: '질문 입력 필드'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: '추론 중...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: '답변 중지됨',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'AI 어시스턴트',
introductionText: '오늘 무엇을 도와드릴까요?'
},
logo: {
poweredByText: '제공'
}
}
}
}
},
translations: {
button: {
buttonText: '검색',
@ -265,22 +326,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: 'AI에게 물어보기: '
},
askAiScreen: {
disclaimerText:
'AI가 생성한 답변으로 오류가 있을 수 있습니다. 반드시 확인하세요.',
relatedSourcesText: '관련 소스',
thinkingText: '생각 중...',
copyButtonText: '복사',
copyButtonCopiedText: '복사됨!',
copyButtonTitle: '복사',
likeButtonTitle: '좋아요',
dislikeButtonTitle: '싫어요',
thanksForFeedbackText: '피드백 감사합니다!',
preToolCallText: '검색 중...',
duringToolCallText: '검색 중 ',
afterToolCallText: '검색 완료',
aggregatedToolCallText: '검색 완료'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: '선택',
submitQuestionText: '질문 보내기',

@ -177,8 +177,69 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText:
'As respostas são geradas por IA e podem conter erros. Verifique as respostas.',
relatedSourcesText: 'Fontes relacionadas',
thinkingText: 'Pensando...',
copyButtonText: 'Copiar',
copyButtonCopiedText: 'Copiado!',
copyButtonTitle: 'Copiar',
likeButtonTitle: 'Curtir',
dislikeButtonTitle: 'Não curtir',
thanksForFeedbackText: 'Obrigado pelo feedback!',
preToolCallText: 'Pesquisando...',
duringToolCallText: 'Pesquisando ',
afterToolCallText: 'Pesquisa concluída'
}
return {
placeholder: 'Pesquisar documentos',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'Assistente de IA',
conversationHistoryTitle: 'Histórico de conversas',
newConversationText: 'Nova conversa',
viewConversationHistoryText: 'Ver histórico'
},
promptForm: {
promptPlaceholderText: 'Pergunte algo...',
promptAnsweringText: 'Respondendo...',
promptAskAnotherQuestionText: 'Fazer outra pergunta...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: 'Sua pergunta',
promptAriaLabelText: 'Campo de entrada de pergunta'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: 'Raciocinando...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: 'Resposta interrompida',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'Assistente de IA',
introductionText: 'Como posso ajudá-lo hoje?'
},
logo: {
poweredByText: 'Desenvolvido por'
}
}
}
}
},
translations: {
button: {
buttonText: 'Pesquisar',
@ -222,22 +283,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: 'Pergunte à IA: '
},
askAiScreen: {
disclaimerText:
'As respostas são geradas por IA e podem conter erros. Verifique as respostas.',
relatedSourcesText: 'Fontes relacionadas',
thinkingText: 'Pensando...',
copyButtonText: 'Copiar',
copyButtonCopiedText: 'Copiado!',
copyButtonTitle: 'Copiar',
likeButtonTitle: 'Curtir',
dislikeButtonTitle: 'Não curtir',
thanksForFeedbackText: 'Obrigado pelo feedback!',
preToolCallText: 'Pesquisando...',
duringToolCallText: 'Pesquisando ',
afterToolCallText: 'Pesquisa concluída',
aggregatedToolCallText: 'Pesquisa concluída'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: 'Selecionar',
submitQuestionText: 'Enviar pergunta',

@ -177,8 +177,69 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText:
'Ответы генерируются ИИ и могут содержать ошибки. Проверяйте информацию.',
relatedSourcesText: 'Связанные источники',
thinkingText: 'Думаю...',
copyButtonText: 'Копировать',
copyButtonCopiedText: 'Скопировано!',
copyButtonTitle: 'Копировать',
likeButtonTitle: 'Нравится',
dislikeButtonTitle: 'Не нравится',
thanksForFeedbackText: 'Спасибо за отзыв!',
preToolCallText: 'Поиск...',
duringToolCallText: 'Поиск ',
afterToolCallText: 'Поиск завершён'
}
return {
placeholder: 'Поиск в документации',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'ИИ-ассистент',
conversationHistoryTitle: 'История диалогов',
newConversationText: 'Новый диалог',
viewConversationHistoryText: 'Просмотр истории'
},
promptForm: {
promptPlaceholderText: 'Задайте вопрос...',
promptAnsweringText: 'Формируется ответ...',
promptAskAnotherQuestionText: 'Задать ещё вопрос...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: 'Ваш вопрос',
promptAriaLabelText: 'Поле ввода вопроса'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: 'Рассуждение...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: 'Ответ остановлен',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'ИИ-ассистент',
introductionText: 'Чем могу помочь сегодня?'
},
logo: {
poweredByText: 'Разработано'
}
}
}
}
},
translations: {
button: {
buttonText: 'Поиск',
@ -222,22 +283,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: 'Задайте вопрос ИИ: '
},
askAiScreen: {
disclaimerText:
'Ответы генерируются ИИ и могут содержать ошибки. Проверяйте информацию.',
relatedSourcesText: 'Связанные источники',
thinkingText: 'Думаю...',
copyButtonText: 'Копировать',
copyButtonCopiedText: 'Скопировано!',
copyButtonTitle: 'Копировать',
likeButtonTitle: 'Нравится',
dislikeButtonTitle: 'Не нравится',
thanksForFeedbackText: 'Спасибо за отзыв!',
preToolCallText: 'Поиск...',
duringToolCallText: 'Поиск ',
afterToolCallText: 'Поиск завершён',
aggregatedToolCallText: 'Поиск завершён'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: 'выбрать',
submitQuestionText: 'Отправить вопрос',

@ -170,8 +170,68 @@ function sidebarReference(): DefaultTheme.SidebarItem[] {
}
function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
const modalAskAiTranslations = {
disclaimerText: '答案由 AI 生成,可能不准确,请自行验证。',
relatedSourcesText: '相关来源',
thinkingText: '思考中...',
copyButtonText: '复制',
copyButtonCopiedText: '已复制!',
copyButtonTitle: '复制',
likeButtonTitle: '赞',
dislikeButtonTitle: '踩',
thanksForFeedbackText: '感谢你的反馈!',
preToolCallText: '搜索中...',
duringToolCallText: '搜索 ',
afterToolCallText: '已搜索'
}
return {
placeholder: '搜索文档',
askAi: {
sidePanel: {
panel: {
translations: {
header: {
title: 'AI 助手',
conversationHistoryTitle: '对话历史',
newConversationText: '新对话',
viewConversationHistoryText: '查看历史'
},
promptForm: {
promptPlaceholderText: '提问...',
promptAnsweringText: '回答中...',
promptAskAnotherQuestionText: '继续提问...',
promptDisclaimerText: modalAskAiTranslations.disclaimerText,
promptLabelText: '你的问题',
promptAriaLabelText: '问题输入框'
},
conversationScreen: {
conversationDisclaimer: modalAskAiTranslations.disclaimerText,
reasoningText: '推理中...',
thinkingText: modalAskAiTranslations.thinkingText,
relatedSourcesText: modalAskAiTranslations.relatedSourcesText,
stoppedStreamingText: '已停止',
copyButtonText: modalAskAiTranslations.copyButtonText,
copyButtonCopiedText: modalAskAiTranslations.copyButtonCopiedText,
likeButtonTitle: modalAskAiTranslations.likeButtonTitle,
dislikeButtonTitle: modalAskAiTranslations.dislikeButtonTitle,
thanksForFeedbackText:
modalAskAiTranslations.thanksForFeedbackText,
preToolCallText: modalAskAiTranslations.preToolCallText,
searchingText: modalAskAiTranslations.duringToolCallText,
toolCallResultText: modalAskAiTranslations.afterToolCallText
},
newConversationScreen: {
titleText: 'AI 助手',
introductionText: '今天我能为你做些什么?'
},
logo: {
poweredByText: '由'
}
}
}
}
},
translations: {
button: {
buttonText: '搜索文档',
@ -213,21 +273,7 @@ function searchOptions(): Partial<DefaultTheme.AlgoliaSearchOptions> {
resultsScreen: {
askAiPlaceholder: '向 AI 提问: '
},
askAiScreen: {
disclaimerText: '答案由 AI 生成,可能不准确,请自行验证。',
relatedSourcesText: '相关来源',
thinkingText: '思考中...',
copyButtonText: '复制',
copyButtonCopiedText: '已复制!',
copyButtonTitle: '复制',
likeButtonTitle: '赞',
dislikeButtonTitle: '踩',
thanksForFeedbackText: '感谢你的反馈!',
preToolCallText: '搜索中...',
duringToolCallText: '搜索 ',
afterToolCallText: '已搜索',
aggregatedToolCallText: '已搜索'
},
askAiScreen: modalAskAiTranslations,
footer: {
selectText: '选择',
submitQuestionText: '提交问题',

@ -8,8 +8,10 @@ import { useData } from '../composables/data'
import {
buildAskAiConfig,
mergeLangFacetFilters,
resolveMode,
validateCredentials
} from '../support/docsearch'
import type { DocSearchAskAi } from '../../../../types/docsearch'
const props = defineProps<{
algolia: DefaultTheme.AlgoliaSearchOptions
@ -100,7 +102,7 @@ async function update() {
...options.searchParameters,
facetFilters
},
askAi: askAi as DocSearchProps["askAi"]
askAi: askAi as DocSearchAskAi
})
}
@ -108,12 +110,14 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
// Always tear down previous instances first (e.g. on locale changes)
cleanup?.()
const { useSidePanel, mode } = resolveMode(userOptions)
const askAi = userOptions.askAi
const sidePanelConfig = askAi && typeof askAi === 'object' ? askAi.sidePanel : undefined
if (askAi && typeof askAi === 'object' && sidePanelConfig) {
if (useSidePanel && askAi && typeof askAi === 'object' && sidePanelConfig) {
const { keyboardShortcuts, ...restConfig } = sidePanelConfig !== true ? sidePanelConfig : {} as SidepanelProps
sidepanelInstance = sidepanel({
...restConfig,
container: '#docsearch-sidepanel',
indexName: askAi.indexName ?? userOptions.indexName,
appId: askAi.appId ?? userOptions.appId,
@ -125,7 +129,6 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
setTimeout(() => { sidepanelInstance?.open() }, 0)
}
},
...restConfig,
} as SidepanelProps)
}
@ -145,8 +148,8 @@ function initialize(userOptions: DefaultTheme.AlgoliaSearchOptions) {
})
},
// When sidepanel is enabled, intercept Ask AI events to open it instead (hybrid mode)
...(sidepanelInstance && {
// When sidepanel is enabled (and not in modal mode), intercept Ask AI events to open it instead (hybrid mode)
...(useSidePanel && sidepanelInstance && mode !== 'modal' && {
interceptAskAiEvent: (initialMessage: { query: string; messageId?: string; suggestedQuestionId?: string }) => {
docsearchInstance?.close()
setTimeout(() => sidepanelInstance?.open(initialMessage), 0)
@ -186,4 +189,5 @@ function getRelativePath(url: string) {
<template>
<div id="docsearch" />
<div id="docsearch-sidepanel" />
</template>

@ -1,6 +1,6 @@
<template>
<button type="button" aria-label="Ask AI" class="DocSearch DocSearch-Button VPNavBarAskAiButton">
<span class="DocSearch-Button-Container">
<button type="button" aria-label="Ask AI" class="VPNavBarAskAiButton DocSearch VPDocSearch-Button ">
<span class="VPDocSearch-Button-Container">
<span class="vpi-sparkles DocSearch-Search-Icon"></span>
</span>
</button>
@ -51,6 +51,7 @@
.VPNavBarAskAiButton {
transition: all 0.25s;
width: 36px !important;
}

@ -5,7 +5,7 @@ import { onKeyStroke } from '@vueuse/core'
import type { DefaultTheme } from 'vitepress/theme'
import { computed, defineAsyncComponent, onMounted, onUnmounted, ref } from 'vue'
import { useData } from '../composables/data'
import { hasKeywordSearch } from '../support/docsearch'
import { resolveMode } from '../support/docsearch'
import VPNavBarAskAiButton from './VPNavBarAskAiButton.vue'
import VPNavBarSearchButton from './VPNavBarSearchButton.vue'
@ -30,12 +30,14 @@ const algoliaOptions = computed(() => {
} as DefaultTheme.AlgoliaSearchOptions
})
const resolvedMode = computed(() => resolveMode(algoliaOptions.value))
const showKeywordSearchButton = computed(
() =>
hasKeywordSearch(algoliaOptions.value)
() => resolvedMode.value.showKeywordSearch
)
const askAiSidePanelConfig = computed(() => {
if (!resolvedMode.value.useSidePanel) return null
const askAi = algoliaOptions.value.askAi
if (!askAi || typeof askAi === 'string') return null
if (!askAi.sidePanel) return null
@ -179,16 +181,11 @@ const provider = __ALGOLIA__ ? 'algolia' : __VP_LOCAL_SEARCH__ ? 'local' : ''
</template>
<template v-else-if="provider === 'algolia'">
<VPAlgoliaSearchBox v-if="loaded" :algolia="theme.search?.options ?? theme.algolia" :open-request="openRequest"
@vue:beforeMount="actuallyLoaded = true" />
<div v-if="!actuallyLoaded">
<VPNavBarSearchButton v-if="showKeywordSearchButton" @click="loadAndOpen('search')" />
</div>
<VPNavBarSearchButton v-if="showKeywordSearchButton" @click="loadAndOpen('search')" />
<VPNavBarAskAiButton v-if="askAiSidePanelConfig"
@click="actuallyLoaded ? loadAndOpen('toggleAskAi') : loadAndOpen('askAi')" />
<div id="docsearch-sidepanel" />
<VPAlgoliaSearchBox v-if="loaded" :algolia="theme.search?.options ?? theme.algolia" :open-request="openRequest"
@vue:beforeMount="actuallyLoaded = true" />
</template>
</div>
</template>

@ -14,17 +14,13 @@ const translate = createSearchTranslate(defaultTranslations)
</script>
<template>
<button
type="button"
:aria-label="translate('button.buttonAriaLabel')"
aria-keyshortcuts="/ control+k meta+k"
class="DocSearch DocSearch-Button"
>
<span class="DocSearch-Button-Container">
<button type="button" :aria-label="translate('button.buttonAriaLabel')" aria-keyshortcuts="/ control+k meta+k"
class="DocSearch VPDocSearch-Button VPNavBarSearchButton">
<span class="VPDocSearch-Button-Container">
<span class="vpi-search DocSearch-Search-Icon"></span>
<span class="DocSearch-Button-Placeholder">{{ translate('button.buttonText') }}</span>
<span class="VPDocSearch-Button-Placeholder">{{ translate('button.buttonText') }}</span>
</span>
<span class="DocSearch-Button-Keys"/>
<span class="VPDocSearch-Button-Keys" />
</button>
</template>
@ -76,7 +72,7 @@ const translate = createSearchTranslate(defaultTranslations)
fill: currentColor;
}
.DocSearch-SearchBar + .DocSearch-Footer {
.DocSearch-SearchBar+.DocSearch-Footer {
border-top-color: transparent;
}
@ -86,37 +82,38 @@ const translate = createSearchTranslate(defaultTranslations)
}
.DocSearch-Button {
display: none;
}
.VPDocSearch-Button {
--docsearch-muted-color: var(--docsearch-text-color);
--docsearch-searchbox-background: transparent;
padding: 4px 8px;
display: inline-flex;
align-items: center;
justify-content: center;
gap: 12px;
height: 36px;
width: auto;
padding: 0px 8px;
border: none;
border-radius: 8px;
}
.VPDocSearch-Button-Container {
display: inline-flex;
height: 100%;
gap: 6px;
align-items: center;
}
.DocSearch-Search-Icon {
color: inherit !important;
width: 20px;
height: 20px;
}
@media (min-width: 768px) {
.DocSearch-Button {
background-color: var(--vp-c-bg-alt);
color: var(--docsearch-secondary-text-color);
}
.DocSearch-Search-Icon {
width: 15px;
height: 15px;
}
.DocSearch-Button-Placeholder {
font-size: 13px;
}
}
.DocSearch-Button-Keys {
.VPDocSearch-Button-Keys {
min-width: auto;
margin: 0;
padding: 4px 6px;
@ -126,19 +123,45 @@ const translate = createSearchTranslate(defaultTranslations)
font-size: 12px;
line-height: 1;
color: var(--docsearch-key-color);
display: none;
}
.DocSearch-Button-Keys > * {
.VPDocSearch-Button-Placeholder {
display: none;
}
.DocSearch-Button-Keys:after {
.VPDocSearch-Button-Keys>* {
display: none;
}
.VPDocSearch-Button-Keys:after {
/*rtl:ignore*/
direction: ltr;
content: 'Ctrl K';
}
.mac .DocSearch-Button-Keys:after {
.mac .VPDocSearch-Button-Keys:after {
content: '\2318 K';
}
@media (min-width: 768px) {
.VPDocSearch-Button {
background-color: var(--vp-c-bg-alt);
color: var(--docsearch-secondary-text-color);
}
.DocSearch-Search-Icon {
width: 15px;
height: 15px;
}
.VPDocSearch-Button-Placeholder {
font-size: 13px;
display: block;
}
.VPDocSearch-Button-Keys {
display: block;
}
}
</style>

@ -1,6 +1,6 @@
import type { DefaultTheme } from 'vitepress/theme'
export type FacetFilter = string | string[]
export type FacetFilter = string | string[] | FacetFilter[]
export interface ValidatedCredentials {
valid: boolean
@ -9,6 +9,76 @@ export interface ValidatedCredentials {
indexName?: string
}
export type DocSearchMode = 'auto' | 'sidePanel' | 'hybrid' | 'modal'
export interface ResolvedMode {
mode: DocSearchMode
showKeywordSearch: boolean
useSidePanel: boolean
}
/**
* Resolves the effective mode based on config and available features.
*
* - 'auto': infer hybrid vs sidePanel-only from provided config
* - 'sidePanel': force sidePanel-only even if keyword search is configured
* - 'hybrid': force hybrid (error if keyword search is not configured)
* - 'modal': force modal even if sidePanel is configured
*/
export function resolveMode(
options: Pick<
DefaultTheme.AlgoliaSearchOptions,
'appId' | 'apiKey' | 'indexName' | 'askAi' | 'mode'
>
): ResolvedMode {
const mode = options.mode ?? 'auto'
const hasKeyword = hasKeywordSearch(options)
const askAi = options.askAi
const hasSidePanelConfig = Boolean(
askAi && typeof askAi === 'object' && askAi.sidePanel
)
switch (mode) {
case 'sidePanel':
// Force sidePanel-only - hide keyword search
return {
mode,
showKeywordSearch: false,
useSidePanel: true
}
case 'hybrid':
// Force hybrid - keyword search must be configured
if (!hasKeyword) {
console.error(
'[vitepress] mode: "hybrid" requires keyword search credentials (appId, apiKey, indexName).'
)
}
return {
mode,
showKeywordSearch: hasKeyword,
useSidePanel: true
}
case 'modal':
// Force modal - don't use sidepanel for askai, even if configured
return {
mode,
showKeywordSearch: hasKeyword,
useSidePanel: true
}
case 'auto':
default:
// Auto-detect based on config
return {
mode: 'auto',
showKeywordSearch: hasKeyword,
useSidePanel: hasSidePanelConfig
}
}
}
export function hasKeywordSearch(
options: Pick<
DefaultTheme.AlgoliaSearchOptions,
@ -44,7 +114,9 @@ export function mergeLangFacetFilters(
.map((filter) => {
if (Array.isArray(filter)) {
// Handle nested arrays (OR conditions)
return filter.filter((f) => !f.startsWith('lang:'))
return filter.filter(
(f) => typeof f === 'string' && !f.startsWith('lang:')
)
}
return filter
})
@ -101,7 +173,10 @@ export function buildAskAiConfig(
const askAiFacetFiltersSource =
askAiSearchParameters?.facetFilters ??
options.searchParameters?.facetFilters
const askAiFacetFilters = mergeLangFacetFilters(askAiFacetFiltersSource, lang)
const askAiFacetFilters = mergeLangFacetFilters(
askAiFacetFiltersSource as FacetFilter | FacetFilter[] | undefined,
lang
)
const mergedAskAiSearchParameters = {
...askAiSearchParameters,

233
types/docsearch.d.ts vendored

@ -1,3 +1,20 @@
import { type DocSearchProps as DocSearchPropsJS } from '@docsearch/js'
import { type SidepanelProps as SidepanelPropsBase } from '@docsearch/sidepanel-js'
/**
* Sidepanel translation configuration (for locale configs).
*/
export type SidepanelTranslations = NonNullable<
NonNullable<SidepanelPropsBase['button']>['translations']
> & {
panel?: NonNullable<NonNullable<SidepanelPropsBase['panel']>['translations']>
}
/**
* Partial sidepanel props for locale configs where auth fields are inherited from the main config.
*/
export type SidepanelProps = Partial<Omit<SidepanelPropsBase, 'container'>>
export interface DocSearchProps {
/**
* Keyword search (optional when using Ask AI side panel only).
@ -6,11 +23,11 @@ export interface DocSearchProps {
apiKey?: string
indexName?: string
placeholder?: string
searchParameters?: SearchOptions
searchParameters?: DocSearchPropsJS['searchParameters']
disableUserPersonalization?: boolean
initialQuery?: string
insights?: boolean
translations?: DocSearchTranslations
translations?: DocSearchPropsJS['translations']
askAi?: DocSearchAskAi | string
/**
* Ask AI side panel integration mode.
@ -19,173 +36,9 @@ export interface DocSearchProps {
* - 'auto': infer hybrid vs sidePanel-only from provided config
* - 'sidePanel': force sidePanel-only even if keyword search is configured
* - 'hybrid': force hybrid (error if keyword search is not configured)
* - 'modal': force modal even if sidePanel is configured (ask ai in modal stays in modal)
*/
mode?: 'auto' | 'sidePanel' | 'hybrid'
}
export interface SearchOptions {
query?: string
similarQuery?: string
facetFilters?: string | string[]
optionalFilters?: string | string[]
numericFilters?: string | string[]
tagFilters?: string | string[]
sumOrFiltersScores?: boolean
filters?: string
page?: number
hitsPerPage?: number
offset?: number
length?: number
attributesToHighlight?: string[]
attributesToSnippet?: string[]
attributesToRetrieve?: string[]
highlightPreTag?: string
highlightPostTag?: string
snippetEllipsisText?: string
restrictHighlightAndSnippetArrays?: boolean
facets?: string[]
maxValuesPerFacet?: number
facetingAfterDistinct?: boolean
minWordSizefor1Typo?: number
minWordSizefor2Typos?: number
allowTyposOnNumericTokens?: boolean
disableTypoToleranceOnAttributes?: string[]
queryType?: 'prefixLast' | 'prefixAll' | 'prefixNone'
removeWordsIfNoResults?: 'none' | 'lastWords' | 'firstWords' | 'allOptional'
advancedSyntax?: boolean
advancedSyntaxFeatures?: ('exactPhrase' | 'excludeWords')[]
optionalWords?: string | string[]
disableExactOnAttributes?: string[]
exactOnSingleWordQuery?: 'attribute' | 'none' | 'word'
alternativesAsExact?: (
| 'ignorePlurals'
| 'singleWordSynonym'
| 'multiWordsSynonym'
)[]
enableRules?: boolean
ruleContexts?: string[]
distinct?: boolean | number
analytics?: boolean
analyticsTags?: string[]
synonyms?: boolean
replaceSynonymsInHighlight?: boolean
minProximity?: number
responseFields?: string[]
maxFacetHits?: number
percentileComputation?: boolean
clickAnalytics?: boolean
personalizationImpact?: number
enablePersonalization?: boolean
restrictSearchableAttributes?: string[]
sortFacetValuesBy?: 'count' | 'alpha'
typoTolerance?: boolean | 'min' | 'strict'
aroundLatLng?: string
aroundLatLngViaIP?: boolean
aroundRadius?: number | 'all'
aroundPrecision?: number | { from: number; value: number }[]
minimumAroundRadius?: number
insideBoundingBox?: number[][]
insidePolygon?: number[][]
ignorePlurals?: boolean | string[]
removeStopWords?: boolean | string[]
naturalLanguages?: string[]
getRankingInfo?: boolean
userToken?: string
enableABTest?: boolean
decompoundQuery?: boolean
relevancyStrictness?: number
}
export interface DocSearchTranslations {
button?: ButtonTranslations
modal?: ModalTranslations
}
export interface ButtonTranslations {
buttonText?: string
buttonAriaLabel?: string
}
export interface ModalTranslations extends ScreenStateTranslations {
searchBox?: SearchBoxTranslations
footer?: FooterTranslations
}
export interface ScreenStateTranslations {
errorScreen?: ErrorScreenTranslations
startScreen?: StartScreenTranslations
resultsScreen?: ResultsScreenTranslations
noResultsScreen?: NoResultsScreenTranslations
askAiScreen?: AskAiScreenTranslations
}
export interface SearchBoxTranslations {
clearButtonTitle?: string
clearButtonAriaLabel?: string
closeButtonText?: string
closeButtonAriaLabel?: string
placeholderText?: string
placeholderTextAskAi?: string
searchInputLabel?: string
placeholderTextAskAiStreaming?: string
backToKeywordSearchButtonText?: string
backToKeywordSearchButtonAriaLabel?: string
}
export interface FooterTranslations {
selectText?: string
submitQuestionText?: string
selectKeyAriaLabel?: string
navigateText?: string
navigateUpKeyAriaLabel?: string
backToSearchText?: string
navigateDownKeyAriaLabel?: string
closeText?: string
closeKeyAriaLabel?: string
poweredByText?: string
}
export interface ErrorScreenTranslations {
titleText?: string
helpText?: string
}
export interface StartScreenTranslations {
recentSearchesTitle?: string
noRecentSearchesText?: string
saveRecentSearchButtonTitle?: string
removeRecentSearchButtonTitle?: string
favoriteSearchesTitle?: string
removeFavoriteSearchButtonTitle?: string
recentConversationsTitle?: string
removeRecentConversationButtonTitle?: string
}
export interface ResultsScreenTranslations {
askAiPlaceholder?: string
}
export interface NoResultsScreenTranslations {
noResultsText?: string
suggestedQueryText?: string
reportMissingResultsText?: string
reportMissingResultsLinkText?: string
}
export interface AskAiScreenTranslations {
disclaimerText?: string
relatedSourcesText?: string
thinkingText?: string
copyButtonText?: string
copyButtonCopiedText?: string
copyButtonTitle?: string
likeButtonTitle?: string
dislikeButtonTitle?: string
thanksForFeedbackText?: string
preToolCallText?: string
duringToolCallText?: string
afterToolCallText?: string
aggregatedToolCallText?: string
mode?: 'auto' | 'sidePanel' | 'hybrid' | 'modal'
}
export interface DocSearchAskAi {
@ -206,13 +59,14 @@ export interface DocSearchAskAi {
appId?: string
/**
* The assistant ID to use for the ask AI feature.
* Optional in locale configs where it's inherited from the main config.
*/
assistantId: string | null
assistantId?: string | null
/**
* The search parameters to use for the ask AI feature.
*/
searchParameters?: Pick<
SearchOptions,
DocSearchPropsJS['searchParameters'],
| 'facetFilters'
| 'filters'
| 'attributesToRetrieve'
@ -226,42 +80,5 @@ export interface DocSearchAskAi {
/**
* Ask AI side panel configuration.
*/
sidePanel?: boolean | SidePanelConfig
}
/**
* Sidepanel configuration (flat, mirrors @docsearch/sidepanel-js API).
* @see https://docsearch.algolia.com/docs/sidepanel/api-reference
*/
export interface SidePanelConfig {
/**
* Default: 'floating'
*/
variant?: 'floating' | 'inline'
/**
* Default: 'right'
*/
side?: 'right' | 'left'
/**
* Default: '360px'
*/
width?: number | string
/**
* Default: '580px'
*/
expandedWidth?: number | string
/**
* Enables displaying suggested questions on new conversation screen.
*/
suggestedQuestions?: boolean
/**
* Default: {'Ctrl/Cmd+I': true}
*/
keyboardShortcuts?: {
'Ctrl/Cmd+I'?: boolean
}
/**
* Default: 'light'
*/
theme?: 'light' | 'dark'
sidePanel?: boolean | SidepanelProps
}

Loading…
Cancel
Save