ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Discuz! 3.2英文语言包改造全指南:从文件结构到避坑实践

Discuz! 3.2英文语言包改造全指南:从文件结构到避坑实践 简介一份完整英文语言包专为Discuz! 3.2论坛系统设计面向站点管理员、开发者和海外用户群体可消除非中文环境下的界面障碍让注册登录、发帖管理、后台设置等场景均呈现自然英文表达。RAR压缩包内共194个文件以136个php翻译文件为核心负责所有界面文案19个htm模板搭建页面结构35个gif/png图标与js脚本完善按钮、提示等视觉效果2个psd源文件便于后续视觉调整整包仅772KB轻量稳定。已有1399人学习下载是站长拓展国际用户的常用工具。安装后能覆盖个人中心、版块帖子、站内消息、积分勋章、插件模板等全部核心功能后台切换语言即可启用无需改动代码管理员与普通用户均能快速适应站点接入海外访客的门槛大幅降低。对开发者来说英文键名和源码注释也有助于理解Discuz!的模块构造方便二次开发与问题排查。1. Discuz! 3.2 英文语言包为什么说“完美”是个伪命题但值得做Discuz! 3.2 是 2014 年发布的经典版本至今仍有大量存量站点在跑。所谓“完美英文语言包”本质上是给这套以中文为默认语言的论坛程序补一套完整的英文界面文案同时不破坏已有帖子和用户数据。做过的人都知道真正的难点从来不是翻译而是让程序在加载语言包时不漏掉任何一处硬编码文字还要保证后续插件不把界面打回原形。这篇文章写给两类人一是接到“把论坛改成英文版”需求的开发者二是想把自己的 Discuz! 3.2 站点推向海外用户但不想换程序的站长。我会从语言包的文件结构和加载机制讲起再给出一套完整的改造顺序、批量替换脚本和避坑清单最后聊怎么验证成果。全程基于 Discuz! X3.2 的实际目录结构不需要你懂很深的技术照着做就能跑通。2. 英文语言包到底改哪些文件先摸清 Discuz! 3.2 的语言加载机制2.1 语言包不是“一个文件”是四层目录的协同Discuz! 3.2 的语言包分散在source/language目录下里面有admin、forum、group、home、member、mobile、portal、rank、search、secquest、userapp等子目录。每个子目录对应一个功能模块forum管帖子列表和发帖页member管登录注册admin管后台管理界面mobile管手机版。每个子目录下是lang_模块名.php文件比如source/language/forum/lang_template.php存的是前台模板里用到的按钮、提示文字、分页导航词source/language/member/lang_template.php存登录注册页的文案。这些文件的核心结构是一个 PHP 数组?php $lang array( admin 管理员, back 返回, edit 编辑, ); ?关键点在于数组的键名左边是程序里写死的标识符值右边才是显示给用户看的文字。做英文语言包时只能改右边不能动左边否则程序找不到对应的键页面会直接输出空白或者 PHP 报错。除了lang_*.php还有一层是模板文件里直接写死的中文。这部分不走语言包而是嵌在template/default目录下的.htm模板文件里。常见行话叫“硬编码文字”。举个例子template/default/forum/discuz.htm里可能有欢迎回来、快捷导航这类文字它们不在语言包里需要单独处理。第三层是static/js目录下的 JavaScript 文件。Discuz! 3.2 的很多提示框、确认弹窗是 JS 弹出来的比如发帖成功后跳转提示、删除确认框这些文字写在static/js/forum.js、static/js/common.js里浏览器执行 JS 时动态拼接出来。第四层才是真正最坑的数据库。版块名称、用户组名、自定义积分名称、分类信息选项这些是站长在后台填进去的数据存储在forum_forum、common_usergroup等数据表里。语言包对它们完全无效——如果站长创建版块时填的是“技术交流”英文语言包也只会原样输出“技术交流”这四个字。2.2 语言包的加载顺序与覆盖关系为什么改完不生效Discuz! 3.2 的语言加载逻辑在source/class/discuz/discuz_application.php的_init_language()方法里。它会先加载默认语言包即中文然后根据当前用户或访客的浏览器语言设置再加载对应语言的覆盖文件。但 X3.2 默认只内置了简体中文的语言文件没有提供完整的英文文件所以所谓的“英文语言包”就是你自己补一套lang_*.php文件放到对应目录并让程序认为当前语言是en。加载顺序很关键程序先加载全局数组再按模块覆盖。例如访问论坛首页时程序会加载source/language/forum/lang_template.php然后按需加载source/language/common下的公共语言文件。如果你改了lang_template.php但没注意到公共变量是从lang_global.php里取的页面上半数按钮文字还是中文。还有一个反直觉的点Discuz! 3.2 支持多语言包并存但语言检测依赖config_global.php里的$_config[lang][default]和$_config[lang][allow]两个配置。默认default是zh-CN而allow里如果不加en即使用户浏览器是英文环境程序也不会切换到英文包。2.3 先做一次“临时切换”不改源码先验证覆盖范围在动手改造之前先验证现有语言包系统能不能被英文环境触发这一步能帮你确认工作量。临时修改config_global.php里的默认语言为英文虽然此时还没有英文文件页面会缺文案或者用浏览器的语言优先级测试——把浏览器首选语言改成en-US再访问站点观察页面元素哪些变成了空白哪些还是中文。空白的部分说明这些文字是从语言包读取但找不到对应键中文部分则说明是硬编码或数据库数据。我一般会用这个命令快速检查语言包目录下到底有哪些文件、哪些模块有对应语言文件find source/language -name lang_*.php | sort执行后你会看到类似source/language/forum/lang_template.php、source/language/forum/lang_action.php这类文件列表。对比中文版的文件清单就能算出需要新建或修改多少个文件。这一步的产出是一张“缺失文件清单”后续翻译就按这个清单逐文件推进。3. 做一套能复现的英文语言包从备份到文件的修改顺序3.1 备份与目录规划语言包必须做成“增量覆盖包”不要直接修改source/language下的原始中文文件否则以后想恢复中文版只能重新覆盖源码。常见做法是在站点根目录建一个独立目录比如language_en把翻译好的英文语言文件按原目录结构放进去然后通过配置或代码层面的路径映射让程序加载。但 Discuz! 3.2 默认不支持自定义语言包路径所以更务实的做法是备份原始文件后直接覆盖source/language下的文件内容同时保留一份原始中文备份在服务器上。我第一次做这个方案时吃的亏就是没做备份翻译了一半发现某个文件改坏了但原始中文文件已经被覆盖只能去官方源码包里翻。所以先把整个source/language目录打包存到站点目录外tar -czf discuz_language_backup_zh.tar.gz source/language tar -czf discuz_template_backup_zh.tar.gz template/default tar -czf discuz_js_backup_zh.tar.gz static/js这三个包分别对应三层需要动的地方语言文件、模板文件、JS 文件。后续所有修改都要在“改坏了还能恢复”的前提下进行。注意不要把备份包放在站点 Web 根目录里否则别人通过 URL 直接下载等于把源码送出去了。3.2 批量替换模板中的硬编码文字sed 脚本与边界模板文件里的中文分两类一类是纯展示文字直接换成对应的英文即可另一类是带有变量拼接的比如欢迎您回来{username}替换时要保留变量标签。对于批量替换我习惯先写一个待替换清单然后用 PHP 脚本而非 sed 处理——因为 sed 对中文编码和特殊符号的处理在 macOS 和 Linux 上表现不一致容易把文件搞出问题。下面是我常用的一个 PHP 替换脚本放在站点根目录的tools文件夹下用完即删?php // replace_cn_in_templates.php $baseDir dirname(__DIR__) . /template/default; $replaceMap array( 欢迎回来 Welcome back, 快捷导航 Quick Navigation, 发表回复 Reply, 发新主题 New Thread, ); $iterator new RecursiveIteratorIterator( new RecursiveDirectoryIterator($baseDir) ); foreach ($iterator as $file) { if ($file-getExtension() ! htm) continue; $path $file-getPathname(); $content file_get_contents($path); $original $content; foreach ($replaceMap as $zh $en) { $content str_replace($zh, $en, $content); } if ($content ! $original) { file_put_contents($path, $content); echo Updated: {$path}\n; } } echo Done.\n; ?这个脚本的逻辑很直接遍历template/default下所有.htm文件把$replaceMap里的中文字符串替换成英文只有内容实际变化时才写回文件。注意我用了数组映射而不是把中文直接写死在脚本里这样后续想调整某个词的翻译只需要改数组。有几个边界必须提醒你第一模板里有些中文是 JS 回调参数或者 CSS class 名的一部分不能盲目替换——替换前先搜索确认这个词有没有被 JS 引用第二{var}变量两边的中文可以替换但变量名本身不能动第三模板里包含lang变量时比如{lang login}这表示文字来自语言包而不是模板不需要在这里处理。3.3 翻译语言文件数组保持键名只改字符串值语言文件里的替换比模板更结构化和安全。每个lang_*.php文件都是一个 PHP 数组键名是程序识别的标识符值是页面显示的文字。翻译时只替换值保持键名完整。以下是source/language/forum/lang_template.php中一段实际的替换示例?php $lang array( login Login, // 原来是 登录 register Register, // 原来是 注册 newthread Post New Thread, // 原来是 发新主题 reply Reply, // 原来是 回复 view Views, // 原来是 查看 author Author, // 原来是 作者 lastpost Last Post, // 原来是 最后发表 ); ?换个说法这些键名是 Discuz! 程序的“接口”模板里用{lang view}调用PHP 代码里用$_G[lang][view]调用。改了键名整个页面该字段位置会输出空字符串而且不报错特别难排查。文件多了之后人工逐个翻译效率低可以写一个简单的词频统计脚本把中文值提出来汇总成翻译对照表集中翻译后再写回。这里给你一个直接用命令行就能跑的小脚本思路用grep提取所有数组里的中文字符串配合sort去重grep -h [^]* [^]*[\x{4e00}-\x{9fa5}][^]* source/language/forum/*.php | sort -u注意这个正则依赖终端支持 Unicode 匹配macOS 的 BSD grep 需要加-P参数Linux 的 GNU grep 直接支持。如果你在 Windows 上操作建议用 PHP 脚本遍历提取避免正则兼容性问题。3.4 处理 JS 文件和后台菜单最容易漏掉的两块JS 文件里的中文比模板和语言文件都隐蔽因为它们在运行时动态拼接到 DOM 里搜索源码时不会一眼看到。典型位置是static/js/forum.js里的删除确认提示、static/js/common.js里的加载失败提示、static/js/ajax.js里的请求异常文案。处理 JS 文件时要注意单引号转义。比如一段 JS 代码写的是alert(确定要删除吗);替换后变成alert(Are you sure to delete?);是安全的但如果原文里是alert(不能删除因为存在子版块);替换时保留转义序列\的原样即可。后台菜单是另一个容易漏掉的地方。Discuz! 3.2 后台的每个菜单项名称虽然存着英文键名但显示的文字是从source/language/admin/lang_menu.php里读的。站长如果希望后台也显示英文需要翻译这个文件。不过这里有分歧很多做英文站的站长反而希望后台保持中文——因为管理团队是中文用户前台英文只是给访客看的。我个人的建议是前台必须全英文后台看团队习惯但至少要把lang_menu.php和lang_admincp.php准备好到时候两个版本切换也方便。做完这三层替换后用 Git 或文件比对工具如 Beyond Compare检查改动重点看有没有误删换行符、有没有把数组的逗号去掉导致语法错误。运行php -l检查所有修改过的 PHP 文件的语法find source/language -name lang_*.php -exec php -l {} \;这条命令会把每个文件的语法检查结果打出来No syntax errors detected才是安全的。我见过太多人改了语言包后整站白屏最后定位就是一个lang_*.php文件多删了一个逗号。4. Discuz! 3.2 英文语言包避坑乱码、数据表中文和插件不兼容4.1 后台变成英文但帖子页还是半中半英模板缓存没清现象翻译完模板文件后刷新前台标题栏变了但帖子列表、版块名称、按钮文字还是中文。原因Discuz! 3.2 有模板缓存机制修改.htm文件后不会立即生效系统会继续读取data/template目录下的缓存文件。只有模版文件修改时间比缓存文件新时才会触发重新编译。解决修改完模板后去后台「工具」→「更新缓存」→勾选“模板缓存”并提交。或者直接用命令行删除data/template下的缓存文件rm -rf data/template/*.htm如果是前后台分离的服务器确认data/template目录有写权限。另外开启了云存储或 CDN 的站点还要刷新 CDN 缓存否则浏览器拿到的是边缘节点的旧页面。4.2 改了语言文件后整站乱码文件编码被改坏现象某个页面变成满屏或方块字符浏览器手动切换编码也没用。原因语言文件是 UTF-8 编码但 Windows 下的记事本或某些编辑器用 GBK 编码保存了文件或者保存时带上了 BOM。Discuz! 3.2 对带 BOM 的 PHP 文件会在输出时直接打印 BOM 字符导致 header 报错和乱码。解决强制所有被修改的文件统一为“UTF-8 无 BOM”。Linux 下用file命令检测编码用sed去掉开头的 BOMfile source/language/forum/lang_template.php sed -i 1s/^\xEF\xBB\xBF// source/language/forum/lang_template.phpWindows 环境下推荐用 Notepad 或 VS Code 把文件重新保存为“UTF-8 without BOM”。别相信记事本的“另存为 UTF-8”它带 BOM。4.3 用户发帖和版块名称仍是中文语言包管不到的数据现象语言包和模板全部改完但版块列表里“技术交流”“灌水乐园”还是中文用户发帖时间格式下面的“发表于”变成英文了但帖子内容里的中文不受影响——这其实是正常的但版块名没变就不正常。原因版块名称存在pre_forum_forum数据表的name字段用户组名称存在pre_common_usergroup的grouptitle字段。这些是数据不是界面文字。语言包只能翻译程序内置的字符串翻译不了站长在后台输入的数据。解决没有一劳永逸的办法。要么在后台逐个把版块名称改成英文要么写 SQL 批量更新注意先备份-- 备份原版块名称 CREATE TABLE pre_forum_forum_bak AS SELECT fid, name FROM pre_forum_forum; -- 按照 fid 逐个更新为英文名称 UPDATE pre_forum_forum SET name Technology WHERE fid 2; UPDATE pre_forum_forum SET name Off-topic WHERE fid 3;需要特别留意如果站点开启了多语言需求将来还要切回中文版块名这个方案就不够了——更合理的方式是使用 Discuz! 的第三方多语言插件来做数据翻译映射或者在模板层根据当前语言动态显示不同的版块名。但这是额外开发量不在语言包本身范围内。4.4 插件自带语言包覆盖了系统语言包优先级反直觉现象装了一个第三方插件插件页面显示英文但系统自带页面上原本已经翻译好的文字又被中文覆盖了。原因很多插件在自己的目录下带有language子目录插件在运行时会加载自己的语言文件。如果插件没有提供英文文件程序会 fallback 到默认语言而默认语言此时是中文——不是英文。解决逐个检查插件目录看看是否有独立的语言目录find source/plugin -maxdepth 3 -name lang_*.php -path *language*找到之后把插件语言文件复制一份键名不动值改成英文放到插件对应目录。但这里有个常见矛盾插件升级会覆盖这些文件所以每次升级插件后都要重新检查。我对关键插件的做法是写一个 shell 脚本一键把系统英文语言包和插件英文语言包重新部署一遍升级完插件就跑一次。4.5 数据库备份文件里的中文不能动语言包不是翻译数据现象有人试图把数据库备份 SQL 文件里的中文全部替换成英文想着“这样导出就是英文站了”。原因这是最危险的误操作。数据库里除了版块名称还有帖子标题、帖子内容、用户签名、短消息、日志记录。替换掉这些内容等于直接销毁用户数据——帖子里的中文是用户产生的内容不是系统界面文字翻译它们绝不是语言包的职责。解决语言包只处理以下三层source/language目录下的 PHP 数组、template/default目录下的模板.htm文件、static/js目录下的浏览器端文字。任何在数据库里的内容都不要碰。如果确实需要把帖子内容翻译成英文那是机器翻译或人工翻译的事需要一套内容翻译流程而不是语言包能实现的。5. 验证语言包完整性的方法与三个提升交付质量的技巧5.1 用“最小英文环境”跑一遍完整用户路径验证语言包是否完整不是打开首页看一眼就完事。我习惯用一个无痕窗口把浏览器语言设置为英文然后从访客视角走完用户的关键路径访问首页 → 打开一个帖子 → 登录 → 发帖 → 回复 → 编辑个人资料 → 搜索 → 退出登录。每一步截图标出还是中文的界面元素。这一步可以配合抓取工具做一次全站扫描。用wget镜像站点后在本地 grep HTML 里的中文字符wget --mirror --convert-links --adjust-extension --no-parent -l 3 http://your-domain.com grep -r --include*.html -P [\x{4e00}-\x{9fa5}] your-domain.com | awk -F: {print $1} | sort -u输出的是所有还包含中文的页面文件清单逐个打开看是硬编码漏改、语言包键值没翻译还是数据库数据正常显示为中文。自动化扫描不能替代人工确认因为有些中文是 AJAX 异步加载的wget 抓不到。但作为第一轮筛选它能帮你把工作量从“检查全站”降到“只检查几十个文件”。5.2 维护一张差异化覆盖表而不是翻译整个文件Discuz! 3.2 的语言文件多而杂全部翻译一遍大约要处理几千条字符串。很多文件里只有一小部分是前台真实会显示的文字其余是面向程序内部的日志、调试或保留字段。全量翻译投入产出比低。我的做法是先跑一轮站点把页面上实际出现的中文收集起来形成一个“前台可见中文清单”然后只翻译这些词对应的语言文件条目。后续发现漏翻译的词再增量补充。用浏览器控制台执行一段 JS 可以快速收集可见文字const walker document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT); let zhText []; while (walker.nextNode()) { const t walker.currentNode.textContent.trim(); if (/[\u4e00-\u9fa5]/.test(t)) zhText.push(t); } console.log([...new Set(zhText)].join(\n));把输出的词表和语言文件数组做比对缺席的词就是需要补翻译的。这个“以实际页面为准”而不是“以文件为准”的思路可以省下至少一半的翻译量。5.3 把语言包打包成独立目录配合后台关闭缓存交付英文语言包时把它做成一个可随时启停的增量覆盖包更有价值。我自己的做法是在站点根目录创建language_en_pack目录里面按source/language、template/default、static/js三个子目录放修改后的文件同时放一个install.sh脚本执行后自动备份当前中文文件并覆盖到对应路径再写一个rollback.sh脚本一键恢复备份的中文版。#!/bin/bash # install.sh TIMESTAMP$(date %Y%m%d%H%M%S) cp -r source/language source/language.bak.$TIMESTAMP cp -r language_en_pack/source/language/* source/language/ cp -r template/default template/default.bak.$TIMESTAMP cp -r language_en_pack/template/default/* template/default/ cp -r static/js static/js.bak.$TIMESTAMP cp -r language_en_pack/static/js/* static/js/ rm -rf data/template/*.htm php -f admin.php?actionupdatecache echo English language pack installed. Backup timestamp: $TIMESTAMP这个脚本每次执行都生成带时间戳的备份目录不会覆盖上一次的备份出问题可以随时回滚到任意版本。后台缓存建议在站点正式切换前手动更新一次避免脚本执行时 PHP CLI 环境缺少某些函数导致缓存清理不完整。最后给你留个建议如果站点以后还要做多语言切换别只停留在“替换文件”这个层面去了解 Discuz! 的语言包检测接口把config_global.php里的allow数组加上en再用插件机制做前台语言切换器。这样才是真正可持续的方案而不是每次换语言都靠备份恢复。我自己最开始就是图省事只替换不切换结果需求从“英文站”变成“中英双语站”时返工了一整天。希望帮到你。本文还有配套的精品资源点击获取
返回列表