Files
Jacek Pyziak cd264483f8 Add PSR HTTP Message Interfaces and Dependencies
- Implemented StreamInterface, UploadedFileInterface, and UriInterface as per PSR standards.
- Added getallheaders function to retrieve HTTP headers in a compatible manner.
- Included LICENSE files for ralouphie/getallheaders and symfony/deprecation-contracts.
- Introduced function for triggering deprecation notices in Symfony.
2025-12-28 12:44:00 +01:00

247 lines
8.0 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* @package AutoPoly - AI Translation For Polylang (Pro)
*/
/**
* Handles cloning and translation of taxonomy terms for AI Translation For Polylang.
*
* Provides methods to translate taxonomy terms (categories, tags, custom taxonomies)
* using translation entries, and to assign parent relationships for translated terms.
*
* @since 1.0.0
*/
class ATFP_Term_Clone {
/**
* Main model for managing languages and translations.
*
* @var ATFP_Model
*/
private $model;
/**
* Constructor for ATFP_Term_Clone.
*
* @since 1.0.0
*
* @param ATFP_Settings|ATFP_Admin $polylang Main plugin object containing model and sync references.
*/
public function __construct( &$polylang ) {
$this->model = &$polylang->model;
}
/**
* Translates a taxonomy term using translation entries.
*
* @since 1.0.0
*
* @param array $entry Array containing term properties and translation data.
* @param PLL_Language $target_language Target language object.
* @return int|WP_Error The translated term ID, or WP_Error on failure.
*/
public function translate( array $entry, PLL_Language $target_language ) {
if ( ! $entry['data'] instanceof Translations ) {
/* translators: %d is a term ID. */
return new WP_Error( 'atfp_translate_term_no_translations', sprintf( __( 'The term with ID %d could not be translated.', 'auto-translate-for-polylang' ), (int) $entry['id'] ) );
}
$source_term = get_term( $entry['id'] );
if ( ! $source_term instanceof WP_Term ) {
/* translators: %d is a term ID. */
return new WP_Error( 'atfp_translate_term_no_source_term', sprintf( __( 'The term with ID %d could not be translated as it doesn\'t exist.', 'auto-translate-for-polylang' ), (int) $entry['id'] ) );
}
$tr_term_name = $this->get_translated_term_name( $source_term, $entry['data'] );
$tr_term_description = $this->get_translated_term_description( $source_term, $entry['data'] );
$tr_term_id = $this->model->term->get( $entry['id'], $target_language );
$tr_term_slug = $this->get_translated_term_slug( $source_term, $entry['data'] );
if ( $tr_term_id ) {
// The translation already exists.
$args = array();
// Only update name or description if provided in translations.
if ( $source_term->name !== $tr_term_name ) {
$args['name'] = $tr_term_name;
}
if ( !empty($source_term->description) && $source_term->description !== $tr_term_description ) {
$args['description'] = $tr_term_description;
}
$tr_term = $this->model->term->update( $tr_term_id, $args );
if ( is_wp_error( $tr_term ) ) {
/* translators: %d is a term ID. */
return new WP_Error( 'atfp_translate_update_term_failed', sprintf( __( 'The term with ID %d could not be updated.', 'auto-translate-for-polylang' ), (int) $tr_term_id ) );
}
} else {
$args = array(
'translations' => $this->model->term->get_translations( $source_term->term_id ),
);
if ( !empty( $source_term->description ) ) {
$args['description'] = $tr_term_description;
}
if ( $tr_term_slug && ! empty( $tr_term_slug ) ) {
$args['slug'] = $tr_term_slug;
}
$tr_term = $this->model->term->insert( $tr_term_name, $source_term->taxonomy, $target_language, $args );
if ( is_wp_error( $tr_term ) ) {
/* translators: %d is a term ID. */
return new WP_Error( 'atfp_translate_term_failed', sprintf( __( 'The term with ID %d could not be translated.', 'auto-translate-for-polylang' ), (int) $entry['id'] ) );
}
$tr_term_id = (int) $tr_term['term_id'];
}
/** @var WP_Term $tr_term */
$tr_term = get_term( $tr_term_id );
/**
* Fires after a term is saved and its translations are updated.
*
* @since 1.0.0
*
* @param int $tr_term_id The translated term ID.
* @param string $taxonomy The taxonomy slug.
* @param array $translations Array of term translations.
*/
do_action( 'atfp_save_term', $tr_term_id, $source_term->taxonomy, $this->model->term->get_translations( $tr_term_id ) );
$this->assign_parents( [ $entry['id'] ], $target_language );
return $tr_term_id;
}
/**
* Gets the translated term name, or falls back to the source name.
*
* @since 1.0.0
*
* @param WP_Term $source_term The source term object.
* @param Translations $translations Translation data object.
* @return string The translated name.
*/
private function get_translated_term_name( WP_Term $source_term, Translations $translations ) {
$entry = new Translation_Entry( array( 'singular' => $source_term->name, 'context' => 'name' ) );
$translated_entry = $translations->translate_entry( $entry );
$translated_text = isset( $translated_entry->translation[0] ) && ! empty( $translated_entry->translation[0] ) ? $translated_entry->translation[0] : $source_term->name;
return $translated_text;
}
/**
* Gets the translated term description, or falls back to the source description.
*
* @since 1.0.0
*
* @param WP_Term $source_term The source term object.
* @param Translations $translations Translation data object.
* @return string The translated description.
*/
private function get_translated_term_description( WP_Term $source_term, Translations $translations ) {
$entry = new Translation_Entry( array( 'singular' => $source_term->description, 'context' => 'description' ) );
$translated_entry = $translations->translate_entry( $entry );
$translated_text = isset( $translated_entry->translation[0] ) && ! empty( $translated_entry->translation[0] ) ? $translated_entry->translation[0] : '';
return $translated_text;
}
/**
* Gets the translated term slug, or returns an empty string if not available.
*
* @since 1.0.0
*
* @param WP_Term $source_term The source term object.
* @param Translations $translations Translation data object.
* @return string The translated slug.
*/
private function get_translated_term_slug( WP_Term $source_term, Translations $translations ) {
$entry = new Translation_Entry( array( 'singular' => $source_term->slug, 'context' => 'slug' ) );
$translated_entry = $translations->translate_entry( $entry );
$translated_text = isset( $translated_entry->translation[0] ) && ! empty( $translated_entry->translation[0] ) ? $translated_entry->translation[0] : '';
return $translated_text;
}
/**
* Assigns parent terms to translated terms after import.
*
* @since 1.0.0
*
* @param int[] $ids Array of source term IDs.
* @param PLL_Language $target_language Target language object.
* @return void
*/
public function assign_parents( array $ids, PLL_Language $target_language ) {
// Get the terms with their parents (or 0).
$terms = get_terms(
array(
'include' => $ids,
'hide_empty' => false,
'fields' => 'id=>parent',
)
);
if ( ! is_array( $terms ) ) {
// No terms with parents.
return;
}
// id=>parent returns an array of numeric strings, so let's cast it into int.
$terms = array_map( 'intval', array_filter( $terms, 'is_numeric' ) );
// Keep only the terms that have a parent.
$terms = array_filter( $terms );
if ( empty( $terms ) ) {
// No terms with parents.
return;
}
$tr_ids = array();
foreach ( $terms as $child => $term_id ) {
$tr_ids[ $child ] = $this->model->term->get( $child, $target_language->slug );
}
$tr_ids = array_filter( $tr_ids );
if ( empty( $tr_ids ) ) {
// No translations.
return;
}
foreach ( $terms as $child => $term_id ) {
if ( empty( $tr_ids[ $child ] ) ) {
// Not translated.
continue;
}
$tr_parent_term = $this->model->term->get( $term_id, $target_language->slug );
if ( empty( $tr_parent_term ) ) {
// The parent term is not translated.
continue;
}
$tr_term_id = $this->model->term->get( $tr_ids[ $child ], $target_language->slug );
if ( empty( $tr_term_id ) ) {
continue;
}
$tr_term = get_term( $tr_term_id );
if ( ! $tr_term instanceof WP_Term ) {
continue;
}
// Set term parent for shared slugs.
$this->model->term->update( $tr_term->term_id, array( 'parent' => $tr_parent_term ) );
}
}
}