feat(site): integrate multilingual content management / 集成多语言内容管理

完善官网、管理后台与后端的多语言内容编辑和发布流程,调整站点页面及相关接口,并同步数据库脚本。

新增容器部署配置,改用环境变量注入数据库凭据;补充仓库忽略规则,并停止跟踪本地环境文件和 Maven 构建产物。
This commit is contained in:
liuwenxin committed 2026-09-10 14:46:06 +08:00
1 parent 4ee6e9ae83
commit 85083ab962
1056 files changed
+15449 -132933

No files matched your search

+1 -3
View File
@@ -37,8 +37,6 @@ export const templateModules = [
name: '客户服务与互动模块',
items: [
{ reqCode: 'REQ-016', title: '在线留言表单', desc: '提供姓名、电话、邮箱、留言内容等字段的表单', type: 'form' },
{ reqCode: 'REQ-017', title: '招商加盟介绍', desc: '展示企业代理合作政策、加盟支持政策等内容', type: 'richtext' },
{ reqCode: 'REQ-018', title: '招商表单提交', desc: '提供加盟意向表单,收集潜在合作伙伴的基本信息和合作需求', type: 'form' },
{ reqCode: 'REQ-019', title: '服务热线展示', desc: '在页面显著位置展示服务热线,支持一键拨打', type: 'text' },
{ reqCode: 'REQ-020', title: '电子邮箱展示', desc: '展示企业官方邮箱地址,提供邮件沟通渠道', type: 'text' },
{ reqCode: 'REQ-021', title: '公司地址展示', desc: '展示企业详细地址', type: 'text' }
@@ -48,7 +46,7 @@ export const templateModules = [
code: 'M04-RES',
name: '资源管理模块',
items: [
{ reqCode: 'REQ-022', title: '保存提交的信息', desc: '对用户、招商提交的表单信息、留言内容等进行存储和归档管理', type: 'storage' },
{ reqCode: 'REQ-022', title: '保存提交的信息', desc: '对用户提交的表单信息、留言内容等进行存储和归档管理', type: 'storage' },
{ reqCode: 'REQ-023', title: '对多媒体资源进行管理', desc: '对网站使用的产品图片、字段媒体资源进行上传、分类、检索与统一管理', type: 'media' }
]
},
@@ -0,0 +1,44 @@
/**
* 翻译占位 / 测试文案判定(与后端 SiteCompanyController 占位逻辑保持一致)。
* 需要调整规则时:改下方常量或 comma 分隔串,勿依赖外部配置文件。
*/
const DEFAULT_EXACT_CSV = 'qq,qw,qwe,qwer,qweqwe,qweqeqe,qweqweqweqwe,qqq,qqqq,ww,www,wwww,vv,vvv,vvvv,test,xxx,asd,asdf'
const DEFAULT_PLAIN_MAX_LEN = 200
const DEFAULT_REPEAT_MAX_LEN = 16
const PLACEHOLDER_EXACT_SET = new Set(
DEFAULT_EXACT_CSV.split(',').map((s) => s.trim().toLowerCase()).filter(Boolean)
)
function stripHtmlToPlain(s) {
return String(s || '')
.replace(/<[^>]+>/g, ' ')
.replace(/&nbsp;/gi, ' ')
.replace(/\s+/g, ' ')
.trim()
}
/**
* 是否为占位测试串(不应覆盖真实中文译文)。
*/
export function translationLooksLikePlaceholder(raw) {
if (raw == null) return true
const trimmed = String(raw).trim()
if (!trimmed) return true
const plain = stripHtmlToPlain(trimmed)
if (!plain) return true
if (plain.length > DEFAULT_PLAIN_MAX_LEN) return false
const lower = plain.toLowerCase()
if (PLACEHOLDER_EXACT_SET.has(lower)) return true
if (/^(qwe|wer|asd|zxc|www|vvv|xxx)+$/i.test(lower)) return true
const chars = [...plain]
if (
chars.length <= DEFAULT_REPEAT_MAX_LEN &&
chars.length > 0 &&
chars.every((c) => c === chars[0])
) {
return true
}
return false
}