< Previous Building mucka.pro Next >
23 Mar 2025

Initial multilingualism

Multilingualism of web service can be quite a challenge. I wanted to implement initial draft of multilingualism without major changes in generator. I have decided that content list subpage will be first to receive this feature.

Idea

Webpage should have language selection menu, showed after clicking on language selection button. Button should have form of a flag, that will match currently selected language. Button should be localised somewhere in header. I have prepared sketch drawing, shown in figure 1.

Figure 1. Sketch of language selection menu

Assumptions and Design

List of languages will be prepared on fly, using content metadata. List of languages will be converted into foldable html menu.

Implementation

Firstly I prepared draft of html, which I would like to be output of generator. Draft is shown in listing 1. Draft was very helpful while preparing style sheet.


    <div class="language menu dropdown">
      <div class="language element top">
        <span class="language top">Język</span>
      </div>
      
      <a href="/la/articles.xhtml">
        <div class="language element selector">
          <img class="language flag" src="/static/lang/en.svg" />
          <span class="language name">English</span>
        </div>
      </a>

      <a href="/la/articles.xhtml">
        <div class="language element selector">
          <img class="language flag" src="/static/lang/jp.svg" />
          <span class="language name">日本語</span>
        </div>
      </a>

      <a href="/la/articles.xhtml">
        <div class="language element selector">
          <img class="language flag" src="/static/lang/kr.svg" />
          <span class="language name">한국어</span>
        </div>
      </a>

      <a disabled="disabled">
        <div class="language element selector">
          <img class="language flag" src="/static/lang/pl.svg" />
          <span class="language name">Polski</span>
        </div>
      </a>
    </div>
  
Listing 1. Language menu draft

Style sheet

Having html draft, I moved to preparing style sheet. First element I want to prepare is language selection button.

I need some national flags, I borrowed some from flag-icons. I have chosen this project, because it is shared by lipis user on MIT license.

I declared button as inline-block with float attribute set as right. I might want to have more buttons in header in future. I tried display: flex but I given up after half an hour.


.language.menu {
  display: inline-block;
  float: right;
}

.language.menu .button {
  padding: 5px;
  width: 20px;
  height: 20px;
  background-color: #8c8f94;
}

.language.flag {
  width: 16px;
  height: 16px;
  max-height: 100%;
  max-width: 100%;
  margin: 2px;
}
  
Listing 2. Language selection button

I define menu-width, menu-max-height global constants. I decided on menu width as 200px for large screen, and full screen for mobile.


:root {
  ...
  --menu-width: 100%;
  --menu-max-height: 80vh;
}

@media only screen and (min-width: 800px) {
  :root {
    ...
    --menu-width: 200px;
  }
}
  
Listing 3. Global constants

In order to be able to set menu position as absolute I need to set body position as relative. Absolute position is relative to the nearest positioned ancestor. Positioned, that means absolute or relative.


body {
  ...
  position: relative;
}
  
Listing 4. body postition

I have found several ways to implement foldable menu in css. I have chosen to change value of opacity attribute. I declare dropdown menu as block with absolute position, with intended height and zero width. I set z-index as 1, as menu should cover other elements. I set top and right coordinates to 0. I set overflow to hidden, that way, unfolding animation will be nicer. For overflow to work as I want, I need to set white-space as nowrap. I select timefrwame for unfolding animation to 300ms. Finally I set opacity to 0.

After hovering button, menu is unfolded. This is possible because of changing opacity and width. Simple showing the menu, would require only opacity change. I wanted to include some animation, and decided that changing width looks best.

Last part was a bit of slippery slope. I seriously doubt it could not have been done simpler or better. I wanted to highlight menu element that is currently selected. In the same time, I did not wanted to highlight elements that are marked inactive. In addition to this, I wanted to dim inactive element a bit. What I ended up is following semantic monster, but it works!


.language.menu.dropdown a[disabled="disabled"] .selector {
  color: #8c8f94;
}

.language.menu.dropdown a:not([disabled="disabled"]) .selector:hover {
  background-color: #f0f0f1;
}
  
Listing 6. Dropdown menu elements attributes

Generator

Extending generator with dropdown menu was pretty simple task. Firstly, I reworked my html draft into template shown in listing 7.


language_menu_entry_template = \
"""
      <a {link}>
        <div class="language element selector">
          <img class="language flag" src="/static/lang/{language}.svg" />
          <span class="language name">{language_name}</span>
        </div>
      </a>
"""
  
Listing 7. Menu element template

I generated buttons for all available languages. Currently selected language was added as well, but as inactive button.


def render_list(content_type, path, content_dict, template, language, languages):
    '''Render list of content basing on template'''
    ...
    language_menu_entries = ""
    for selected in sorted(languages):
        link = f"href=\"/{selected}/{content_type}s.xhtml\""
        if selected == language:
            link = "disabled=\"disabled\""

        language_menu_entries += language_menu_entry_template.format(
            link=link,
            language=selected,
            language_name=language_name[selected]
        )

    name = content_type_name_plural[content_type][language]
  
Listing 8. Menu element renderer

Entire implementation can be found in commit 0d610216.

Effect

Final effect is shown in wideo 1. Animation looks smooth, without any visible artifacts, which was not an easy task. Language selection is easy and intuitive, I hope at least. Square button fits rest of the page layout well.

Video 1. Final effect

Summary

Adding multilingualism to list subpage was not a difficult task. All elements required for implementation were ready. Only CSS was a bit of pain. But I know well that it was an easy part. Multilingualism of content page will not be as easy. For now I did not designed any link between multiple translations of the same content. So I need to extend somehow metadata of content first.

release date: 23 Mar 2025
language: en
stage: release
type: article
tags: python html css
< Previous Building mucka.pro Next >