Skip to content

Commit 6d4e469

Browse files
Option to switch languages
1 parent 6565bd1 commit 6d4e469

File tree

7 files changed

+188
-19
lines changed

7 files changed

+188
-19
lines changed

_config.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,104 +33,150 @@ plugins:
3333
# Navigation
3434
nav:
3535
- title: "Getting Started"
36+
page_id: getting_started
3637
url: "/en/docs/getting-started/"
3738
children:
3839
- title: "Installation"
40+
page_id: getting_started__installation
3941
url: "/en/docs/getting-started/installation/"
4042
- title: "Quick Start"
43+
page_id: getting_started__quick_start
4144
url: "/en/docs/getting-started/quick-start/"
4245
- title: "REPL Guide"
46+
page_id: getting_started__repl
4347
url: "/en/docs/getting-started/repl/"
4448
- title: "Language Guide"
49+
page_id: language_guide
4550
url: "/en/docs/language-guide/"
4651
children:
4752
- title: "Overview"
53+
page_id: language_guide
4854
url: "/en/docs/language-guide/"
4955
- title: "Syntax Reference"
56+
page_id: language_guide__syntax
5057
url: "/en/docs/language-guide/syntax/"
5158
- title: "Keywords"
59+
page_id: language_guide__keywords
5260
url: "/en/docs/language-guide/keywords/"
5361
- title: "Control Flow"
62+
page_id: language_guide__control_flow
5463
url: "/en/docs/language-guide/control-flow/"
5564
- title: "Functions & Classes"
65+
page_id: language_guide__functions_classes
5666
url: "/en/docs/language-guide/functions-classes/"
5767
- title: "Async & Generators"
68+
page_id: language_guide__async_generators
5869
url: "/en/docs/language-guide/async-generators/"
5970
- title: "All 17 Languages"
71+
page_id: language_guide__all_languages
6072
url: "/en/docs/language-guide/all-languages/"
6173
- title: "Guide Français"
74+
page_id: language_guide__french
6275
url: "/en/docs/language-guide/french/"
6376
- title: "Reference"
77+
page_id: reference
6478
url: "/en/docs/reference/"
6579
children:
6680
- title: "Language Concepts"
81+
page_id: reference
6782
url: "/en/docs/reference/"
6883
- title: "Built-in Aliases"
84+
page_id: reference__builtins
6985
url: "/en/docs/reference/builtins/"
7086
- title: "Operators"
87+
page_id: reference__operators
7188
url: "/en/docs/reference/operators/"
7289
- title: "Numerals"
90+
page_id: reference__numerals
7391
url: "/en/docs/reference/numerals/"
7492
- title: "Date & Time"
93+
page_id: reference__datetime
7594
url: "/en/docs/reference/datetime/"
7695
- title: "Compatibility Matrix"
96+
page_id: reference__compatibility
7797
url: "/en/docs/reference/compatibility/"
7898
- title: "WASM Backend"
99+
page_id: wasm
79100
url: "/en/docs/wasm/"
80101
children:
81102
- title: "Overview"
103+
page_id: wasm
82104
url: "/en/docs/wasm/"
83105
- title: "Installation"
106+
page_id: wasm__installation
84107
url: "/en/docs/wasm/installation/"
85108
- title: "Architecture"
109+
page_id: wasm__architecture
86110
url: "/en/docs/wasm/architecture/"
87111
- title: "Performance"
112+
page_id: wasm__performance
88113
url: "/en/docs/wasm/performance/"
89114
- title: "Development"
115+
page_id: wasm__development
90116
url: "/en/docs/wasm/development/"
91117
- title: "Troubleshooting"
118+
page_id: wasm__troubleshooting
92119
url: "/en/docs/wasm/troubleshooting/"
93120
- title: "FAQ"
121+
page_id: wasm__faq
94122
url: "/en/docs/wasm/faq/"
95123
- title: "Upgrade to v0.4"
124+
page_id: wasm__upgrade
96125
url: "/en/docs/wasm/upgrade/"
97126
- title: "Python Codegen"
127+
page_id: codegen
98128
url: "/en/docs/codegen/"
99129
children:
100130
- title: "Overview"
131+
page_id: codegen
101132
url: "/en/docs/codegen/"
102133
- title: "API Reference"
134+
page_id: codegen__api
103135
url: "/en/docs/codegen/api/"
104136
- title: "Design"
137+
page_id: design
105138
url: "/en/docs/design/"
106139
children:
107140
- title: "Architecture"
141+
page_id: design
108142
url: "/en/docs/design/"
109143
- title: "Core Specification"
144+
page_id: design__core_spec
110145
url: "/en/docs/design/core-spec/"
111146
- title: "Frontend Contracts"
147+
page_id: design__frontend_contracts
112148
url: "/en/docs/design/frontend-contracts/"
113149
- title: "Surface Normalization"
150+
page_id: design__surface_normalization
114151
url: "/en/docs/design/surface-normalization/"
115152
- title: "Stdlib Localization"
153+
page_id: design__stdlib_localization
116154
url: "/en/docs/design/stdlib-localization/"
117155
- title: "Related Work"
156+
page_id: design__related_work
118157
url: "/en/docs/design/related-work/"
119158
- title: "Extending"
159+
page_id: extending
120160
url: "/en/docs/extending/"
121161
children:
122162
- title: "Add a Language"
163+
page_id: extending
123164
url: "/en/docs/extending/"
124165
- title: "Translation Guidelines"
166+
page_id: extending__translation
125167
url: "/en/docs/extending/translation/"
126168
- title: "CNL Scope"
169+
page_id: extending__cnl_scope
127170
url: "/en/docs/extending/cnl-scope/"
128171
- title: "Contributing"
172+
page_id: contributing
129173
url: "/en/docs/contributing/"
130174
children:
131175
- title: "Development Guide"
176+
page_id: contributing
132177
url: "/en/docs/contributing/"
133178
- title: "Multilingual Docs Ops"
179+
page_id: contributing__multilingual_docs
134180
url: "/en/docs/contributing/multilingual-docs/"
135181

