first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
<?php
namespace WPML\ST\Main;
use WPML\Element\API\Languages;
use WPML\FP\Relation;
use WPML\ST\Main\Ajax\FetchCompletedStrings;
use WPML\ST\Main\Ajax\SaveTranslation;
use WPML\ST\WP\App\Resources;
use WPML\LIB\WP\Hooks as WPHooks;
class UI implements \IWPML_Backend_Action_Loader {
/**
* @return callable|null
*/
public function create() {
$isAdminTextsPage = isset( $_GET['trop'] );
if ( Relation::propEq( 'page', WPML_ST_FOLDER . '/menu/string-translation.php', $_GET ) && ! $isAdminTextsPage ) {
return function () {
WPHooks::onAction( 'admin_enqueue_scripts' )
->then( [ self::class, 'localize' ] )
->then( Resources::enqueueApp( 'main-ui' ) );
};
} else {
return null;
}
}
public static function localize() {
return [
'name' => 'wpml_st_main_ui',
'data' => [
'languageDetails' => Languages::withRtl( Languages::withFlags( Languages::getAll() ) ),
'endpoints' => [
'saveTranslation' => SaveTranslation::class,
'translationMemory' => apply_filters( 'wpml_st_translation_memory_endpoint', '' ),
'fetchStrings' => FetchCompletedStrings::class,
],
],
];
}
}

View File

@@ -0,0 +1,31 @@
<?php
namespace WPML\ST\Main\Ajax;
use WPML\Ajax\IHandler;
use WPML\Collect\Support\Collection;
use WPML\FP\Either;
class FetchCompletedStrings implements IHandler {
public function run( Collection $data ) {
global $wpdb;
$strings = $data->get( 'strings', [] );
if( count( $strings ) ) {
$strings_in = wpml_prepare_in( $strings, '%d' );
$result = $wpdb->get_results(
$wpdb->prepare(
"SELECT string_id, language AS lang, value AS translation FROM {$wpdb->prefix}icl_string_translations WHERE string_id IN({$strings_in}) AND status=%d",
ICL_TM_COMPLETE
)
);
return Either::of( $result );
} else {
return Either::of( [] );
}
}
}

View File

@@ -0,0 +1,25 @@
<?php
namespace WPML\ST\Main\Ajax;
use WPML\Ajax\IHandler;
use WPML\Collect\Support\Collection;
use WPML\FP\Either;
use WPML\FP\Obj;
use WPML\ST\API\Fns as STAPI;
class SaveTranslation implements IHandler {
public function run( Collection $data ) {
$id = Obj::prop( 'id', $data );
$translation = Obj::prop( 'translation', $data );
$lang = Obj::prop( 'lang', $data );
if ( $id && $translation && $lang ) {
return Either::of( STAPI::saveTranslation( $id, $lang, $translation, ICL_TM_COMPLETE ) );
} else {
return Either::left( 'invalid data' );
}
}
}

View File

