f-string不能用于国际化,因编译期插值阻碍运行时翻译;应先用_()翻译纯字符串,再用.format()插入变量,并用ngettext处理复数。

Python f-string 不能直接用于国际化(i18n)
因为 f-string 在编译期就完成插值,而翻译必须在运行时根据用户语言动态选择字符串。如果你写了 f"欢迎,{name}!",那这整条字符串会作为一条不可分割的键被提取——哪怕 name 是变量,也没法让翻译系统识别出“欢迎”和“!”是固定部分、“{name}”是占位符。
常见错误现象:gettext 工具(如 xgettext)完全提取不到这类字符串;或提取了但带变量名,导致翻译后无法正确替换。
- 必须把模板逻辑和翻译分离:先用
_()翻译纯字符串,再用.format()或%插入变量 - 推荐用
str.format(),它支持命名占位符,和gettext配合更清晰,比如_("Hello, {name}!").format(name=name) - 避免用
%格式化含复数或性别敏感场景,因为不同语言的词序、语法变化会让%s失效
用 gettext 的 ngettext 处理复数形式
英文里 “1 message” 和 “2 messages” 只需加 s,但中文没有复数变化,俄语有 3 种形式,阿拉伯语甚至有 6 种。硬写 f"{n} message{'s' if n != 1 else ''}" 在其他语言里会翻车。
使用场景:消息计数、购物车数量提示、评论数等所有含数字 + 名词的组合。
立即学习“Python免费学习笔记(深入)”;
系统介绍:YIXUNCMS中专专版是易迅软件工作室在中秋节来临之即推出的专题模板建站系统,使用增强版后台管控系统,板板设计符合节日特点。易迅软件工作室恭祝全国人民中秋快乐。特别提示:由于网站页面的不同设计,部分后台功能未在前端进行体现。系统特点:1、采用目前流行的PHP语言编写,底层采用超轻量级框架作为系统支撑;2、页面布局使用DIV+CSS技术,遵循WEB标准,及大提高页面的浏览速度;3、使用应
-
ngettext接收单数字符串、复数字符串、数字三个参数,由 gettext 库根据语言规则自动选型 - 示例:
ngettext("{n} file", "{n} files", n).format(n=n)—— 注意format()必须放在外层,ngettext返回的是已翻译的字符串,不是模板 - 提取时要确保
xgettext支持 Python 格式化语法(加--language=Python),否则可能漏掉{n}占位符
gettext 提取时跳过 f-string 是默认行为,别指望它“聪明”
工具不会解析 f-string 内部表达式,也不会尝试拼接字符串来还原语义。你写 f"{'欢迎'},{user}" 或 "欢迎" + "," + user,xgettext 都只会看到空字符串或乱序碎片。
容易踩的坑:以为把 _() 包在 f-string 里就行,比如 f"{_('Welcome')}, {name}" —— 这看似拆开了,但 f-string 仍会阻止工具识别整个句子结构,且增加运行时开销(重复调用 _())。
- 所有待翻译的文本必须是字面量字符串,即直接写死的
"欢迎"、"Loading..." - 如果必须动态拼接(比如带品牌名的标题),用
gettext的上下文功能:pgettext("homepage", "Welcome to {brand}"),再配合.format() - 路径中含变量?别拼进翻译字符串,用独立字段传入,比如
_("Download from {url}").format(url=url)
性能与兼容性:gettext + .format() 比 f-string 略慢,但可忽略
一次 .format() 调用比 f-string 多一次方法查找和解析,实测在万级调用下差异约 0.1ms/次。真正影响性能的是翻译缓存未命中或域(domain)加载失败。
兼容性方面,.format() 在 Python 2.7+ 全支持;若项目还跑在旧环境,% 格式化也可用,但注意它不支持位置重排(如阿拉伯语要把数字放词后)。
- 确保
gettext.translation正确加载了对应语言的.mo文件,否则_()返回原字符串,格式化照常执行,但用户看到的是英文 - 测试时强制切换语言:
gettext.translation('messages', localedir='locale', languages=['zh']).install() - 线上环境别用
locale.setlocale()控制语言,它进程全局生效,多线程下会冲突
{name})必须和代码里传入的变量名一致,且不能依赖顺序——.format(name=x) 和 .format(x) 效果完全不同。









