Skip to content

Commit 0964c17

Browse files
committed
Create preprocessor and fix review comments
1 parent 0d2bfff commit 0964c17

File tree

4 files changed

+103
-138
lines changed

4 files changed

+103
-138
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ doc/source/savefig/
146146
# Web & Translations #
147147
##############################
148148
web/preview/
149-
web/translations/
149+
web/pandas-translations-main/
150150
web/pandas/es/
151151
web/pandas/pt/
152152
web/pandas/fr/

web/pandas/_templates/layout.html

Lines changed: 44 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<!DOCTYPE html>
2-
<html lang="{{ selected_language }}">
2+
<html lang="{{ lang }}">
33
<head>
44
<script defer data-domain="pandas.pydata.org" src="https://views.scientific-python.org/js/script.js"></script>
55
<title>pandas - Python Data Analysis Library</title>
@@ -16,80 +16,36 @@
1616
{% endfor %}
1717
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/[email protected]/font/bootstrap-icons.min.css">
1818
<script type="text/javascript">
19-
window.addEventListener("DOMContentLoaded", function() {
20-
var absBaseUrl = document.baseURI;
21-
var baseUrl = location.protocol + "//" + location.hostname
22-
if (location.port) {
23-
baseUrl = baseUrl + ":" + location.port
24-
}
25-
var currentLanguage = document.documentElement.lang;
26-
var languages = [
27-
{% for lang, name in translations["languages"].items() -%}
28-
"{{ lang }}",
29-
{% endfor -%}
30-
]
31-
var languageNames = {
32-
{% for lang, name in translations["languages"].items() -%}
33-
{{ lang }}: '{{ name }}',
34-
{% endfor -%}
35-
}
36-
37-
// Handle preview URLs on github
38-
// If preview URL changes, this regex will need to be updated
39-
var re = /preview\/pandas-dev\/pandas\/(?<pr>[0-9]*)\//g;
40-
var previewUrl = '';
41-
for (const match of absBaseUrl.matchAll(re)) {
42-
previewUrl = `/preview/pandas-dev/pandas/${match.groups.pr}`;
43-
}
44-
var pathName = location.pathname.replace(previewUrl, '')
45-
46-
// Create dropdown menu
47-
function makeDropdown(options) {
48-
var dropdown = document.createElement("li");
49-
dropdown.classList.add("nav-item");
50-
dropdown.classList.add("dropdown");
19+
function changeLanguage(lang) {
20+
var absBaseUrl = document.baseURI;
21+
var baseUrl = location.protocol + "//" + location.hostname
22+
var currentLanguage = document.documentElement.lang;
23+
var languages = [
24+
{% for lang, name in translations["languages"].items() -%}
25+
"{{ lang }}",
26+
{% endfor -%}
27+
]
5128

52-
var link = document.createElement("a");
53-
link.classList.add("nav-link");
54-
link.classList.add("dropdown-toggle");
55-
link.setAttribute("data-bs-toggle", "dropdown");
56-
link.setAttribute("href", "#");
57-
link.setAttribute("role", "button");
58-
link.setAttribute("aria-haspopup", "true");
59-
link.setAttribute("aria-expanded", "false");
60-
link.textContent = languageNames[currentLanguage];
61-
62-
var dropdownMenu = document.createElement("div");
63-
dropdownMenu.classList.add("dropdown-menu");
64-
65-
options.forEach(function(i) {
66-
var dropdownItem = document.createElement("a");
67-
dropdownItem.classList.add("dropdown-item");
68-
dropdownItem.textContent = languageNames[i] || i.toUpperCase();
69-
dropdownItem.setAttribute("href", "#");
70-
dropdownItem.addEventListener("click", function() {
71-
var urlLanguage = '';
72-
if (i !== 'en') {
73-
urlLanguage = '/' + i;
74-
}
75-
pathName = pathName.replace('/' + currentLanguage + '/', '/')
76-
var newUrl = baseUrl + previewUrl + urlLanguage + pathName
77-
window.location.href = newUrl;
78-
});
79-
dropdownMenu.appendChild(dropdownItem);
80-
});
81-
82-
dropdown.appendChild(link);
83-
dropdown.appendChild(dropdownMenu);
84-
return dropdown;
85-
}
29+
if (location.port) {
30+
baseUrl = baseUrl + ":" + location.port
31+
}
8632

87-
var container = document.getElementById("language-switcher-container");
88-
if (container) {
89-
var dropdown = makeDropdown(languages);
90-
container.appendChild(dropdown);
33+
// Handle preview URLs on github
34+
// If preview URL changes, this regex will need to be updated
35+
var re = /preview\/pandas-dev\/pandas\/(?<pr>[0-9]*)\//g;
36+
var previewUrl = '';
37+
for (const match of absBaseUrl.matchAll(re)) {
38+
previewUrl = `/preview/pandas-dev/pandas/${match.groups.pr}`;
39+
}
40+
var pathName = location.pathname.replace(previewUrl, '')
41+
var urlLanguage = '';
42+
if (lang !== 'en') {
43+
urlLanguage = '/' + lang;
44+
}
45+
pathName = pathName.replace('/' + currentLanguage + '/', '/')
46+
var newUrl = baseUrl + previewUrl + urlLanguage + pathName
47+
window.location.href = newUrl;
9148
}
92-
});
9349
</script>
9450
</head>
9551
<body>
@@ -104,7 +60,7 @@
10460

10561
<div class="collapse navbar-collapse" id="nav-content">
10662
<ul class="navbar-nav ms-auto">
107-
{% for item in navbar[selected_language] %}
63+
{% for item in navbar[lang] %}
10864
{% if not item.has_subitems %}
10965
<li class="nav-item">
11066
<a class="nav-link" href="{% if not item.target.startswith("http") %}{{ base_url }}{% endif %}{{ item.target }}">{{ item.name }}</a>
@@ -127,7 +83,21 @@
12783
{% endif %}
12884
{% endfor %}
12985
<!-- Language switcher -->
130-
<div id="language-switcher-container"></div>
86+
<li class="nav-item dropdown">
87+
<a class="nav-link dropdown-toggle"
88+
data-bs-toggle="dropdown"
89+
href="#"
90+
role="button"
91+
aria-haspopup="true"
92+
aria-expanded="false">{{ translations["languages"][lang] }}</a>
93+
<div class="dropdown-menu">
94+
{% for language, name in translations["languages"].items() -%}
95+
<a class="dropdown-item"
96+
href="#"
97+
onclick="changeLanguage('{{ language }}')">{{ name }}</a>
98+
{% endfor -%}
99+
</div>
100+
</li>
131101
</ul>
132102
</div>
133103
</div>

web/pandas/config.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
main:
22
templates_path: _templates
33
base_template: "layout.html"
4+
navbar_fname: "navbar.yml"
45
production_url: "https://pandas.pydata.org/"
56
ignore:
67
- _templates/layout.html
78
- config.yml
89
github_repo_url: pandas-dev/pandas
910
context_preprocessors:
11+
- pandas_web.Preprocessors.process_translations
1012
- pandas_web.Preprocessors.current_year
1113
- pandas_web.Preprocessors.navbar_add_info
1214
- pandas_web.Preprocessors.blog_add_posts
@@ -173,12 +175,8 @@ roadmap:
173175
pdeps_path: pdeps
174176
translations:
175177
url: https://github.com/Scientific-Python-Translations/pandas-translations/archive/refs/heads/main.tar.gz
176-
folder: translations
177178
source_path: pandas-translations-main/web/pandas/
178-
default_language: 'en'
179-
default_prefix: ''
180179
languages:
181180
en: English
182181
es: Español
183182
pt: Português
184-
# fr: Français

web/pandas_web.py

Lines changed: 56 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,29 @@ class Preprocessors:
6666
anything else needed just be added with context preprocessors.
6767
"""
6868

69+
@staticmethod
70+
def process_translations(context: dict) -> dict:
71+
"""
72+
Download the translations from the GitHub repository and extract them.
73+
"""
74+
base_folder = os.path.dirname(__file__)
75+
extract_path = os.path.join(base_folder, context["translations"]["source_path"])
76+
shutil.rmtree(extract_path, ignore_errors=True)
77+
response = requests.get(context["translations"]["url"])
78+
if response.status_code == 200:
79+
with tarfile.open(None, "r:gz", io.BytesIO(response.content)) as tar:
80+
tar.extractall(base_folder)
81+
else:
82+
raise Exception(f"Failed to download translations: {response.status_code}")
83+
84+
for lang in list(context["translations"]["languages"].keys())[1:]:
85+
shutil.rmtree(os.path.join(base_folder, "pandas", lang), ignore_errors=True)
86+
shutil.move(
87+
os.path.join(extract_path, lang),
88+
os.path.join(base_folder, "pandas", lang),
89+
)
90+
return context
91+
6992
@staticmethod
7093
def current_year(context: dict) -> dict:
7194
"""
@@ -83,14 +106,38 @@ def navbar_add_info(context: dict) -> dict:
83106
``has_subitems`` that tells which one of them every element is. It
84107
also adds a ``slug`` field to be used as a CSS id.
85108
"""
86-
for language in context["translations"]["languages"]:
87-
for i, item in enumerate(context["navbar"][language]):
88-
if not item.get("translated", True):
89-
item["target"] = f"../{item['target']}"
90109

91-
context["navbar"][language][i] = dict(
110+
def update_target(item: dict, url_prefix: str) -> None:
111+
if item.get("translated", True):
112+
item["target"] = f"{url_prefix}{item['target']}"
113+
else:
114+
item["target"] = f"../{item['target']}"
115+
116+
context["navbar"] = {}
117+
for lang in context["translations"]["languages"]:
118+
prefix = "" if lang == "en" else lang
119+
url_prefix = "" if lang == "en" else lang + "/"
120+
with open(
121+
os.path.join(
122+
context["source_path"], prefix, context["main"]["navbar_fname"]
123+
),
124+
encoding="utf-8",
125+
) as f:
126+
navbar_lang = yaml.safe_load(f)
127+
128+
context["navbar"][lang] = navbar_lang["navbar"]
129+
for i, item in enumerate(navbar_lang["navbar"]):
130+
has_subitems = isinstance(item["target"], list)
131+
if lang != "en":
132+
if has_subitems:
133+
for sub_item in item["target"]:
134+
update_target(sub_item, url_prefix)
135+
else:
136+
update_target(item, url_prefix)
137+
138+
context["navbar"][lang][i] = dict(
92139
item,
93-
has_subitems=isinstance(item["target"], list),
140+
has_subitems=has_subitems,
94141
slug=(item["name"].replace(" ", "-").lower()),
95142
)
96143
return context
@@ -392,7 +439,7 @@ def get_callable(obj_as_str: str) -> object:
392439
return obj
393440

394441

395-
def get_context(config_fname: str, navbar_fname: str, **kwargs: dict) -> dict:
442+
def get_context(config_fname: str, **kwargs: dict) -> dict:
396443
"""
397444
Load the config yaml as the base context, and enrich it with the
398445
information added by the context preprocessors defined in the file.
@@ -401,24 +448,8 @@ def get_context(config_fname: str, navbar_fname: str, **kwargs: dict) -> dict:
401448
context = yaml.safe_load(f)
402449

403450
context["source_path"] = os.path.dirname(config_fname)
404-
405-
default_language = context["translations"]["default_language"]
406-
default_prefix = context["translations"]["default_prefix"]
407-
translated_languages = context["translations"]["languages"].copy()
408-
translated_languages.pop(default_language)
409-
context["translated_languages"] = translated_languages
410-
download_and_extract_translations(context)
411-
navbar = {}
412-
for language in context["translations"]["languages"]:
413-
prefix = default_prefix if language == default_language else language
414-
with open(
415-
os.path.join(context["source_path"], prefix, navbar_fname), encoding="utf-8"
416-
) as f:
417-
navbar_lang = yaml.safe_load(f)
418-
navbar[language] = navbar_lang["navbar"]
419-
context["navbar"] = navbar
420-
421451
context.update(kwargs)
452+
422453
preprocessors = (
423454
get_callable(context_prep)
424455
for context_prep in context["main"]["context_preprocessors"]
@@ -453,27 +484,6 @@ def extend_base_template(content: str, base_template: str) -> str:
453484
return result
454485

455486

456-
def download_and_extract_translations(context: dict) -> None:
457-
"""
458-
Download the translations from the GitHub repository and extract them.
459-
"""
460-
base_folder = os.path.dirname(__file__)
461-
extract_path = os.path.join(base_folder, context["translations"]["folder"])
462-
shutil.rmtree(extract_path, ignore_errors=True)
463-
response = requests.get(context["translations"]["url"])
464-
if response.status_code == 200:
465-
with tarfile.open(None, "r:gz", io.BytesIO(response.content)) as tar:
466-
tar.extractall(os.path.join(base_folder, context["translations"]["folder"]))
467-
else:
468-
raise Exception(f"Failed to download translations: {response.status_code}")
469-
for lang in context["translated_languages"]:
470-
shutil.rmtree(os.path.join(base_folder, "pandas", lang), ignore_errors=True)
471-
shutil.move(
472-
os.path.join(extract_path, context["translations"]["source_path"], lang),
473-
os.path.join(base_folder, "pandas", lang),
474-
)
475-
476-
477487
def main(
478488
source_path: str,
479489
target_path: str,
@@ -490,22 +500,14 @@ def main(
490500
sys.stderr.write("Generating context...\n")
491501
context = get_context(
492502
os.path.join(source_path, "config.yml"),
493-
navbar_fname="navbar.yml",
494503
target_path=target_path,
495504
)
496505
sys.stderr.write("Context generated\n")
497506

498507
templates_path = os.path.join(source_path, context["main"]["templates_path"])
499508
jinja_env = jinja2.Environment(loader=jinja2.FileSystemLoader(templates_path))
500-
501509
for fname in get_source_files(source_path):
502-
selected_language = context["translations"]["default_language"]
503-
for language in context["translated_languages"]:
504-
if fname.startswith(language + "/"):
505-
selected_language = language
506-
break
507-
508-
context["selected_language"] = selected_language
510+
context["lang"] = fname[0:2] if fname[2] == "/" else "en"
509511
if os.path.normpath(fname) in context["main"]["ignore"]:
510512
continue
511513

@@ -527,11 +529,6 @@ def main(
527529
content = extend_base_template(body, context["main"]["base_template"])
528530

529531
context["base_url"] = "".join(["../"] * os.path.normpath(fname).count("/"))
530-
if selected_language != context["translations"]["default_language"]:
531-
context["base_url"] = "".join(
532-
["../"] * (os.path.normpath(fname).count("/") - 1)
533-
)
534-
535532
content = jinja_env.from_string(content).render(**context)
536533
fname_html = os.path.splitext(fname)[0] + ".html"
537534
with open(

0 commit comments

Comments
 (0)