Server : LiteSpeed
System : Linux server104.web-hosting.com 4.18.0-513.24.1.lve.1.el8.x86_64 #1 SMP Thu May 9 15:10:09 UTC 2024 x86_64
User : saleoqej ( 6848)
PHP Version : 8.0.30
Disable Function : NONE
Directory :  /home/saleoqej/chijamzacademy.com/wp-content/plugins/sfwd-lms/includes/
Upload File :
Current Directory [ Writeable ] Root Directory [ Writeable ]


Current File : /home/saleoqej/chijamzacademy.com/wp-content/plugins/sfwd-lms/includes/class-ld-translations.php
<?php
/**
 * LearnDash Admin Translations handler.
 * This class connects to a remote GlotPress server to retrieve needed translations for LearnDash core and related add-ons.
 *
 * @package LearnDash\Admin
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

if ( ! class_exists( 'LearnDash_Translations' ) ) {
	/**
	 * Class for LearnDash Translations.
	 */
	class LearnDash_Translations {

		/**
		 * Project slug for this instance.
		 *
		 * @var string $project_slug Project Slug.
		 */
		private $project_slug = '';

		/**
		 * Available Translations for project.
		 *
		 * @var array $available_translations Available Translations.
		 */
		private $available_translations = array();

		/**
		 * Installed Translations for project.
		 *
		 * @var array $installed_translations Installed Translations.
		 */
		private $installed_translations = array();

		/**
		 * Array of All Project Slugs.
		 *
		 * @var array $project_slugs.
		 */
		private static $project_slugs = array();

		/**
		 * Translations Directory on server.
		 *
		 * @var string $translations_dir.
		 */
		private static $translations_dir = '';

		/**
		 * Options Key for storing translations data.
		 *
		 * @var string $options_key.
		 */
		private static $options_key = 'ld-translations';

		/**
		 * Debug capture variable.
		 *
		 * @var array $debug_log_array.
		 */
		public static $debug_log_array = array();

		/**
		 * Public constructor for class.
		 *
		 * @param string $project_slug Project slug for instance.
		 */
		public function __construct( $project_slug = '' ) {
			if ( ! empty( $project_slug ) ) {
				$this->project_slug = $project_slug;
			}
		}

		/**
		 * Interface function to register new translation slug.
		 *
		 * @param string $project_slug Project Slug.
		 * @param string $project_language_dir Project Language Directory.
		 */
		public static function register_translation_slug( $project_slug = '', $project_language_dir = '' ) {
			if ( ( ! empty( $project_slug ) ) && ( ! isset( self::$project_slugs[ $project_slug ] ) ) ) {
				self::$project_slugs[ $project_slug ] = trailingslashit( $project_language_dir );
			}
		}

		/**
		 * Get last update information.
		 */
		public static function get_last_update() {
			$ld_translations = get_option( self::$options_key );
			if ( isset( $ld_translations['last_check'] ) ) {
				return $ld_translations['last_check'];
			}
		}

		/**
		 * Get Language Directory for Project.
		 *
		 * @param string  $project_slug Project Slug.
		 * @param boolean $relative_to_home if true relative directory is returned.
		 * @return string directory path.
		 */
		public static function get_language_directory( $project_slug = '', $relative_to_home = true ) {
			if ( ( ! empty( $project_slug ) ) && ( isset( self::$project_slugs [ $project_slug ] ) ) ) {

				if ( true !== $relative_to_home ) {
					return trailingslashit( self::$project_slugs[ $project_slug ] );
				} else {
					$abspath_tmp = str_replace( '\\', '/', ABSPATH );
					return str_replace( $abspath_tmp, '/', trailingslashit( self::$project_slugs[ $project_slug ] ) );
				}
			}

			return '';
		}

		/**
		 * Check if language directory is writable for Project Slug.
		 *
		 * @param string $project_slug Project Slug.
		 * @return boolean true if directory is writable.
		 */
		public static function is_language_directory_writable( $project_slug = '' ) {
			if ( ! empty( $project_slug ) ) {
				$translations_dir = self::get_language_directory( $project_slug, false );
				if ( ( ! empty( $translations_dir ) ) && ( is_writable( $translations_dir ) ) ) {
					return true;
				}
			}

			return false;
		}

		/**
		 * Check if project has available translations.
		 *
		 * @param string $project_slug Project Slug.
		 * @return boolean true.
		 */
		public static function project_has_available_translations( $project_slug = '' ) {
			$ld_translations = get_option( self::$options_key );
			if ( isset( $ld_translations['translation_sets'][ $project_slug ] ) ) {
				return true;
			}

			return false;
		}

		/** Return available translations for project slug.
		 *
		 * @param string $project_slug Project Slug.
		 * @param string $locale Locale for translations.
		 * @return mixed Translation set array.
		 */
		public static function project_get_available_translations( $project_slug = '', $locale = '' ) {
			$ld_translations = get_option( self::$options_key );
			if ( isset( $ld_translations['translation_sets'][ $project_slug ] ) ) {
				if ( ! empty( $locale ) ) {
					foreach ( $ld_translations['translation_sets'][ $project_slug ] as $translation_set ) {
						if ( $translation_set['wp_locale'] == $locale ) {
							return $translation_set;
						}
					}
				}
				return $ld_translations['translation_sets'][ $project_slug ];
			}

			return array();
		}

		/**
		 * Get Action URL.
		 *
		 * @param string $action Action.
		 * @param string $project Project Slug.
		 * @param string $locale Locale.
		 * @return string action URL.
		 */
		public static function get_action_url( $action = '', $project = '', $locale = '' ) {
			if ( ! empty( $action ) ) {
				$action_url = remove_query_arg( array( 'action', 'project', 'locale', 'ld-translation-nonce' ) );

				$nonce_key  = 'ld-translation-' . $action;
				$action_url = add_query_arg( array( 'action' => $action ), $action_url );

				if ( ! empty( $project ) ) {
					$nonce_key .= '-' . $project;
					$action_url = add_query_arg( array( 'project' => $project ), $action_url );
				}

				if ( ! empty( $locale ) ) {
					$nonce_key .= '-' . $locale;
					$action_url = add_query_arg( array( 'locale' => $locale ), $action_url );
				}

				$action_nonce = wp_create_nonce( $nonce_key );
				$action_url   = add_query_arg( array( 'ld-translation-nonce' => $action_nonce ), $action_url );

				return $action_url;
			}

			return '';
		}

		/**
		 * Install Translations
		 *
		 * @param string $project Project Slug.
		 * @param string $locale Translation Locale.
		 */
		public static function install_translation( $project = '', $locale = '' ) {
			$reply_data = array();

			if ( ( ! empty( $project ) ) && ( ! empty( $locale ) ) ) {

				if ( self::is_language_directory_writable( $project ) ) {
					$translation_set = self::project_get_available_translations( $project, $locale );

					if ( ( isset( $translation_set['links'] ) ) && ( ! empty( $translation_set['links'] ) ) ) {
						foreach ( $translation_set['links'] as $link_key => $link_url ) {

							/**
							 * Filters translation URL arguments.
							 *
							 * @param array $name An array of URL translation arguments.
							 */
							$url_args = apply_filters( 'learndash_translations_url_args', array( 'timeout' => LEARNDASH_HTTP_REMOTE_GET_TIMEOUT ) );

							$dest_filename = self::get_language_directory( $project, false ) . $project . '-' . $locale . '.' . $link_key;
							if ( file_exists( $dest_filename ) ) {
								unlink( $dest_filename );
							}

							$response = wp_remote_get( $link_url, $url_args );
							if ( ( is_array( $response ) ) && ( wp_remote_retrieve_response_code( $response ) == '200' ) ) {
								$response_body = wp_remote_retrieve_body( $response );
								if ( ! empty( $response_body ) ) {
									$fp = fopen( $dest_filename, 'w+' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
									if ( false !== $fp ) {
										fwrite( $fp, $response_body ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
										fclose( $fp ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
										$reply_data['status']  = true;
										$reply_data['message'] = '<p>' . sprintf(
											// translators: placeholders: Language Name, Language code.
											esc_html_x( 'Translation installed: %1$s (%2$s)', 'placeholders: Language Name, Language code', 'learndash' ),
											$translation_set['english_name'],
											$translation_set['wp_locale']
										) . '</p>';
										$reply_data['translation_set'] = $translation_set;
									}
								}
							}
						}
					}
				}
			}

			return $reply_data;
		}

		/**
		 * Download .pot file
		 *
		 * @param string $project_slug Translation project slug.
		 */
		public static function download_pot_file( $project_slug = '' ) {
			$reply_data = array();

			if ( ! empty( $project_slug ) ) {
				$pot_filename = self::get_language_directory( $project_slug, false ) . '' . $project_slug . '.pot';
				if ( file_exists( $pot_filename ) ) {
					$pot_file_contents = file_get_contents( $pot_filename ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

					header( 'Content-type: text/x-gettext-translation' );
					header( 'Content-Length: ' . strlen( $pot_file_contents ) );
					header( 'Cache-Control: no-cache, must-revalidate' );
					header( 'Pragma: no-cache' );
					header( 'Expires: 0' );
					header( 'Content-Disposition: attachment; filename="' . basename( $pot_filename ) . '"; modification-date="' . date( 'r' ) . '";' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
					echo $pot_file_contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
					die();
				}

				$action_url = remove_query_arg( array( 'action', 'project', 'locale', 'ld-translation-nonce' ) );
				learndash_safe_redirect( $action_url );
			}
		}

		/**
		 * Download .po file
		 *
		 * @param string $project_slug Translation project slug.
		 * @param string $locale_slug  Locale slug.
		 */
		public static function download_po_file( $project_slug = '', $locale_slug = '' ) {
			$reply_data = array();

			if ( ( ! empty( $project_slug ) ) && ( ! empty( $locale_slug ) ) ) {
				$installed_translations = self::get_installed_translations( $project_slug );
				if ( isset( $installed_translations[ $locale_slug ] ) ) {
					$installed_set = $installed_translations[ $locale_slug ];
					$po_filename   = self::get_language_directory( $project_slug, false ) . $installed_set['po'];
					if ( file_exists( $po_filename ) ) {
						$po_file_contents = file_get_contents( $po_filename ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents

						header( 'Content-type: text/x-gettext-translation' );
						header( 'Content-Length: ' . strlen( $po_file_contents ) );
						header( 'Cache-Control: no-cache, must-revalidate' );
						header( 'Pragma: no-cache' );
						header( 'Expires: 0' );
						header( 'Content-Disposition: attachment; filename="' . basename( $po_filename ) . '"; modification-date="' . date( 'r' ) . '";' ); // phpcs:ignore WordPress.DateTime.RestrictedFunctions.date_date
						echo $po_file_contents; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Need to output HTML.
						die();
					}

					$action_url = remove_query_arg( array( 'action', 'project', 'locale', 'ld-translation-nonce' ) );
					learndash_safe_redirect( $action_url );
				}
			}
		}

		/**
		 * Update Translations for Project
		 *
		 * @param string $project Project Slug.
		 * @param string $locale Locale.
		 */
		public static function update_translation( $project = '', $locale = '' ) {
			$reply_data = array();

			if ( ( ! empty( $project ) ) && ( ! empty( $locale ) ) ) {

				if ( self::is_language_directory_writable( $project ) ) {
					$translation_set = self::project_get_available_translations( $project, $locale );

					if ( ( isset( $translation_set['links'] ) ) && ( ! empty( $translation_set['links'] ) ) ) {
						foreach ( $translation_set['links'] as $link_key => $link_url ) {

							/** This filter is documented in includes/class-ld-translations.php */
							$url_args = apply_filters( 'learndash_translations_url_args', array( 'timeout' => LEARNDASH_HTTP_REMOTE_GET_TIMEOUT ) );

							$dest_filename = self::get_language_directory( $project, false ) . $project . '-' . $locale . '.' . $link_key;
							if ( file_exists( $dest_filename ) ) {
								unlink( $dest_filename );
							}

							$response = wp_remote_get( $link_url, $url_args );
							if ( ( is_array( $response ) ) && ( wp_remote_retrieve_response_code( $response ) == '200' ) ) {
								$response_body = wp_remote_retrieve_body( $response );
								if ( ! empty( $response_body ) ) {
									$fp = fopen( $dest_filename, 'w+' ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fopen
									if ( false !== $fp ) {
										fwrite( $fp, $response_body ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
										fclose( $fp );  // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
										$reply_data['status']  = true;
										$reply_data['message'] = '<p>' . sprintf(
											// translators: placeholders: Language Name, Language code.
											esc_html_x( 'Translation updated: %1$s (%2$s)', 'placeholders: Language Name, Language code', 'learndash' ),
											$translation_set['english_name'],
											$translation_set['wp_locale']
										) . '</p>';
									}
								}
							}
						}
					}
				}
			}

			return $reply_data;
		}

		/**
		 * Remove translations for Project.
		 *
		 * @param string $project Project Slug.
		 * @param string $locale Locale for translation.
		 */
		public static function remove_translation( $project = '', $locale = '' ) {
			$reply_data = array();

			if ( ( ! empty( $project ) ) && ( ! empty( $locale ) ) ) {

				if ( self::is_language_directory_writable( $project ) ) {
					$translation_set = self::project_get_available_translations( $project, $locale );

					if ( ( isset( $translation_set['links'] ) ) && ( ! empty( $translation_set['links'] ) ) ) {
						foreach ( $translation_set['links'] as $link_key => $link_url ) {
							/** This filter is documented in includes/class-ld-translations.php */
							$url_args = apply_filters( 'learndash_translations_url_args', array() );

							$dest_filename = self::get_language_directory( $project, false ) . $project . '-' . $locale . '.' . $link_key;
							if ( file_exists( $dest_filename ) ) {
								unlink( $dest_filename );
								$reply_data['status']  = true;
								$reply_data['message'] = '<p>' . sprintf(
									// translators: placeholders: Language Name, Language code.
									esc_html_x( 'Translation removed: %1$s (%2$s)', 'placeholders: Language Name, Language code', 'learndash' ),
									$translation_set['english_name'],
									$translation_set['wp_locale']
								) . '</p>';
							}
						}
					}
				}
			}

			return $reply_data;
		}

		/**
		 * Refresh Translations
		 */
		public static function refresh_translations() {
			$ld_translations               = get_option( self::$options_key );
			$ld_translations['last_check'] = 0;
			update_option( self::$options_key, $ld_translations );
			self::get_available_translations();
		}

		/**
		 * Show translations metabox for Project Slug.
		 */
		public function show_meta_box() {
			if ( ! empty( $this->project_slug ) ) {
				$this->installed_translations = self::get_installed_translations( $this->project_slug );
				$this->available_translations = self::get_available_translations( $this->project_slug );
				?>
				<div id="wrap-ld-translations-<?php echo esc_attr( $this->project_slug ); ?>" class="wrap wrap-ld-translations">
					<?php
					if ( ( ! empty( $this->available_translations ) ) || ( ! empty( $this->installed_translations ) ) ) {
						$this->show_installed_translations();
						$this->show_available_translations();
					} else {
						?>
						<p><?php esc_html_e( 'No translations available for this plugin.', 'learndash' ); ?></p>
						<?php
					}
					?>
				</div>
				<?php
			}
		}

		/**
		 * Get available translations for project.
		 *
		 * @param string  $project Project Slug.
		 * @param boolean $force Force update.
		 */
		public static function get_available_translations( $project = '', $force = false ) {
			if ( ! empty( self::$project_slugs ) ) {
				$ld_translations = get_option( self::$options_key, null );
				if ( ! isset( $ld_translations['last_check'] ) ) {
					$ld_translations['last_check'] = time() - ( LEARNDASH_TRANSLATIONS_URL_CACHE + 1 );
				} elseif ( ( isset( $_GET['action'] ) ) && ( 'refresh' === $_GET['action'] ) ) {
					if ( ( isset( $_GET['ld-translation-nonce'] ) ) && ( ! empty( $_GET['ld-translation-nonce'] ) ) && ( wp_verify_nonce( $_GET['ld-translation-nonce'], 'ld-translation-refresh' ) ) ) {
						$ld_translations['last_check'] = time() - ( LEARNDASH_TRANSLATIONS_URL_CACHE + 1 );
					}
				}

				$time_diff = abs( time() - intval( $ld_translations['last_check'] ) );

				if ( ( true === $force ) || ( $time_diff > LEARNDASH_TRANSLATIONS_URL_CACHE ) ) {

					$project_slugs = implode( ',', array_keys( self::$project_slugs ) );

					$url      = add_query_arg(
						array(
							'ldlms-glotpress' => 1,
							'action'          => 'translation_sets',
							'project'         => $project_slugs,
						),
						trailingslashit( LEARNDASH_TRANSLATIONS_URL_BASE )
					);
					$url_args = array( 'timeout' => 10 );
					/** This filter is documented in includes/class-ld-translations.php */
					$url_args = apply_filters( 'learndash_translations_url_args', $url_args );

					$response = wp_remote_get( $url, $url_args );
					if ( ( is_array( $response ) ) && ( wp_remote_retrieve_response_code( $response ) == '200' ) ) {
						$response_body = wp_remote_retrieve_body( $response );

						if ( ! empty( $response_body ) ) {
							$ld_translation_sets = json_decode( $response_body, true );

							$ld_translation = array(
								'last_check'       => time(),
								'translation_sets' => $ld_translation_sets,
							);
							update_option( self::$options_key, $ld_translation );
						}
					}
				}

				if ( ! empty( $project ) ) {
					if ( ( isset( $ld_translations['translation_sets'][ $project ] ) ) && ( ! empty( $ld_translations['translation_sets'][ $project ] ) ) ) {
						return $ld_translations['translation_sets'][ $project ];
					}
				}
			}
		}

		/**
		 * Show installed translations
		 */
		public function show_installed_translations() {

			$pot_file = self::get_language_directory( $this->project_slug, false ) . '' . $this->project_slug . '.pot';
			if ( file_exists( $pot_file ) ) {
				?>
				<p style="float:right"><?php esc_html_e( 'Download the original strings (POT) File.', 'learndash' ); ?>

				<a id="learndash-translations-pot-file-<?php echo esc_attr( $this->project_slug ); ?>" class="button button-secondary learndash-translations-pot-file" href="<?php echo esc_url( self::get_action_url( 'pot_download', esc_attr( $this->project_slug ) ) ); ?>" title="<?php esc_html_e( 'Download POT File from your server.', 'learndash' ); ?>"><span class="dashicons dashicons-download"></span><?php esc_html_e( 'POT', 'learndash' ); ?></a>

				</p><div style="clear:both"></div>
				<?php
			}
			?>

			<h4><?php esc_html_e( 'Installed Translations', 'learndash' ); ?></h4>
			<table class="ld-installed-translations wp-list-table widefat fixed striped posts">
			<thead>
				<tr>
					<th class="column-locale"><?php esc_html_e( 'Locale', 'learndash' ); ?></th>
					<th class="column-title"><?php esc_html_e( 'Name / Native', 'learndash' ); ?></th>
					<th class="column-actions-local"><?php esc_html_e( 'Download', 'learndash' ); ?></th>
					<th class="column-action-remote"><?php esc_html_e( 'Actions', 'learndash' ); ?></th>
				</tr>
			</thead>
			<tbody>
				<?php
				if ( ( is_array( $this->available_translations ) ) && ( ! empty( $this->available_translations ) ) && ( is_array( $this->installed_translations ) ) && ( ! empty( $this->installed_translations ) ) ) {
					foreach ( $this->available_translations as $idx => $translation_set ) {
						$translation_locale = $translation_set['wp_locale'];
						if ( isset( $this->installed_translations[ $translation_locale ] ) ) {
							$installed_set = $this->installed_translations[ $translation_locale ];
							$this->show_installed_translation_row( $translation_locale, $translation_set, $installed_set );
						}
					}

					foreach ( $this->installed_translations as $installed_locale => $installed_set ) {
						$install_matched = false;
						foreach ( $this->available_translations as $idx => $translation_set ) {
							$translation_locale = $translation_set['wp_locale'];
							if ( $translation_locale == $installed_locale ) {
								$install_matched = true;
								break;
							}
						}

						if ( ! $install_matched ) {
							$this->show_installed_translation_row( $installed_locale, null, $installed_set );
						}
					}
				} else {
					?>
					<tr>
						<td colspan="4"><?php echo esc_html__( 'No Translations installed', 'learndash' ); ?></td>
						</tr>
						<?php
				}
				?>
			</tbody>
			</table>
			<p>
			<?php
			echo sprintf(
				// translators: placeholder: Language directory.
				esc_html_x( 'All translations are stored into the directory: %s', 'placeholder: Language directory', 'learndash' ),
				'<code>' . esc_attr( '<site root>' ) . esc_attr( self::get_language_directory( $this->project_slug, true ) ) . '</code>'
			);
			?>
			<?php
			if ( ! self::is_language_directory_writable( $this->project_slug ) ) {
				?>
					<br /><span class="error"><?php esc_html_e( 'The language directory is not writable', 'learndash' ); ?></span>
					<?php
			}
			?>
			</p>
			<?php
		}

		/**
		 * Show installed translations row.
		 *
		 * @param string $locale Locale.
		 * @param mixed  $translation_set Array of translations.
		 * @param mixed  $installed_set Array of installed translations.
		 */
		public function show_installed_translation_row( $locale = '', $translation_set = null, $installed_set = null ) {
			if ( ! empty( $locale ) ) {
				?>
				<tr>
					<td class="column-locale"><?php echo esc_attr( $locale ); ?></td>
					<td class="column-title">
					<?php
					if ( ! is_null( $translation_set ) ) {
						echo esc_html( $translation_set['english_name'] ) . '/' . esc_html( $translation_set['native_name'] );
					} else {
						esc_html_e( 'Not from LearnDash', 'learndash' );
					}
					?>
					</td>
					<td class="column-actions-local">
						<?php
						if ( isset( $installed_set['po'] ) ) {
							?>
							<a id="learndash-translations-po-file-<?php echo esc_attr( $locale ); ?>" class="button button-secondary learndash-translations-po-file" href="<?php echo esc_url( self::get_action_url( 'po_download', $this->project_slug, $locale ) ); ?>" title="<?php esc_html_e( 'Download PO File from your server.', 'learndash' ); ?>"><span class="dashicons dashicons-download"></span><?php esc_html_e( 'PO', 'learndash' ); ?></a>
							<?php
						}
						?>
					</td>
					<td class="column-actions-remote">
						<a id="learndash-translations-<?php echo esc_attr( $this->project_slug ); ?>-<?php echo esc_attr( $locale ); ?>-remove" class="button button-secondary learndash-translations-remove" href="<?php echo esc_url( self::get_action_url( 'remove', $this->project_slug, $locale ) ); ?>" title="<?php esc_html_e( 'Remove translation from server', 'learndash' ); ?>"><span class="dashicons dashicons-trash"></span></a>
						<?php

						if ( ! is_null( $translation_set ) ) {
							?>
							<a href="<?php echo esc_url( self::get_action_url( 'update', $this->project_slug, $locale ) ); ?>" class="button button-primary learndash-translations-update" title="<?php esc_html_e( 'Update translation from LearnDash', 'learndash' ); ?>"><?php esc_html_e( 'Update', 'learndash' ); ?></a>
							<?php
						}
						?>
					</td>
				</tr>
				<?php
			}
		}

		/**
		 * Show available translations.
		 */
		public function show_available_translations() {
			$wp_languages = get_available_languages();

			if ( empty( $wp_languages ) ) {
				$wp_languages = array();
			}

			if ( ! in_array( 'en_US', $wp_languages, true ) ) {
				$wp_languages = array_merge( array( 'en_US' ), $wp_languages );
			}

			// Taken from options-general.php.
			if ( ! is_multisite() && defined( 'WPLANG' ) && '' !== WPLANG && 'en_US' !== WPLANG && ! in_array( WPLANG, $wp_languages, true ) ) {
				$wp_languages[] = WPLANG;
			}

			$wp_locale = get_locale();
			if ( ( ! empty( $wp_locale ) ) && ( ! in_array( $wp_locale, $wp_languages, true ) ) ) {
				$wp_languages[] = $wp_locale;
			}

			if ( ( is_array( $this->available_translations ) ) && ( ! empty( $this->available_translations ) ) ) {

				$available_translations                = array();
				$available_translations['recommended'] = array();
				$available_translations['available']   = array();

				// First we split into buckets based on languages installed to WP.
				foreach ( $this->available_translations as $translation_set ) {
					if ( ! isset( $this->installed_translations[ $translation_set['wp_locale'] ] ) ) {
						if ( in_array( $translation_set['wp_locale'], $wp_languages, true ) === true ) {
							$available_translations['recommended'][ $translation_set['wp_locale'] ] = $translation_set;
						} else {
							$available_translations['available'][ $translation_set['wp_locale'] ] = $translation_set;
						}
					}
				}

				if ( ( ! empty( $available_translations['recommended'] ) ) || ( ! empty( $available_translations['available'] ) ) ) {
					?>
					<div id="learndash-translations-available">
						<h4><?php esc_html_e( 'Available Translations', 'learndash' ); ?></h4>
						<select id="ld-translation-install-locale-<?php echo esc_attr( $this->project_slug ); ?>" class="ld-translation-install-locale" data-project="<?php echo esc_attr( $this->project_slug ); ?>">
							<option value=""><?php esc_html_e( '-- Install Translation --', 'learndash' ); ?></option>
							<?php
							$show_opt_group = false;
							if ( ( ! empty( $available_translations['recommended'] ) ) && ( ! empty( $available_translations['available'] ) ) ) {
								$show_opt_group = true;
							}
							if ( ! empty( $available_translations['recommended'] ) ) {
								if ( $show_opt_group ) {
									?>
									<optgroup label="<?php esc_html_e( 'Recommended', 'learndash' ); ?>">
									<?php
								}
								foreach ( $available_translations['recommended'] as $translation_set ) {
									?>
									<option value="<?php echo esc_url( self::get_action_url( 'install', $this->project_slug, $translation_set['wp_locale'] ) ); ?>"><?php echo esc_html( $translation_set['english_name'] ) . ' / ' . esc_html( $translation_set['native_name'] ) . ' (' . esc_html( $translation_set['wp_locale'] ) . ')'; ?></option>
									<?php
								}
								if ( $show_opt_group ) {
									?>
									</optgroup>
									<?php
								}
							}

							if ( ! empty( $available_translations['available'] ) ) {
								if ( $show_opt_group ) {
									?>
									<optgroup label="<?php esc_html_e( 'Available', 'learndash' ); ?>">
									<?php
								}
								foreach ( $available_translations['available'] as $translation_set ) {
									?>
									<option value="<?php echo esc_url( self::get_action_url( 'install', $this->project_slug, $translation_set['wp_locale'] ) ); ?>"><?php echo esc_html( $translation_set['english_name'] ) . ' / ' . esc_html( $translation_set['native_name'] ) . ' (' . esc_html( $translation_set['wp_locale'] ) . ')'; ?></option>
									<?php
								}
								if ( $show_opt_group ) {
									?>
									</optgroup>
									<?php
								}
							}
							?>
						</select>
						<a id="learndash-translation-install-<?php echo esc_attr( $this->project_slug ); ?>" class="button button-primary learndash-translations-install" href="#"><?php esc_html_e( 'Install', 'learndash' ); ?></a>
					</div>
					<?php
				}
			}
		}

		/**
		 * Get installed translations.
		 *
		 * @param string $project_slug Translation project slug.
		 */
		public static function get_installed_translations( $project_slug = '' ) {
			$translation_files = array();

			if ( ! empty( $project_slug ) ) {

				$languages_plugins_dir    = self::get_language_directory( $project_slug, false );
				$languages_plugins_dir_mo = $languages_plugins_dir . $project_slug . '-*.mo';

				$mo_files = glob( $languages_plugins_dir_mo );
				if ( ! empty( $mo_files ) ) {
					foreach ( $mo_files as $mo_file ) {
						$mo_file       = basename( $mo_file );
						$mo_file_local = str_replace( array( $project_slug . '-', '.mo' ), '', $mo_file );
						if ( ! empty( $mo_file_local ) ) {

							if ( ! isset( $translation_files[ $mo_file_local ] ) ) {
								$translation_files[ $mo_file_local ]             = array();
								$translation_files[ $mo_file_local ]['mo']       = $mo_file;
								$translation_files[ $mo_file_local ]['mo_mtime'] = filemtime( $languages_plugins_dir . $mo_file );

								$po_file                  = str_replace( '.mo', '.po', $mo_file );
								$languages_plugins_dir_po = $languages_plugins_dir . $po_file;
								if ( file_exists( $languages_plugins_dir_po ) ) {
									$translation_files[ $mo_file_local ]['po']       = $po_file;
									$translation_files[ $mo_file_local ]['po_mtime'] = filemtime( $languages_plugins_dir . $po_file );
								}
							}
						}
					}
				}
			}
			return $translation_files;
		}

		/**
		 * Log debug message
		 *
		 * @param string $message Message.
		 */
		public static function log_debug_message( $message = '' ) {
			self::$debug_log_array[] = $message;
		}

		/**
		 * Show debug log output
		 */
		public static function show_debug_log_output() {
			if ( ! empty( self::$debug_log_array ) ) {
				foreach ( self::$debug_log_array as $message ) {
					echo '<br />' . esc_html( $message );
				}
			}
		}
		// End of functions.
	}
}