Multilingual support for Algolia search

This commit is contained in:
Mimi 2020-08-19 00:23:45 +08:00
parent 15a21eeca7
commit 60facf4b00
8 changed files with 38 additions and 28 deletions

View File

@ -725,10 +725,6 @@ algolia_search:
enable: false
hits:
per_page: 10
labels:
input_placeholder: Search for Posts
hits_empty: "We didn't find any results for the search: ${query}"
hits_stats: "${hits} results found in ${time} ms"
# Local Search
# Dependencies: https://github.com/next-theme/hexo-generator-searchdb

View File

@ -67,6 +67,9 @@ state:
search:
placeholder: Searching...
empty: "We didn't find any results for the search: %s"
hits_time: "%s results found in %s ms"
hits: "%s results found"
cheers:
um: Um..

View File

@ -12,7 +12,7 @@
</span>
</div>
<div class="search-result-container">
<div class="no-result">
<div class="search-result-icon">
<i class="fa fa-spinner fa-pulse fa-5x"></i>
</div>
</div>

View File

@ -8,7 +8,7 @@ const { parse } = require('url');
* Export theme config to js
*/
hexo.extend.helper.register('next_config', function() {
const { config, theme, next_version } = this;
const { config, theme, next_version, __ } = this;
const exportConfig = {
hostname : parse(config.url).hostname || config.url,
root : config.root,
@ -24,15 +24,20 @@ hexo.extend.helper.register('next_config', function() {
pangu : theme.pangu,
comments : theme.comments,
motion : theme.motion,
prism : config.prismjs.enable && !config.prismjs.preprocess
prism : config.prismjs.enable && !config.prismjs.preprocess,
i18n : {
placeholder: __('search.placeholder'),
empty : __('search.empty', '${query}'),
hits_time : __('search.hits_time', '${hits}', '${time}'),
hits : __('search.hits', '${hits}')
}
};
if (config.algolia && theme.algolia_search && theme.algolia_search.enable) {
exportConfig.algolia = {
appID : config.algolia.applicationID || config.algolia.appId,
apiKey : config.algolia.apiKey,
indexName: config.algolia.indexName,
hits : theme.algolia_search.hits,
labels : theme.algolia_search.labels
hits : theme.algolia_search.hits
};
}
if (config.search && theme.local_search && theme.local_search.enable) {

View File

@ -102,7 +102,7 @@
height: 100%;
margin-left: -2px;
position: absolute;
// 1.25em is inaccurate when .collection-title has line breaks on mobile
// To do: 1.25em is inaccurate when .collection-title has line breaks on mobile
top: 1.25em;
width: 4px;
}

View File

@ -114,11 +114,11 @@ if (hexo-config('algolia_search.enable')) {
align-items: center;
display: flex;
justify-content: space-between;
}
.algolia-powered {
height: 1em;
margin: 0;
img {
height: 1em;
margin: 0;
}
}
.algolia-pagination {
@ -149,7 +149,7 @@ if (hexo-config('local_search.enable')) {
padding: 2px;
}
.search-result-container {
.no-result {
display: flex;
}
@ -157,7 +157,7 @@ if (hexo-config('local_search.enable')) {
width: 100%;
}
.no-result {
.search-result-icon {
color: $grey-light;
margin: auto;
}

View File

@ -1,8 +1,7 @@
/* global instantsearch, algoliasearch, CONFIG */
document.addEventListener('DOMContentLoaded', () => {
const algoliaSettings = CONFIG.algolia;
const { indexName, appID, apiKey } = algoliaSettings;
const { indexName, appID, apiKey, hits } = CONFIG.algolia;
const search = instantsearch({
indexName,
@ -21,12 +20,12 @@ document.addEventListener('DOMContentLoaded', () => {
// Registering Widgets
search.addWidgets([
instantsearch.widgets.configure({
hitsPerPage: algoliaSettings.hits.per_page || 10
hitsPerPage: hits.per_page || 10
}),
instantsearch.widgets.searchBox({
container : '.search-input-container',
placeholder : algoliaSettings.labels.input_placeholder,
placeholder : CONFIG.i18n.placeholder,
// Hide default icons of algolia search
showReset : false,
showSubmit : false,
@ -40,11 +39,11 @@ document.addEventListener('DOMContentLoaded', () => {
container: '.algolia-stats',
templates: {
text: data => {
const stats = algoliaSettings.labels.hits_stats
const stats = CONFIG.i18n.hits_time
.replace(/\$\{hits}/, data.nbHits)
.replace(/\$\{time}/, data.processingTimeMS);
return `<span>${stats}</span>
<img src="${CONFIG.root}images/logo-algolia-nebula-blue-full.svg" class="algolia-powered" alt="Algolia">`;
<img src="${CONFIG.root}images/logo-algolia-nebula-blue-full.svg" alt="Algolia">`;
}
},
cssClasses: {
@ -69,7 +68,7 @@ document.addEventListener('DOMContentLoaded', () => {
},
empty: data => {
return `<div id="algolia-hits-empty">
${algoliaSettings.labels.hits_empty.replace(/\$\{query}/, data.query)}
${CONFIG.i18n.empty.replace(/\$\{query}/, data.query)}
</div>`;
}
},

View File

@ -164,16 +164,18 @@ document.addEventListener('DOMContentLoaded', () => {
if (!isfetched) return;
const searchText = input.value.trim().toLowerCase();
const keywords = searchText.split(/[-\s]+/);
const resultContent = document.querySelector('.search-result-container');
const container = document.querySelector('.search-result-container');
let resultItems = [];
if (searchText.length > 0) {
// Perform local searching
resultItems = getResultItems(keywords);
}
if (keywords.length === 1 && keywords[0] === '') {
resultContent.innerHTML = '<div class="no-result"><i class="fa fa-search fa-5x"></i></div>';
container.classList.add('no-result');
container.innerHTML = '<div class="search-result-icon"><i class="fa fa-search fa-5x"></i></div>';
} else if (resultItems.length === 0) {
resultContent.innerHTML = '<div class="no-result"><i class="far fa-frown fa-5x"></i></div>';
container.classList.add('no-result');
container.innerHTML = '<div class="search-result-icon"><i class="far fa-frown fa-5x"></i></div>';
} else {
resultItems.sort((left, right) => {
if (left.includedCount !== right.includedCount) {
@ -183,8 +185,13 @@ document.addEventListener('DOMContentLoaded', () => {
}
return right.id - left.id;
});
resultContent.innerHTML = `<ul class="search-result-list">${resultItems.map(result => result.item).join('')}</ul>`;
window.pjax && window.pjax.refresh(resultContent);
const stats = CONFIG.i18n.hits.replace(/\$\{hits}/, resultItems.length);
container.classList.remove('no-result');
container.innerHTML = `<div class="search-stats">${stats}</div>
<hr>
<ul class="search-result-list">${resultItems.map(result => result.item).join('')}</ul>`;
window.pjax && window.pjax.refresh(container);
}
};