Laravel Post模型嵌套数组转扁平数组用于DeepL翻译及回写问题
解决方案:通过路径映射实现嵌套数组的翻译来回
核心思路是在扁平化嵌套数组时,为每个待翻译文本保留其在原数组中的路径标识,翻译完成后再根据路径将结果回填到原数组对应位置,全程只需调用一次DeepL API。
步骤1:实现嵌套数组的扁平化(带路径映射)
在Post模型中添加递归遍历方法,提取所有需要翻译的文本,并以路径字符串作为键(比如blocks.0.text)生成扁平数组:
class Post extends Model { // 假设content是JSON字段,已转为数组 protected $casts = [ 'content' => 'array', ]; /** * 将嵌套的content转为带路径标识的扁平翻译数组 */ public function flattenContentForTranslation(): array { $flatTranslations = []; $this->traverseContentNodes($this->content, '', $flatTranslations); return $flatTranslations; } /** * 递归遍历content节点,提取待翻译文本 */ private function traverseContentNodes(array $nodes, string $parentPath, array &$flat): void { // 可自定义需要翻译的字段名,灵活调整范围 $translatableFields = ['text', 'caption', 'description']; foreach ($nodes as $key => $value) { $currentPath = $parentPath ? "{$parentPath}.{$key}" : (string)$key; if (is_array($value)) { $this->traverseContentNodes($value, $currentPath, $flat); } elseif (is_string($value) && trim($value) !== '' && in_array($key, $translatableFields)) { $flat[$currentPath] = $value; } } } }
步骤2:调用DeepL API翻译扁平数组
使用DeepL SDK(或API请求)一次性翻译整个扁平数组:
// 取出待翻译的Post实例 $post = Post::find($postId); // 生成带路径的扁平翻译数组 $toTranslate = $post->flattenContentForTranslation(); // 调用DeepL API翻译(示例用官方SDK写法,实际根据你的集成调整) $translatedResult = \DeepL\Translator::translateText( $toTranslate, null, // 自动检测源语言 'zh', // 目标语言 ['tag_handling' => 'html'] // 若文本含HTML可开启,按需调整 ); // 整理翻译后的结果为「路径=>翻译文本」的数组 $translatedFlat = []; foreach ($translatedResult as $item) { $translatedFlat[array_keys($toTranslate)[$item->index]] = $item->text; }
步骤3:将翻译结果回填到原嵌套数组
在Post模型中添加回填方法,根据路径字符串定位原数组位置并替换值:
class Post extends Model { // ... 其他代码 ... /** * 将翻译后的扁平数组回填到原content嵌套结构 */ public function fillTranslatedContent(array $translatedFlat): void { $content = $this->content; foreach ($translatedFlat as $path => $translatedText) { $keys = explode('.', $path); $currentNode = &$content; foreach ($keys as $index => $key) { // 跳过不存在的路径,避免数组报错 if (!isset($currentNode[$key])) { break; } // 到达路径最后一个节点,赋值翻译文本 if ($index === count($keys) - 1) { $currentNode[$key] = $translatedText; } else { $currentNode = &$currentNode[$key]; } } } $this->content = $content; } }
完整使用流程
// 1. 获取Post $post = Post::find(1); // 2. 生成扁平翻译数组 $toTranslate = $post->flattenContentForTranslation(); // 3. 调用DeepL翻译(这里需根据你的实际API集成调整) $translatedFlat = $this->callDeepLAPI($toTranslate); // 4. 回填翻译结果 $post->fillTranslatedContent($translatedFlat); // 5. 保存到数据库 $post->save();
灵活性调整
- 可修改
$translatableFields数组来增减需要翻译的字段类型; - 若content结构有特殊节点(比如嵌套深度变化、动态字段),只需调整
traverseContentNodes中的遍历逻辑即可适配; - 若需要处理多语言版本,可将翻译后的content存储为新字段(比如
content_zh),而非覆盖原字段。
内容的提问来源于stack exchange,提问作者Chris
相关产品推荐
相关产品推荐

