尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

架构师必备:绕不开的国际化和本地化支持

发布时间:2026/9/28 21:11:42

资讯中心
01
ARTICLE

架构师必备:绕不开的国际化和本地化支持

架构师必备:绕不开的国际化和本地化支持
大家好我是Java烘焙师这次分享一些技术和商业上的思考。从第一天起就应该支持国际化和本地化否则越到后期改造成本越高。等代码和DB里到处是硬编码的文本、日期格式、写死“元”的金额字段时就很难重构了。跟商务开拓层面的困难相比技术层面反而是简单的别再只盯着那一亩三分地卷存量了。先说一下经济常识美国是全球最大消费市场欧盟跟中国也在同一量级。按语言使用人数排序前几大语言是英语、中文、印地语、西语、法语、阿拉伯语。如果只支持国内市场就错失了更大的市场了。国际化internationalization简写为i18n解决“通用”问题系统层面兼容多语言、时间、货币。本地化localization简写为l10n解决“定制”问题针对特定地区做特殊逻辑。先说国际化。国际化多语言基本常识字符编码应当统一用UTF-8前端页面、后端服务、数据库存储都是。前端声明charsetMySQL用utf8mb4三字节的utf8是残缺版如果文本包含emoji表情就可能展示出错JDK 18起默认编码也终于改成UTF-8了。语言存在区域变种比如简体中文、繁体中文美国英语、英国英语拉美西语、西班牙西语。所以locale是“语言_地区”只记语言不够。还有展示异化比如RTL即从右往左展示阿拉伯语就是这样。固定文本、模板文本相对固定的UI文案做成key、value配置可变部分用占位符。Java标准做法是ResourceBundle加properties文件占位符交给MessageFormat# messages_zh_CN.properties login.welcome欢迎回来{0}你上次登录是{1,date,long}。 # messages_en_US.properties login.welcomeWelcome back, {0}! Your last login was on {1,date,long}.ResourceBundlemessagesResourceBundle.getBundle(messages,locale);StringtextMessageFormat.format(messages.getString(login.welcome),username,lastLogin);{1,date,long}这种占位符能带日期格式日期会按目标locale的惯例渲染。某些语言有复数一个小技巧是做成同时兼容单数、复数比如写成几天就是{0} day(s)动态内容动态内容需要存储在DB的多语言表里比如用户发的帖子、评论商家发的商品信息内容不固定可能包含文本、图片、视频。现在有了AI翻译文本翻译准确率大幅提升连图片里的文字视频里的声音也能翻译替换了。表结构上多语言信息需要增加一个locale字段。翻译策略上业界有两种代表做法按照实际需求选择。推特手动选择帖子翻译翻译后存储结果后来的人直接命中缓存。优点是按需翻译和存储冷门内容无需处理缺点是要用户手动点一下。亚马逊全局切换语种商品、评价预先翻译好。优点是用户体验好进去就是母语缺点是耗费存储某些小语种可能几乎没人用。时间基本常识各地区的惯用写法不同年月日、日月年、月日年都有。比如美国人习惯用月日年欧洲人习惯用日月年。时间戳与时区无关是距离1970年1月1号流逝的时间数据库中应该记录时间戳而非datetime避免时区带来的麻烦。有的区域在特定时间范围内还实行夏令时每年有两天“凌晨2点”要么出现两次要么不存在。日期格式借助JDK的DateTimeFormatter实现按区域惯例展示。LocalDatedateLocalDate.of(2026,9,26);DateTimeFormatterfDateTimeFormatter.ofLocalizedDate(FormatStyle.LONG);f.withLocale(Locale.US).format(date);// September 26, 2026f.withLocale(Locale.UK).format(date);// 26 September 2026f.withLocale(Locale.GERMANY).format(date);// 26. September 2026时区存储数据时用时间戳展示时明确指定时区不要依赖默认值。因为JVM默认时区会随部署环境变化比如容器里是UTC、宿主机里是东八区。InstantnowInstant.now();// 与时区无关ZonedDateTimeshnow.atZone(ZoneId.of(Asia/Shanghai));ZonedDateTimenynow.atZone(ZoneId.of(America/New_York));夏令时不用自己算时区数据库里带着规则ZoneRules.isDaylightSavings、nextTransition。定时任务注意cron按服务器本地时间跑夏令时切换日会少跑或跑两次跨国任务统一用UTC调度。货币基本常识金额数字应当使用BigDecimal而非Integer或Long类型更不能是浮点数。比较两个金额数字要用compareTo而不是equalsequals除了比较数值还会比较scale精度。货币用java.util.Currency表示比如欧元EUR在欧元区流通如德国、法国、西班牙、意大利等美元USD、日元JPY、英镑GBP有各自的地盘。表结构上金额字段需要配套一个币种字段。金额精度日元最低精度是元美元最低精度是分。每种货币的小数位是法定的JDK里已经记好了Currency.getInstance(JPY).getDefaultFractionDigits();// 0Currency.getInstance(USD).getDefaultFractionDigits();// 2入库统一存到足够细的精度展示、业务计算时再按币种法定精度取整。金额展示千位分隔各国有各国的规矩国内还有“万”和“亿”的习惯。借助NumberFormat实现金额精度、展示NumberFormatfmtNumberFormat.getCurrencyInstance(Locale.US);fmt.format(newBigDecimal(1234.5));// $1,234.50NumberFormatcompactNumberFormat.getCompactNumberInstance(Locale.CHINA,NumberFormat.Style.SHORT);compact.format(123456);// 12万汇率借助开源组件JavaMoneyJSR 354实现汇率换算它的参考实现Moneta自带ECB汇率Provider数据源就是欧洲央行的参考汇率每个工作日更新非实时汇率内部也做了缓存MonetaryAmountusdMoney.of(newBigDecimal(9.99),USD);MonetaryAmountcnyusd.with(MonetaryConversions.getConversion(CNY,ECB));如果要计算实时汇率还得接入银行或支付机构。还有一点容易被忽略下单时刻的汇率要随订单落库因为订单金额是既定事实不能跟随汇率波动。本地化国际化支持是为了通用而本地化则是根据当地法律法规、或风俗习惯做的定制逻辑。有的本地化功能关乎合规直接影响到能否在当地正常开门营业多了解一些案例可以少走弯路。法律法规、风俗习惯欧盟在互联网、AI等技术领域跟中美相比是落后许多的但法律法规走在了前头比如GDPR、数字服务法、AI法案时不时给企业开罚单。技术上意味着欧洲用户数据要留在欧洲、删除权要落实到底层存储。数据留在欧洲已经不是文案问题了涉及多区域部署、用户按区域路由、跨区同步只同步非用户数据。这是最体现系统架构设计价值的地方了。美国保护数字版权比如DMCA规定“通知-下架”机制权利人一发通知平台就得删直接塑造了所有UGC平台的内容处理流程。中东地区比如不吃猪肉、着装不能过于暴露需要尊重当地习俗。度量衡世界上绝大部分地区都用的是公制单位比如厘米、毫升、克、摄氏度。但是美国是个例外仍然在用英制单位连英国自己都基本改成公制了比如英寸、液量盎司、华氏度。处理思路和金额一致存储统一用公制展示时按用户locale换算成英制。反例品牌出海翻车的案例有的已经写进营销教科书的反例了。比如1990年代国内某日化品牌在国内做得不错出口到欧美时发现品牌名在当地语言里是负面禁忌词根本没法上架导致损失惨重。这些需要专人本地人评估做好前期准备工作。再举一个最近的例子闹钟的节假日跳过。国内假期闹铃需要考虑调休而不是只看工作日。某国际手机大厂直到近期才支持而国内手机厂商早就支持了。只能认为是不够重视中国市场、态度比较傲慢。总结以上就是国际化本地化支持的思考了。世界是多样的有各自的风土人情前人踩过的坑就没必要再掉进去了。
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。