
    iX>                     |   U d Z ddlZddlmZ ddlZddlmZ ddlZddl	Zddl
Z
ddlmZ ddlmZmZmZ ddlmZ  ej&                  d      Ze
j(                  Zi Zeeef   ed	<   	  e       Zee   ed
<   	 dddddZ	 dddddddZ	 d Zd Zg ae e   ed<   de e   fdZ!d Z"dejF                  defdZ$dejF                  defdZ%d edejF                  dz  fd!Z&	 d0d"ed#e e   dz  d$e'd%e'deejF                     f
d&Z(d1d'ed(eeef   d)edz  dedz  fd*Z)d1d'ed+e e   d,edz  dedz  fd-Z*d.e e   deeef   fd/Z+y)2uY  
SearXNG’s locale data
=====================

The variables :py:obj:`RTL_LOCALES` and :py:obj:`LOCALE_NAMES` are loaded from
:origin:`searx/data/locales.json` / see :py:obj:`locales_initialize` and
:ref:`update_locales.py`.

.. hint::

   Whenever the value of :py:obj:`ADDITIONAL_TRANSLATIONS` or
   :py:obj:`LOCALE_BEST_MATCH` is modified, the
   :origin:`searx/data/locales.json` needs to be rebuild::

     ./manage data.locales

SearXNG's locale codes
======================

.. automodule:: searx.sxng_locales
   :members:


SearXNG’s locale implementations
================================
    N)Path)Translations)has_request_context)datalogger	searx_dir)sxng_requestlocalesLOCALE_NAMESRTL_LOCALESu   ދިވެހި (Dhivehi)Occitanu   Ślōnski (Silesian)
Papiamento)dvocszlpapsizfr-FRplnlz
zh-Hant-TWzpt-BR)r   r   r   znl-BEzzh-HKr   c                      d} t               r#t        j                  j                  d      }|r|} | t        v r| t        j
                  d<   t        j                  | |       } | dk(  rd} | j                  dd      } | S )Nenlocaleuse-translation -_)	r   r	   preferences	get_valueADDITIONAL_TRANSLATIONSformLOCALE_BEST_MATCHgetreplace)r   values     /root/searxng/searx/locales.pylocaleselectorr&   V   s    F!--77AF ((/5+, ""662F|  ^^C%FM    c                      t               rgt        j                  j                  d      } | t        v r@t
        j                  j                  d   }t        j                  |j                  d   |       S t               S )z6Monkey patch of :py:obj:`flask_babel.get_translations`r   babelr   )r   r	   r    r"   r   flask_babelcurrent_app
extensionsr   loadtranslation_directories_flask_babel_get_translations)use_translation	babel_exts     r%   get_translationsr2   n   se    &++//0AB55#//::7CI$$Y%F%Fq%I?[[(**r'   _TR_LOCALESreturnc                  
   t         rt         S g } t        t              dz  j                         D ]B  }|j	                         s|dz  j	                         s(| j                  |j                         D t        |       a t         S )zReturns the list of translation locales (*underscore*).  The list is
    generated from the translation folders in :origin:`searx/translations`translationsLC_MESSAGES)r3   r   r   iterdiris_dirappendnamesorted)
tr_localesfolders     r%   get_translation_localesr?   {   sw    
 J	?^3<<> '}}&..0&++&' $Kr'   c                      t         t        _         t        j                  t        j
                  d          t        j                  t        j
                  d          y)zInitialize locales environment of the SearXNG session.

    - monkey patch :py:obj:`flask_babel.get_translations` by :py:obj:`get_translations`
    - init global names :py:obj:`LOCALE_NAMES`, :py:obj:`RTL_LOCALES`
    r   r   N)r2   r*   r   updater   LOCALESr    r'   r%   locales_initializerD      s:     $4K ^45t||M23r'   r   c                 n    | j                   st        d| z        | j                  dz   | j                   z   S )zBReturns SearXNG's region tag from the locale (e.g. zh-TW , en-US).z#babel.Locale %s: missed a territoryr   )	territory
ValueErrorlanguage)r   s    r%   
region_tagrI      s6    >GHH??S 6#3#333r'   c                 Z    | j                   }| j                  r|d| j                  z   z  }|S )zzReturns SearXNG's language tag from the locale and if exits, the tag
    includes the script name (e.g. en, zh_Hant).
    r   )rH   script)r   	sxng_langs     r%   language_tagrM      s-     I}}S6==((	r'   
locale_tagc                     	 t         j                  j                  | d      }|S # t         j                  j                  $ r Y yw xY w)zOReturns a :py:obj:`babel.Locale` object parsed from argument
    ``locale_tag``r   sepN)r)   LocaleparsecoreUnknownLocaleError)rN   r   s     r%   
get_localerV      sA    ##JC#8::(( s   "% AArF   	languagesregionalde_factoc                    t               }t        j                  j                  | ||      }r2D cg c]  }|j	                          c}t        fd|D              }|D ]9  }	 t        j
                  j                  |dz   | z         }|j                  |       ; |S c c}w # t        j                  $ r Y Xw xY w)u  Returns a list of :py:obj:`babel.Locale` with languages from
    :py:obj:`babel.languages.get_official_languages`.

    :param territory: The territory (country or region) code.

    :param languages: A list of language codes the languages from
      :py:obj:`babel.languages.get_official_languages` should be in
      (intersection).  If this argument is ``None``, all official languages in
      this territory are used.

    :param regional: If the regional flag is set, then languages which are
      regionally official are also returned.

    :param de_facto: If the de_facto flag is set to `False`, then languages
      which are “de facto” official are not returned.

    )rX   rY   c              3   H   K   | ]  }|j                         v s|  y wN)lower).0lrW   s     r%   	<genexpr>z'get_official_locales.<locals>.<genexpr>   s     KAGGI4J!Ks   ""r   )	setr)   rW   get_official_languagesr]   rR   rS   addrU   )	rF   rW   rX   rY   ret_valo_languagesr_   langr   s	    `       r%   get_official_localesrg      s    ( "%G//88X`h8iK(121QWWY2	K[KK 	\\''s
