Agent产品的国际化架构:i18n、时区处理与内容本地化的工程实践
2026/7/17 14:54:25 网站建设 项目流程

Agent产品的国际化架构:i18n、时区处理与内容本地化的工程实践

一、引言

AI Agent产品出海时,国际化是第一道技术门槛。不是翻译几个词条就算国际化。时区混乱导致报表错位,本地化不足导致用户流失。这些问题在产品上线后的修复成本远超提前规划。

国际化架构需要覆盖三个层面:文本翻译(i18n)、时间处理(时区)、内容适配(本地化)。本文给出一个生产级的实现方案。

行业案例:某Agent产品的多语言支持实践

一家做AI客服Agent的公司,产品原来只支持中文。2024年决定支持英文和日文。

第一版做法:用GPT-4o实时翻译所有Agent输出。用户输入英文,Agent用英文回复。用户输入日文,Agent用日文回复。

上线后发现:

  • 英文回复质量可以,用户接受度约75%。
  • 日文回复质量差,特别是敬语使用不准确。日本用户接受度约48%。

问题:实时翻译的日文输出,语气和敬语级别不稳定。日本企业客户对语气敏感,不接受。

修复方案:

  • 英文:继续用GPT-4o实时翻译。英文容错率高。
  • 日文:建立人工翻译的提示词库。针对客服场景,预翻译了200个高频回复模板。Agent优先用模板回复,模板覆盖不到的才实时翻译。
  • 系统消息(如"正在处理")全部人工翻译,不用实时翻译。

修复后,日本用户接受度提升到71%。

数据说明:AI翻译适合容错率高的语言(英文),不适合容错率低的语言(日文、阿拉伯文)。关键场景(系统消息、法律文本)必须人工翻译。

二、原理:三层国际化架构

三层架构的设计逻辑:

  1. 展示层:根据用户设置渲染界面。
  2. 服务层:核心转换逻辑。
  3. AI层:LLM自动感知用户语言生成内容。

核心原则:存储用UTC,展示按用户时区。

三、代码:国际化核心模块