136182
# Collections

_data/locales.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
- code: en
2+
label: English
3+
native_label: English
4+
docs_enabled: true
5+
docs_home_page_id: getting_started
6+
- code: fr
7+
label: French
8+
native_label: Francais
9+
docs_enabled: true
10+
docs_home_page_id: getting_started

_includes/localized-url.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{% assign resolved_url = include.fallback_url | default: '/' %}
2+
{% assign target_locale = include.locale | default: page.locale | default: 'en' %}
3+
{% if include.page_id %}
4+
{% assign candidates = site.pages | where: "page_id", include.page_id %}
5+
{% for candidate in candidates %}
6+
{% if candidate.locale == target_locale %}
7+
{% assign resolved_url = candidate.url %}
8+
{% break %}
9+
{% endif %}
10+
{% endfor %}
11+
{% endif %}
12+
{{ resolved_url | relative_url }}

_includes/sidebar.html

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
{% assign nav = site.nav %}
2+
{% assign current_locale = page.locale | default: 'en' %}
23
<div class="sidebar-nav">
34
{% for section in nav %}
5+
{% capture section_url %}{% include localized-url.html page_id=section.page_id fallback_url=section.url locale=current_locale %}{% endcapture %}
6+
{% assign section_active_prefix = section.page_id | append: '__' %}
47
<div class="sidebar-section">
5-
<a href="{{ section.url | relative_url }}" class="sidebar-section-title{% if page.url == section.url or page.url contains section.url %} active{% endif %}">
8+
<a href="{{ section_url | strip }}" class="sidebar-section-title{% if page.page_id == section.page_id or page.page_id contains section_active_prefix %} active{% endif %}">
69
{{ section.title }}
710
</a>
811
{% if section.children %}
912
<ul class="sidebar-items">
1013
{% for item in section.children %}
14+
{% capture item_url %}{% include localized-url.html page_id=item.page_id fallback_url=item.url locale=current_locale %}{% endcapture %}
1115
<li class="sidebar-item">
12-
<a href="{{ item.url | relative_url }}" class="sidebar-link{% if page.url == item.url %} active{% endif %}">
16+
<a href="{{ item_url | strip }}" class="sidebar-link{% if page.page_id == item.page_id %} active{% endif %}">
1317
{{ item.title }}
1418
</a>
1519
</li>

