
    `gj+-                       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dldaZdmdbZdndcZdoddZ edef      dpdg       ZdqdhZdrdiZdsdtdjZg dkZy)ua  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_cachec                    t        j                  dd      j                         } | r3t        |       }|j	                         r|S t
        j                  d|        t        t              j                         j                  j                  dz  }|j	                         r|S dD ]<  }t        j                  |      }|st        |      dz  }|j	                         s:|c S  |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        =/root/.hermes/venv/lib/python3.12/site-packages/agent/i18n.py_locales_dirrP   X   s    $ yy126<<>HN	?	
 h'')0077)CJ 1   (I	)	     c                    t        | t              st        S | j                         j	                         }|st        S |t
        v r|S |t        v r	t        |   S |j                  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   )
isinstancestrDEFAULT_LANGUAGErA   lowerr   r6   split)valuekeybases      rO   _normalize_langr]      s~     eS!
++-


C
!!

 %% 99S!QD""rQ   c                   t         5  t        j                  |       }||cddd       S 	 ddd       t               |  dz  }|j	                         s1t
        j                  d| |       t         5  i t        | <   ddd       i S 	 ddl}|j                  dd      5 }|j                  |      xs i }ddd       i }t        d	|       t         5  |t        | <   ddd       |S # 1 sw Y   xY w# 1 sw Y   i S xY w# 1 sw Y   KxY w# t        $ rH}t
        j                  d||       t         5  i t        | <   ddd       n# 1 sw Y   nxY wi cY d}~S d}~ww xY w# 1 sw Y   |S xY w)
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   getrP   is_filerC   debugyamlopen	safe_load	ExceptionrD   _flatten_into)langcachedpathre   frN   excflats           rO   _load_catalogrp      sZ    
 ##D) 
 >tfEN*D<<>8$E 	&#%N4 	&	YYsWY- 	*..#)rC	* D#r4 	 $#t$K5 	&		* 	* ;T3G 	&#%N4 	& 	& 	&		$Ksq   C#0
C/D C<2D 
E#C,/C9<DD 	EE.
E8	EE
	EEEE&c                    t        | t              r:| j                         D ]&  \  }}|r| d| n
t        |      }t	        |||       ( y t        | t              r| ||<   y y )N.)rU   dictitemsrV   ri   )nodeprefixoutr[   rZ   	child_keys         rO   ri   ri      sc    $**, 	1JC-36(!C5)SI%C0	1 
D#	F 
rQ   rT   )maxsizec                     	 ddl m}   |        }|j                  d      xs i j                  d      }|rt        |      S 	 y# t        $ r }t
        j                  d|       Y d}~yd}~ww xY w)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{   rb   r]   rh   rC   rd   )r{   cfgrj   rn   s       rO   _config_language_cachedr      sq    M1m	"(b--j9"4((    MFLLMs   =A 	A+A&&A+c                     t         j                          t        5  t        j	                          ddd       y# 1 sw Y   yxY w)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_clearra   r7   clear rQ   rO   reset_language_cacher      s4     '')	   s	   9Ac                     t         j                  j                  d      } | rt        |       S t	               }|r|S t
        S )z?Resolve the active language using env > config > default order.HERMES_LANGUAGE)r?   environrb   r]   r   rW   )env_langcfg_langs     rO   get_languager      s9    zz~~/0Hx((&(HrQ   c                   |rt        |      n	t               }t        |      }|j                  |       }|'|t        k7  rt        t              j                  |       }|t
        j                  d| |       | }|r	  |j                  di |S |S # t        t        t        f$ r%}t
        j                  d| |||       |cY d}~S d}~ww xY w)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   rp   rb   rW   rC   rd   formatKeyError
IndexError
ValueErrorrD   )r[   rj   format_kwargstargetcatalogrZ   rn   s          rO   tr      s    $ '+_T"FF#GKKE}#33./33C8} 	0#v>	5<<0-00 L *j1 	NNEV]C L	s   ;B C#C=CC)r   rW   r   r   r   )returnr   )rZ   r   r   rV   )rj   rV   r   r5   )ru   r   rv   rV   rw   r5   r   None)r   
str | None)r   r   )r   rV   )N)r[   rV   rj   r   r   r   r   rV   ) __doc__
__future__r   loggingr?   rH   	threading	functoolsr   pathlibr   typingr   	getLogger__name__rC   r   __annotations__rW   r6   r7   Lockra   rP   r]   rp   ri   r   r   r   r   __all__r   rQ   rO   <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j0 F 1 &)XrQ   