Y(>?FKK N 3 '' 		s   B"(6B''B=<B=searxng_localeengine_localesdefaultc                    |j                  |       }||S 	 t        j                  j                  | d      }t        |      }|j                  |      }||S |j                  rYt        j                  j                  |j                  d      D ]+  }|dz   |j                  z   } |j                  |       }|)|c S  |j                  r'i }t        j                  j                  d      j                         D ]/  \  }}	|	j                  |      }
|
|
j                  d      +|
||<   1 |j                  j                         }|dk(  rd	}|j                  |      r'|j                  dz   |z   } |j                  |       }||S g }|j                         D ]  \  }}|j                  ||f        t!        |d
 d      D ].  \  }}
|j                  dz   |z   } |j                  |       }|,|c S  ||}|S # t        j                  j
                  $ r^ 	 t        j                  j                  | j                  d      d         }n'# t        j                  j
                  $ r |cY cY S w xY wY 9w xY w)a:  Return engine's language (aka locale) string that best fits to argument
    ``searxng_locale``.

    Argument ``engine_locales`` is a python dict that maps *SearXNG locales* to
    corresponding *engine locales*::

      <engine>: {
          # SearXNG string : engine-string
          'ca-ES'          : 'ca_ES',
          'fr-BE'          : 'fr_BE',
          'fr-CA'          : 'fr_CA',
          'fr-CH'          : 'fr_CH',
          'fr'             : 'fr_FR',
          ...
          'pl-PL'          : 'pl_PL',
          'pt-PT'          : 'pt_PT'
          ..
          'zh'             : 'zh'
          'zh_Hans'        : 'zh'
          'zh_Hant'        : 'zh_TW'
      }

    .. hint::

       The *SearXNG locale* string has to be known by babel!

    If there is no direct 1:1 mapping, this functions tries to narrow down
    engine's language (locale).  If no value can be determined by these
    approximation attempts the ``default`` value is returned.

    Assumptions:

    A. When user select a language the results should be optimized according to
       the selected language.

    B. When user select a language and a territory the results should be
       optimized with first priority on territory and second on language.

    First approximation rule (*by territory*):

      When the user selects a locale with territory (and a language), the
      territory has priority over the language.  If any of the official languages
      in the territory is supported by the engine (``engine_locales``) it will
      be used.

    Second approximation rule (*by language*):

      If "First approximation rule" brings no result or the user selects only a
      language without a territory.  Check in which territories the language
      has an official status and if one of these territories is supported by the
      engine.

    r   rP   r   T)rY   territory_languagesofficial_statusENUSc                     | d   d   S )N   population_percentrC   )items    r%   <lambda>z#get_engine_locale.<locals>.<lambda>e  s    QPdHe r'   )keyreverse)r"   r)   rR   rS   rT   rU   splitrM   rF   rW   rb   rH   
get_globalitemsupperr:   r<   )rh   ri   rj   engine_localer   searxng_langofficial_languageterr_lang_dictrF   langs_langterr_lang_listkvs                 r%   get_engine_localer      s   p #&&~6M  ##N#<  'L"&&|4M   "'!G!GHXHXcg!G!h 	%.4v7G7GGN*..~>M($$		% 68 !&

 5 56K L R R T 	.IuIIl+E}		*; < D(-N9%		. OO))+	Ii(#__s2Y>N*..~>M($$$ >@"((* 	*DAq!!1a&)	* !'~;eos t 	%Iu#__s2Y>N*..~>M($$		% m ::(( 	\\''(<(<S(A!(DEFzz,, 	N	 s5   !G7 7I21II2I+&I2*I++I21I2locale_tag_listfallbackc                     | s|S t        |       }||S t        |      } |j                  rt        |      } g }|D ]   }|dv s|t        v r|j                  |       " t        |      }t        | ||      S )a  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.
    )allauto)rj   )rV   rM   rF   rI   r   r:   build_engine_localesr   )rh   r   r   r   tag_listtagri   s          r%   match_localer   t  s    . 'F~ "&)N#F+ H /!S,C%C *(3N^^XNNr'   r   c                     i }| D ]j  }t        |      }|t        j                  d|       '|j                  r*||t	        |      <   |j
                  sN||t        |      <   ]||t        |      <   l |S )an  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.

    z;build_engine_locales: skip locale tag %s / unknown by babel)rV   r   warningrF   rI   rK   rM   )r   ri   r   r   s       r%   r   r     s~    < &(N 
7C>NNXZ]^14N:f-.}}7:|F3436N</0
7 r'   )NFTr\   ),__doc__typingtpathlibr   r)   babel.supportr   babel.languages
babel.corer*   	flask.ctxr   searxr   r   r   searx.extended_typesr	   getChildr2   r/   r   dictstr__annotations__ra   r   r   r!   r&   r3   listr?   rD   rR   rI   rM   rV   boolrg   r   r   r   rC   r'   r%   <module>r      s  8    &    ) 
 .		# !, < < !d38n ! SX " #
!	 4 
 	
0+ T#Y c &44u|| 4 4 # 3 5<<$#6  bf""#Cy4/"BF"Z^""JWc W4S> WTWZ^T^ Wjmptjt Wt.O .OtCy .OCRVJ .Obehlbl .Ob+49 +c3h +r'   