_layouts/default.html

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<!DOCTYPE html>
2-
<html lang="en" class="dark-theme">
2+
{% assign current_locale = page.locale | default: 'en' %}
3+
<html lang="{{ current_locale }}" class="dark-theme">
34
<head>
45
<meta charset="UTF-8" />
56
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
@@ -44,15 +45,44 @@
4445
</a>
4546

4647
<div class="nav-links" role="navigation">
47-
<a href="{{ '/en/docs/getting-started/' | relative_url }}" class="nav-link{% if page.url contains '/getting-started' %} active{% endif %}">Getting Started</a>
48-
<a href="{{ '/en/docs/language-guide/' | relative_url }}" class="nav-link{% if page.url contains '/language-guide' %} active{% endif %}">Language Guide</a>
49-
<a href="{{ '/en/docs/reference/' | relative_url }}" class="nav-link{% if page.url contains '/reference' %} active{% endif %}">Reference</a>
50-
<a href="{{ '/en/docs/wasm/' | relative_url }}" class="nav-link{% if page.url contains '/wasm' %} active{% endif %}">WASM</a>
51-
<a href="{{ '/en/docs/design/' | relative_url }}" class="nav-link{% if page.url contains '/design' %} active{% endif %}">Design</a>
48+
{% for section in site.nav limit: 5 %}
49+
{% capture section_url %}{% include localized-url.html page_id=section.page_id fallback_url=section.url locale=current_locale %}{% endcapture %}
50+
{% assign section_active_prefix = section.page_id | append: '__' %}
51+
<a href="{{ section_url | strip }}" class="nav-link{% if page.page_id == section.page_id or page.page_id contains section_active_prefix %} active{% endif %}">{{ section.title }}</a>
52+
{% endfor %}
5253
<a href="https://github.com/johnsamuelwrites/multilingual" class="nav-link nav-link-external" target="_blank" rel="noopener noreferrer">
5354
<svg class="icon-github" viewBox="0 0 24 24" fill="currentColor" width="18" height="18" aria-hidden="true"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z"/></svg>
5455
GitHub
5556
</a>
57+
{% assign docs_locales = site.data.locales | where: "docs_enabled", true %}
58+
{% if docs_locales.size > 1 %}
59+
<div class="language-switcher">
60+
<label class="language-switcher-label" for="language-switcher">Language</label>
61+
<select id="language-switcher" class="language-switcher-select" aria-label="Switch documentation language">
62+
{% for locale in docs_locales %}
63+
{% assign option_url = '/' %}
64+
{% if page.page_id %}
65+
{% assign sibling_pages = site.pages | where: "page_id", page.page_id %}
66+
{% for sibling in sibling_pages %}
67+
{% if sibling.locale == locale.code %}
68+
{% assign option_url = sibling.url %}
69+
{% break %}
70+
{% endif %}
71+
{% endfor %}
72+
{% elsif locale.docs_home_page_id %}
73+
{% assign home_pages = site.pages | where: "page_id", locale.docs_home_page_id %}
74+
{% for home_page in home_pages %}
75+
{% if home_page.locale == locale.code %}
76+
{% assign option_url = home_page.url %}
77+
{% break %}
78+
{% endif %}
79+
{% endfor %}
80+
{% endif %}
81+
<option value="{{ option_url | relative_url }}"{% if locale.code == current_locale %} selected{% endif %}>{{ locale.native_label }}</option>
82+
{% endfor %}
83+
</select>
84+
</div>
85+
{% endif %}
5686
</div>
5787

