|
<?php |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
final class WP_Translation_Controller { |
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $current_locale = 'en_US'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $loaded_translations = array(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected $loaded_files = array(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private static $instance = null; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static function get_instance(): WP_Translation_Controller { |
|
if ( null === self::$instance ) { |
|
self::$instance = new self(); |
|
} |
|
|
|
return self::$instance; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function get_locale(): string { |
|
return $this->current_locale; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function set_locale( string $locale ) { |
|
$this->current_locale = $locale; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function load_file( string $translation_file, string $textdomain = 'default', ?string $locale = null ): bool { |
|
if ( null === $locale ) { |
|
$locale = $this->current_locale; |
|
} |
|
|
|
$translation_file = realpath( $translation_file ); |
|
|
|
if ( false === $translation_file ) { |
|
return false; |
|
} |
|
|
|
if ( |
|
isset( $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] ) && |
|
false !== $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] |
|
) { |
|
return null === $this->loaded_files[ $translation_file ][ $locale ][ $textdomain ]->error(); |
|
} |
|
|
|
if ( |
|
isset( $this->loaded_files[ $translation_file ][ $locale ] ) && |
|
array() !== $this->loaded_files[ $translation_file ][ $locale ] |
|
) { |
|
$moe = reset( $this->loaded_files[ $translation_file ][ $locale ] ); |
|
} else { |
|
$moe = WP_Translation_File::create( $translation_file ); |
|
if ( false === $moe || null !== $moe->error() ) { |
|
$moe = false; |
|
} |
|
} |
|
|
|
$this->loaded_files[ $translation_file ][ $locale ][ $textdomain ] = $moe; |
|
|
|
if ( ! $moe instanceof WP_Translation_File ) { |
|
return false; |
|
} |
|
|
|
if ( ! isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) { |
|
$this->loaded_translations[ $locale ][ $textdomain ] = array(); |
|
} |
|
|
|
$this->loaded_translations[ $locale ][ $textdomain ][] = $moe; |
|
|
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function unload_file( $file, string $textdomain = 'default', ?string $locale = null ): bool { |
|
if ( is_string( $file ) ) { |
|
$file = realpath( $file ); |
|
} |
|
|
|
if ( null !== $locale ) { |
|
if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) { |
|
foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $i => $moe ) { |
|
if ( $file === $moe || $file === $moe->get_file() ) { |
|
unset( $this->loaded_translations[ $locale ][ $textdomain ][ $i ] ); |
|
unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] ); |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
foreach ( $this->loaded_translations as $l => $domains ) { |
|
if ( ! isset( $domains[ $textdomain ] ) ) { |
|
continue; |
|
} |
|
|
|
foreach ( $domains[ $textdomain ] as $i => $moe ) { |
|
if ( $file === $moe || $file === $moe->get_file() ) { |
|
unset( $this->loaded_translations[ $l ][ $textdomain ][ $i ] ); |
|
unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] ); |
|
return true; |
|
} |
|
} |
|
} |
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function unload_textdomain( string $textdomain = 'default', ?string $locale = null ): bool { |
|
$unloaded = false; |
|
|
|
if ( null !== $locale ) { |
|
if ( isset( $this->loaded_translations[ $locale ][ $textdomain ] ) ) { |
|
$unloaded = true; |
|
foreach ( $this->loaded_translations[ $locale ][ $textdomain ] as $moe ) { |
|
unset( $this->loaded_files[ $moe->get_file() ][ $locale ][ $textdomain ] ); |
|
} |
|
} |
|
|
|
unset( $this->loaded_translations[ $locale ][ $textdomain ] ); |
|
|
|
return $unloaded; |
|
} |
|
|
|
foreach ( $this->loaded_translations as $l => $domains ) { |
|
if ( ! isset( $domains[ $textdomain ] ) ) { |
|
continue; |
|
} |
|
|
|
$unloaded = true; |
|
|
|
foreach ( $domains[ $textdomain ] as $moe ) { |
|
unset( $this->loaded_files[ $moe->get_file() ][ $l ][ $textdomain ] ); |
|
} |
|
|
|
unset( $this->loaded_translations[ $l ][ $textdomain ] ); |
|
} |
|
|
|
return $unloaded; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function is_textdomain_loaded( string $textdomain = 'default', ?string $locale = null ): bool { |
|
if ( null === $locale ) { |
|
$locale = $this->current_locale; |
|
} |
|
|
|
return isset( $this->loaded_translations[ $locale ][ $textdomain ] ) && |
|
array() !== $this->loaded_translations[ $locale ][ $textdomain ]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function translate( string $text, string $context = '', string $textdomain = 'default', ?string $locale = null ) { |
|
if ( '' !== $context ) { |
|
$context .= "\4"; |
|
} |
|
|
|
$translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale ); |
|
|
|
if ( false === $translation ) { |
|
return false; |
|
} |
|
|
|
return $translation['entries'][0]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function translate_plural( array $plurals, int $number, string $context = '', string $textdomain = 'default', ?string $locale = null ) { |
|
if ( '' !== $context ) { |
|
$context .= "\4"; |
|
} |
|
|
|
$text = implode( "\0", $plurals ); |
|
$translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale ); |
|
|
|
if ( false === $translation ) { |
|
$text = $plurals[0]; |
|
$translation = $this->locate_translation( "{$context}{$text}", $textdomain, $locale ); |
|
|
|
if ( false === $translation ) { |
|
return false; |
|
} |
|
} |
|
|
|
|
|
$source = $translation['source']; |
|
$num = $source->get_plural_form( $number ); |
|
|
|
|
|
return $translation['entries'][ $num ] ?? $translation['entries'][0]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function get_headers( string $textdomain = 'default' ): array { |
|
if ( array() === $this->loaded_translations ) { |
|
return array(); |
|
} |
|
|
|
$headers = array(); |
|
|
|
foreach ( $this->get_files( $textdomain ) as $moe ) { |
|
foreach ( $moe->headers() as $header => $value ) { |
|
$headers[ $this->normalize_header( $header ) ] = $value; |
|
} |
|
} |
|
|
|
return $headers; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function normalize_header( string $header ): string { |
|
$parts = explode( '-', $header ); |
|
$parts = array_map( 'ucfirst', $parts ); |
|
return implode( '-', $parts ); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public function get_entries( string $textdomain = 'default' ): array { |
|
if ( array() === $this->loaded_translations ) { |
|
return array(); |
|
} |
|
|
|
$entries = array(); |
|
|
|
foreach ( $this->get_files( $textdomain ) as $moe ) { |
|
$entries = array_merge( $entries, $moe->entries() ); |
|
} |
|
|
|
return $entries; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function locate_translation( string $singular, string $textdomain = 'default', ?string $locale = null ) { |
|
if ( array() === $this->loaded_translations ) { |
|
return false; |
|
} |
|
|
|
|
|
foreach ( $this->get_files( $textdomain, $locale ) as $moe ) { |
|
$translation = $moe->translate( $singular ); |
|
if ( false !== $translation ) { |
|
return array( |
|
'entries' => explode( "\0", $translation ), |
|
'source' => $moe, |
|
); |
|
} |
|
if ( null !== $moe->error() ) { |
|
|
|
$this->unload_file( $moe, $textdomain, $locale ); |
|
} |
|
} |
|
|
|
|
|
return false; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
protected function get_files( string $textdomain = 'default', ?string $locale = null ): array { |
|
if ( null === $locale ) { |
|
$locale = $this->current_locale; |
|
} |
|
|
|
return $this->loaded_translations[ $locale ][ $textdomain ] ?? array(); |
|
} |
|
} |
|
|