Spaces:
Runtime error
Runtime error
| """Tiny dictionary-based i18n helper. | |
| Selects the active language from ``HY_LANG`` env var (falls back to ``LANG`` / | |
| ``LC_ALL``). Anything starting with ``zh`` resolves to Simplified Chinese, | |
| everything else to English. | |
| Usage:: | |
| from i18n import t | |
| label = t("send") # -> "Send" or "发送" | |
| msg = t("warn.empty_msg") # nested-dotted keys | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import os | |
| from typing import Any | |
| logger = logging.getLogger(__name__) | |
| DEFAULT_LANG = "en" | |
| SUPPORTED_LANGS = ("en", "zh") | |
| def _detect_lang() -> str: | |
| raw = ( | |
| os.environ.get("HY_LANG") | |
| or os.environ.get("LC_ALL") | |
| or os.environ.get("LANG") | |
| or DEFAULT_LANG | |
| ) | |
| raw = raw.strip().lower() | |
| if raw.startswith("zh"): | |
| return "zh" | |
| if raw[:2] in SUPPORTED_LANGS: | |
| return raw[:2] | |
| return DEFAULT_LANG | |
| LANG = _detect_lang() | |
| # ─── Dictionary ──────────────────────────────────────────────────────────── | |
| # Keys are flat dotted strings to keep lookup simple. Add new keys below in | |
| # alphabetical groups for readability. | |
| TRANSLATIONS: dict[str, dict[str, str]] = { | |
| "en": { | |
| # App chrome | |
| "title": "Hy3 Chat Demo", | |
| "title.notice_html": ( | |
| "The current demo version is offline; full-featured capabilities " | |
| "will be available on the Tencent HY official website." | |
| ), | |
| "examples_heading": "What can I help you with?", | |
| "msg_placeholder": "Type a message...", | |
| # Sidebar | |
| "sidebar.think_level": "Think level", | |
| "sidebar.think_level.info": "Control reasoning depth", | |
| "sidebar.system_prompt": "System prompt", | |
| "sidebar.system_prompt.placeholder": "You are a helpful AI assistant...", | |
| "sidebar.temperature": "Temperature", | |
| "sidebar.temperature.info": "Higher values produce more random outputs", | |
| "sidebar.temperature.use_default": "Use model default", | |
| "sidebar.max_tokens": "Max output tokens", | |
| "sidebar.max_tokens.info": "Maximum tokens per response. Set to 0 to use the model's default.", | |
| "sidebar.top_p": "Top P", | |
| "sidebar.top_p.info": "Nucleus sampling probability threshold. Set to 0 to use the model's default.", | |
| "sidebar.preserved_thinking": "Preserved thinking", | |
| "sidebar.preserved_thinking.info": "When enabled, the model can retain reasoning content from previous assistant turns in the context, helping maintain reasoning continuity and conversation integrity while improving model performance.", | |
| "sidebar.preserved_thinking.use_default": "Preserved thinking-Use model default", | |
| "sidebar.preserved_thinking.use_default.info": "We recommend using \"Use model default\", which automatically enables this option for tool call workflows and disables it for pure text conversations.", | |
| "sidebar.functions": "🔧 Functions", | |
| "sidebar.functions.label": "Function definitions (JSON array)", | |
| "sidebar.validate_btn": "Validate & Format", | |
| # Tool area | |
| "tool.result_label": "Function result", | |
| "tool.result_placeholder": "Enter function return value... (Enter to submit)", | |
| "tool.submit": "Submit", | |
| "tool.call_header": "Function call ({i}/{n})", | |
| "tool.call_label": "🔧 Call function", | |
| # Display | |
| "display.thinking": "Thinking...", | |
| "display.thinking_done": "Thinking complete", | |
| "display.code_copy": "Copy", | |
| "display.code_copied": "Copied", | |
| # Warnings / info | |
| "warn.empty_msg": "Please enter a message", | |
| "warn.invalid_fn_json": "Invalid function JSON, please fix or clear before sending: {err}", | |
| "warn.request_failed": "Request failed, please retry or adjust parameters", | |
| "warn.model_busy": "Model is still responding. Please wait for it to finish before sending a new message.", | |
| "info.new_chat": "Start a new chat", | |
| "warn.fn.enter_json": "Please enter function definition JSON", | |
| "warn.fn.invalid_format": "Invalid JSON format: {err}", | |
| "warn.fn.must_be_array": "JSON must be an array [...] or a single object {{...}}", | |
| "warn.fn.item_not_object": "Item {i} is not a JSON object", | |
| "warn.fn.item_invalid": "Item {i} has invalid format, expected {{type, function}} or {{name, parameters}}", | |
| "warn.fn.duplicate_name": "Duplicate function name '{name}'", | |
| "info.fn.validation_passed": "Validation passed, {n} function(s): {names}", | |
| }, | |
| "zh": { | |
| "title": "Hy3 Chat Demo", | |
| "title.notice_html": ( | |
| "The current demo version is offline; full-featured capabilities " | |
| "will be available on the Tencent HY official website." | |
| ), | |
| "examples_heading": "今天我能帮你做点什么?", | |
| "msg_placeholder": "输入消息...", | |
| "sidebar.think_level": "思考等级", | |
| "sidebar.think_level.info": "控制模型推理深度", | |
| "sidebar.system_prompt": "系统提示词", | |
| "sidebar.system_prompt.placeholder": "你是一个有帮助的 AI 助手...", | |
| "sidebar.temperature": "Temperature", | |
| "sidebar.temperature.info": "数值越高,回复越随机", | |
| "sidebar.temperature.use_default": "Use model default", | |
| "sidebar.max_tokens": "最大输出 Tokens", | |
| "sidebar.max_tokens.info": "单次回复的最大 token 数。Set to 0 to use the model's default.", | |
| "sidebar.top_p": "Top P", | |
| "sidebar.top_p.info": "核采样概率阈值。Set to 0 to use the model's default.", | |
| "sidebar.preserved_thinking": "Preserved thinking", | |
| "sidebar.preserved_thinking.info": "是否在上下文中保留模型的思考过程。", | |
| "sidebar.preserved_thinking.use_default": "Preserved thinking-Use model default", | |
| "sidebar.preserved_thinking.use_default.info": "We recommend using \"Use model default\", which automatically enables this option for tool call workflows and disables it for pure text conversations.", | |
| "sidebar.functions": "🔧 函数", | |
| "sidebar.functions.label": "函数定义(JSON 数组)", | |
| "sidebar.validate_btn": "校验 & 格式化", | |
| "tool.result_label": "函数返回值", | |
| "tool.result_placeholder": "请输入函数返回值...(回车提交)", | |
| "tool.submit": "提交", | |
| "tool.call_header": "函数调用 ({i}/{n})", | |
| "tool.call_label": "🔧 调用函数", | |
| "display.thinking": "思考中...", | |
| "display.thinking_done": "已思考", | |
| "display.code_copy": "复制", | |
| "display.code_copied": "已复制", | |
| "warn.empty_msg": "请输入消息内容", | |
| "warn.invalid_fn_json": "函数 JSON 不合法,请先修正或清空: {err}", | |
| "warn.request_failed": "请求失败,请重试或调整参数", | |
| # Intentionally English for both locales: the warning should always | |
| # appear in English regardless of the UI language. | |
| "warn.model_busy": "Model is still responding. Please wait for it to finish before sending a new message.", | |
| "info.new_chat": "已开启新会话", | |
| "warn.fn.enter_json": "请输入函数定义 JSON", | |
| "warn.fn.invalid_format": "JSON 格式错误: {err}", | |
| "warn.fn.must_be_array": "JSON 必须是数组 [...] 或单个对象 {{...}}", | |
| "warn.fn.item_not_object": "第 {i} 项不是 JSON 对象", | |
| "warn.fn.item_invalid": "第 {i} 项格式不合法,期望 {{type, function}} 或 {{name, parameters}}", | |
| "warn.fn.duplicate_name": "函数名 '{name}' 重复", | |
| "info.fn.validation_passed": "校验通过,共 {n} 个函数: {names}", | |
| }, | |
| } | |
| def t(key: str, /, **fmt: Any) -> str: | |
| """Translate ``key`` for the active language with optional formatting.""" | |
| table = TRANSLATIONS.get(LANG, TRANSLATIONS[DEFAULT_LANG]) | |
| template = table.get(key) or TRANSLATIONS[DEFAULT_LANG].get(key) | |
| if template is None: | |
| logger.warning("missing i18n key: %s", key) | |
| return key | |
| if not fmt: | |
| return template | |
| try: | |
| return template.format(**fmt) | |
| except (KeyError, IndexError): | |
| logger.warning("i18n format failure for key=%s args=%r", key, fmt) | |
| return template | |