From 8ce181bfbfe171065a3d016284a666a88a53b80f Mon Sep 17 00:00:00 2001
From: Ziwei Wang <ziwei.wang@savoirfairelinux.com>
Date: Fri, 4 Aug 2023 17:30:14 -0400
Subject: [PATCH] Add dropdown for selecting languages

Change-Id: If40c46320cf3db24b4b94fb9982f5fa589a0011d
---
 _templates/language-selector.html |  66 ++++++++
 _templates/layout.html            | 252 ++++++++++++++++++++++++++++++
 conf.py                           |  53 ++++++-
 3 files changed, 370 insertions(+), 1 deletion(-)
 create mode 100644 _templates/language-selector.html
 create mode 100644 _templates/layout.html

diff --git a/_templates/language-selector.html b/_templates/language-selector.html
new file mode 100644
index 00000000..caf90781
--- /dev/null
+++ b/_templates/language-selector.html
@@ -0,0 +1,66 @@
+<select id="language-selector" onchange="handleChangeLanguage();" style="width: 100%; position: absolute;">
+    {% for lang, lang_url in languages %}
+    <option value="{{ lang_url }}">
+        {{ lang }}
+    </option>
+    {% endfor %}
+</select>
+
+<script>
+    // Should be consistent with the list `languages` in conf.py
+    let available_lang_code = ['/ar/', '/bg/', '/bn/', '/ca/', '/da/', '/de/', '/el/', '/en_US/', '/eo/', '/es/', '/et/', '/eu/', '/fa/', '/fi/', '/fr/', '/he/', '/hi/', '/hi_IN/', '/hr/', '/hu/', '/id/', '/it/', '/ja/', '/ko/', '/lt/', '/ne/', '/nl/', '/pl/', '/pt/', '/pt_BR/', '/pt_PT/', '/ro/', '/ru/', '/si/', '/sk/', '/sl/', '/sr/', '/sv/', '/ta/', '/te/', '/tr/', '/vi/', '/zh_CN/', '/zh_TW/'];
+    let selector = document.getElementById('language-selector');
+    let site_domain = /docs\.jami\.net/;
+    function handleChangeLanguage(e) {
+        let target_lang_code = selector.value;
+        let current_url = window.location.href;
+        let found_site_domain = current_url.match(site_domain);
+        // Replace lang code
+        window.location.href = current_url.slice(0, found_site_domain.index + found_site_domain[0].length) + '/' + target_lang_code + '/' + current_url.slice(found_site_domain.index + found_site_domain[0].length + getCurrentLangCode().length + 2);
+    }
+
+    //Get current lang code from the URL
+    function getCurrentLangCode() {
+        let current_url = window.location.href;
+        let current_lang_code = '';
+
+        for (let i = 0; i < available_lang_code.length; ++i) {
+            if (current_url.indexOf(available_lang_code[i]) !== -1) {
+                // exclude the leading and trailing '/''
+                current_lang_code = available_lang_code[i].slice(1, -1);
+            }
+        }
+        return current_lang_code;
+    }
+
+     // Use system language if avaiable lang codes not found in the URL
+     document.addEventListener('DOMContentLoaded', function () {
+        let current_lang_code = getCurrentLangCode();
+
+        //Most modern browsers use hypen (IETF language tags) as a separator. Transifex uses underscore. Underscores are preferred for the convenience of working with Transifex.
+        let browserLang = navigator.language.replace('-', '_') || 'en_US'; 
+
+        let current_url = window.location.href;
+        let found_site_domain = current_url.match(site_domain);
+        
+        if(current_lang_code === ''){
+            let lang = browserLang;
+            // if browser language is not supported, use en_US
+            if(available_lang_code.indexOf(`/${browserLang}/`) === -1){
+                lang = 'en_US';
+            }
+                
+            window.location.href = current_url.slice(0, found_site_domain.index + found_site_domain[0].length) + '/' + lang + current_url.slice(found_site_domain.index + found_site_domain[0].length);
+        }
+
+    })
+
+    //Display current language in language selector on page load
+    document.addEventListener('DOMContentLoaded', function () {
+        let current_lang_code = getCurrentLangCode();
+
+        document.querySelectorAll(`option[value='${current_lang_code}']`).forEach(option => {
+            option.setAttribute('selected', '');
+        })
+    })
+</script>
\ No newline at end of file
diff --git a/_templates/layout.html b/_templates/layout.html
new file mode 100644
index 00000000..993b52ce
--- /dev/null
+++ b/_templates/layout.html
@@ -0,0 +1,252 @@
+<!-- This file is identical to layout.html in sphinx_rtd_theme. The only difference is the language selector added at the bottom of the nav with class 'wy-nav-side' -->
+{# TEMPLATE VAR SETTINGS #}
+{%- set url_root = pathto('', 1) %}
+{%- if url_root == '#' %}{% set url_root = '' %}{% endif %}
+{%- if not embedded and docstitle %}
+  {%- set titlesuffix = " &mdash; "|safe + docstitle|e %}
+{%- else %}
+  {%- set titlesuffix = "" %}
+{%- endif %}
+{%- set lang_attr = 'en' if language == None else (language | replace('_', '-')) %}
+{%- set sphinx_writer = 'writer-html5' if html5_doctype else 'writer-html4' -%}
+
+{# Build sphinx_version_info tuple from sphinx_version string in pure Jinja #}
+{%- set (_ver_major, _ver_minor) = (sphinx_version.split('.') | list)[:2] | map('int') -%}
+{%- set sphinx_version_info = (_ver_major, _ver_minor, -1) -%}
+
+<!DOCTYPE html>
+<html class="{{ sphinx_writer }}" lang="{{ lang_attr }}" >
+<head>
+  <meta charset="utf-8" />
+  {{- metatags }}
+  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+  {%- block htmltitle %}
+  <title>{{ title|striptags|e }}{{ titlesuffix }}</title>
+  {%- endblock -%}
+
+  {#- CSS #}
+  {%- if sphinx_version_info < (4, 0) -%}
+    <link rel="stylesheet" href="{{ pathto('_static/' + style, 1) }}" type="text/css" />
+    <link rel="stylesheet" href="{{ pathto('_static/pygments.css', 1) }}" type="text/css" />
+  {%- endif %}
+  {%- for css in css_files %}
+    {%- if css|attr("rel") %}
+      <link rel="{{ css.rel }}" href="{{ pathto(css.filename, 1) }}" type="text/css"{% if css.title is not none %} title="{{ css.title }}"{% endif %} />
+    {%- else %}
+      <link rel="stylesheet" href="{{ pathto(css, 1) }}" type="text/css" />
+    {%- endif %}
+  {%- endfor %}
+
+  {%- for cssfile in extra_css_files %}
+    <link rel="stylesheet" href="{{ pathto(cssfile, 1) }}" type="text/css" />
+  {%- endfor -%}
+
+  {#- FAVICON
+      favicon_url is the only context var necessary since Sphinx 4.
+      In Sphinx<4, we use favicon but need to prepend path info.
+  #}
+  {%- set _favicon_url = favicon_url | default(pathto('_static/' + (favicon or ""), 1)) %}
+  {%- if favicon_url or favicon %}
+    <link rel="shortcut icon" href="{{ _favicon_url }}"/>
+  {%- endif %}
+
+  {#- CANONICAL URL (deprecated) #}
+  {%- if theme_canonical_url and not pageurl %}
+    <link rel="canonical" href="{{ theme_canonical_url }}{{ pagename }}.html"/>
+  {%- endif -%}
+
+  {#- CANONICAL URL #}
+  {%- if pageurl %}
+    <link rel="canonical" href="{{ pageurl|e }}" />
+  {%- endif -%}
+
+  {#- JAVASCRIPTS #}
+  {%- block scripts %}
+  <!--[if lt IE 9]>
+    <script src="{{ pathto('_static/js/html5shiv.min.js', 1) }}"></script>
+  <![endif]-->
+  {%- if not embedded %}
+  {# XXX Sphinx 1.8.0 made this an external js-file, quick fix until we refactor the template to inherert more blocks directly from sphinx #}
+    {%- if sphinx_version_info >= (1, 8) -%}
+      {%- if sphinx_version_info < (4, 0) -%}
+      <script id="documentation_options" data-url_root="{{ url_root }}" src="{{ pathto('_static/documentation_options.js', 1) }}"></script>
+      {%- endif -%}
+      {%- for scriptfile in script_files %}
+        {{ js_tag(scriptfile) }}
+      {%- endfor %}
+    {%- else %}
+      <script>
+          var DOCUMENTATION_OPTIONS = {
+              URL_ROOT:'{{ url_root }}',
+              VERSION:'{{ release|e }}',
+              LANGUAGE:'{{ language }}',
+              COLLAPSE_INDEX:false,
+              FILE_SUFFIX:'{{ '' if no_search_suffix else file_suffix }}',
+              HAS_SOURCE:  {{ has_source|lower }},
+              SOURCELINK_SUFFIX: '{{ sourcelink_suffix }}'
+          };
+      </script>
+      {%- for scriptfile in script_files %}
+        <script src="{{ pathto(scriptfile, 1) }}"></script>
+      {%- endfor %}
+    {%- endif %}
+    <script src="{{ pathto('_static/js/theme.js', 1) }}"></script>
+
+    {#- OPENSEARCH #}
+    {%- if use_opensearch %}
+    <link rel="search" type="application/opensearchdescription+xml"
+          title="{% trans docstitle=docstitle|e %}Search within {{ docstitle }}{% endtrans %}"
+          href="{{ pathto('_static/opensearch.xml', 1) }}"/>
+    {%- endif %}
+  {%- endif %}
+  {%- endblock %}
+
+  {%- block linktags %}
+    {%- if hasdoc('about') %}
+    <link rel="author" title="{{ _('About these documents') }}" href="{{ pathto('about') }}" />
+    {%- endif %}
+    {%- if hasdoc('genindex') %}
+    <link rel="index" title="{{ _('Index') }}" href="{{ pathto('genindex') }}" />
+    {%- endif %}
+    {%- if hasdoc('search') %}
+    <link rel="search" title="{{ _('Search') }}" href="{{ pathto('search') }}" />
+    {%- endif %}
+    {%- if hasdoc('copyright') %}
+    <link rel="copyright" title="{{ _('Copyright') }}" href="{{ pathto('copyright') }}" />
+    {%- endif %}
+    {%- if next %}
+    <link rel="next" title="{{ next.title|striptags|e }}" href="{{ next.link|e }}" />
+    {%- endif %}
+    {%- if prev %}
+    <link rel="prev" title="{{ prev.title|striptags|e }}" href="{{ prev.link|e }}" />
+    {%- endif %}
+  {%- endblock %}
+  {%- block extrahead %} {% endblock %}
+</head>
+
+<body class="wy-body-for-nav">
+
+  {%- block extrabody %} {% endblock %}
+  <div class="wy-grid-for-nav">
+    {#- SIDE NAV, TOGGLES ON MOBILE #}
+    <nav data-toggle="wy-nav-shift" class="wy-nav-side">
+      <div class="wy-side-scroll">
+        <div class="wy-side-nav-search" {% if theme_style_nav_header_background %} style="background: {{theme_style_nav_header_background}}" {% endif %}>
+          {%- block sidebartitle %}
+
+          {# the logo helper function was removed in Sphinx 6 and deprecated since Sphinx 4 #}
+          {# the master_doc variable was renamed to root_doc in Sphinx 4 (master_doc still exists in later Sphinx versions) #}
+          {%- set _logo_url = logo_url|default(pathto('_static/' + (logo or ""), 1)) %}
+          {%- set _root_doc = root_doc|default(master_doc) %}
+          <a href="{{ pathto(_root_doc) }}"{% if not theme_logo_only %} class="icon icon-home"{% endif %}>
+            {% if not theme_logo_only %}{{ project }}{% endif %}
+            {%- if logo or logo_url %}
+              <img src="{{ _logo_url }}" class="logo" alt="{{ _('Logo') }}"/>
+            {%- endif %}
+          </a>
+
+          {%- if theme_display_version %}
+            {%- set nav_version = version %}
+            {%- if READTHEDOCS and current_version %}
+              {%- set nav_version = current_version %}
+            {%- endif %}
+            {%- if nav_version %}
+              <div class="version">
+                {{ nav_version }}
+              </div>
+            {%- endif %}
+          {%- endif %}
+
+          {%- include "searchbox.html" %}
+
+          {%- endblock %}
+        </div>
+
+        {%- block navigation %}
+        {#- Translators: This is an ARIA section label for the main navigation menu -#}
+        <div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="{{ _('Navigation menu') }}">
+          {%- block menu %}
+            {%- set toctree = toctree(maxdepth=theme_navigation_depth|int,
+                                      collapse=theme_collapse_navigation|tobool,
+                                      includehidden=theme_includehidden|tobool,
+                                      titles_only=theme_titles_only|tobool) %}
+            {%- if toctree %}
+              {{ toctree }}
+            {%- else %}
+              <!-- Local TOC -->
+              <div class="local-toc">{{ toc }}</div>
+            {%- endif %}
+          {%- endblock %}
+        </div>
+        {%- endblock %}
+      </div>
+      {% include "language-selector.html" %} 
+    </nav>
+
+    <section data-toggle="wy-nav-shift" class="wy-nav-content-wrap">
+
+      {#- MOBILE NAV, TRIGGLES SIDE NAV ON TOGGLE #}
+      {#- Translators: This is an ARIA section label for the navigation menu that is visible when viewing the page on mobile devices -#}
+      <nav class="wy-nav-top" aria-label="{{ _('Mobile navigation menu') }}" {% if theme_style_nav_header_background %} style="background: {{theme_style_nav_header_background}}" {% endif %}>
+        {%- block mobile_nav %}
+          <i data-toggle="wy-nav-top" class="fa fa-bars"></i>
+          <a href="{{ pathto(master_doc) }}">{{ project }}</a>
+        {%- endblock %}
+      </nav>
+
+      <div class="wy-nav-content">
+      {%- block content %}
+        {%- if theme_style_external_links|tobool %}
+        <div class="rst-content style-external-links">
+        {%- else %}
+        <div class="rst-content">
+        {%- endif %}
+          {% include "breadcrumbs.html" %}
+          <div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
+          {%- block document %}
+           <div itemprop="articleBody">
+             {% block body %}{% endblock %}
+           </div>
+           {%- if self.comments()|trim %}
+             <div class="articleComments">
+               {%- block comments %}{% endblock %}
+             </div>
+           {%- endif%}
+          </div>
+          {%- endblock %}
+          {% include "footer.html" %}
+        </div>
+      {%- endblock %}
+      </div>
+    </section>
+  </div>
+  {% include "versions.html" -%}
+
+  <script>
+      jQuery(function () {
+          SphinxRtdTheme.Navigation.enable({{ 'true' if theme_sticky_navigation|tobool else 'false' }});
+      });
+  </script>
+
+  {#- Do not conflict with RTD insertion of analytics script #}
+  {%- if not READTHEDOCS %}
+    {%- if theme_analytics_id %}
+    <!-- Theme Analytics -->
+    <script async src="https://www.googletagmanager.com/gtag/js?id={{ theme_analytics_id }}"></script>
+    <script>
+      window.dataLayer = window.dataLayer || [];
+      function gtag(){dataLayer.push(arguments);}
+      gtag('js', new Date());
+
+      gtag('config', '{{ theme_analytics_id }}', {
+          'anonymize_ip': {{ 'true' if theme_analytics_anonymize_ip|tobool else 'false' }},
+      });
+    </script>
+
+    {%- endif %}
+  {%- endif %}
+
+  {%- block footer %} {% endblock %}
+
+</body>
+</html>
diff --git a/conf.py b/conf.py
index 80157e9b..3fe5c7c9 100644
--- a/conf.py
+++ b/conf.py
@@ -75,7 +75,7 @@ autosectionlabel_maxdepth = 4
 
 templates_path = ['_templates']
 
-exclude_patterns = ['_build']
+exclude_patterns = ['_build', '*env*', 'README.md']
 
 html_theme = 'sphinx_rtd_theme'
 
@@ -93,3 +93,54 @@ html_static_path = ['_static']
 # internationalization / translations
 locale_dirs = ['locales']
 gettext_compact = True
+
+languages = {
+    'العربية': 'ar',
+    'Български': 'bg',
+    'বাংলা': 'bn',
+    'Català': 'ca',
+    'Dansk': 'da',
+    'Deutsch': 'de',  
+    'Ελληνικά': 'el',
+    'English (US)': 'en_US',
+    'Esperanto': 'eo',
+    'Español': 'es',  
+    'Eesti': 'et',
+    'Euskara': 'eu',
+    'فارسی': 'fa',
+    'Suomi': 'fi',
+    'Français': 'fr',
+    'עברית': 'he',
+    'हिन्दी': 'hi',
+    'हिन्दी (भारत)': 'hi_IN',
+    'Hrvatski': 'hr',
+    'magyar': 'hu',
+    'Indonesia': 'id',
+    'Italiano': 'it',
+    '日本語': 'ja',
+    '한국어': 'ko',
+    'Lietuvių': 'lt',
+    'नेपाली': 'ne',
+    'Nederlands': 'nl',
+    'Polski': 'pl',
+    'Português': 'pt',
+    'Português (Brasil)': 'pt_BR',
+    'Português (Portugal)': 'pt_PT',
+    'Română': 'ro',
+    'Русский': 'ru',
+    #'සිංහල': 'si',  # TODO: Enable this language when translations are provided
+    'Slovenčina': 'sk',
+    'Slovenščina': 'sl',
+    'Српски': 'sr',
+    'Svenska': 'sv',
+    'தமிழ்': 'ta',
+    'తెలుగు': 'te',
+    'Türkçe': 'tr',
+    'Tiếng Việt': 'vi',
+    '中文简体': 'zh_CN',
+    '中文繁體': 'zh_TW',
+}
+
+html_context = {
+    'languages' : list(languages.items()),
+}  
\ No newline at end of file
-- 
GitLab