## Esun MultiLocaleTranslation 这个模块是按你当前需求实现的“低复杂度维护”版: - 后台支持“按实体弹窗翻译” Product / Category / CMS Page / CMS Block / Mageplaza Blog Post / Wiki Category / Wiki Homepage - CMS Page / Block / Mageplaza Blog Post / Wiki 使用同一套实体 ID,不复制实体,使用额外翻译表进行同 ID 覆盖 - CMS Page / Block 编辑页提供 `Scope` 切换;切换 Store View 后原生表单直接显示并保存该语言内容 - 先保留现有 Magento 的多语言/多网站机制,只加一个轻量可控的翻译入口 - 支持 DeepL 和 Google Cloud Translation Advanced v3 自动翻译,弹窗可选择 Provider ### 已安装文件说明 - `Block/Adminhtml/*`:后台翻译弹窗和按钮入口 - `Controller/Adminhtml/Translation/*`:获取字段 / 保存字段 API - `Model/Entity/*`:不同实体的可翻译字段映射 - `Plugin/Cms/*`:前台渲染时把 CMS 翻译覆盖到同一 page/block id - `Plugin/Blog/*`:前台详情页和博客列表按 Store View 覆盖 Blog Post 译文 - `etc/db_schema.xml`:新增表 `esun_localetranslation_cms` ### 安装与生效(开发/测试环境) ```bash php bin/magento module:enable Esun_MultiLocaleTranslation php bin/magento setup:upgrade php bin/magento cache:flush ``` 清缓存后,检查后台: 1. 打开任意商品编辑页、分类编辑页、CMS 页面/区块、Mageplaza Blog Post 或 Wiki 编辑页 2. 页面右上角看到 `Translate` 按钮 3. 点击后在当前编辑页面打开弹窗,并自动加载除源语言外的全部 Store View 4. 也可以重新选择部分 Store View,再点 `Load Fields` 按需加载 5. 点 `Save All Translations`,一次保存当前显示的全部目标 Store View 自动翻译会按 Store View 逐个处理,并显示当前 Store、总进度、成功数和失败数。单个 Store 翻译失败不会中断其余 Store,结束后可根据提示检查失败项。 ### 跳过不需要翻译的字段 配置位置: `Stores > Configuration > Esun > Multi-Locale Translation > General > Skipped Fields` - 默认不选择任何字段,继续翻译程序当前支持的全部字段。 - 选择后的字段不会出现在翻译弹窗中,也不会进入批量翻译 API 请求、翻译日志或目标 Store View 保存流程。 - 支持分别配置 Category、Product、CMS Page 和 CMS Block 的现有可翻译字段。 - 保存配置并刷新已打开的编辑页面后生效;此设置不会删除以前已保存的译文。 ### 业务规则(和你需求一致) - `entity_type` - `product`:商品 - `category`:分类 - `cms_page`:CMS 页面(同 `page_id`) - `cms_block`:CMS 区块(同 `block_id`) - 源语言:`source_store_id` - 可能是 `0`(默认值) - 弹窗会显示 `Default Store View` 或具体 Store View 名称 - 目标语言:`target_store_id` - 不能与源语言相同 ### CMS Page / Block 原生 Scope - 默认 Scope 编辑原始 `cms_page` / `cms_block` 数据。 - 选择具体 Store View 后,原生表单显示该 Store View 的翻译内容。 - CMS Page 可翻译 `title`、`content_heading`、`content` 和 SEO 字段。 - CMS Block 可翻译 `title` 和 `content`;`identifier`、启用状态和 Store View 分配继续共用默认数据。 - Mageplaza Blog Post 可翻译 `name`、`short_description`、`post_content` 和 SEO 字段;`url_key`、图片、作者、日期、状态、Store View 和关联数据继续共用默认数据。 - Blog Post 的 `url_key` 永不进入人工翻译、自动翻译或队列保存,因此所有语言继续使用原始 URL。 - Wiki Category 可翻译 `title`、`summary`、`content` 和 SEO 字段;`slug`、`custom_url_path`、层级、状态和功能开关继续共用默认数据。 - Wiki Homepage 可翻译 `title`、`content` 和 SEO 字段;前台会按当前 Store View 读取对应译文。 - 勾选 `Use Default Value` 后保存,会删除该字段的 Store View 翻译并继承默认值。 - Store View Scope 下保存不会修改默认 Page / Block,也不会创建新的 Page / Block ID。 ### 数据库(CMS 同ID翻译) 表名:`esun_localetranslation_cms` 字段含义: - `entity_type`: `page|block|blog_post` - `entity_id`: CMS page_id、block_id 或 Mageplaza post_id(同站点复用同 ID) - `store_id`: 目标 Store View ID - `field_name`: title/content/... - `translated_value`: 翻译结果 ### Google V3 自动翻译 配置位置: `Stores > Configuration > Esun > Multi-Locale Translation > Google Cloud Translation` 1. 在 Google Cloud 项目启用 Cloud Translation API。 2. 创建有 Cloud Translation 权限的 Service Account,并下载 JSON Key。 3. 后台上传 Service Account JSON、选择 Location,然后启用 Google 翻译。 4. 翻译弹窗点击 `Google Auto Translate`,检查结果后再点击保存。 JSON Key 会被验证并保存在 Magento `var/esun/multilocale_translation/google/` 私有目录,不会放入 `pub/media` 或输出到浏览器。Google 的所有 HTML 字段都会先提取可见文字、分批翻译,再按原位置写回;Page Builder HTML、CSS、JavaScript 和标签结构不会发送给 Google。 Default Scope 使用后台配置的源语言(默认 `en`);从具体 Store View 翻译时使用该 Store View 的 Locale。 不使用术语表时 Location 选择 `global`。使用 Google Glossary 时填写 Glossary ID,并把 Location 改为 `us-central1`。 后续增加其他 Provider 时,只需实现 `TranslationProviderInterface` 并注入 `ProviderPool`,实体保存逻辑无需变更。人工填写流程继续保留。 ### DeepL 自动翻译 配置位置同样在: `Stores > Configuration > Esun > Multi-Locale Translation` 1. General 中把 Default Translation Provider 设置为 `DeepL`。 2. 在 DeepL Translation API 中启用 DeepL。 3. API Free 选择 `https://api-free.deepl.com/v2/translate`;API Pro 选择 `https://api.deepl.com/v2/translate`。 4. 填写 DeepL API Key。Key 使用 Magento 加密配置保存,不会输出到浏览器。 5. 翻译弹窗选择 DeepL 并点击 `Auto Translate`。 DeepL 的所有 HTML 字段都会先提取可见文字、分批翻译,再按原位置写回。HTML 标签、注释、CSS、JavaScript、Magento 指令和编码后的代码块不会发送给 DeepL;文字片段使用 `tag_handling=html` 和 v2 标签算法。 ### Translation API Log 后台菜单 `Esun > Translation API Log` 显示每个自动翻译字段的调用记录,包括: - Provider、成功/失败状态、实体类型、实体 ID 和字段名 - 源/目标 Store View 与语言 - 原文、译文、字符数和调用时间 - 失败请求的错误信息(在 Columns 中打开 `Error` 列) 日志支持筛选、分页、列显示控制和批量删除。日志仅记录点击 `Auto Translate` 产生的结果;人工编辑和最终保存不重复记录。 HTML 字段的日志只保存和显示实际送去翻译的可见文字,不记录 Page Builder HTML、CSS、JavaScript 等结构代码;历史日志在列表显示时也会自动提取可见文字。 `Clear All Logs` 可在二次确认后一次清空全部 Translation API Log,不会删除队列或已保存译文。 ### Batch Translation Queue - Product、CMS Page、CMS Block、Mageplaza Blog Post 列表的批量操作中选择 `Add to Translation Queue`。 - Category 可在原生分类树中勾选多个节点后点击 `Translate Selected`,也可以在后台 `Esun > Batch Translation` 输入多个 Category ID。 - Wiki Category 可在 Wiki 分类列表勾选多个节点后点击 `Add Selected to Translation Queue`,再选择目标 Store Views 和翻译服务加入队列。 - 在确认页面选择 Source Store View、一个或多个 Target Store View 和 Provider。 - 每个“实体 × Target Store View”生成一条数据库队列任务;重复的 Pending/Processing 任务会跳过。 - Magento Cron 默认每分钟最多处理 10 条任务,并在约 50 秒后停止领取新任务;当前任务会执行完成。可在 `Esun > Translation Management > Configuration > Translation Queue` 调整(数量 1–50,时间 10–300 秒)。 - `Esun > Translation Queue` 查看 Pending、Processing、Success、Failed、执行次数和错误信息。 - Failed 任务可批量 `Retry Failed`,非 Processing 任务可批量删除。 - `Clear All Queue` 可在二次确认后清空所有队列记录;已被 Cron 取走并正在执行的任务无法中断,仍可能完成翻译写入。 队列依赖 Magento Cron。服务器必须已经配置每分钟执行: ```bash * * * * * php /path/to/magento/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /path/to/magento/var/log/magento.cron.log ``` 开发环境可手动执行一次 `php bin/magento cron:run`;若服务器没有 Magento Cron,任务会保持 Pending,不会丢失。 ### 注意 - 插件不会改写现有 URL 或多站点主站映射逻辑 - 不建议与已有同名翻译覆盖逻辑并行写入 CMS 同字段,避免内容互相覆盖