fix: link and img translate error
This commit is contained in:
@@ -153,36 +153,27 @@ class WPT_Content_Controller {
|
|||||||
|
|
||||||
public function translate_content( $content ) {
|
public function translate_content( $content ) {
|
||||||
$post_id = get_the_ID();
|
$post_id = get_the_ID();
|
||||||
if ( ! $post_id || false === stripos( $content, '<a' ) ) {
|
if ( ! $post_id || false === strpos( $content, '<' ) ) {
|
||||||
return $this->translated_value( $content, 'post:' . $post_id . ':post_content' );
|
return $this->translated_value( $content, 'post:' . $post_id . ':post_content' );
|
||||||
}
|
}
|
||||||
|
|
||||||
$links = array();
|
$protected = WPT_Content_Translator::protect( $content );
|
||||||
$template = preg_replace_callback(
|
if ( false === $protected ) {
|
||||||
'#<a\b([^>]*)>(.*?)</a>#is',
|
|
||||||
function ( $matches ) use ( &$links ) {
|
|
||||||
$index = count( $links );
|
|
||||||
$links[] = $matches;
|
|
||||||
|
|
||||||
return '[[WPT_LINK_' . $index . ']]';
|
|
||||||
},
|
|
||||||
$content
|
|
||||||
);
|
|
||||||
if ( null === $template ) {
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
$translated_template = $this->translated_value( $template, 'post:' . $post_id . ':post_content:template' );
|
$translated_template = $this->translated_value( $protected['template'], 'post:' . $post_id . ':post_content:template' );
|
||||||
if ( $translated_template === $template ) {
|
if ( $translated_template === $protected['template'] ) {
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( $links as $index => $link ) {
|
$anchors = array();
|
||||||
$translated_text = $this->translated_value( $link[2], 'post:' . $post_id . ':post_content:link:' . $index );
|
foreach ( $protected['anchors'] as $index => $anchor ) {
|
||||||
$translated_template = str_replace( '[[WPT_LINK_' . $index . ']]', '<a' . $link[1] . '>' . $translated_text . '</a>', $translated_template );
|
$translated_text = $this->translated_value( $anchor['text'], 'post:' . $post_id . ':post_content:anchor:' . $index );
|
||||||
|
$anchors[ $index ] = '<a' . $anchor['attributes'] . '>' . $translated_text . '</a>';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $translated_template;
|
return WPT_Content_Translator::restore( $translated_template, $anchors, $protected['tags'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
public function translate_excerpt( $excerpt, $post ) {
|
public function translate_excerpt( $excerpt, $post ) {
|
||||||
|
|||||||
@@ -10,40 +10,25 @@ class WPT_Content_Translator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function translate( $content, $source_language, $target_language, $context, $force_refresh = false ) {
|
public function translate( $content, $source_language, $target_language, $context, $force_refresh = false ) {
|
||||||
$links = array();
|
$protected = self::protect( $content );
|
||||||
$template = preg_replace_callback(
|
if ( false === $protected ) {
|
||||||
'#<a\b([^>]*)>(.*?)</a>#is',
|
|
||||||
function ( $matches ) use ( &$links ) {
|
|
||||||
$index = count( $links );
|
|
||||||
$links[ $index ] = array(
|
|
||||||
'attributes' => $matches[1],
|
|
||||||
'text' => $matches[2],
|
|
||||||
);
|
|
||||||
|
|
||||||
return '[[WPT_LINK_' . $index . ']]';
|
|
||||||
},
|
|
||||||
$content
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( null === $template ) {
|
|
||||||
return WPT_Translation_Result::failure( 'content_parse_failed', 'Unable to protect links before translation.' );
|
return WPT_Translation_Result::failure( 'content_parse_failed', 'Unable to protect links before translation.' );
|
||||||
}
|
}
|
||||||
|
|
||||||
$template_context = empty( $links ) ? $context : $context . ':template';
|
$template_result = $this->service->get_or_translate( $protected['template'], $source_language, $target_language, $context . ':template', $force_refresh );
|
||||||
$template_result = $this->service->get_or_translate( $template, $source_language, $target_language, $template_context, $force_refresh );
|
|
||||||
|
|
||||||
if ( ! $template_result->success || empty( $links ) ) {
|
if ( ! $template_result->success ) {
|
||||||
return $template_result;
|
return $template_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
$translated_content = $template_result->value;
|
$anchors = array();
|
||||||
|
|
||||||
foreach ( $links as $index => $link ) {
|
foreach ( $protected['anchors'] as $index => $anchor ) {
|
||||||
$link_result = $this->service->get_or_translate(
|
$link_result = $this->service->get_or_translate(
|
||||||
$link['text'],
|
$anchor['text'],
|
||||||
$source_language,
|
$source_language,
|
||||||
$target_language,
|
$target_language,
|
||||||
$context . ':link:' . $index,
|
$context . ':anchor:' . $index,
|
||||||
$force_refresh
|
$force_refresh
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -51,10 +36,71 @@ class WPT_Content_Translator {
|
|||||||
return $link_result;
|
return $link_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
$anchor = '<a' . $link['attributes'] . '>' . $link_result->value . '</a>';
|
$anchors[ $index ] = '<a' . $anchor['attributes'] . '>' . $link_result->value . '</a>';
|
||||||
$translated_content = str_replace( '[[WPT_LINK_' . $index . ']]', $anchor, $translated_content );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return WPT_Translation_Result::success( $translated_content );
|
return WPT_Translation_Result::success( self::restore( $template_result->value, $anchors, $protected['tags'] ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function protect( $content ) {
|
||||||
|
$anchors = array();
|
||||||
|
$template = preg_replace_callback(
|
||||||
|
'#<a\b([^>]*)>(.*?)</a>#is',
|
||||||
|
function ( $matches ) use ( &$anchors ) {
|
||||||
|
$index = count( $anchors );
|
||||||
|
$anchors[ $index ] = array(
|
||||||
|
'attributes' => $matches[1],
|
||||||
|
'text' => $matches[2],
|
||||||
|
);
|
||||||
|
|
||||||
|
return self::token( 'ANCHOR', $index );
|
||||||
|
},
|
||||||
|
$content
|
||||||
|
);
|
||||||
|
if ( null === $template ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$tags = array();
|
||||||
|
$template = preg_replace_callback(
|
||||||
|
'#<[^>]+>#s',
|
||||||
|
function ( $matches ) use ( &$tags ) {
|
||||||
|
$index = count( $tags );
|
||||||
|
$tags[ $index ] = $matches[0];
|
||||||
|
|
||||||
|
return self::token( 'TAG', $index );
|
||||||
|
},
|
||||||
|
$template
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( null === $template ) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'template' => $template,
|
||||||
|
'anchors' => $anchors,
|
||||||
|
'tags' => $tags,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function restore( $content, $anchors, $tags ) {
|
||||||
|
foreach ( $anchors as $index => $anchor ) {
|
||||||
|
$content = preg_replace( self::token_pattern( 'ANCHOR', $index ), $anchor, $content );
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ( $tags as $index => $tag ) {
|
||||||
|
$content = preg_replace( self::token_pattern( 'TAG', $index ), $tag, $content );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function token( $type, $index ) {
|
||||||
|
return 'WPTTOKEN' . $type . $index . 'END';
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function token_pattern( $type, $index ) {
|
||||||
|
return '#(?:\[\s*)?WPT\s*TOKEN\s*' . $type . '\s*' . $index . '\s*END(?:\s*\]|)#i';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,27 @@ class ContentTranslatorTest extends TestCase {
|
|||||||
$this->assertSame( '[zh] Read <a href="https://example.com/docs" target="_blank">[zh] our guide</a>.', $result->value );
|
$this->assertSame( '[zh] Read <a href="https://example.com/docs" target="_blank">[zh] our guide</a>.', $result->value );
|
||||||
$this->assertSame( 2, $provider->calls );
|
$this->assertSame( 2, $provider->calls );
|
||||||
$this->assertSame( 'post:1:post_content:template', $store->save_calls[0]['field_context'] );
|
$this->assertSame( 'post:1:post_content:template', $store->save_calls[0]['field_context'] );
|
||||||
$this->assertSame( 'post:1:post_content:link:0', $store->save_calls[1]['field_context'] );
|
$this->assertSame( 'post:1:post_content:anchor:0', $store->save_calls[1]['field_context'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_restores_tokens_when_the_provider_wraps_them_in_brackets() {
|
||||||
|
$store = new WPT_Test_Translation_Store();
|
||||||
|
$provider = new class implements WPT_Translation_Provider {
|
||||||
|
public function get_version() {
|
||||||
|
return 'test-provider-v1';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function translate( $source_value, $source_language, $target_language, $context ) {
|
||||||
|
$value = preg_replace( '/(WPTTOKEN[A-Z]+\d+END)/', '[$1]', $source_value );
|
||||||
|
|
||||||
|
return WPT_Translation_Result::success( $value );
|
||||||
|
}
|
||||||
|
};
|
||||||
|
$translator = new WPT_Content_Translator( new WPT_Translation_Service( $store, $provider ) );
|
||||||
|
|
||||||
|
$result = $translator->translate( 'See <a href="/docs">docs</a><img src="/hero.jpg" alt="Hero">.', 'en', 'zh', 'post:1:post_content' );
|
||||||
|
|
||||||
|
$this->assertTrue( $result->success );
|
||||||
|
$this->assertSame( 'See <a href="/docs">docs</a><img src="/hero.jpg" alt="Hero">.', $result->value );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user