
    #j+-                       U d Z ddlmZ ddlZddlZddlZddlZddlmZ ddl	m
Z
 ddlmZ  ej        e          ZdZded	<   d
Zi dd
dd
dd
ddddddddddddddddddddddddddddi d dd!dd"dd#dd$d%d&d%d'd%d(d%d)d%d*d%d+d,d-d,d.d,d/d,d0d,d1d,d2d,i d3d4d5d4d6d4d7d4d8d4d9d:d;d:d<d:d=d>d?d>d@dAdBdAdCdAdDdEdFdEdGdEdHdEi dIdJdKdJdLdJdMdNdOdNdPdNdQdNdRdNdSdNdTdNdUdVdWdVdXdVdYdZd[dZd\dZZd]ed^<   i Zd_ed`<    ej                    ZdydcZdzdgZd{diZd|dnZ edop          d}dr            Zd~dsZddtZdddwZg dxZdS )a  Lightweight internationalization (i18n) for Hermes static user-facing messages.

Scope (thin slice, by design): only the highest-impact static strings shown
to the user by Hermes itself -- approval prompts, a handful of gateway slash
command replies, restart-drain notices.  Agent-generated output, log lines,
error tracebacks, tool outputs, and slash-command descriptions all stay in
English.

Catalog files live under ``locales/<lang>.yaml`` at the repo root.  Each
catalog is a flat dict keyed by dotted paths (e.g. ``approval.choose`` or
``gateway.approval_expired``).  Missing keys fall back to English; if English
is missing too, the key path itself is returned so a broken catalog never
crashes the agent.

Usage::

    from agent.i18n import t
    print(t("approval.choose_long"))                       # current lang
    print(t("gateway.draining", count=3))                  # {count} formatted
    print(t("approval.choose_long", lang="zh"))            # explicit override

Language resolution order:
    1. Explicit ``lang=`` argument passed to :func:`t`
    2. ``HERMES_LANGUAGE`` environment variable (for tests / quick override)
    3. ``display.language`` from config.yaml
    4. ``"en"`` (baseline)

Supported languages: en, zh, ja, de, es, fr, tr, uk.  Unknown values fall back to en.
    )annotationsN)	lru_cache)Path)Any)enzhzh-hantjadeesfrtrukafkoitgaptruhuztuple[str, ...]SUPPORTED_LANGUAGESr   englishzen-uszen-gbchineser   mandarinzzh-cnzzh-hanszzh-sgztraditional-chineser	   traditional_chinesezzh-twzzh-hkzzh-mojapaneser
   jpzja-jpgermanr   deutschzde-dezde-atzde-chspanishr   u   españolespanolzes-eszes-mxzes-arfrenchr   u	   françaisfrancezfr-frzfr-bezfr-cazfr-ch	ukrainianr   
ukrainischu   українськаzuk-uauaturkishr   u   türkçeztr-tr	afrikaansr   zaf-zakoreanr   u	   한국어zko-kritalianr   italianozit-itzit-chirishr   gaeilgezga-ie
portugueser   u
   português	portugueszpt-ptzpt-br	brazilian
