first commit
This commit is contained in:
@@ -0,0 +1,145 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Polylang-Pro
|
||||
*/
|
||||
|
||||
use WP_Syntex\Polylang_Pro\Modules\Import_Export\Services\Context;
|
||||
|
||||
/**
|
||||
* PO file, generated from exporting Polylang translations.
|
||||
*
|
||||
* @phpstan-import-type translationEntryRef from PLL_Export_Data
|
||||
*
|
||||
* @since 2.7
|
||||
*/
|
||||
class PLL_PO_Export extends PLL_Export_File {
|
||||
/**
|
||||
* Po object.
|
||||
*
|
||||
* @var PO
|
||||
*/
|
||||
private $po;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Creates a PO object.
|
||||
*
|
||||
* @since 2.7
|
||||
* @since 3.6 Added `$source_language` and `$target_language` parameters.
|
||||
*
|
||||
* @param PLL_Language $source_language The source language of the exported data.
|
||||
* @param PLL_Language $target_language The target language of the exported data.
|
||||
*/
|
||||
public function __construct( PLL_Language $source_language, PLL_Language $target_language ) {
|
||||
parent::__construct( $source_language, $target_language );
|
||||
require_once ABSPATH . '/wp-includes/pomo/po.php';
|
||||
$this->po = new PO();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a source string to exported data and optionally a pre-existing translated one.
|
||||
*
|
||||
* @since 2.7
|
||||
* @since 3.6 The first parameter is changed from `string $type` to `array $ref`.
|
||||
* Type-hinted.
|
||||
*
|
||||
* @param array $ref {
|
||||
* Array containing the content type and optionally the corresponding object ID.
|
||||
*
|
||||
* @type string $object_type Object type to be exported (e.g. `post` or `term`).
|
||||
* @type string $field_type Field type to be exported (e.g. `post_content`, `post_title`...).
|
||||
* @type int $object_id A unique identifier to retrieve the corresponding object from the database.
|
||||
* @type string $field_id Optional, a unique identifier to retrieve the corresponding field from the database.
|
||||
* @type string $field_comment Optional, a comment meant for the translators.
|
||||
* @type string $encoding Optional, encoding format for the field group.
|
||||
* }
|
||||
* @param string $source The source to be translated.
|
||||
* @param string $target Optional, a preexisting translation, if any.
|
||||
* @return void
|
||||
*
|
||||
* @phpstan-param translationEntryRef $ref
|
||||
* @phpstan-param non-empty-string $source
|
||||
*/
|
||||
public function add_translation_entry( array $ref, string $source, string $target = '' ) {
|
||||
if ( '' === $source ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$entry = new Translation_Entry(
|
||||
array(
|
||||
'singular' => $source,
|
||||
'translations' => array( $target ),
|
||||
'context' => $ref['field_id'] ?? '',
|
||||
'extracted_comments' => $ref['field_comment'] ?? '',
|
||||
)
|
||||
);
|
||||
|
||||
$this->po->add_entry( $entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns exported data.
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string {
|
||||
$this->po->set_comment_before_headers( $this->get_comment_before_headers() );
|
||||
|
||||
$this->set_file_headers();
|
||||
|
||||
return $this->po->export();
|
||||
}
|
||||
|
||||
/**
|
||||
* Assigns the necessary headers to the PO file.
|
||||
*
|
||||
* @see https://www.gnu.org/software/trans-coord/manual/gnun/html_node/PO-Header.html
|
||||
*
|
||||
* @since 2.7
|
||||
* @since 3.3 Add a reference to the application that generated the export file (name + version).
|
||||
* @since 3.3.1 Replace non-official "Language-Target" header to the official Language.
|
||||
* Use the Poedit header "X-Source-Language" instead of non official "Language-source".
|
||||
* Replace non official 'Site-Reference" header by "X-Polylang-Site-Reference".
|
||||
* @since 3.6 Visibility is now private.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function set_file_headers() {
|
||||
$this->po->set_header( 'Language', $this->get_target_language()->get_locale( 'display' ) );
|
||||
$this->po->set_header( 'Project-Id-Version', PLL_Import_Export::APP_NAME . '/' . POLYLANG_VERSION );
|
||||
$this->po->set_header( 'POT-Creation-Date', current_time( 'Y-m-d H:iO', true ) );
|
||||
$this->po->set_header( 'PO-Revision-Date', current_time( 'Y-m-d H:iO', true ) );
|
||||
$this->po->set_header( 'MIME-Version', '1.0' );
|
||||
$this->po->set_header( 'Content-Type', 'text/plain; charset=utf-8' );
|
||||
$this->po->set_header( 'Content-Transfer-Encoding', '8bit' );
|
||||
$this->po->set_header( 'X-Source-Language', $this->get_source_language()->get_locale( 'display' ) );
|
||||
$this->po->set_header( 'X-Polylang-Site-Reference', get_site_url() );
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the necessary text comment to add to the PO file.
|
||||
*
|
||||
* @since 3.6 Visibility is now private.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_comment_before_headers(): string {
|
||||
$po = 'This file was generated by ' . POLYLANG . PHP_EOL;
|
||||
$po .= 'https://polylang.pro/' . PHP_EOL;
|
||||
return $po;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current file extension.
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return string The file extension.
|
||||
*/
|
||||
protected function get_extension(): string {
|
||||
return 'po';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Polylang-Pro
|
||||
*/
|
||||
|
||||
/**
|
||||
* Class PLL_PO_Format
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* Manages the support for Po format for Polylang Import / Export feature.
|
||||
*/
|
||||
class PLL_PO_Format extends PLL_File_Format {
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $extension = 'po';
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
public $mime_type = array( 'po' => 'text/x-po' );
|
||||
|
||||
/**
|
||||
* Po format is always supported.
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return true
|
||||
*/
|
||||
public function is_supported() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated import class.
|
||||
*
|
||||
* @since 3.1
|
||||
*
|
||||
* @return PLL_PO_Import
|
||||
*/
|
||||
public function get_import() {
|
||||
return new PLL_PO_Import();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated export class.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param string $version Optional file format version. Not used for PO.
|
||||
* @return string
|
||||
*
|
||||
* @phpstan-return class-string<PLL_PO_Export>
|
||||
*/
|
||||
public function get_export_class( $version = '' ): string { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable
|
||||
return PLL_PO_Export::class;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Polylang-Pro
|
||||
*/
|
||||
|
||||
/**
|
||||
* PO file, generated from importing translations
|
||||
*
|
||||
* Handles the reading of a PO file.
|
||||
*
|
||||
* @since 2.7
|
||||
*/
|
||||
class PLL_PO_Import implements PLL_Import_File_Interface {
|
||||
|
||||
/**
|
||||
* Po object.
|
||||
*
|
||||
* @var PO
|
||||
*/
|
||||
private $po;
|
||||
|
||||
/**
|
||||
* If we have already retrieved the entry or not.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
private $once;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Creates a PO object from an imported file.
|
||||
*
|
||||
* @since 2.7
|
||||
*/
|
||||
public function __construct() {
|
||||
require_once ABSPATH . '/wp-includes/pomo/po.php';
|
||||
$this->po = new PO();
|
||||
}
|
||||
|
||||
/**
|
||||
* Import the translations from a file.
|
||||
*
|
||||
* Relies on {@see PO::import_from_file()}
|
||||
*
|
||||
* @since 2.7
|
||||
*
|
||||
* @param string $filepath The path on the filesystem where the import file is located.
|
||||
* @return true|WP_Error True on success, a `WP_Error` object if a problem occurs during file import.
|
||||
*/
|
||||
public function import_from_file( string $filepath ) {
|
||||
// PO::import_from_file returns false in case it does not succeed to parse the file.
|
||||
if ( ! $this->po->import_from_file( $filepath ) ) {
|
||||
return new WP_Error( 'pll_import_invalid_file', __( 'Error: Invalid file.', 'polylang-pro' ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the target language
|
||||
*
|
||||
* @since 2.7
|
||||
* @since 3.3.1 Change the target language header label. We're now using the official "Language" header
|
||||
* and add a backward condition to accept the old header.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function get_target_language() {
|
||||
if ( ! empty( $this->po->headers['Language'] ) ) {
|
||||
return $this->po->headers['Language'];
|
||||
}
|
||||
|
||||
// Backward compatibility with Polylang < 3.3.1.
|
||||
if ( ! empty( $this->po->headers['Language-Target'] ) ) {
|
||||
return $this->po->headers['Language-Target'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the site reference.
|
||||
*
|
||||
* @since 2.7
|
||||
* @since 3.3.1 Change the site reference header label.
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function get_site_reference() {
|
||||
if ( ! empty( $this->po->headers['X-Polylang-Site-Reference'] ) ) {
|
||||
return $this->po->headers['X-Polylang-Site-Reference'];
|
||||
}
|
||||
|
||||
// Backward compatibility with Polylang < 3.3.1.
|
||||
if ( ! empty( $this->po->headers['Site-Reference'] ) ) {
|
||||
return $this->po->headers['Site-Reference'];
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference to the name of the application that generated the file.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @return string The application name. An empty string if it couldn't be found.
|
||||
*/
|
||||
public function get_generator_name(): string {
|
||||
return $this->get_generator()['name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference to the version of the application that generated the file.
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @return string The application version. An empty string if it couldn't be found or the name of the application.
|
||||
* couldn't be found.
|
||||
*/
|
||||
public function get_generator_version(): string {
|
||||
return $this->get_generator()['version'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the next string translation to import.
|
||||
*
|
||||
* @since 2.7
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_next_entry(): array {
|
||||
if ( $this->once ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$this->once = true;
|
||||
return array(
|
||||
'id' => null,
|
||||
'type' => PLL_Import_Export::STRINGS_TRANSLATIONS,
|
||||
'data' => $this->po,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the reference to the application that generated the file (name + version).
|
||||
*
|
||||
* @since 3.3
|
||||
*
|
||||
* @return array {
|
||||
* An array containing the application's name and version.
|
||||
*
|
||||
* @type string $name The application's name.
|
||||
* @type string $version The application's version.
|
||||
* }
|
||||
*
|
||||
* @phpstan-return array{name:string,version:string}
|
||||
*/
|
||||
private function get_generator() {
|
||||
if ( empty( $this->po->headers['Project-Id-Version'] ) || ! is_string( $this->po->headers['Project-Id-Version'] ) ) {
|
||||
return array(
|
||||
'name' => '',
|
||||
'version' => '',
|
||||
);
|
||||
}
|
||||
|
||||
$generator = explode( '/', trim( $this->po->headers['Project-Id-Version'], '/ ' ) );
|
||||
$product_version = isset( $generator[1] ) ? trim( array_pop( $generator ) ) : '';
|
||||
$product_name = trim( implode( '/', $generator ) );
|
||||
$product_name = 'POLYLANG_EXPORT' === $product_name ? PLL_Import_Export::APP_NAME : $product_name; // Backward compatibility with Polylang Pro < 3.3.
|
||||
|
||||
return array(
|
||||
'name' => $product_name,
|
||||
'version' => $product_version,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user