迪拜那个阿拉伯语站点是周一上午十点切的流量。当天下午就出了四件事:页面正文整行的字序反了,订单号里的数字跟着跑到左边去;后台导出的人名被截掉一半,客户投诉注册信息不对;给利雅得客户发的确认短信,原本一条的话被拆成三条发出去,月底对账时短信费用比预算多了将近两倍;财务批量导出的对账 CSV,在对方电脑上打开是一串方块和问号。翻译稿两个月前就验收完了,语料库、术语表、人工校对一项不落。真正把上线拖住的,是翻译之后那几件从来没人认领的服务器侧工程事。
多语言上线卡住的通常不是翻译,而是服务器侧六件工程事:双向文本、字体与渲染、排序规则、短信与邮件编码、无空格语言的分词、导出文件兼容。
这六件事必须在选节点、选镜像的阶段就定下来,因为它们会反向决定镜像里要装哪些字体包、要不要单独起渲染服务、数据库初始化时用什么字符集与排序规则。
数据库的字符集与排序规则属于"建库时定、后改代价极大"的参数,等页面都写完了再回头改,往往意味着索引重建和数据迁移。
短信编码直接决定成本:同一句话在两种承载编码下可容纳的字符数差别很大,业界常见口径是 160 与 70 左右,实际以运营商与通道商规则为准。
泰语、高棉语、缅甸语、老挝语、中文、日文不使用空格分词,默认按空格切词的检索引擎在这些语言上召回极差,需要专门的分词或按字符切分策略。
多语言项目常见的分工是:语言同事负责翻译,前端负责界面,运维负责上架机器。这套分工在拉丁语系之间互相切换时问题不大——英语换成法语、德语、西班牙语,本质是同一套字符、同一套方向、同一套分词逻辑,顶多多几个重音字母。一旦目标市场换成中东的阿拉伯语、希伯来语,南亚的乌尔都语、孟加拉语,东南亚的泰语、高棉语、缅甸语,这套分工就会出现一个明显的真空地带:有些事情既不属于翻译,也不属于前端页面,它落在服务器、数据库、中间件和导出链路上。
这个真空地带一共六块。第一块是双向文本,阿拉伯语和希伯来语是从右向左书写的,和拉丁文字、数字混排时需要双向文本算法来判定每一段的视觉顺序,服务器生成的页面、单据、邮件正文都得跟着走。第二块是字体与渲染,服务端合成 PDF 合同、发票、提单,或者往图片上打水印、生成验证码时,如果镜像里没有对应语种的字体,输出的就是一片空白方块。第三块是排序规则,同一个姓名列表在华沙和曼谷排出来的顺序是两回事,这件事由数据库的排序规则决定,不由应用层决定。第四块是短信与邮件的编码,一条阿语短信和一条英语短信能装的字符数完全不是一个量级。第五块是无空格语言的分词,决定了搜索能不能搜到东西。第六块是导出与对接,CSV、Excel、接口字段的编码声明一环没对齐,下游系统收到的就是乱码。
存储层还有一类问题——比如特定字符或表情符号存进数据库变成问号,那属于字符集字节宽度的问题,是另一个话题,本篇只在建库参数那里提一句,不展开。本篇要讲的是上面这六块,它们共同的特点:决定权在服务器侧,而决策窗口在下单选机型和镜像的时候。等到代码写完、节点开好、数据库已经灌了几十万条数据才发现排序规则选错,那已经不是改一个配置的事了。
阿拉伯语、希伯来语属于 RTL(从右向左)书写方向,这几乎是所有人知道的常识。真正让人翻车的是常识后面那半句:这两种文字在实际业务内容里几乎不会"纯"着出现。订单号是数字,商品型号是拉丁字母,品牌名常常保留英文原文,金额后面跟着货币代码,URL 和邮箱地址清一色是拉丁字符。于是一行文字里同时存在从左向右的段和从右向左的段,谁在前谁在后,由 Unicode 的双向文本算法根据每个字符的方向属性来算。
第一个是数字与单位。欧洲数字在 RTL 段落里会被当作一个独立的从左向右的片段处理,视觉上它保持自己的内部顺序,但它作为一个整体块在行内的位置由上下文决定。订单号、电话号码、金额这些字段如果和阿拉伯语文本贴在一起,很容易出现"数字跑到了句子的另一头"的观感。金额尤其麻烦,"1,250 SAR"这种结构里既有数字、又有逗号、又有拉丁字母,视觉顺序和逻辑顺序的差别最直观。
第二个是成对标点。括号、方括号、引号这类字符在 RTL 环境下会发生镜像,左括号显示成右括号的样子。如果后端做字符串拼接时手工拼了括号,或者日志把内容拼进括号里再看,就容易出现方向相反的结果。
第三个是路径、URL 和邮箱。斜杠、点号、@ 这些中性字符夹在 RTL 文本中间时,算法判定的结果经常和预期不一致,一条完整 URL 可能被切成几段按奇怪的顺序显示。这类内容在邮件正文里尤其常见。
第四个是表单输入与截断。用户在阿语界面里输入姓名,后端按字节长度或字符长度做校验和截断,如果截断位置正好落在一个组合字符序列中间,存进去的就是半个词。这类问题在数据库里看不出来——字段长度没超,字符数也对——只有渲染出来才发现断得莫名其妙。
原则只有一条:数据库和接口里存"逻辑顺序",视觉方向交给渲染层处理。很多团队早期图省事,在后端把字符串反转了再存,这条路的后果是灾难性的——反转后的字符串没法做检索、没法做排序、没法做长度校验,一旦要加第二个 RTL 语种或者要把数据对接给第三方,全部要重来。
具体落地是三件事。模板层要有明确的方向声明,页面、邮件模板、PDF 模板都要能按语种设置书写方向,而不是靠样式表里写死一个方向。混排边界处需要插入不可见的双向文本控制字符(比如用于强制相邻字符方向判定的标记字符),让算法在数字串、拉丁串的前后给出确定的方向。校验逻辑要按"字素簇"而不是按单个码位来算长度和截断,避免把组合字符序列切碎。
还有一件容易被跳过的事:日志和审计。后端日志里如果打印了 RTL 内容,运维在终端里看到的方向可能和真实内容相反,排查问题时很容易被误导。建议在日志里对这类字段做转义或者加明确标记,别让人凭肉眼去猜方向。
验证方法也不复杂:准备一组固定样例串,每个样例里同时包含阿拉伯语文本、数字、拉丁品牌名、括号和 URL,在页面、PDF、邮件、导出文件四种载体上各渲染一次,做快照比对。这组样例应该进回归测试,每次模板改动都跑一遍。中东的迪拜、利雅得这两个市场是这套验证的第一落点。
客户端显示多语言内容,字体由用户设备提供,缺字是用户自己的事。服务端生成文件就完全不同——PDF 合同、发票、提单、报关单据,图片水印、分享卡片、验证码,这些内容的字体全部由服务器自己提供。镜像里没有对应字体的字形,输出的就是那个著名的空白方块(排版里叫 .notdef,俗称豆腐块)。
比豆腐块更隐蔽的问题是"能显示但位置错"。阿拉伯语的字形会根据它在词里的位置(词首、词中、词尾、独立)发生替换和连写;泰语的元音符号有的在辅音上方、有的在下方、有的在前后,声调符号还要叠在元音上面;缅甸文和高棉文存在字符堆叠。这些都属于复杂文本整形,需要字体本身带相应的排列表,也需要渲染库支持整形。缺字体是白块,缺整形是字符位置乱掉——后者的截图看起来"好像有字",更容易在验收时蒙混过关,然后在客户手里变成一份读不通的合同。
服务端 PDF 生成是最常见的一处,无论是用报表库、HTML 转 PDF 的无头浏览器,还是直接用排版引擎,都绕不开字体和整形两件事。单据类业务在中东和南亚尤其重,迪拜、利雅得的清关单据,孟买、卡拉奇的发票与收货单,达卡的物流面单,这些都是要打印、要盖章、要拿去办事的纸质文件,出白块等于整个单据作废。
第二处是图片类输出:水印、验证码、海报、社交分享卡片。验证码尤其坑——验证码图片通常由一组轻量级绘图库生成,默认只带几款基础字体,换成阿拉伯语或泰语的随机串,画出来的就是一片方块,用户根本没法输入。
第三处是文档转换链路。把 Office 文档转成 PDF 做在线预览,或者把 HTML 转成图片做长图分享,中间的转换服务同样需要字体。很多团队在应用服务器上装齐了字体,却漏掉了转换服务所在的那个容器,结果只有转换出来的文件是坏的。
字体要装进镜像,不是装进运行环境。镜像里要有字体包、字体配置工具的缓存、以及支持复杂文本整形的渲染库。字体体积是个现实问题——覆盖全部语种的通用字体全集非常大,如果每个节点、每个容器都塞一份,镜像体积和分发时间都会失控。更务实的做法是按目标市场做字体子集:中东节点装阿拉伯语与希伯来语相关字体,东南亚节点装泰文、高棉文、缅文、老挝文字体,南亚节点装乌尔都语(阿拉伯字母体系)、孟加拉文、天城体相关字体。子集化还能顺带避开字体授权上的一些麻烦,商用字体是否允许内嵌进 PDF 是有条款差异的,这一步要按授权来,别想当然。
字体配置要有明确的回退链。一个字符在当前字体里找不到字形时,应该按预设顺序去下一个字体找,而不是直接吐白块。回退链的顺序需要在镜像里配置好并做验证,不能依赖默认值。
渲染服务建议独立部署。无头浏览器和文档转换服务的内存开销不小,把它们和主应用挤在同一台机器上,高峰期很容易互相拖垮。这一点会直接影响机型选择——具体需要多少内存,取决于并发渲染任务数和文档复杂度,实际数值仍需结合自身业务实测确认。
排序这件事表面上由应用层的一句 ORDER BY 完成,实际结果由数据库的排序规则(collation)决定。排序规则定义了字符之间的先后关系:重音字母算不算独立字母、大小写谁在前、不同文字之间怎么排。
欧洲重音语言的差异是最直观的例子。波兰语的 Ł 在传统排序里有自己的位置,不是简单的 L 加个撇;捷克语的 Č、Ř 带钩字母排序位置也与基础拉丁字母不同;匈牙利语的重音字母与双字母组合(比如 dzs)各有规则。华沙和布达佩斯这两个市场如果共用一套通用的西欧排序规则,姓名列表的顺序就是错的——不是"有点不一样",而是用户翻半天找不到自己名字那种错。用户不会认为这是排序规则问题,只会认为这个站点做得糙。
东南亚又是另一套。泰语的词典序按辅音类别、元音、声调的组合规则排,和字符的编码码位顺序不一致。按码位排出来的泰语姓名列表,在泰国用户眼里是乱的。缅文、高棉文同理。
因为排序规则是建库建表时确定的参数,后期修改的代价极大。改排序规则意味着索引要重建,大表上重建索引不是几分钟的事;如果排序规则变了导致已有索引的字节序不再匹配,还要处理数据迁移和校验。换句话说,这是一个在下单选数据库配置时就要定好的东西,不是上线后发现顺序不对再改的东西。
多语种混合的字段是这里最难的一处。一个"姓名"列里同时有阿拉伯语、泰语、英语三种内容,没有任何单一排序规则能把三种都排得符合各自语言习惯。可选的做法是按语种分列或分字段存储,排序时先按语种分组再各组内按对应规则排;或者接受一个统一规则,在业务上明确"按码位排、仅用于去重和分页稳定",并在界面上不做词典序承诺。这两种取舍都要提前写进设计,不能留给上线前的临场决定。
还有一处一致性问题:应用层排序和数据库排序必须一致。很多系统为了分页稳定,在数据库里按 A 规则排,在应用内存里对同一批数据再按 B 规则排一次,结果分页交界处会出现重复行和漏行。这类 bug 只在数据量大到触发多页时才暴露,排查起来非常费时间。
验证方法:每个目标语种准备一组 20–30 条的固定姓名样例,导入测试库跑排序,把结果和该语种的词典序预期逐条比对。这组样例应该固化成测试用例,数据库版本升级时也要跑一遍——排序规则的实现在不同数据库版本间是有过变化的。
短信的费用是按条算的,一条能装多少字符取决于承载编码。GSM 7-bit 编码针对拉丁字符集设计,业界常见口径是一条可容纳 160 个字符左右;一旦内容里出现非拉丁字符(阿拉伯语、乌尔都语、泰语、孟加拉语都在其列),通道会切到 UCS-2 这类双字节承载,常见口径是一条 70 个字符左右。超出部分会拆成多条发送,分摊到每一条的拼接头还会再占掉几个字符(常见口径是 153 与 67 左右)。以上为业界常见口径,具体以运营商与通道商的实际规则为准。
换算到业务上就是:一条 60 字的英语验证码通知是一条短信,同样的内容写成阿拉伯语,还是一条;但写成 150 字的订单状态通知,英语是一条,阿拉伯语就变成三条。一个面向中东、南亚、东南亚同时发货的跨境业务,短信账单上的差异是实打实的。这部分预算如果没在选型阶段算进去,第一个月的通道账单会很难看。
第一件事是在发送前算清楚分段。不是数字符数,而是按实际将要使用的编码来算分段数:先判断内容字符是否全部落在 7-bit 字符集内,是则按 160 口径算,否则按 70 口径算,再减去拼接头的开销。这个计算要放在发送服务里,作为模板校验的一部分——模板保存时就应该给出"这条模板在阿语下会拆成几条"的提示,而不是等发送完看回执统计。
第二件事是给每个语种做模板长度预算。同一个业务通知,阿语、乌尔都语、泰语各写一版,每版都要在编码口径内控制分段数。中文短、阿拉伯语表达同样意思可能更长,这种跨语种的长度差异要靠预算表管起来。
第三件事是通道策略。不同通道对不同语种的支持程度、编码处理、拼接方式都有差别,面向孟买、达卡、卡拉奇这类南亚市场和曼谷、金边、仰光这类东南亚市场时,通道的选择应该按语种实测结果来定,而不是按价格定。拼接短信在接收端能否正确合并,也需要在真实设备上验证。
邮件这边是另一套坑。邮件主题和附件名如果包含非 ASCII 字符,需要按 MIME 的编码规则处理(业界常见做法是按 RFC 2047 一类的编码方式把主题编码成带字符集标记的 encoded-word,附件名按对应的参数编码规则处理)。不做这步,收件人看到的就是一串乱码或者一串看不懂的等号。邮件正文的编码要在邮件头里明确声明,客户端才知道按什么解。落地方式是在邮件发送服务里统一做编码封装,并准备多客户端验证清单:网页邮箱、桌面客户端、手机客户端各发一遍,确认主题、发件人名、附件名三项都正常。
泰语、高棉语、缅甸语、老挝语不使用空格分词,中文、日文同理。检索系统默认的切词逻辑大多是按空格和标点把文本切开,这套逻辑在这些语言上直接失效——整段文字被当成一个巨大的词,或者被按标点切成几个超长的块,无论哪种,用户输入的查询词都匹配不上。
后果很具体:曼谷站点上用户搜一个商品名,搜不出东西,用户就认定这个站点没货。这不是翻译质量问题,也不是数据没导进去,是检索链路的分词策略没做。高棉语还有一个额外的坑:它在短语之间用空格、在词内部不用空格,按空格切出来的片段既不是词也不是短语,召回和精度两头都不讨好。
第一条是语种专用分词器。基于词典或基于统计模型把句子切成词,精度最好,但要为每个语种引入对应的分词组件和词典,维护成本随语种数量线性上升。泰语、缅甸语、高棉语各有成熟度和维护状况不同的开源实现,选型时要看清楚是否还在维护。
第二条是按字符 n-gram 切分。不做真正的分词,把文本切成重叠的字符片段(比如二元组),用片段建索引。这条路对任何语种都通用,不需要词典,召回高;代价是索引体积膨胀、精度下降,短查询上容易召回一堆弱相关结果。对于语种覆盖面广、每个语种数据量都不大的业务,这是性价比很高的一条路。
第三条是基于 Unicode 断词规则的通用切分。按照标准的文本分段规则(词边界判定)来切,覆盖语种广、实现统一,对无空格语言的效果介于前两者之间,很多国际化组件库走的就是这条路。
选择依据是业务形态:搜索是核心转化路径的电商类站点,值得为泰语这样的主力语种上专用分词;搜索只是辅助功能的后台系统,用通用切分或 n-gram 就够了。这个判断要提前做,因为它决定了检索组件的技术选型和索引结构。
分词策略变了,索引要重建,这是和数据库排序规则同级别的"提前决策"事项。除此之外还有三处容易忘:搜索建议(输入联想)要用和检索一致的分词,否则联想出来的词搜不出结果;高亮要用和索引一致的切分边界,否则高亮的片段会错位;排序里的相关性打分也依赖分词结果,切分方式变了,排序结果跟着变。这三处都要在同一套分词配置下验证。
验证方法:每个语种准备 30–50 组"查询词—预期命中文档"的测试对,跑召回率测试,把召回率作为上线门槛指标。没有这组测试对,分词策略的改动就是盲改。
| 环节 | 常见现象 | 根因 | 服务器侧要准备什么 | 验证方法 |
|---|---|---|---|---|
| 双向文本(RTL) | 阿语页面整行字序反了,订单号数字跑到句子另一头,括号方向相反 | 模板与单据未按从右向左方向渲染,混排处缺少方向控制 | 数据层存逻辑顺序;模板层按语种设方向声明;混排边界插方向控制字符;长度校验按字素簇算 | 固定混排样例串在页面、PDF、邮件、导出四种载体上做快照比对,进回归测试 |
| 字体与渲染 | PDF 合同里人名是空白方块,验证码图片一片豆腐块,泰文元音符号位置错乱 | 镜像缺该语种字体,或渲染链路缺复杂文本整形支持 | 按目标市场做字体子集并预装进镜像;配字体回退链;渲染与转换服务独立部署 | 生成样例 PDF 后抽文本并截图比对;逐个语种过一遍验证码与单据 |
| 排序规则 | 波兰语、匈牙利语姓名排序位置不对,泰语姓名列表顺序在本地用户看来是乱的 | 数据库排序规则与目标语言习惯不匹配,多语种混合字段无单一解 | 建库时按目标语种定排序规则;多语种混合字段按语种分列或明确统一规则 | 每语种 20–30 条固定样例跑排序,与词典序预期逐条比对,数据库升级后复跑 |
| 短信编码 | 一条通知变成三条发出去,短信账单超预算 | 非拉丁字符触发双字节承载,单条可容纳字符数大幅下降 | 发送前按实际编码算分段数;各语种模板做长度预算;通道按语种实测选型 | 每语种模板跑分段数回归;真实设备验证拼接短信能否正确合并 |
| 邮件编码 | 邮件主题、发件人名、附件名显示成一串乱码或等号 | 头部非 ASCII 字段未按 MIME 编码规则处理,正文未声明字符集 | 发送服务统一做头部编码封装与正文字符集声明 | 网页邮箱、桌面客户端、手机客户端各收一遍,逐项确认主题与附件名 |
| 分词与检索 | 泰语、高棉语搜商品名搜不出来,用户以为没货 | 检索组件按空格切词,对无空格语言失效 | 改用 ICU 断词、语种专用分词或字符 n-gram;联想、高亮、打分用同一套切分 | 每语种 30–50 组查询词与预期命中文档跑召回率,设上线门槛 |
| 导出与对接 | 导出的 CSV 在对方 Excel 里是乱码,接口字段在下游系统里不可读 | 文件缺少 BOM 或编码声明,接口未统一编码约定 | 导出加 BOM 或明确编码声明;接口统一编码并在头部声明;老系统对接加转码网关 | 多版本表格软件、多地区系统环境各打开一遍,字段级逐项核对 |
导出是整条链路的末端,也是最容易在验收时被漏掉的一环。开发和测试都在 UTF-8 环境里工作,导出文件在自己机器上打开一切正常;文件到了孟买、达卡、曼谷的合作方手里,对方用本地环境的表格软件打开,是一串方块。原因很简单:这类表格软件在打开 CSV 时,如果文件开头没有 BOM 标记,会按系统默认的本地代码页去解,UTF-8 的字节序列在非 UTF-8 的本地环境下解出来就是乱码。常见做法是在导出文件头部写 BOM,或者在导出说明里明确声明编码并建议使用导入向导。
RTL 内容在表格软件里还有额外一层问题:单元格内容的显示方向由软件自己的设置决定,服务端无法控制。单据里如果一个单元格同时有阿拉伯语和数字,不同软件的呈现可能有差异。务实的做法是把方向和编号拆到不同列,编号列保持纯拉丁数字,减少混排单元格的数量。
数字与日期格式也要单独处理。不同地区的日期分隔符、千分位、小数位习惯不同,还有部分地区使用本地数字字符体系。稳妥的做法是:单据编号、金额、日期这类需要机器读取的字段保持最通用、最不易歧义的格式,不做本地化;本地化只作用于给人看的展示层。对账文件一旦把金额本地化,下游系统的解析就会出错,这类事故的排查成本非常高。
接口字段的编码要显式约定。HTTP 头里要带字符集声明,JSON 本身默认按 UTF-8 处理但也要在文档里写死,签名计算要在同一份字节序列上做——签名时按 A 编码算、验签时按 B 编码算,结果永远对不上,这是对接联调阶段最常见的卡点之一。老系统对接如果对方只能接收特定编码,就在网关层做转码,不要让转码逻辑散落在各个业务服务里。
还有一处容易忽略:CSV 的分隔符。阿拉伯语、乌尔都语的文本内容里出现逗号的概率不低,逗号分隔的 CSV 在这些内容上会串列。要么换用内容中出现概率极低的分隔符,要么老老实实做转义和引号包裹,并在导出后做一次字段数校验。
前面六件事如果都被当成"上线前再说",代价会在节点和镜像这一层集中体现。
第一处影响是镜像。字体必须进镜像,而字体进镜像就意味着镜像体积上升、构建和分发时间变长。全语种字体全集非常大,如果做成一份"什么都装"的大镜像推到所有节点,每次扩容和重建都在为用不到的语种付传输成本。更合理的是按地区做镜像变体:中东节点用带阿拉伯语、希伯来语字体与整形库的镜像,东南亚节点用带泰文、高棉文、缅文、老挝文字体的镜像,南亚节点用带乌尔都语、孟加拉文、天城文字体的镜像。这要求镜像构建流程从一开始就支持变体,而不是只产出一个通用镜像。
第二处影响是要不要单独起渲染服务。PDF 与图片合成的内存和 CPU 开销不小,如果单据生成量集中在月底或大促,这个服务会周期性地把整机内存吃满。把它和主应用分开部署,是这类业务里很常见的一个取舍:多一台机器的成本,换来主链路不被单据生成拖垮。具体要不要分、分多大,取决于并发渲染任务数与文档复杂度,实际数值仍需结合自身业务实测确认。
第三处影响是数据库参数。字符集要能覆盖目标语言,常见的 UTF-8 四字节编码(MySQL 系里常写作 utf8mb4 一类)才能存下所有目标字符;排序规则要按主要目标语种选。这两个参数在数据库初始化时定,后期改动的代价前面说过——索引重建加上可能的数据迁移。所以"选节点"这一步其实同时包括"选数据库初始化参数",这两件事应该在同一份部署清单里,不该分成两次决策。
第四处影响是检索组件。如果主力语种是无空格语言且搜索是核心路径,检索服务需要独立的分词配置和索引结构,往往也要独立的资源。这同样属于"选节点阶段就要定"的范畴。
把多地区节点放到一起比选时,可以这样排:中东的迪拜、利雅得是 RTL 与字体整形要求最高的一组,验证成本也最高,建议作为镜像与渲染链路的第一验证点;南亚的孟买、达卡、卡拉奇语种多、文字体系杂,适合作为字体子集与接口编码验证的第二落点;东南亚的曼谷、金边、仰光是无空格语言分词的主战场,检索链路要在这里重点验;欧洲的华沙、布达佩斯主要验排序规则与重音处理,工程难度相对最低,可以放在最后。
预算这一侧,多语言业务并不必然要求高配,真正的增量在内存和镜像分发上:渲染服务吃内存,字体包吃镜像体积和分发带宽。做比选时可以把配置档位拉通来看——比如一万云 ¥25 起这类入门档适合先把镜像和字体管线跑通、做验证环境;单据生成和检索服务这类内存压力明确的环节,可以考虑裸金属 E5-2698v4×2 ¥3999 起这类档位(以上均为官网明示档,以官网实时价为准)。海外非明示档位的物理机月租,公开渠道差异较大,一律按需询价 / 以官网实时报价为准处理,不要在预算表里填一个拍脑袋的数字。
为什么坑:建库向导和云数据库的默认值几乎都是通用的西欧规则,建库时一路下一步,库和表就带着这套规则诞生了。等数据量上来才发现顺序不对,改规则要重建索引,大表上这是以小时计的停机窗口,还得安排数据校验和回滚方案。
怎么判断:在测试库里灌一组目标语种的真实姓名样例,跑一次排序,把结果拿给该语种的母语同事看——不用问他"排序规则对不对",直接问"你能不能快速找到自己的名字"。这个判断比看参数表可靠得多。
怎么避:把字符集与排序规则写进部署清单的必填项,建库脚本里显式指定,不允许走默认;每个目标语种准备固定排序样例集并固化成测试用例。
为什么坑:字体是跟着渲染进程走的,不是跟着机器走的。一台机器上跑着主应用、文档转换服务、报表服务、验证码服务四个容器,只在主应用的镜像里装了字体,另外三个输出的文件全是白块。而且这类问题在开发环境经常不出现——开发机上字体装得齐,全链路都是好的。
怎么判断:把系统里所有会产出文件(PDF、图片、Office 转换、邮件附件)的服务列一张清单,逐个进容器执行字体列表检查,确认目标语种字体在位。这张清单本身就是交付物的一部分。
怎么避:字体包做成基础镜像层或独立的挂载卷,所有涉及渲染的容器统一继承;镜像构建完成后跑一次字体存在性检查,作为流水线的门禁。
为什么坑:字符数和计费条数不是一回事。同样是 150 个字符,拉丁语内容是一条,阿拉伯语内容是三条。按字符数做预算,账单出来就是三倍。更麻烦的是拼接短信在接收端不一定能合并成一条,用户收到的是三条语序断裂的片段。
怎么判断:把每个语种的主力模板各发一次到真实设备,看回执里的分段数和终端上的显示效果,拿这两个数去对账单。
怎么避:在模板保存环节就按实际编码算分段数并给出提示;给每个语种设模板长度预算上限;通道选型按语种实测结果定,别只比价。
共用一套完全可以,绝大多数多语言业务就是共用一套后端服务的,区别不在机器,在配置。真正需要分开的是渲染和检索这两类资源:字体子集按语种装、渲染服务因为内存占用独立部署、检索索引按语种建。这三个都可以在同一套后端架构里通过服务拆分和索引配置实现,不需要为每个语种单独开一套集群。只有当某个地区的单据生成量或检索量大到明显挤压主链路时,才值得在区域节点上做资源隔离。
有,但都有代价。轻一点的做法是在应用层做排序:把数据取出来在内存里按目标语言规则排,代价是分页要在应用层做,数据量大时内存和延迟都扛不住。中间做法是对特定字段建一个"排序键"列,写入时按目标规则生成一个用于排序的辅助值,排序时按这个列排,代价是写入逻辑复杂化、辅助列要维护。重一点的做法就是改排序规则并重建索引,这是最干净的,但需要停机窗口。选哪条路取决于数据量和业务对停机的容忍度,建议在小表上先试。
三种可能。一是字体装了但字体配置缓存没刷新,渲染进程读的还是旧的字形索引,重启渲染服务或者重建字体缓存即可。二是字体本身不含目标字符,回退链没配好,进程找不到替代字体就直接吐白块,这种情况要检查回退链顺序。三是字体内嵌被禁止——部分商用字体的授权条款不允许内嵌进 PDF,生成时字体被替换掉了,这种情况要换字体或者确认授权范围。排查顺序建议是:先查缓存,再查回退链,最后查授权。
行,但要接受精度下降。n-gram 的优势是不依赖词典、任何语种都能用、召回高,适合语种多而每个语种数据量都不大的场景。它的短板是索引体积膨胀、短查询容易召回一堆弱相关内容。判断标准是这个搜索在业务里的位置:如果搜索是用户找货的主路径,值得为主力语种上专用分词器;如果只是后台客服查单的辅助功能,n-gram 够用。折中做法是主力语种用专用分词,长尾语种用通用切分。
主要差在内存和镜像,不是 CPU。渲染服务(PDF 合成、文档转换、图片水印)是内存消耗大户,无头浏览器实例的开销尤其明显;检索服务如果走了 n-gram,索引体积膨胀也会推高内存需求。CPU 这一侧,多语言带来的增量主要体现在文本处理(分词、编码转换)上,通常不是瓶颈。所以做配置比选时,与其往上堆核心数,不如先把内存给足,并把渲染服务从主应用里拆出来。
有一个粗略算法:先判断模板内容里有没有非拉丁字符,没有就按 160 的常见口径算单条容量,有就按 70 的常见口径算;分段时每条还要扣掉拼接头占用的几个字符(常见口径是 153 与 67 左右)。用模板最长的一版算分段数,乘上预计发送量,再乘上通道单价。这个算法能给出一个量级,但不能作为最终预算——不同运营商和通道商的编码处理、拼接方式、计费口径都有差异,实际以所用通道的规则为准,建议先用小批量实测校准。
不够。BOM 解决的是表格软件猜错编码的问题,还有三类问题它管不了:一是 RTL 内容在单元格里的显示方向由客户端软件决定,服务端控制不了,要靠拆列减少混排;二是数字与日期的本地化,本地化过头的金额和日期会让下游系统解析失败,需要保持机器可读的通用格式;三是分隔符冲突,阿拉伯语、乌尔都语文本里的逗号会造成串列,需要换分隔符或严格做引号转义。这三项都要单独验证。
不建议只看市场大小,建议按工程验证难度倒着排:把工程难度最高、验证成本最大的地区放在前面,用真实流量把镜像、字体、渲染、排序这条链路压一遍,后面地区的边际成本就会显著下降。按这个逻辑,中东(迪拜、利雅得)因为 RTL 和字体整形要求最高,适合打头阵;东南亚(曼谷、金边、仰光)的分词问题独立性强,可以和中东并行准备;南亚(孟买、达卡、卡拉奇)语种杂,放在字体子集流程成熟之后;欧洲(华沙、布达佩斯)工程难度最低,最后补。
六件工程事做完之后,地区顺序其实就不是一个需要反复权衡的决策了,而是一个按验证成本排序的执行清单。
第一批放中东。迪拜、利雅得这两个点同时压着 RTL 混排、字体整形、单据 PDF 三件事,是整条链路上最容易出问题、也最能暴露问题的一组。在这里跑通之后,模板方向声明、字体回退链、渲染服务拆分这三件事的正确性就都有了真实流量背书。
第二批放东南亚,曼谷、金边、仰光。这一批的主战场是分词与检索,工程上相对独立,可以和第一批的准备并行推进,但上线建议放在第一批之后——因为检索链路的验证需要真实的查询日志,而查询日志的规模取决于用户量,先有中东的流量再验东南亚的检索,样本更充足。
第三批放南亚,孟买、达卡、卡拉奇。这一批的特点是语种多、文字体系杂(乌尔都语走阿拉伯字母体系、孟加拉语和印地语各有自己的文字),字体子集和接口编码的覆盖面在这里接受检验。放在第三批是因为前两批已经把字体管线的流程跑顺了,这里主要是扩充覆盖,不是新建能力。
第四批放欧洲,华沙、布达佩斯。这一批主要是排序规则与重音字符处理,工程难度最低,但因为排序规则是建库参数,如果它变了,前面三批的数据库都要受影响——所以排序规则这件事必须在第一批之前就定死,不能拖到第四批才想起来。
执行上有两个建议。一是每个地区上线前跑一遍固定的验收清单:混排样例渲染、字体存在性检查、排序样例比对、模板分段数、邮件多客户端收件、检索召回率、导出文件多环境打开,七项全绿才切流量。二是镜像变体和字体子集要纳入版本管理,节点扩容时用的必须是同一份经过验证的镜像,不能临时手工补装字体。一万网络这家深圳南山的服务商成立于 2007 年,在 IDC 这行做了 19 年,中文工单 7×24 有人接、平均 5 分钟响应,镜像里要预装哪些字体包和语言包,可以在下单时一并提出来。
本文涉及的工程规则,参考了以下公开资料:Unicode 联盟发布的双向文本算法(UAX #9)与文本分段规则(UAX #29),用于说明 RTL 混排与无空格语言的切分依据;IETF 的 RFC 2047 邮件头部非 ASCII 文本编码规则与 RFC 2231 参数值编码规则,用于说明邮件主题与附件名的编码处理;GSM 与 UCS-2 短信承载编码的行业公开资料(GSMA 相关规范文档),其中单条字符容量属业界常见口径,实际以运营商与通道商规则为准;MySQL、PostgreSQL 官方文档中关于字符集与排序规则的章节,用于说明建库参数的确定时机与修改代价;W3C 国际化(i18n)活动发布的双向文本与语言标记相关文档,用于说明模板层方向声明的做法;一万网络官网(idc10000.net)产品与报价页面,用于文中出现的配置档位与价格区间。
适用边界需要说明几点。第一,各语言的规则差异很大,阿拉伯语的连写整形、泰语的元音声调堆叠、高棉语的字符堆叠、欧洲各语言的重音排序规则各不相同,本文给出的清单是通用的检查框架,具体到每个语种都必须单独验证,不能用"跑通了一个语种"推定其他语种也没问题。第二,文中涉及的具体数值——短信单条字符容量、渲染服务内存开销、镜像体积——都受运营商规则、通道商实现、文档复杂度与字体选择影响,公开渠道差异较大,实际数值仍需结合具体业务实测确认。第三,本文讨论的是服务器与后端侧的工程准备,不涉及翻译质量管理、术语一致性、本地化文案的文化适配,也不涉及数据存储层字符编码字节宽度相关的专题。第四,文中涉及的海外地区部署内容为行业部署分析,不构成对任何服务商在特定城市有机房的表述。具体以签约时最新报价与合同为准。
Copyright © 2013-2020 idc10000.net. All Rights Reserved. 一万网络 科技有限公司 版权所有 深圳市科技有限公司 粤ICP备07026347号
本网站的域名注册业务代理北京新网数码信息技术有限公司的产品