summaryrefslogtreecommitdiff
path: root/searx/locales.py
diff options
context:
space:
mode:
Diffstat (limited to 'searx/locales.py')
-rw-r--r--searx/locales.py108
1 files changed, 107 insertions, 1 deletions
diff --git a/searx/locales.py b/searx/locales.py
index a4560aab7..ffa5e731c 100644
--- a/searx/locales.py
+++ b/searx/locales.py
@@ -4,7 +4,7 @@
"""Initialize :py:obj:`LOCALE_NAMES`, :py:obj:`RTL_LOCALES`.
"""
-from typing import Set
+from typing import Set, Optional, List
import os
import pathlib
@@ -177,6 +177,17 @@ def language_tag(locale: babel.Locale) -> str:
return sxng_lang
+def get_locale(locale_tag: str) -> Optional[babel.Locale]:
+ """Returns a :py:obj:`babel.Locale` object parsed from argument
+ ``locale_tag``"""
+ try:
+ locale = babel.Locale.parse(locale_tag, sep='-')
+ return locale
+
+ except babel.core.UnknownLocaleError:
+ return None
+
+
def get_offical_locales(
territory: str, languages=None, regional: bool = False, de_facto: bool = True
) -> Set[babel.Locale]:
@@ -363,3 +374,98 @@ def get_engine_locale(searxng_locale, engine_locales, default=None):
engine_locale = default
return default
+
+
+def match_locale(searxng_locale: str, locale_tag_list: List[str], fallback: Optional[str] = None) -> Optional[str]:
+ """Return tag from ``locale_tag_list`` that best fits to ``searxng_locale``.
+
+ :param str searxng_locale: SearXNG's internal representation of locale (de,
+ de-DE, fr-BE, zh, zh-CN, zh-TW ..).
+
+ :param list locale_tag_list: The list of locale tags to select from
+
+ :param str fallback: fallback locale tag (if unset --> ``None``)
+
+ The rules to find a match are implemented in :py:obj:`get_engine_locale`,
+ the ``engine_locales`` is build up by :py:obj:`build_engine_locales`.
+
+ .. hint::
+
+ The *SearXNG locale* string and the members of ``locale_tag_list`` has to
+ be known by babel! The :py:obj:`ADDITIONAL_TRANSLATIONS` are used in the
+ UI and are not known by babel --> will be ignored.
+ """
+
+ # searxng_locale = 'es'
+ # locale_tag_list = ['es-AR', 'es-ES', 'es-MX']
+
+ if not searxng_locale:
+ return fallback
+
+ locale = get_locale(searxng_locale)
+ if locale is None:
+ return fallback
+
+ # normalize to a SearXNG locale that can be passed to get_engine_locale
+
+ searxng_locale = language_tag(locale)
+ if locale.territory:
+ searxng_locale = region_tag(locale)
+
+ # clean up locale_tag_list
+
+ tag_list = []
+ for tag in locale_tag_list:
+ if tag in ('all', 'auto') or tag in ADDITIONAL_TRANSLATIONS:
+ continue
+ tag_list.append(tag)
+
+ # emulate fetch_traits
+ engine_locales = build_engine_locales(tag_list)
+ return get_engine_locale(searxng_locale, engine_locales, default=fallback)
+
+
+def build_engine_locales(tag_list: List[str]):
+ """From a list of locale tags a dictionary is build that can be passed by
+ argument ``engine_locales`` to :py:obj:`get_engine_locale`. This function
+ is mainly used by :py:obj:`match_locale` and is similar to what the
+ ``fetch_traits(..)`` function of engines do.
+
+ If there are territory codes in the ``tag_list`` that have a *script code*
+ additional keys are added to the returned dictionary.
+
+ .. code:: python
+
+ >>> import locales
+ >>> engine_locales = locales.build_engine_locales(['en', 'en-US', 'zh', 'zh-CN', 'zh-TW'])
+ >>> engine_locales
+ {
+ 'en': 'en', 'en-US': 'en-US',
+ 'zh': 'zh', 'zh-CN': 'zh-CN', 'zh_Hans': 'zh-CN',
+ 'zh-TW': 'zh-TW', 'zh_Hant': 'zh-TW'
+ }
+ >>> get_engine_locale('zh-Hans', engine_locales)
+ 'zh-CN'
+
+ This function is a good example to understand the language/region model
+ of SearXNG:
+
+ SearXNG only distinguishes between **search languages** and **search
+ regions**, by adding the *script-tags*, languages with *script-tags* can
+ be assigned to the **regions** that SearXNG supports.
+
+ """
+ engine_locales = {}
+
+ for tag in tag_list:
+ locale = get_locale(tag)
+ if locale is None:
+ logger.warn("build_engine_locales: skip locale tag %s / unknown by babel", tag)
+ continue
+ if locale.territory:
+ engine_locales[region_tag(locale)] = tag
+ if locale.script:
+ engine_locales[language_tag(locale)] = tag
+ else:
+ engine_locales[language_tag(locale)] = tag
+ return engine_locales