@@ -0,0 +1,127 @@
<?php
class WPML_Change_String_Domain_Language_Dialog extends WPML_WPDB_And_SP_User {
/** @var WPML_Language_Of_Domain $language_of_domain */
private $language_of_domain;
/** @var WPML_ST_String_Factory $string_factory */
private $string_factory;
public function __construct( &$wpdb, &$sitepress, &$string_factory ) {
parent::__construct( $wpdb, $sitepress );
$this->string_factory = &$string_factory;
$this->language_of_domain = new WPML_Language_Of_Domain( $sitepress );
}
public function render( $domains ) {
$all_languages = $this->sitepress->get_languages( $this->sitepress->get_admin_language() );
?>
<div id="wpml-change-domain-language-dialog"
class="wpml-change-language-dialog"
title="<?php _e( 'Language of domains', 'wpml-string-translation' ); ?>"
style="display:none"
data-button-text="<?php _e( 'Apply', 'wpml-string-translation' ); ?>"
data-cancel-text="<?php _e( 'Cancel', 'wpml-string-translation' ); ?>" >
<label for="wpml-domain-select">
<?php _e( 'Select for which domain to set the language: ', 'wpml-string-translation' ); ?>
</label>
<select id="wpml-domain-select">
<option value="" selected="selected"><?php _e( '-- Please select --', 'wpml-string-translation' ); ?></option>
<?php
foreach ( $domains as $domain ) {
$results = $this->wpdb->get_results(
$this->wpdb->prepare(
"
SELECT language, COUNT(language) AS count
FROM {$this->wpdb->prefix}icl_strings s
WHERE context = %s
AND language IN (" . wpml_prepare_in( array_keys( $all_languages ) ) . ')
GROUP BY language
',
$domain->context
),
ARRAY_A
);
foreach ( $results as &$result ) {
$result['display_name'] = $all_languages[ $result['language'] ]['display_name'];
}
$domain_lang = $this->language_of_domain->get_language( $domain->context );
if ( $domain_lang ) {
$domain_data = 'data-domain_lang="' . $domain_lang . '" ';
} else {
$domain_data = 'data-domain_lang="" ';
}
echo '<option value="' . $domain->context .
'" data-langs="' . esc_attr( wp_json_encode( $results ) ) .
'"' . $domain_data . '>' . $domain->context . '</option>';
}
?>
</select>
<div class="js-summary wpml-cdl-summary" style="display:none" >
<p class="wpml-cdl-info">
<?php _e( 'This domain currently has the following strings:', 'wpml-string-translation' ); ?>
</p>
<table class="widefat striped wpml-cdl-table">
<thead>
<tr>
<td class="manage-column column-cb check-column"><input class="js-all-check" type="checkbox" value="all" /></td>
<th><?php _e( 'Current source language', 'wpml-string-translation' ); ?></th>
<th class="num"><?php _e( 'Number of strings', 'wpml-string-translation' ); ?></th>
</tr>
</thead>
<tbody>
</tbody>
</table>
<div class="js-lang-select-area wpml-cdl-info">
<label for="wpml-source-domain-language-change"><?php _e( 'Set the source language of these strings to:', 'wpml-string-translation' ); ?></label>
<?php
$lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
echo $lang_selector->render( array( 'id' => 'wpml-source-domain-language-change' ) );
?>
<label for="wpml-cdl-set-default">
<input id="wpml-cdl-set-default" type="checkbox" class="js-default" value="use-as-default" checked="checked" />
<?php _e( 'Use this language as the default language for new strings in this domain', 'wpml-string-translation' ); ?>
</label>
</div>
</div>
<span class="spinner"></span>
<?php wp_nonce_field( 'wpml_change_string_domain_language_nonce', 'wpml_change_string_domain_language_nonce' ); ?>
</div>
<?php
}
public function change_language_of_strings( $domain, $langs, $to_lang, $set_as_default ) {
$package_translation = new WPML_Package_Helper();
$package_translation->change_language_of_strings_in_domain( $domain, $langs, $to_lang );
if ( ! empty( $langs ) ) {
foreach ( $langs as &$lang ) {
$lang = "'" . $lang . "'";
}
$langs = implode( ',', $langs );
$string_ids = $this->wpdb->get_col( $this->wpdb->prepare( "SELECT id FROM {$this->wpdb->prefix}icl_strings WHERE context=%s AND language IN ($langs)", $domain ) );
foreach ( $string_ids as $str_id ) {
$this->string_factory->find_by_id( $str_id )->set_language( $to_lang );
}
}
if ( $set_as_default ) {
$lang_of_domain = new WPML_Language_Of_Domain( $this->sitepress );
$lang_of_domain->set_language( $domain, $to_lang );
}
$string_ids = $this->wpdb->get_col(
$this->wpdb->prepare( "SELECT id FROM {$this->wpdb->prefix}icl_strings WHERE context = %s", $domain )
);
foreach ( $string_ids as $strid ) {
$this->string_factory->find_by_id( $strid )->update_status();
}
do_action( 'wpml_st_language_of_strings_changed', $string_ids );
return array( 'success' => true );
}
}

View File

@@ -0,0 +1,67 @@
<?php
class WPML_Change_String_Language_Select {
/**
* @var wpdb
*/
private $wpdb;
/**
* @var SitePress
*/
private $sitepress;
/**
* @param wpdb $wpdb
* @param SitePress $sitepress
*/
public function __construct( wpdb $wpdb, SitePress $sitepress ) {
$this->wpdb = $wpdb;
$this->sitepress = $sitepress;
}
public function show() {
$lang_selector = new WPML_Simple_Language_Selector( $this->sitepress );
echo $lang_selector->render(
array(
'id' => 'icl_st_change_lang_selected',
'class' => 'wpml-select2-button',
'please_select_text' => __( 'Change the language of selected strings', 'wpml-string-translation' ),
'disabled' => true,
)
);
wp_nonce_field( 'wpml_change_string_language_nonce', 'wpml_change_string_language_nonce' );
}
/**
* @param int[] $strings
* @param string $lang
*
* @return array
*/
public function change_language_of_strings( $strings, $lang ) {
$package_translation = new WPML_Package_Helper();
$response = $package_translation->change_language_of_strings( $strings, $lang );
if ( $response['success'] ) {
$strings_in = implode( ',', $strings );
$update_query = "UPDATE {$this->wpdb->prefix}icl_strings SET language=%s WHERE id IN ($strings_in)";
$update_prepare = $this->wpdb->prepare( $update_query, $lang );
$this->wpdb->query( $update_prepare );
$response['success'] = true;
foreach ( $strings as $string ) {
icl_update_string_status( $string );
}
do_action( 'wpml_st_language_of_strings_changed', $strings );
}
return $response;
}
}

View File

@@ -0,0 +1,276 @@
<?php
use WPML\Element\API\Languages;
use WPML\FP\Fns;
use WPML\FP\Obj;
use WPML\FP\Wrapper;
use function WPML\FP\partialRight;
class WPML_String_Translation_Table {
private $strings;
private $active_languages;
private $additional_columns_to_render;
private $strings_in_page;
/**
* WPML_String_Translation_Table constructor.
*
* @param array<string> $strings
*/
public function __construct( $strings ) {
global $sitepress;
$this->strings = $strings;
if ( ! empty( $strings ) ) {
$this->strings_in_page = icl_get_strings_tracked_in_pages( $strings );
}
$this->additional_columns_to_render = wpml_collect();
$this->active_languages = $sitepress->get_active_languages();
}
public function render() {
?>
<table id="icl_string_translations" class="widefat" cellspacing="0">
<?php
Fns::each( [ $this, 'updateColumnsForString' ], $this->strings );
$this->render_table_header_or_footer( 'thead' );
$this->render_table_header_or_footer( 'tfoot' );
?>
<tbody>
<?php
if ( empty( $this->strings ) ) {
?>
<tr>
<td colspan="6" align="center">
<?php esc_html_e( 'No strings found', 'wpml-string-translation' ); ?>
</td>
</tr>
<?php
} else {
foreach ( $this->strings as $string_id => $icl_string ) {
$this->render_string_row( $string_id, $icl_string );
}
}
?>
</tbody>
</table>
<?php
}
private function render_table_header_or_footer( $tag ) {
$codes = Obj::keys( $this->active_languages );
$getFlagData = function ( $langData ) {
return [
'title' => $langData['display_name'],
'flagUrl' => Languages::getFlagUrl( $langData['code'] ),
'code' => $langData['code'],
];
};
$getFlagImg = function ($langData) {
if ($langData['flagUrl'] !== '') {
return '<img
src="'.esc_attr( $langData['flagUrl'] ).'"
alt="'.esc_attr( $langData['title'] ).'"
>';
} else {
return $langData['code'];
}
};
$makeFlag = function ( $langData ) use ($getFlagImg) {
ob_start();
?>
<span
data-code="<?php esc_attr_e( $langData['code'] ); ?>"
title="<?php esc_attr_e( $langData['title'] ); ?>"
>
<?php echo $getFlagImg($langData) ?>
</span>
<?php
return ob_get_clean();
};
$flags = Wrapper::of( $this->active_languages )
->map( Fns::map( $getFlagData ) )
->map( Fns::map( $makeFlag ) )
->map( Fns::reduce( WPML\FP\Str::concat(), '' ) );
?>
<<?php echo $tag; ?>>
<tr>
<td scope="col" class="manage-column column-cb check-column"><input type="checkbox"/></td>
<th scope="col"><?php esc_html_e( 'Domain', 'wpml-string-translation' ); ?></th>
<?php if ( $this->additional_columns_to_render->contains( 'context' ) ) : ?>
<th scope="col"><?php esc_html_e( 'Context', 'wpml-string-translation' ); ?></th>
<?php endif; ?>
<?php if ( $this->additional_columns_to_render->contains( 'name' ) ) : ?>
<th scope="col"><?php esc_html_e( 'Name', 'wpml-string-translation' ); ?></th>
<?php endif; ?>
<?php if ( $this->additional_columns_to_render->contains( 'view' ) ) : ?>
<th scope="col"><?php esc_html_e( 'View', 'wpml-string-translation' ); ?></th>
<?php endif; ?>
<th scope="col"><?php esc_html_e( 'String', 'wpml-string-translation' ); ?></th>
<th scope="col" class="wpml-col-languages"
data-langs="<?php echo esc_attr( json_encode( $codes ) ); ?>"><?php echo $flags->get(); ?></th>
</tr>
<<?php echo $tag; ?>>
<?php
}
public function render_string_row( $string_id, $icl_string ) {
global $wpdb, $sitepress, $WPML_String_Translation;
$icl_string = $this->decodeHtmlEntitiesForStringAndTranslations( $icl_string );
?>
<tr valign="top" data-string="<?php echo esc_attr( htmlentities( json_encode( $icl_string ), ENT_QUOTES ) ); ?>">
<?php echo $this->render_checkbox_cell( $icl_string ); ?>
<td class="wpml-st-col-domain"><?php echo esc_html( $icl_string['context'] ); ?></td>
<?php if ( $this->additional_columns_to_render->contains( 'context' ) ) : ?>
<td class="wpml-st-col-context"><?php echo esc_html( $icl_string['gettext_context'] ); ?></td>
<?php endif; ?>
<?php if ( $this->additional_columns_to_render->contains( 'name' ) ) : ?>
<td class="wpml-st-col-name"><?php echo esc_html( $this->hide_if_md5( $icl_string['name'] ) ); ?></td>
<?php endif; ?>
<?php if ( $this->additional_columns_to_render->contains( 'view' ) ) : ?>
<td class="wpml-st-col-view" nowrap="nowrap">
<?php $this->render_view_column( $string_id ); ?>
</td>
<?php endif; ?>
<td class="wpml-st-col-string">
<div class="icl-st-original"<?php _icl_string_translation_rtl_div( $icl_string['string_language'] ); ?>>
<img width="18" height="12"
src="<?php echo esc_url( $sitepress->get_flag_url( $icl_string['string_language'] ) ); ?>"> <?php echo esc_html( $icl_string['value'] ); ?>
</div>
<input type="hidden" id="icl_st_wc_<?php echo esc_attr( $string_id ); ?>" value="
<?php
echo $WPML_String_Translation->estimate_word_count( $icl_string['value'], $icl_string['string_language'] )
?>
"/>
</td>
<td class="languages-status wpml-col-languages"></td>
</tr>
<?php
}
private function decodeHtmlEntitiesForStringAndTranslations( $string ) {
$decode = partialRight( 'html_entity_decode', ENT_QUOTES );
$string['value'] = $decode( $string['value'] );
$string['name'] = $decode( $string['name'] );
if ( Obj::prop( 'translations', $string ) ) {
$string['translations'] = Fns::map(
Obj::over( Obj::lensProp( 'value' ), $decode ),
$string['translations']
);
}
return $string;
}
/**
* @param array $string
*
* @return string html for the checkbox and the table cell it resides in
*/
private function render_checkbox_cell( $string ) {
$class = 'icl_st_row_cb' . ( ! empty( $string['string_package_id'] ) ? ' icl_st_row_package' : '' );
return '<td><input class="' . esc_attr( $class ) . '" type="checkbox" value="' . esc_attr( $string['string_id'] )
. '" data-language="' . esc_attr( $string['string_language'] ) . '" /></td>';
}
private function render_view_column( $string_id ) {
if ( isset( $this->strings_in_page[ ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_SOURCE ][ $string_id ] ) ) {
$thickbox_url = $this->get_thickbox_url( WPML_ST_String_Tracking_AJAX_Factory::ACTION_POSITION_IN_SOURCE, $string_id );
?>
<a class="thickbox" title="<?php esc_attr_e( 'view in source', 'wpml-string-translation' ); ?>"
href="<?php echo esc_url( $thickbox_url ); ?>">
<img src="<?php echo WPML_ST_URL; ?>/res/img/view-in-source.png" width="16" height="16"
alt="<?php esc_attr_e( 'view in page', 'wpml-string-translation' ); ?>"/>
</a>
<?php
}
if ( isset( $this->strings_in_page[ ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_PAGE ][ $string_id ] ) ) {
$thickbox_url = $this->get_thickbox_url( WPML_ST_String_Tracking_AJAX_Factory::ACTION_POSITION_IN_PAGE, $string_id );
?>
<a class="thickbox" title="<?php esc_attr_e( 'view in page', 'wpml-string-translation' ); ?>"
href="<?php echo esc_url( $thickbox_url ); ?>">
<img src="<?php echo WPML_ST_URL; ?>/res/img/view-in-page.png" width="16" height="16"
alt="<?php esc_attr_e( 'view in page', 'wpml-string-translation' ); ?>"/>
</a>
<?php
}
}
/**
* @param string $action
* @param int $string_id
*
* @return string
*/
private function get_thickbox_url( $action, $string_id ) {
return add_query_arg(
array(
'page' => WPML_ST_FOLDER . '/menu/string-translation.php',
'action' => $action,
'nonce' => wp_create_nonce( $action ),
'string_id' => $string_id,
'width' => 810,
'height' => 600,
),
'admin-ajax.php'
);
}
private function hide_if_md5( $str ) {
return preg_replace( '#^((.+)( - ))?([a-z0-9]{32})$#', '$2', $str );
}
/**
* @param array<string,string|int> $string
*/
public function updateColumnsForString( $string ) {
if (
! $this->additional_columns_to_render->contains( 'context' )
&& $string['gettext_context']
) {
$this->additional_columns_to_render->push( 'context' );
}
if (
! $this->additional_columns_to_render->contains( 'name' )
&& $this->hide_if_md5( $string['name'] )
) {
$this->additional_columns_to_render->push( 'name' );
}
if (
! $this->additional_columns_to_render->contains( 'view' )
&& $this->is_string_tracked( $string['string_id'] )
) {
$this->additional_columns_to_render->push( 'view' );
}
}
private function is_string_tracked( $string_id ) {
$tracked_source = Obj::prop( ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_SOURCE, $this->strings_in_page );
$tracked_page = Obj::prop( ICL_STRING_TRANSLATION_STRING_TRACKING_TYPE_PAGE, $this->strings_in_page );
return ( $tracked_source && Obj::prop( $string_id, $tracked_source ) )
|| ( $tracked_page && Obj::prop( $string_id, $tracked_page ) );
}
}

View File

@@ -0,0 +1,46 @@
<?php
/**
* Created by OnTheGoSystems
*/
class WPML_Translation_Priority_Select extends WPML_Templates_Factory {
const NONCE = 'wpml_change_string_translation_priority_nonce';
public function get_model() {
$model = array(
'translation_priorities' => get_terms(
array(
'taxonomy' => 'translation_priority',
'hide_empty' => false,
)
),
'nonce' => wp_nonce_field( self::NONCE, self::NONCE ),
'strings' => array(
'empty_text' => __( 'Change translation priority of selected strings', 'wpml-string-translation' ),
),
);
$this->enqueue_scripts();
return $model;
}
public function init_template_base_dir() {
$this->template_paths = array(
WPML_ST_PATH . '/templates/translation-priority/',
);
}
public function get_template() {
return 'translation-priority-select.twig';
}
private function enqueue_scripts() {
if ( ! wp_script_is( 'wpml-select-2' ) ) {
// Enqueue in the footer because this is usually called late.
wp_enqueue_script( 'wpml-select-2', ICL_PLUGIN_URL . '/lib/select2/select2.min.js', array( 'jquery' ), ICL_SITEPRESS_VERSION, true );
}
}
}