mirror of
https://github.com/elyby/docs.git
synced 2025-05-31 14:11:48 +05:30
Completely upgrade project:
- removed all translations and used Russian as the base language - integrated crowdin - new multilang site layout - upgraded sphinx - fixed search, now it correctly handles articles language
This commit is contained in:
169
build-multilang.py
Executable file
169
build-multilang.py
Executable file
@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from glob import glob
|
||||
from pathlib import Path
|
||||
from lxml import html, etree
|
||||
|
||||
base_lang: str = "ru"
|
||||
build_dir: str = "build"
|
||||
per_lang_static: list[str] = [
|
||||
r"documentation_options\.js",
|
||||
r"language_data\.js",
|
||||
r"^(?!basic)\w+-stemmer\.js",
|
||||
r"translations\.js",
|
||||
]
|
||||
|
||||
# Cleanup
|
||||
shutil.rmtree(build_dir, True)
|
||||
os.mkdir(build_dir)
|
||||
|
||||
# Build languages
|
||||
def sphinx_build(lang: str) -> None:
|
||||
subprocess.run([
|
||||
sys.executable, "-m", "sphinx",
|
||||
"-b", "html",
|
||||
"-D", f"language={lang}",
|
||||
"source",
|
||||
f"{build_dir}/{lang}",
|
||||
])
|
||||
|
||||
languages: list[str] = [base_lang]
|
||||
if os.path.isdir("locale"):
|
||||
languages += os.listdir("locale")
|
||||
|
||||
index_page_lang: str = "en" if "en" in languages else base_lang
|
||||
|
||||
for lang in languages:
|
||||
sphinx_build(lang)
|
||||
|
||||
# Extract common assets
|
||||
for i, lang in enumerate(languages):
|
||||
if i == 0:
|
||||
os.rename(f"{build_dir}/{lang}/_downloads", f"{build_dir}/_downloads")
|
||||
os.rename(f"{build_dir}/{lang}/_images", f"{build_dir}/_images")
|
||||
os.rename(f"{build_dir}/{lang}/CNAME", f"{build_dir}/CNAME")
|
||||
os.rename(f"{build_dir}/{lang}/.nojekyll", f"{build_dir}/.nojekyll")
|
||||
else:
|
||||
shutil.rmtree(f"{build_dir}/{lang}/_downloads")
|
||||
shutil.rmtree(f"{build_dir}/{lang}/_images")
|
||||
os.remove(f"{build_dir}/{lang}/CNAME")
|
||||
os.remove(f"{build_dir}/{lang}/.nojekyll")
|
||||
|
||||
for static_file in glob(f"{build_dir}/{lang}/_static/**/*", recursive=True):
|
||||
if not os.path.isfile(static_file):
|
||||
continue
|
||||
|
||||
relative_path = static_file.removeprefix(f"{build_dir}/{lang}/_static/")
|
||||
matched: bool = False
|
||||
for pattern in per_lang_static:
|
||||
if re.match(pattern, relative_path):
|
||||
matched = True
|
||||
break
|
||||
|
||||
# I have no idea how to make "continue 2" from the loop above so...
|
||||
if matched:
|
||||
continue
|
||||
|
||||
dir = os.path.dirname(relative_path)
|
||||
os.makedirs(f"{build_dir}/_static/{dir}", exist_ok=True)
|
||||
os.rename(static_file, f"{build_dir}/_static/{relative_path}")
|
||||
|
||||
shutil.rmtree(f"{build_dir}/{lang}/_sources")
|
||||
shutil.rmtree(f"{build_dir}/{lang}/.doctrees")
|
||||
os.remove(f"{build_dir}/{lang}/.buildinfo")
|
||||
os.remove(f"{build_dir}/{lang}/objects.inv")
|
||||
|
||||
# Convert all relative routes into absolute
|
||||
def make_links_absolute(file_path: str, link: str) -> str:
|
||||
# Skip local anchor links
|
||||
if link.startswith("#"):
|
||||
return link
|
||||
|
||||
# Skip external links (including links without protocol "//ely.by")
|
||||
if link.startswith("//") or re.match(r"^https?://", link):
|
||||
return link
|
||||
|
||||
if ".html" in link:
|
||||
working_directory = os.getcwd()
|
||||
os.chdir(Path(file_path).parent.absolute())
|
||||
resolved = str(Path(link).resolve())
|
||||
os.chdir(working_directory)
|
||||
|
||||
link = resolved.removeprefix(f"{working_directory}/{build_dir}")
|
||||
link = link.replace("\\", "/") # fix for the Windows
|
||||
|
||||
return link
|
||||
|
||||
# Other links are links to some static assets
|
||||
# There is no need to resolve relative links since _static is placed in the root directory,
|
||||
# so after removing all ../ parts we can safely append / to make the path absolute
|
||||
while link.startswith("../"):
|
||||
link = link.removeprefix("../")
|
||||
|
||||
no_static_link = link.removeprefix("_static/")
|
||||
for pattern in per_lang_static:
|
||||
if re.match(pattern, no_static_link):
|
||||
lang = re.match(fr"^{build_dir}/(\w+)/", file_path).group(1)
|
||||
|
||||
return f"/{lang}/{link}"
|
||||
|
||||
return f"/{link}"
|
||||
|
||||
for file in glob(f"{build_dir}/**/*.html", recursive=True):
|
||||
tree = html.parse(file) # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
root.rewrite_links(lambda link: make_links_absolute(file, link))
|
||||
|
||||
tree.write(file, method="html", encoding="UTF-8")
|
||||
|
||||
# Create index.html for the site root
|
||||
shutil.copyfile(f"{build_dir}/{index_page_lang}/index.html", f"{build_dir}/index.html")
|
||||
index_file_tree = html.parse(f"{build_dir}/index.html") # type: etree._ElementTree
|
||||
index_file_root = index_file_tree.getroot() # type: html.HtmlElement
|
||||
index_file_last_toctree = index_file_root.find_class("toctree-wrapper")[0] # type: html.HtmlElement
|
||||
|
||||
for lang in languages:
|
||||
if lang == index_page_lang:
|
||||
continue
|
||||
|
||||
tree = html.parse(f"{build_dir}/{lang}/index.html") # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
toctree = root.find_class("toctree-wrapper")[0] # type: html.HtmlElement
|
||||
index_file_last_toctree.addnext(toctree)
|
||||
|
||||
index_file_last_toctree = index_file_root.find_class("toctree-wrapper")[-1] # type: html.HtmlElement
|
||||
|
||||
index_file_tree.write(f"{build_dir}/index.html", method="html", encoding="UTF-8")
|
||||
|
||||
# Add cross-lang links to the sidebar
|
||||
sidebar_menus: dict[str, html.HtmlElement] = {}
|
||||
for lang in languages:
|
||||
tree = html.parse(f"{build_dir}/{lang}/index.html") # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
sidebar_menus[lang] = root.find_class("wy-menu")[0]
|
||||
|
||||
for file in glob(f"{build_dir}/**/*.html") + [f"{build_dir}/index.html"]:
|
||||
result = re.match(fr"^{build_dir}/(\w+)/", file)
|
||||
lang: str = result.group(1) if result is not None else index_page_lang
|
||||
|
||||
tree = html.parse(file) # type: etree._ElementTree
|
||||
root = tree.getroot() # type: html.HtmlElement
|
||||
|
||||
sidebar_menu_last = root.find_class("wy-menu")[0] # type: html.HtmlElement
|
||||
for menuLang in sidebar_menus:
|
||||
if menuLang == lang:
|
||||
continue
|
||||
|
||||
sidebar_menu_last.addnext(sidebar_menus[menuLang])
|
||||
sidebar_menu_last = root.find_class("wy-menu")[-1] # type: html.HtmlElement
|
||||
|
||||
tree.write(file, method="html", encoding="UTF-8")
|
Reference in New Issue
Block a user