from __future__ import annotations import json import os from datetime import datetime, timezone, timedelta from typing import Dict, Optional, Any from dataclasses import dataclass from zoneinfo import ZoneInfo import gettext # ==================== 1. i18n 翻译引擎 ==================== class I18nEngine: """国际化翻译引擎""" SUPPORTED_LANGUAGES = { "zh-CN": "简体中文", "zh-TW": "繁體中文", "en-US": "English", "ja-JP": "日本語", "ko-KR": "한국어", } def __init__(self, translations_dir: str = "./locales"): self.translations_dir = translations_dir self._translations: Dict[str, Dict[str, str]] = {} self._load_all() def _load_all(self): """加载所有翻译文件""" for lang in self.SUPPORTED_LANGUAGES: path = os.path.join( self.translations_dir, f"{lang}.json" ) if os.path.exists(path): with open(path, "r", encoding="utf-8") as f: self._translations[lang] = json.load(f) def translate( self, key: str, locale: str = "zh-CN", **kwargs ) -> str: """翻译并支持变量插值""" locale = locale if locale in self._translations else "zh-CN" text = self._translations.get(locale, {}).get(key, key) if kwargs: text = text.format(**kwargs) return text def add_translation(self, key: str, translations: Dict[str, str]): """动态添加翻译""" for lang, text in translations.items(): if lang not in self._translations: self._translations[lang] = {} self._translations[lang][key] = text # ==================== 2. 时区处理引擎 ==================== class TimezoneEngine: """时区处理引擎""" # 常用时区映射 TIMEZONE_MAP = { "Asia/Shanghai": "+08:00", "Asia/Tokyo": "+09:00", "America/New_York": "-05:00", "America/Los_Angeles": "-08:00", "Europe/London": "+01:00", } @staticmethod def utc_now() -> datetime: """获取当前UTC时间""" return datetime.now(timezone.utc) @staticmethod def to_user_tz( dt: datetime, tz_name: str = "Asia/Shanghai" ) -> datetime: """UTC时间转换为用户时区""" if dt.tzinfo is None: dt = dt.replace(tzinfo=timezone.utc) return dt.astimezone(ZoneInfo(tz_name)) @staticmethod def from_user_tz( dt_str: str, tz_name: str = "Asia/Shanghai", fmt: str = "%Y-%m-%d %H:%M" ) -> datetime: """用户输入时间转为UTC""" user_tz = ZoneInfo(tz_name) dt = datetime.strptime(dt_str, fmt) dt = dt.replace(tzinfo=user_tz) return dt.astimezone(timezone.utc) @staticmethod def format_for_user( dt: datetime, tz_name: str = "Asia/Shanghai", fmt: str = "%Y-%m-%d %H:%M" ) -> str: """格式化为用户时区的可读时间""" local_dt = TimezoneEngine.to_user_tz(dt, tz_name) return local_dt.strftime(fmt) @staticmethod def relative_time(dt: datetime, tz_name: str = "Asia/Shanghai") -> str: """相对时间描述""" local_dt = TimezoneEngine.to_user_tz(dt, tz_name) now = TimezoneEngine.utc_now() now_local = TimezoneEngine.to_user_tz(now, tz_name) diff = now_local - local_dt if diff < timedelta(minutes=1): return "刚刚" elif diff < timedelta(hours=1): return f"{diff.seconds // 60}分钟前" elif diff < timedelta(days=1): return f"{diff.seconds // 3600}小时前" elif diff < timedelta(days=30): return f"{diff.days}天前" return local_dt.strftime("%m月%d日") @staticmethod def business_hours(tz_name: str) -> tuple: """判断指定时区是否在工作时间""" now_utc = TimezoneEngine.utc_now() local = TimezoneEngine.to_user_tz(now_utc, tz_name) return 9 <= local.hour < 18 and local.weekday() < 5 # ==================== 3. 内容本地化引擎 ==================== class ContentLocalizer: """内容本地化引擎""" # 地区配置 REGION_CONFIG = { "CN": { "currency": "CNY", "currency_symbol": "¥", "date_format": "%Y-%m-%d", "number_format": {"thousands_sep": ",", "decimal_sep": "."}, "first_day_of_week": 0, # 周日 }, "US": { "currency": "USD", "currency_symbol": "$", "date_format": "%m/%d/%Y", "number_format": {"thousands_sep": ",", "decimal_sep": "."}, "first_day_of_week": 6, # 周六 }, "JP": { "currency": "JPY", "currency_symbol": "¥", "date_format": "%Y年%m月%d日", "number_format": {"thousands_sep": ",", "decimal_sep": "."}, "first_day_of_week": 0, }, } @classmethod def format_price(cls, amount: float, region: str = "CN") -> str: """价格本地化""" config = cls.REGION_CONFIG.get(region, cls.REGION_CONFIG["CN"]) symbol = config["currency_symbol"] if region == "JP": return f"{symbol}{int(amount):,}" return f"{symbol}{amount:,.2f}" @classmethod def format_number(cls, value: float, region: str = "CN") -> str: """数字本地化""" config = cls.REGION_CONFIG.get(region, cls.REGION_CONFIG["CN"]) fmt = config["number_format"] return f"{value:,.0f}" if value == int(value) else f"{value:,.2f}" @classmethod def system_prompt_for_locale(cls, locale: str) -> str: """根据语言生成系统提示词片段""" prompts = { "zh-CN": "请用简体中文回复。", "en-US": "Please respond in English.", "ja-JP": "日本語で返信してください。", } return prompts.get(locale, prompts["zh-CN"]) # ==================== 4. 翻译文件示例 (locales/zh-CN.json) ========== """ { "welcome": "欢迎使用,{name}!", "task_completed": "任务已完成", "error_network": "网络连接失败,请检查网络", "settings_language": "语言设置", "settings_timezone": "时区设置", "billing_monthly": "月付 {price}" } """ # ==================== 使用示例 ==================== @dataclass class UserPreferences: locale: str = "zh-CN" timezone: str = "Asia/Shanghai" region: str = "CN" class InternationalizationService: """国际化服务统一入口""" def __init__(self, translations_dir: str = "./locales"): self.i18n = I18nEngine(translations_dir) self.tz = TimezoneEngine() self.localizer = ContentLocalizer() def render_message( self, key: str, user: UserPreferences, **kwargs ) -> str: """渲染国际化消息""" return self.i18n.translate(key, user.locale, **kwargs) def render_time( self, dt: datetime, user: UserPreferences ) -> str: """渲染用户时区时间""" return self.tz.format_for_user(dt, user.timezone) def render_price( self, amount: float, user: UserPreferences ) -> str: """渲染本地化价格""" return self.localizer.format_price(amount, user.region) if __name__ == "__main__": service = InternationalizationService() # 中国用户 user_cn = UserPreferences() print(service.render_message("welcome", user_cn, name="张三")) print(service.render_price(99.9, user_cn)) # 美国用户 user_us = UserPreferences( locale="en-US", timezone="America/New_York", region="US" ) print(service.render_message("welcome", user_us, name="John")) print(service.render_price(14.99, user_us))

