Skip to content

Commit e93135d

Browse files
JulienPalardvstinner
authored andcommitted
bpo-31045: Language switch (#2652) (#3023)
* Doc: Indicate the language * Renaming version_switcher to switchers (to add language_switcher). * Adding language switch. * Doc switchers: Enhance readability of regex parsing versions. * Doc switchers: Desambiguate the need of a replace(/\/+$/g, '') by proper naming. * Doc switchers: py3k can't reach js, it's redirected server-side by nginx. * Doc switchers: Examples matching actual regexes. * Doc switchers: Better fallback on unexisting translated version. (cherry picked from commit dff9b5f)
1 parent 9d7d928 commit e93135d

File tree

4 files changed

+151
-71
lines changed

4 files changed

+151
-71
lines changed

Doc/Makefile

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -167,12 +167,12 @@ serve:
167167

168168
# for development releases: always build
169169
autobuild-dev:
170-
make dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1 -A versionswitcher=1'
170+
make dist SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1 -A switchers=1'
171171
-make suspicious
172172

173173
# for quick rebuilds (HTML only)
174174
autobuild-dev-html:
175-
make html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1 -A versionswitcher=1'
175+
make html SPHINXOPTS='$(SPHINXOPTS) -Ea -A daily=1 -A switchers=1'
176176

177177
# for stable releases: only build if not in pre-release stage (alpha, beta)
178178
# release candidate downloads are okay, since the stable tree can be in that stage

Doc/tools/static/switchers.js

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
(function() {
2+
'use strict';
3+
4+
// Parses versions in URL segments like:
5+
// "3", "dev", "release/2.7" or "3.6rc2"
6+
var version_regexs = [
7+
'(?:\\d)',
8+
'(?:\\d\\.\\d[\\w\\d\\.]*)',
9+
'(?:dev)',
10+
'(?:release/\\d.\\d[\\x\\d\\.]*)'];
11+
12+
var all_versions = {
13+
'3.7': 'dev (3.7)',
14+
'3.6': '3.6',
15+
'3.5': '3.5',
16+
'3.4': '3.4',
17+
'3.3': '3.3',
18+
'2.7': '2.7',
19+
};
20+
21+
var all_languages = {
22+
'en': 'English',
23+
'fr': 'Français',
24+
};
25+
26+
function build_version_select(current_version, current_release) {
27+
var buf = ['<select>'];
28+
29+
$.each(all_versions, function(version, title) {
30+
buf.push('<option value="' + version + '"');
31+
if (version == current_version)
32+
buf.push(' selected="selected">' + current_release + '</option>');
33+
else
34+
buf.push('>' + title + '</option>');
35+
});
36+
37+
buf.push('</select>');
38+
return buf.join('');
39+
}
40+
41+
function build_language_select(current_language) {
42+
var buf = ['<select>'];
43+
44+
$.each(all_languages, function(language, title) {
45+
if (language == current_language)
46+
buf.push('<option value="' + language + '" selected="selected">' +
47+
all_languages[current_language] + '</option>');
48+
else
49+
buf.push('<option value="' + language + '">' + title + '</option>');
50+
});
51+
buf.push('</select>');
52+
return buf.join('');
53+
}
54+
55+
function navigate_to_first_existing(urls) {
56+
// Navigate to the first existing URL in urls.
57+
var url = urls.shift();
58+
if (urls.length == 0) {
59+
window.location.href = url;
60+
return;
61+
}
62+
$.ajax({
63+
url: url,
64+
success: function() {
65+
window.location.href = url;
66+
},
67+
error: function() {
68+
navigate_to_first_existing(urls);
69+
}
70+
});
71+
}
72+
73+
function on_version_switch() {
74+
var selected_version = $(this).children('option:selected').attr('value') + '/';
75+
var url = window.location.href;
76+
var current_language = language_segment_from_url(url);
77+
var current_version = version_segment_in_url(url);
78+
var new_url = url.replace('.org/' + current_language + current_version,
79+
'.org/' + current_language + selected_version);
80+
if (new_url != url) {
81+
navigate_to_first_existing([
82+
new_url,
83+
url.replace('.org/' + current_language + current_version,
84+
'.org/' + selected_version),
85+
'https://docs.python.org/' + current_language + selected_version,
86+
'https://docs.python.org/' + selected_version,
87+
'https://docs.python.org/'
88+
]);
89+
}
90+
}
91+
92+
function on_language_switch() {
93+
var selected_language = $(this).children('option:selected').attr('value') + '/';
94+
var url = window.location.href;
95+
var current_language = language_segment_from_url(url);
96+
var current_version = version_segment_in_url(url);
97+
if (selected_language == 'en/') // Special 'default' case for english.
98+
selected_language = '';
99+
var new_url = url.replace('.org/' + current_language + current_version,
100+
'.org/' + selected_language + current_version);
101+
if (new_url != url) {
102+
navigate_to_first_existing([
103+
new_url,
104+
'https://docs.python.org/'
105+
]);
106+
}
107+
}
108+
109+
// Returns the path segment of the language as a string, like 'fr/'
110+
// or '' if not found.
111+
function language_segment_from_url(url) {
112+
var language_regexp = '\.org/(' + Object.keys(all_languages).join('|') + '/)';
113+
var match = url.match(language_regexp);
114+
if (match !== null)
115+
return match[1];
116+
return '';
117+
}
118+
119+
// Returns the path segment of the version as a string, like '3.6/'
120+
// or '' if not found.
121+
function version_segment_in_url(url) {
122+
var language_segment = '(?:(?:' + Object.keys(all_languages).join('|') + ')/)';
123+
var version_segment = '(?:(?:' + version_regexs.join('|') + ')/)';
124+
var version_regexp = '\\.org/' + language_segment + '?(' + version_segment + ')';
125+
var match = url.match(version_regexp);
126+
if (match !== null)
127+
return match[1];
128+
return ''
129+
}
130+
131+
$(document).ready(function() {
132+
var release = DOCUMENTATION_OPTIONS.VERSION;
133+
var language_segment = language_segment_from_url(window.location.href);
134+
var current_language = language_segment.replace(/\/+$/g, '') || 'en';
135+
var version = release.substr(0, 3);
136+
var version_select = build_version_select(version, release);
137+
138+
$('.version_switcher_placeholder').html(version_select);
139+
$('.version_switcher_placeholder select').bind('change', on_version_switch);
140+
141+
var language_select = build_language_select(current_language);
142+
143+
$('.language_switcher_placeholder').html(language_select);
144+
$('.language_switcher_placeholder select').bind('change', on_language_switch);
145+
});
146+
})();

Doc/tools/static/version_switch.js

Lines changed: 0 additions & 67 deletions
This file was deleted.

Doc/tools/templates/layout.html

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
style="vertical-align: middle; margin-top: -1px"/></li>
55
<li><a href="https://www.python.org/">Python</a>{{ reldelim1 }}</li>
66
<li>
7-
{%- if versionswitcher is defined %}
7+
{%- if switchers is defined %}
8+
<span class="language_switcher_placeholder">{{ language or 'en' }}</span>
89
<span class="version_switcher_placeholder">{{ release }}</span>
910
<a href="{{ pathto('index') }}">{% trans %}Documentation {% endtrans %}</a>{{ reldelim1 }}
1011
{%- else %}
@@ -41,7 +42,7 @@
4142
<link rel="canonical" href="https://docs.python.org/3/{{pagename}}.html" />
4243
{% if builder != "htmlhelp" %}
4344
{% if not embedded %}<script type="text/javascript" src="{{ pathto('_static/copybutton.js', 1) }}"></script>{% endif %}
44-
{% if versionswitcher is defined and not embedded %}<script type="text/javascript" src="{{ pathto('_static/version_switch.js', 1) }}"></script>{% endif %}
45+
{% if switchers is defined and not embedded %}<script type="text/javascript" src="{{ pathto('_static/switchers.js', 1) }}"></script>{% endif %}
4546
{% if pagename == 'whatsnew/changelog' and not embedded %}
4647
<script type="text/javascript">
4748
$(document).ready(function() {

0 commit comments

Comments
 (0)