我想使用 DeepL 来翻译我的 Laravel Post 模型。问题是,他们的 API 要求我们提交一个平面数组的翻译。例如。我们的有效载荷是 -
{
"target_lang": "ES",
"text": [
"The post title",
"A quote goes here (translatable)",
"<p>A content block goes here (translatable)</p>",
"A quote goes here",
"<p>A content block goes here (translatable)<\/p>"
]
}
但是,我的实际帖子使用“内容”数组来定义内容块,如下所示:
[
{
"type": "quote",
"data": {
"name": "A quote name",
"quote": "A quote goes here (translatable)"
}
},
{
"type": "content",
"data": {
"content": "<p>A content block goes here (translatable)<\/p>"
}
},
{
"type": "quote",
"data": {
"name": "A quote name (not translatable)",
"quote": "A quote goes here"
}
},
{
"type": "content",
"data": {
"content": "<p>A content block goes here (translatable)<\/p>"
}
}
]
上面的数据非常灵活多变,但始终取决于块类型。我可以使用如下所示轻松地将数据扁平化:
public function translatableAttributes(): array
{
return [
$this->title,
...collect($this->content)
->mapWithKeys(fn (array &$content) => match ($content['type']) {
'quote' => $content['data']['quote'],
'content' => $content['data']['content'],
})->flatten()->toArray(),
];
}
但我遇到的大问题是将其推回到数组中。我只是想不出一种方法可以在保持灵活性的同时做到这一点。
我想过也许实现承诺,然后为每个键解决它们,但再次无法思考如何实现这一点。
我可以进行单独的 API 调用,但当我可以在一次 API 调用中一次翻译 50 个字符串时,这又是非常低效的。
我建议使用简单的 array_map()
public function translatableAttributes(): array
{
return [
$this->title,
...array_map(
fn($content) => $content['data'][$content['type']],
$this->content,
),
];
}
public function applyTranslations(array $translations): void
{
$this->title = $translations[0];
$this->content = array_map(
static function ($content, $translation) {
$content['data'][$content['type']] = $translation;
return $content;
},
$this->content,
array_slice($translations, 1),
);
}
更复杂,但更灵活(例如,如果一个内容中有多个翻译字段;那么我们需要在 getTranslatableKeys() 中使用
foreach
)
public function translatableAttributes(): array
{
return [
$this->title,
...array_map(
fn($key) => Arr::get($this->content, $key),
$this->getTranslatableKeys(),
),
];
}
private function getTranslatableKeys(): array
{
return array_map(
fn($content, $index) => $index.'.data.'.$content['type'],
$this->content,
array_keys($this->content),
);
}
public function applyTranslations(array $translations): void
{
$this->title = $translations[0];
foreach ($this->getTranslatableKeys() as $index => $key) {
Arr::set($this->content, $key, $translations[$index + 1]);
}
}
具有数组解构语法的无体 foreach 循环可以通过动态键路径将所需值推送到结果数组中。
$payload = [
'target_lang' => 'ES',
'text' => ['The post title']
];
foreach ($array as ['type' => $t, 'data' => [$t => $payload['text'][]]]);
var_export($payload);
输出:
array (
0 => 'The post title',
1 => 'A quote goes here (translatable)',
2 => '<p>A content block goes here (translatable)</p>',
3 => 'A quote goes here',
4 => '<p>A content block goes here (translatable)</p>',
)