关键设计:

  1. 翻译文件JSON格式:支持变量插值{name}
  2. UTC存储铁律:所有时间存UTC,展示时转换。
  3. ZoneInfo标准库:无需第三方依赖。
  4. 地区配置表:货币、日期、数字格式集中管理。

四、权衡:国际化深度决策

前期投入 vs 后期补救。国际化要在产品初期就做架构设计。初期花1-2周搭建框架,避免后期全部重写。

翻译文件管理。JSON文件适合早期,超过500条翻译就需要翻译管理平台(如Lokalise、Crowdin)。

AI翻译 vs 人工翻译。LLM翻译速度飞快,但专业术语准确率只有85-90%。核心界面建议人工校对。

时区带来的复杂度。跨时区协作用户的日程、统计报表都需要额外处理。建议从两个时区开始覆盖,逐步扩展。

取舍决策:国际化深度的选择框架

国际化做到什么深度?根据目标市场和产品特性决定:

目标市场判断

  • 英语市场:容错率高,AI翻译质量足够。国际化成本低。
  • 日语、韩语、阿拉伯语市场:容错率低,需要人工校对。国际化成本高。
  • 欧盟市场:有GDPR合规要求。数据不能随便出境。国际化不仅是翻译,还有合规。

产品特性判断

  • 面向消费者的产品:UI翻译用AI翻译+人工校对,内容翻译用AI实时翻译。
  • 面向企业的产品:所有翻译都需要人工校对。企业客户对语言准确度要求高。
  • 有合规要求的产品(金融、医疗):法律文书必须人工翻译,不能靠AI。

投入优先级

第一步:支持英文(覆盖最多用户)。

第二步:支持目标市场的本地语言(如做日本市场就支持日文)。

第三步:根据用户反馈,逐步完善翻译质量。

不建议:一次性支持10种语言。翻译质量不高,维护成本高。不如先支持2-3种语言,把质量做好。

决策输出:根据目标市场和产品特性,选择国际化的深度和优先级。不要为了"支持多语言"而支持多语言,要为"服务好目标市场"而做国际化。

五、总结

国际化不是可选项,是AI产品出海的必修课。三层架构涵盖了i18n、时区和内容本地化的核心需求。本文代码零外部依赖,可直接集成。

落地建议:先用zh-CNen-US两个语言验证框架,稳定后逐步增加。时区先覆盖东亚和北美,这两个区域的用户占比最高。翻译文件单独管理,方便后续接入翻译平台。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询