brasileirorussianr   u   русскийzru-ru	hungarianr   magyarzhu-hudict[str, str]_LANGUAGE_ALIASESzdict[str, dict[str, str]]_catalog_cachereturnr   c                    t          j        dd                                          } | r@t          |           }|                                r|S t
                              d|            t          t                                                    j	        j	        dz  }|                                r|S dD ]C}t          j        |          }|st          |          dz  }|                                r|c S D|S )a=  Return the directory containing locale YAML files.

    Resolution order, first existing wins:

    1. ``HERMES_BUNDLED_LOCALES`` env var -- set by the Nix wrapper (or any
       sealed-packaging system) to point at the installed catalog directory.
    2. ``<repo-root>/locales`` -- source checkouts and ``pip install -e .``,
       where the working tree sits next to ``agent/``.
    3. ``<sysconfig data|purelib|platlib>/locales`` -- pip wheel installs.
       setuptools ``data-files`` extracts ``locales/*.yaml`` under the
       interpreter's ``data`` scheme; the other schemes are checked as a
       safety net for nonstandard layouts.

    Falling through to the source-style path (even when missing) keeps
    ``_load_catalog`` error messages informative -- it logs the path it
    looked at -- rather than raising.
    HERMES_BUNDLED_LOCALES zlHERMES_BUNDLED_LOCALES points to a non-directory path (%s); falling back to bundled/source locale resolutionlocales)datapurelibplatlib)osgetenvstripr   is_dirloggerwarning__file__resolveparent	sysconfigget_path)override	candidate
source_dirschemeraws        //home/ubuntu/.hermes/hermes-agent/agent/i18n.py_locales_dirrQ   X   s   $ y1266<<>>H 
NN	 	?	
 	
 	
 h''))07)CJ  1   (( 	II	)	 		
     valuer   strc                6   t          | t                    st          S |                                                                 }|st          S |t
          v r|S |t          v rt          |         S |                    dd          d         }|t
          v r|S t          S )a  Normalize a user-supplied language value to a supported code.

    Accepts supported codes directly, common aliases (``chinese`` -> ``zh``),
    and case-insensitive regional tags (``zh-CN`` -> ``zh``).  Returns the
    default language for unknown values.
    -   r   )
isinstancerT   DEFAULT_LANGUAGErB   lowerr   r6   split)rS   keybases      rP   _normalize_langr^      s     eS!!  
++--



C  
!!!

 %% 99S!QD"""rR   langc                D   t           5  t                              |           }||cddd           S 	 ddd           n# 1 swxY w Y   t                      |  dz  }|                                sGt
                              d| |           t           5  i t          | <   ddd           n# 1 swxY w Y   i S 	 ddl}|                    dd          5 }|	                    |          pi }ddd           n# 1 swxY w Y   n^# t          $ rQ}t
                              d||           t           5  i t          | <   ddd           n# 1 swxY w Y   i cY d}~S d}~ww xY wi }t          |d	|           t           5  |t          | <   ddd           n# 1 swxY w Y   |S )
zLoad and flatten one locale YAML file into a dotted-key dict.

    YAML files can be nested for human readability; this produces the flat
    key space :func:`t` expects.  Cached per-language for the process.
    Nz.yamlz!i18n catalog missing for %s at %sr   rzutf-8)encodingz"Failed to load i18n catalog %s: %sr;   )_catalog_lockr7   getrQ   is_filerD   debugyamlopen	safe_load	ExceptionrE   _flatten_into)r_   cachedpathrg   frO   excflats           rP   _load_catalogrq      s    
  ##D))                     
 >>tNNN*D<<>> 8$EEE 	& 	&#%N4 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	&	YYsWY-- 	*..##)rC	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	* 	*   ;T3GGG 	& 	&#%N4 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	& 	&							 D#r4   	 $ $#t$ $ $ $ $ $ $ $ $ $ $ $ $ $ $Ks   A  AAB--B14B1;D C:.D :C>>D C>D 
E!#E3E
>E
E	EE	EE!E!>FFFnodeprefixoutNonec                    t          | t                    rE|                                 D ].\  }}|r| d| nt          |          }t	          |||           /d S t          | t                    r| ||<   d S d S )N.)rX   dictitemsrT   rk   )rr   rs   rt   r\   rS   	child_keys         rP   rk   rk      s    $ **,, 	1 	1JC-3A6))C)))SI%C0000	1 	1 
D#		 F rR   rW   )maxsize
str | Nonec                    	 ddl m}   |             }|                    d          pi                     d          }|rt          |          S n2# t          $ r%}t
                              d|           Y d}~nd}~ww xY wdS )aC  Read ``display.language`` from config.yaml once per process.

    Cached because ``t()`` is called in hot paths (every approval prompt,
    every gateway reply) and re-reading YAML each call would be wasteful.
    ``reset_language_cache()`` clears this when config changes at runtime
    (e.g. after the setup wizard).
    r   )load_configdisplaylanguagez/Could not read display.language from config: %sN)hermes_cli.configr~   rd   r^   rj   rD   rf   )r~   cfgr_   ro   s       rP   _config_language_cachedr      s    M111111kmm	""(b--j99 	)"4(((	) M M MFLLLLLLLLM4s   A
A 
A=A88A=c                     t                                            t          5  t                                           ddd           dS # 1 swxY w Y   dS )zInvalidate cached language resolution and catalogs.

    Call after :func:`hermes_cli.config.save_config` if a running process
    needs to pick up a changed ``display.language`` without restart.
    N)r   cache_clearrc   r7   clear rR   rP   reset_language_cacher      s     '')))	                   s   AAAc                     t           j                            d          } | rt          |           S t	                      }|r|S t
          S )z?Resolve the active language using env > config > default order.HERMES_LANGUAGE)r@   environrd   r^   r   rY   )env_langcfg_langs     rP   get_languager      sJ    z~~/00H )x(((&((H rR   r\   format_kwargsc                   |rt          |          nt                      }t          |          }|                    |           }|2|t          k    r't          t                                        |           }|t
                              d| |           | }|rR	  |j        di |S # t          t          t          f$ r*}t
                              d| |||           |cY d}~S d}~ww xY w|S )aA  Translate a dotted key to the active language.

    Parameters
    ----------
    key
        Dotted path into the catalog, e.g. ``"approval.choose_long"``.
    lang
        Explicit language override.  Takes precedence over env + config.
    **format_kwargs
        ``str.format`` substitution arguments (``t("gateway.drain", count=3)``
        expects a catalog entry with a ``{count}`` placeholder).

    Returns
    -------
    The translated string, or the English fallback if the key is missing in
    the target language, or the bare key if English is also missing.
    Nzi18n miss: key=%r lang=%rz3i18n format failed for key=%r lang=%r kwargs=%r: %sr   )r^   r   rq   rd   rY   rD   rf   formatKeyError
IndexError
ValueErrorrE   )r\   r_   r   targetcatalogrS   ro   s          rP   tr      s   $ '+>_T"""FF##GKKE}#333.//33C88} 	0#v>>> 	5<00-000*j1 	 	 	NNEV]C   LLLLLL	 Ls   B( (C)?C$C)$C))r   rY   r   r   r   )r8   r   )rS   r   r8   rT   )r_   rT   r8   r5   )rr   r   rs   rT   rt   r5   r8   ru   )r8   r|   )r8   ru   )r8   rT   )N)r\   rT   r_   r|   r   r   r8   rT   ) __doc__
__future__r   loggingr@   rI   	threading	functoolsr   pathlibr   typingr   	getLogger__name__rD   r   __annotations__rY   r6   r7   Lockrc   rQ   r^   rq   rk   r   r   r   r   __all__r   rR   rP   <module>r      s-    < # " " " " "  				                          		8	$	$(       %t%d%$+T% t	%  	% (/	% 7@	% HOPT	% 9% '<Y% Y%  % -4Y% % D% #*4% d% % t% &-d% 5<T% DKD% t%  % (1$% 9@% HOPT% W^_c% d%  % (0% 8?% GNt% V]^b% elmq% % % % $T% ,B4% JQRV% Y]^b% t%  % (/%  !%  !%$ d%%$  %%$ (/%%( t)%(  )%( (/)%( 7>t)% % %, T-%, d-%, %,T-%2 $3%2 %d3%2 -83%4 T5%4 D5%4 #.t5%4 6B45%8 t9%8 &t9%8 .5d9%< =%<  =%< (/=% %     B -/ . . . .	  2 2 2 2j   0       F    1   &      ) ) ) ) )X  rR   