5888
<button class="nav-toggle" aria-label="Toggle menu" aria-expanded="false">
@@ -87,28 +117,38 @@
87117
<div class="footer-col">
88118
<h4>Documentation</h4>
89119
<ul>
90-
<li><a href="{{ '/en/docs/getting-started/' | relative_url }}">Getting Started</a></li>
91-
<li><a href="{{ '/en/docs/language-guide/' | relative_url }}">Language Guide</a></li>
92-
<li><a href="{{ '/en/docs/reference/' | relative_url }}">Reference</a></li>
93-
<li><a href="{{ '/en/docs/wasm/' | relative_url }}">WASM Backend</a></li>
94-
<li><a href="{{ '/en/docs/design/' | relative_url }}">Design &amp; Architecture</a></li>
120+
{% capture footer_getting_started_url %}{% include localized-url.html page_id='getting_started' fallback_url='/en/docs/getting-started/' locale=current_locale %}{% endcapture %}
121+
{% capture footer_language_guide_url %}{% include localized-url.html page_id='language_guide' fallback_url='/en/docs/language-guide/' locale=current_locale %}{% endcapture %}
122+
{% capture footer_reference_url %}{% include localized-url.html page_id='reference' fallback_url='/en/docs/reference/' locale=current_locale %}{% endcapture %}
123+
{% capture footer_wasm_url %}{% include localized-url.html page_id='wasm' fallback_url='/en/docs/wasm/' locale=current_locale %}{% endcapture %}
124+
{% capture footer_design_url %}{% include localized-url.html page_id='design' fallback_url='/en/docs/design/' locale=current_locale %}{% endcapture %}
125+
<li><a href="{{ footer_getting_started_url | strip }}">Getting Started</a></li>
126+
<li><a href="{{ footer_language_guide_url | strip }}">Language Guide</a></li>
127+
<li><a href="{{ footer_reference_url | strip }}">Reference</a></li>
128+
<li><a href="{{ footer_wasm_url | strip }}">WASM Backend</a></li>
129+
<li><a href="{{ footer_design_url | strip }}">Design &amp; Architecture</a></li>
95130
</ul>
96131
</div>
97132
<div class="footer-col">
98133
<h4>Languages</h4>
99134
<ul>
100-
<li><a href="{{ '/en/docs/language-guide/all-languages/' | relative_url }}">All 17 Languages</a></li>
101-
<li><a href="{{ '/en/docs/language-guide/keywords/' | relative_url }}">Keywords</a></li>
102-
<li><a href="{{ '/en/docs/extending/' | relative_url }}">Add a Language</a></li>
103-
<li><a href="{{ '/en/docs/extending/translation/' | relative_url }}">Translation Guide</a></li>
135+
{% capture footer_all_languages_url %}{% include localized-url.html page_id='language_guide__all_languages' fallback_url='/en/docs/language-guide/all-languages/' locale=current_locale %}{% endcapture %}
136+
{% capture footer_keywords_url %}{% include localized-url.html page_id='language_guide__keywords' fallback_url='/en/docs/language-guide/keywords/' locale=current_locale %}{% endcapture %}
137+
{% capture footer_extending_url %}{% include localized-url.html page_id='extending' fallback_url='/en/docs/extending/' locale=current_locale %}{% endcapture %}
138+
{% capture footer_translation_url %}{% include localized-url.html page_id='extending__translation' fallback_url='/en/docs/extending/translation/' locale=current_locale %}{% endcapture %}
139+
<li><a href="{{ footer_all_languages_url | strip }}">All 17 Languages</a></li>
140+
<li><a href="{{ footer_keywords_url | strip }}">Keywords</a></li>
141+
<li><a href="{{ footer_extending_url | strip }}">Add a Language</a></li>
142+
<li><a href="{{ footer_translation_url | strip }}">Translation Guide</a></li>
104143
</ul>
105144
</div>
106145
<div class="footer-col">
107146
<h4>Project</h4>
108147
<ul>
109148
<li><a href="https://github.com/johnsamuelwrites/multilingual" target="_blank" rel="noopener">GitHub</a></li>
110149
<li><a href="https://github.com/johnsamuelwrites/multilingual/issues" target="_blank" rel="noopener">Issues</a></li>
111-
<li><a href="{{ '/en/docs/design/related-work/' | relative_url }}">Related Work</a></li>
150+
{% capture footer_related_work_url %}{% include localized-url.html page_id='design__related_work' fallback_url='/en/docs/design/related-work/' locale=current_locale %}{% endcapture %}
151+
<li><a href="{{ footer_related_work_url | strip }}">Related Work</a></li>
112152
</ul>
113153
</div>
114154
</div>

