Skip to content

Commit

Permalink
Add config setting to disable cross language search
Browse files Browse the repository at this point in the history
  • Loading branch information
mondeja committed Feb 26, 2022
1 parent 5afc215 commit 76bf0d9
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 1 deletion.
10 changes: 10 additions & 0 deletions docs/locale/es/config.md.po
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,13 @@ msgstr ""

msgid "Content"
msgstr "Contenido"

msgid ""
"By default is enabled. You can disable it to restrict the search to the "
"active language."
msgstr ""
"Por defecto está habilitado. Puedes deshabilitarlo para restringir la "
"búsqueda al idioma activo."

msgid "Currently is only compatible with the [mkdocs-material] theme."
msgstr "Actualmente sólo es compatible con el tema [mkdocs-material]."
8 changes: 8 additions & 0 deletions docs/src/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,14 @@ File extensions that are ignored from being added to site directory, defaults to
You can ignore certain messages from being dumped into PO files adding them to
this list.

<!-- mdpo-disable-next-line -->
### **`cross_language_search`** (*bool*)

By default is enabled. You can disable it to restrict the search to the active
language.

Currently is only compatible with the [mkdocs-material] theme.

[iso-369]: https://en.wikipedia.org/wiki/ISO_639
[mkdocs-material]: https://squidfunk.github.io/mkdocs-material
[mkdocs-material-site-language]: https://squidfunk.github.io/mkdocs-material/setup/changing-the-language/#site-language
Expand Down
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ plugins:
root_domain: true
- mdpo:
locale_dir: ../locale
cross_language_search: false
- minify:
minify_html: true

Expand Down
1 change: 1 addition & 0 deletions mkdocs_mdpo_plugin/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
),
('ignore_extensions', Type(list, default=['.po', '.pot', '.mo'])),
('ignore_msgids', Type(list, default=[])),
('cross_language_search', Type(bool, default=True)),
)


Expand Down
22 changes: 21 additions & 1 deletion mkdocs_mdpo_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,11 @@
MkdocsBuild,
set_on_build_error_event,
)
from mkdocs_mdpo_plugin.translations import Translation, Translations
from mkdocs_mdpo_plugin.translations import (
Translation,
Translations,
TranslationSearchIndexes,
)


class MdpoPlugin(mkdocs.plugins.BasePlugin):
Expand Down Expand Up @@ -329,6 +333,7 @@ def on_page_markdown(self, markdown, page, config, files):
_translated_entries_msgstrs.append(entry.msgstr)
_translated_entries_msgids.append(entry.msgid)

# create translation object
translation = Translation(
language,
po,
Expand All @@ -349,6 +354,7 @@ def on_page_markdown(self, markdown, page, config, files):
self.translations.nav[page.title][language] = [
translated_page_title, new_page.file.url,
]

mkdocs.commands.build._populate_page(
new_page,
config,
Expand Down Expand Up @@ -398,6 +404,20 @@ def on_post_page(self, output, page, config):
def on_post_build(self, config):
self.translations.tempdir.cleanup()

if (
not self.config['cross_language_search'] and
'search' in config['plugins']
):
# cross language search is disabled, so build indexes
# for each language and patch the 'site_dir' directory
search_indexes = TranslationSearchIndexes(
config['site_dir'],
self.config['languages'],
self.config['default_language'],
)
search_indexes.patch_site_dir()

# save PO files
for translations in self.translations.all.values():
for translation in translations:
translation.po.save(translation.po_filepath)
Expand Down
125 changes: 125 additions & 0 deletions mkdocs_mdpo_plugin/translations.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import json
import os
import re
import tempfile


Expand Down Expand Up @@ -96,3 +99,125 @@ def __str__(self): # pragma: no cover
f' current={current}'
')'
)


class TranslationSearchIndexes:
def __init__(self, site_dir, languages, default_language):
self.site_dir = site_dir
self.search_index_json_path = os.path.join(
site_dir,
'search',
'search_index.json',
)

with open(self.search_index_json_path) as f:
self.search_index_json = json.load(f)

self.search_index = self.search_index_json['docs']

self.languages = languages
self.default_language = default_language

self.lang_search_indexes = {default_language: []} # {lang: [records]}

self.index_loader_js = self._search_index_loader_js_filepath()

def patch_site_dir(self):
for language in self.languages:
# build indexes for languages
self.lang_search_indexes[language] = []

if language == self.default_language:
lang_matchers = tuple(f'{lang}/' for lang in self.languages)
for record in self.search_index:
if not record['location'].startswith(lang_matchers):
self.lang_search_indexes[language].append(record)
else:
for record in self.search_index:
if record['location'].startswith(f'{language}/'):
self.lang_search_indexes[language].append(record)

lang_search_index_path, lang_search_index = (
self._lang_search_index_json(
language,
self.lang_search_indexes[language],
)
)

# create JSON indexes
with open(lang_search_index_path, 'w') as f:
f.write(lang_search_index)

# create javascript assets by language to load custom
# search_index_{language}.json files depending on the
# theme used

# generate js loader for the language
lang_index_loader_js_path, lang_index_loader_js = (
self._lang_index_loader_js(language)
)
with open(lang_index_loader_js_path, 'w') as f:
f.write(lang_index_loader_js)

self._patch_html_files()

def _lang_search_index_json(self, language, records):
search_index = self.search_index_json
search_index['docs'] = records
if 'config' in search_index and 'lang' in search_index['config']:
search_index['config']['lang'] = [language]
return (
self.search_index_json_path.rstrip('.json') + f'_{language}.json',
json.dumps(search_index),
)

def _lang_index_loader_js(self, language):
return (
self.index_loader_js['path'].rstrip('.js') + f'_{language}.js',
self.index_loader_js['content'].replace(
'/search/search_index.json',
f'/search/search_index_{language}.json',
),
)

def _patch_html_files(self):
for root, _, files in os.walk(self.site_dir):
for fname in files:
if fname.endswith('.html'):
fpath = os.path.join(root, fname)
with open(fpath) as f:
content = f.read()
match = re.search(r'lang="([^"]+)"', content)
if match:
language = match.group(1)
index_loader_js_fname = os.path.basename(
self.index_loader_js['path'],
)
index_loader_js_fname_lang = (
index_loader_js_fname.rstrip('.js')
+ f'_{language}.js'
)
new_content = content.replace(
f'assets/javascripts/{index_loader_js_fname}"',
(
'assets/javascripts/'
f'{index_loader_js_fname_lang}"'
),
)
with open(fpath, 'w') as f:
f.write(new_content)

def _search_index_loader_js_filepath(self):
javascripts_dir = os.path.join(self.site_dir, 'assets', 'javascripts')
js_loader_filepath, js_loader_content = None, None
if os.path.isdir(javascripts_dir):
for fname in os.listdir(javascripts_dir):
if fname.endswith('.js'):
fpath = os.path.join(javascripts_dir, fname)
with open(fpath) as f:
content = f.read()
if '/search/search_index.json' in content:
js_loader_filepath = fpath
js_loader_content = content
continue
return {'path': js_loader_filepath, 'content': js_loader_content}

0 comments on commit 76bf0d9

Please sign in to comment.