✨ feat(i18n): implement pluralization logic (#277)
Co-authored-by: welpo <welpo@users.noreply.github.com>
This commit is contained in:

committed by
GitHub

parent
daef40338c
commit
c4893d4fdd
@@ -1,3 +1,72 @@
|
||||
{% macro translate(key, language_strings="", default="") %}
|
||||
{{- language_strings[key] | default(value=default) | safe -}}
|
||||
{#- Dynamically selects the appropriate translation key based on the provided `number` and `lang` context.
|
||||
If a `number` is provided, the macro will attempt to pluralize the translation key based on the language's rules.
|
||||
|
||||
Parameters:
|
||||
- `key`: The base key for the translation string, matching the i18n files. Example: `results` to get `zero_results`, `one_results`, `many_results`, etc.
|
||||
- `number`: Optional. The numerical value associated with the key.
|
||||
- `language_strings`: A dictionary containing the translation strings.
|
||||
- `default`: A default string to use if no translation is found for the key.
|
||||
- `replace`: Optional. If `true`, the macro will replace the `$NUMBER` placeholder in the translation string with the provided `number`.
|
||||
|
||||
The macro supports special pluralization rules for:
|
||||
- Arabic (`ar`): Has unique forms for zero, one, two, few, and many.
|
||||
- Slavic languages: Pluralization depends on the last digit of the number, with exceptions for numbers ending in 11-14.
|
||||
|
||||
NOTE: If the logic for pluralization is modified, it needs to be replicated on the JavaScript search.
|
||||
Files: static/js/searchElasticlunr.js and its minified version at static/js/searchElasticlunr.min.js
|
||||
Function name: getPluralizationKey -#}
|
||||
{% macro translate(key, number=-1, language_strings="", default="", replace=true) %}
|
||||
{%- set slavic_plural_languages = ["uk", "be", "bs", "hr", "ru", "sr"] -%}
|
||||
|
||||
{%- set key_prefix = "" -%}
|
||||
{#- `zero_` and `one_` are common cases. We handle "many" (plural) later, after language-specific pluralization -#}
|
||||
{%- if number == 0 -%}
|
||||
{%- set key_prefix = "zero_" -%}
|
||||
{%- elif number == 1 -%}
|
||||
{%- set key_prefix = "one_" -%}
|
||||
{%- endif -%}
|
||||
|
||||
{#- Pluralization -#}
|
||||
{%- if number != -1 and key_prefix == "" -%}
|
||||
{#- Arabic -#}
|
||||
{%- if lang == "ar" -%}
|
||||
{%- set modulo = number % 100 -%}
|
||||
{%- if number == 2 -%}
|
||||
{%- set key_prefix = "two_" -%}
|
||||
{%- elif modulo >= 3 and modulo <= 10 -%}
|
||||
{%- set key_prefix = "few_" -%}
|
||||
{%- else -%}
|
||||
{%- set key_prefix = "many_" -%}
|
||||
{%- endif -%}
|
||||
{#- Slavic languages like Russian or Ukrainian -#}
|
||||
{%- elif lang in slavic_plural_languages -%}
|
||||
{%- set modulo10 = number % 10 -%}
|
||||
{%- set modulo100 = number % 100 -%}
|
||||
{%- if modulo10 == 1 and modulo100 != 11 -%}
|
||||
{%- set key_prefix = "one_" -%}
|
||||
{%- elif modulo10 >= 2 and modulo10 <= 4 -%}
|
||||
{%- if modulo100 >= 12 and modulo100 <= 14 -%}
|
||||
{%- set key_prefix = "many_" -%}
|
||||
{%- else -%}
|
||||
{%- set key_prefix = "few_" -%}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{%- set key_prefix = "many_" -%}
|
||||
{%- endif -%}
|
||||
{%- else -%}
|
||||
{#- Default pluralization -#}
|
||||
{#- Zero and one are already handled -#}
|
||||
{%- set key_prefix = "many_" -%}
|
||||
{%- endif -%}
|
||||
{%- endif -%}
|
||||
|
||||
{#- Translated string -#}
|
||||
{%- set final_key = key_prefix ~ key -%}
|
||||
{%- set translated_text = language_strings[final_key] | default(value=default) | safe -%}
|
||||
|
||||
{#- Replace $NUMBER with the number -#}
|
||||
{%- if replace -%}
|
||||
{%- set translated_text = translated_text | replace(from="$NUMBER", to=number | as_str) -%}
|
||||
{%- endif -%}
|
||||
{{- translated_text -}}
|
||||
{% endmacro %}
|
||||
|
@@ -69,7 +69,7 @@
|
||||
|
||||
{# page settings override config settings #}
|
||||
{% if macros_settings::evaluate_setting_priority(setting="show_reading_time", page=page, default_global_value=true) == "true" %}
|
||||
{{ separator }} <li title="{{ page.word_count }} {{ macros_translate::translate(key="words", default="words", language_strings=language_strings) }}">{{ page.reading_time }} {{ macros_translate::translate(key="min_read", default="min read", language_strings=language_strings) }}</li>
|
||||
{{ separator }} <li title="{{ macros_translate::translate(key="words", number=page.word_count, default="$NUMBER words", language_strings=language_strings) }}">{{ macros_translate::translate(key="min_read", number=page.reading_time, default="$NUMBER min read", language_strings=language_strings) }}</li>
|
||||
{% endif %}
|
||||
|
||||
{%- if page.taxonomies and page.taxonomies.tags -%}
|
||||
|
@@ -16,8 +16,14 @@
|
||||
</div>
|
||||
<div id="results-container">
|
||||
<div id="results-info">
|
||||
<span id="n-results">0</span> <span id="result-text-singular">{{ macros_translate::translate(key='result', default='result', language_strings=language_strings) }}</span>
|
||||
<span id="result-text-plural">{{ macros_translate::translate(key='results', default='results', language_strings=language_strings) }}</span>
|
||||
{#- Add the strings here so JavaScript can grab them -#}
|
||||
{#- These are used in all languages -#}
|
||||
<span id="zero_results"> {{ macros_translate::translate(key='results', number=0, default='No results', language_strings=language_strings, replace=false) }}</span>
|
||||
<span id="one_results"> {{ macros_translate::translate(key='results', number=1, default='1 result', language_strings=language_strings, replace=false) }}</span>
|
||||
<span id="many_results"> {{ macros_translate::translate(key='results', number=11, default='$NUMBER results', language_strings=language_strings, replace=false) }}</span>
|
||||
{#- Strings for specific languages -#}
|
||||
<span id="two_results"> {{ macros_translate::translate(key='results', number=2, default='$NUMBER results', language_strings=language_strings, replace=false) }}</span>
|
||||
<span id="few_results"> {{ macros_translate::translate(key='results', number=2, default='$NUMBER results', language_strings=language_strings, replace=false) }}</span>
|
||||
</div>
|
||||
<div id="results" role="listbox"></div>
|
||||
</div>
|
||||
|
@@ -11,28 +11,21 @@
|
||||
<ul class="tags">
|
||||
{%- for term in terms -%}
|
||||
<li class="tags-item">
|
||||
{%- set number_of_posts = term.pages | length -%}
|
||||
{% if config.extra.compact_tags %}
|
||||
{# Shows the number of posts per tag as a superscript #}
|
||||
<a href="{{ term.permalink | safe }}"
|
||||
aria-label="{{ term.name }} –
|
||||
{{ term.pages | length }}
|
||||
{% if term.pages | length == 1 -%}
|
||||
{{- macros_translate::translate(key="post", default="post", language_strings=language_strings) -}}
|
||||
{%- else -%}
|
||||
{{- macros_translate::translate(key="posts", default="posts", language_strings=language_strings) -}}
|
||||
{%- endif -%}">
|
||||
aria-label="{{ term.name }} –
|
||||
{{ term.pages | length }}
|
||||
{{- macros_translate::translate(key="posts", number=number_of_posts, default="$NUMBER posts", language_strings=language_strings) -}}
|
||||
">
|
||||
{{ term.name }}
|
||||
</a> <sup>{{ term.pages | length }}</sup>
|
||||
</a> <sup>{{ number_of_posts }}</sup>
|
||||
{% else %}
|
||||
<a href="{{ term.permalink | safe }}">
|
||||
{{ term.name }}</a>
|
||||
– {{ term.pages | length }}{%- if term.pages | length == 1 %}
|
||||
{# Only one post. Singular. #}
|
||||
{{- macros_translate::translate(key="post", default="post", language_strings=language_strings) -}}
|
||||
{% elif term.pages | length > 1 %}
|
||||
{# More than one post per tag. Plural. #}
|
||||
{{- macros_translate::translate(key="posts", default="posts", language_strings=language_strings) -}}
|
||||
{%- endif -%}
|
||||
{{ term.name }} </a>
|
||||
<span> – </span>
|
||||
{{- macros_translate::translate(key="posts", number=number_of_posts, default="$NUMBER posts", language_strings=language_strings) -}}
|
||||
{% endif %}
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
|
@@ -11,28 +11,21 @@
|
||||
<ul class="tags">
|
||||
{%- for term in terms -%}
|
||||
<li class="tags-item">
|
||||
{%- set number_of_posts = term.pages | length -%}
|
||||
{% if config.extra.compact_tags %}
|
||||
{# Shows the number of posts per tag as a superscript #}
|
||||
<a href="{{ term.permalink | safe }}"
|
||||
aria-label="{{ term.name }} –
|
||||
{{ term.pages | length }}
|
||||
{% if term.pages | length == 1 -%}
|
||||
{{- macros_translate::translate(key="post", default="post", language_strings=language_strings) -}}
|
||||
{%- else -%}
|
||||
{{- macros_translate::translate(key="posts", default="posts", language_strings=language_strings) -}}
|
||||
{%- endif -%}">
|
||||
aria-label="{{ term.name }} –
|
||||
{{ term.pages | length }}
|
||||
{{- macros_translate::translate(key="posts", number=number_of_posts, default="$NUMBER posts", language_strings=language_strings) -}}
|
||||
">
|
||||
{{ term.name }}
|
||||
</a> <sup>{{ term.pages | length }}</sup>
|
||||
</a> <sup>{{ number_of_posts }}</sup>
|
||||
{% else %}
|
||||
<a href="{{ term.permalink | safe }}">
|
||||
{{ term.name }}</a>
|
||||
– {{ term.pages | length }}{%- if term.pages | length == 1 %}
|
||||
{# Only one post. Singular. #}
|
||||
{{- macros_translate::translate(key="post", default="post", language_strings=language_strings) -}}
|
||||
{% elif term.pages | length > 1 %}
|
||||
{# More than one post per tag. Plural. #}
|
||||
{{- macros_translate::translate(key="posts", default="posts", language_strings=language_strings) -}}
|
||||
{%- endif -%}
|
||||
{{ term.name }} </a>
|
||||
<span> – </span>
|
||||
{{- macros_translate::translate(key="posts", number=number_of_posts, default="$NUMBER posts", language_strings=language_strings) -}}
|
||||
{% endif %}
|
||||
</li>
|
||||
{%- endfor -%}
|
||||
|
Reference in New Issue
Block a user