I18N: Introduce a more performant localization library.
This introduces a more lightweight library for loading `.mo` translation files which offers increased speed and lower memory usage.
It also supports loading multiple locales at the same time, which makes locale switching faster too.
For plugins interacting with the `$l10n` global variable in core, a shim is added to retain backward compatibility with the existing `pomo` library.
In addition to that, this library supports translations contained in PHP files, avoiding a binary file format and leveraging OPCache if available.
If an `.mo` translation file has a corresponding `.l10n.php` file, the latter will be loaded instead.
This behavior can be adjusted using the new `translation_file_format` and `load_translation_file` filters.
PHP translation files will be typically created by downloading language packs, but can also be generated by plugins.
See https://make.wordpress.org/core/2023/11/08/merging-performant-translations-into-core/ for more context.
Props dd32, swissspidy, flixos90, joemcgill, westonruter, akirk, SergeyBiryukov.
Fixes #59656.
Built from https://develop.svn.wordpress.org/trunk@57337
git-svn-id: http://core.svn.wordpress.org/trunk@56843 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-23 08:34:11 -05:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* I18N: WP_Translations class.
|
|
|
|
*
|
|
|
|
* @package WordPress
|
|
|
|
* @subpackage I18N
|
|
|
|
* @since 6.5.0
|
|
|
|
*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Class WP_Translations.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
|
|
|
* @property-read array<string, string> $headers
|
|
|
|
* @property-read array<string, string[]> $entries
|
|
|
|
*/
|
|
|
|
class WP_Translations {
|
|
|
|
/**
|
|
|
|
* Text domain.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $textdomain = 'default';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translation controller instance.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
* @var WP_Translation_Controller
|
|
|
|
*/
|
|
|
|
protected $controller;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Constructor.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
|
|
|
* @param WP_Translation_Controller $controller I18N controller.
|
|
|
|
* @param string $textdomain Optional. Text domain. Default 'default'.
|
|
|
|
*/
|
|
|
|
public function __construct( WP_Translation_Controller $controller, string $textdomain = 'default' ) {
|
|
|
|
$this->controller = $controller;
|
|
|
|
$this->textdomain = $textdomain;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Magic getter for backward compatibility.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
|
|
|
* @param string $name Property name.
|
|
|
|
* @return mixed
|
|
|
|
*/
|
|
|
|
public function __get( string $name ) {
|
|
|
|
if ( 'entries' === $name ) {
|
|
|
|
$entries = $this->controller->get_entries( $this->textdomain );
|
|
|
|
|
|
|
|
$result = array();
|
|
|
|
|
|
|
|
foreach ( $entries as $original => $translations ) {
|
|
|
|
$result[] = $this->make_entry( $original, $translations );
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( 'headers' === $name ) {
|
|
|
|
return $this->controller->get_headers( $this->textdomain );
|
|
|
|
}
|
|
|
|
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Builds a Translation_Entry from original string and translation strings.
|
|
|
|
*
|
|
|
|
* @see MO::make_entry()
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
2024-01-24 02:57:14 -05:00
|
|
|
* @param string $original Original string to translate from MO file. Might contain
|
|
|
|
* 0x04 as context separator or 0x00 as singular/plural separator.
|
I18N: Introduce a more performant localization library.
This introduces a more lightweight library for loading `.mo` translation files which offers increased speed and lower memory usage.
It also supports loading multiple locales at the same time, which makes locale switching faster too.
For plugins interacting with the `$l10n` global variable in core, a shim is added to retain backward compatibility with the existing `pomo` library.
In addition to that, this library supports translations contained in PHP files, avoiding a binary file format and leveraging OPCache if available.
If an `.mo` translation file has a corresponding `.l10n.php` file, the latter will be loaded instead.
This behavior can be adjusted using the new `translation_file_format` and `load_translation_file` filters.
PHP translation files will be typically created by downloading language packs, but can also be generated by plugins.
See https://make.wordpress.org/core/2023/11/08/merging-performant-translations-into-core/ for more context.
Props dd32, swissspidy, flixos90, joemcgill, westonruter, akirk, SergeyBiryukov.
Fixes #59656.
Built from https://develop.svn.wordpress.org/trunk@57337
git-svn-id: http://core.svn.wordpress.org/trunk@56843 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2024-01-23 08:34:11 -05:00
|
|
|
* @param string $translations Translation strings from MO file.
|
|
|
|
* @return Translation_Entry Entry instance.
|
|
|
|
*/
|
|
|
|
private function make_entry( $original, $translations ): Translation_Entry {
|
|
|
|
$entry = new Translation_Entry();
|
|
|
|
|
|
|
|
// Look for context, separated by \4.
|
|
|
|
$parts = explode( "\4", $original );
|
|
|
|
if ( isset( $parts[1] ) ) {
|
|
|
|
$original = $parts[1];
|
|
|
|
$entry->context = $parts[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Look for plural original.
|
|
|
|
$parts = explode( "\0", $original );
|
|
|
|
$entry->singular = $parts[0];
|
|
|
|
if ( isset( $parts[1] ) ) {
|
|
|
|
$entry->is_plural = true;
|
|
|
|
$entry->plural = $parts[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
$entry->translations = explode( "\0", $translations );
|
|
|
|
return $entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translates a plural string.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
|
|
|
* @param string|null $singular Singular string.
|
|
|
|
* @param string|null $plural Plural string.
|
|
|
|
* @param int|float $count Count. Should be an integer, but some plugins pass floats.
|
|
|
|
* @param string|null $context Context.
|
|
|
|
* @return string|null Translation if it exists, or the unchanged singular string.
|
|
|
|
*/
|
|
|
|
public function translate_plural( $singular, $plural, $count = 1, $context = '' ) {
|
|
|
|
if ( null === $singular || null === $plural ) {
|
|
|
|
return $singular;
|
|
|
|
}
|
|
|
|
|
|
|
|
$translation = $this->controller->translate_plural( array( $singular, $plural ), (int) $count, (string) $context, $this->textdomain );
|
|
|
|
if ( false !== $translation ) {
|
|
|
|
return $translation;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to the original with English grammar rules.
|
|
|
|
return ( 1 === $count ? $singular : $plural );
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Translates a singular string.
|
|
|
|
*
|
|
|
|
* @since 6.5.0
|
|
|
|
*
|
|
|
|
* @param string|null $singular Singular string.
|
|
|
|
* @param string|null $context Context.
|
|
|
|
* @return string|null Translation if it exists, or the unchanged singular string
|
|
|
|
*/
|
|
|
|
public function translate( $singular, $context = '' ) {
|
|
|
|
if ( null === $singular ) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
$translation = $this->controller->translate( $singular, (string) $context, $this->textdomain );
|
|
|
|
if ( false !== $translation ) {
|
|
|
|
return $translation;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fall back to the original.
|
|
|
|
return $singular;
|
|
|
|
}
|
|
|
|
}
|