Display data from array x in 'for' loop based on array y

Hello!

In a site’s config.yml I have languages: ["en", "de"]. For each of the languages listed in the config file, I would like to include an item in the language menu. The language menu currently has the following code:

{% for language in site.data.languages %}
<a class="dropdown-item" onchange="location = this.value;"
    href="{% if language.code != 'en' %}/{{ language.code }}{% endif %}{{ page.url | replace: '.html', '' | remove: 'index' }}">{{ language.name }}</a>
{% endfor %}

I need to add code that, given the language code, prints the corresponding language name, from the file _data/languages.yml:

- code: en
  name: English
- code: de
  name: Deutsch
- code: nl
  name: Nederlands

From this reference (linked from this thread), I figured that {% assign lang-code = language[] %} will print each array item (all the language codes in the config file, with the forloop).

But now the question is: based on that lang-code, how do I print the matching language name, based on that code? I thought of something like {% assign lang-name = site.data.languages.{{ lang-code }}.name %} but that doesn’t work :slight_smile:

Many thanks for any pointers!

Don’t use a hyphen in a variable name. It can give errors.

And just use hard bracket to look up

site.data.languages[lang_code].name 

But still that solution is going to work.

Make sure you understand the difference between an array and a map.

You have an array of map objects. Which means you need a numeric index from 0 to 2 to look up. e.g. site.data.languages[0]

- code: en
  name: English
- code: de
  name: Deutsch
- code: nl
  name: Nederlands

Your use case makes sense as a map instead. Which uses a string to look up as a key, not a numeric index.

en: English
de: Deutch
ne: Nederlands

Given

{% assign lang_code = "en" %}

You can look up the full name using

{% assign lang_name = site.data.languages[lang_code] %}

Or for more complex data:

en:
  name: English
  country: England
de: 
  name: Deutch
  # ...
{% assign lang_name = site.data.languages[lang_code].name %}
{% assign country = site.data.languages[lang_code].country %}
1 Like

I don’t see the point in doing this.

If you don’t like .html extension then use

permalink: pretty

So

/about.html
/about/me.html

Becomes

/about/
/about/me/

And I don’t think removing index helps either as the index.md page will have page.url of / and not /index.html, regardless of what permalink setting to you use.

Thanks again @MichaelCurrin!

Duly noted.

I have looked it up and understand it now. It appears I had tried using a map before (copying the structure used for the files containing translation strings), but my liquid code was not correct to pick it up :slight_smile:

I set the _data/languages.yml to this:

en: English
de: Deutsch
nl: Nederlands

and the _includes/nav_languages.html to this:

{% for lang_code in site.languages %}
{% assign lang_name = site.data.languages[lang_code] %}
<a class="dropdown-item" onchange="location = this.value;"
    href="{% if lang_code != 'en' %}/{{ lang_code }}{% endif %}{{ page.url | replace: '.html', '' | remove: 'index' }}">{{ lang_name }}</a>
{% endfor %}

I wasn’t sure why you mentioned {% assign lang_code = "en" %} (assigning a fixed lang_code would only repeatedly show one language in the menu), but I figure that was to introduce the variable used in the next line.

All worked! But then I got thinking that actually the languages should be displayed in alphabetical order, not in whatever order we added them in _config.yml.

Thinking & experimenting process

To do that, I think, I would need to:

  • load the map, and created a sorted array based on the values - is that possible?
    I saw something like {% assign languages = site.data.languages | sort_natural: 'name' %} but, I don’t get where the ‘name’ comes from (?) And how can I set
  • base the forloop not on site.languages, but on site.data.languages
    (I reckon it’s not possible to base the forloop on site.languages while make its sorting based on the values of another map (site.data.languages).)
  • in each loop, check if the language code is present in _config.yml and if not, simply skip it/do nothing. I saw I can use the contain operator for this.

So I tried the following, but that threw an error :slight_smile:

{% assign languages = site.data.languages | sort: 'title' %}
{% for language in languages %}
  {% assign lang_code = language[0] %}
  {% if site.languages contains lang_code %}
    {% assign lang_name = language[1] %}
    <a class="dropdown-item" onchange="location = this.value;"
      href="{% if lang_code != 'en' %}/{{ lang_code }}{% endif %}{{ page.url | replace: '.html', '' | remove: 'index' }}">{{ lang_name }}</a>
  {% endif %}
{% endfor %}

So I changed the data back to an array (instead of map) and adjusted the liquid code.

Now I have the following in _data/languages.yml

- code: en
  name: English
- code: de
  name: Deutsch
- code: nl
  name: Nederlands

And is _includes/nav_languages.html as follows:

{% assign languages = site.data.languages | sort: 'name' %}
{% for language in languages %}
  {% if site.languages contains language.code %}
    <a class="dropdown-item" onchange="location = this.value;"
      href="{% if language.code != 'en' %}/{{ language.code }}{% endif %}{{ page.url | replace: '.html', '' | remove: 'index' }}">{{ language.name }}</a>
  {% endif %}
{% endfor %}

And it seems to work :smiley: Is this a good/sensible approach?


About the page.url code: this code was already there, from the person creating the site. That code is used in multiple places across the site. I’ll experiment with the ‘pretty permalink’ per your suggestion. (Maybe it doesn’t work with the translation plugin that we use.) Will report back.

As my previous post got blocked automatically by the system, the discussion & feedback continued on GitHub.
So for others reading this: catch up with the rest here: Improve site-readiness for translations by keunes · Pull Request #112 · AntennaPod/antennapod.github.io · GitHub
TL;DR: the approach mentioned is fine (if you want to sort the language list automatically) :slight_smile:

1 Like