assets/css/main.css

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,51 @@ body {
157157
margin-left: auto;
158158
}
159159

160+
.language-switcher {
161+
display: flex;
162+
align-items: center;
163+
gap: 0.5rem;
164+
margin-left: 0.5rem;
165+
padding-left: 0.75rem;
166+
border-left: 1px solid var(--border-secondary);
167+
}
168+
169+
.language-switcher-label {
170+
font-size: 0.72rem;
171+
letter-spacing: 0.08em;
172+
text-transform: uppercase;
173+
color: var(--text-muted);
174+
}
175+
176+
.language-switcher-select {
177+
min-width: 8.5rem;
178+
appearance: none;
179+
background:
180+
linear-gradient(180deg, rgba(17, 24, 39, 0.98), rgba(13, 18, 32, 0.98));
181+
border: 1px solid var(--border-secondary);
182+
border-radius: 999px;
183+
color: var(--text-primary);
184+
font-family: var(--font-body);
185+
font-size: 0.84rem;
186+
font-weight: 500;
187+
padding: 0.42rem 2rem 0.42rem 0.85rem;
188+
cursor: pointer;
189+
transition: border-color var(--transition-fast), box-shadow var(--transition-fast), color var(--transition-fast);
190+
background-image:
191+
linear-gradient(180deg, rgba(17, 24, 39, 0.98), rgba(13, 18, 32, 0.98)),
192+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 14 14'%3E%3Cpath fill='%2300d4ff' d='M3.2 4.8L7 8.6l3.8-3.8.9.9L7 10.4 2.3 5.7z'/%3E%3C/svg%3E");
193+
background-repeat: no-repeat, no-repeat;
194+
background-position: 0 0, calc(100% - 0.7rem) 50%;
195+
background-size: auto, 0.9rem;
196+
}
197+
198+
.language-switcher-select:hover,
199+
.language-switcher-select:focus {
200+
border-color: var(--border-primary);
201+
box-shadow: 0 0 0 3px rgba(0, 212, 255, 0.08);
202+
outline: none;
203+
}
204+
160205
.nav-link {
161206
display: flex;
162207
align-items: center;
@@ -1159,6 +1204,8 @@ body {
11591204
.nav-links { display: none; }
11601205
.nav-toggle { display: flex; }
11611206
.nav-links.open { display: flex; flex-direction: column; position: absolute; top: 100%; left: 0; right: 0; background: var(--bg-header); border-bottom: 1px solid var(--border-secondary); padding: 1rem; gap: 0.25rem; }
1207+
.language-switcher { width: 100%; margin: 0.5rem 0 0; padding: 0.75rem 0 0; border-left: none; border-top: 1px solid var(--border-secondary); justify-content: space-between; }
1208+
.language-switcher-select { width: min(100%, 12rem); }
11621209
.footer-grid { grid-template-columns: 1fr; gap: 2rem; }
11631210
.footer-links { grid-template-columns: 1fr 1fr; }
11641211
.stats-strip { gap: 2rem; }
@@ -1441,4 +1488,3 @@ pre:hover .wat-btn { opacity: 1; }
14411488
.main-content { padding: 0; }
14421489
body { background: white; color: black; }
14431490
}
1444-

assets/js/main.js

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,17 @@ except Exception as _e:
379379
});
380380
}
381381

382+
/* ---- Docs language switcher ---- */
383+
const languageSwitcher = document.getElementById('language-switcher');
384+
if (languageSwitcher) {
385+
languageSwitcher.addEventListener('change', event => {
386+
const nextUrl = event.target.value;
387+
if (nextUrl) {
388+
window.location.href = nextUrl;
389+
}
390+
});
391+
}
392+
382393
/* ---- TOC generation ---- */
383394
const toc = document.getElementById('toc');
384395
const article = document.querySelector('.content-body');

0 commit comments

Comments
 (0)