mirror of
https://github.com/gosticks/wordpress-develop.git
synced 2026-08-11 20:30:23 +00:00
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. git-svn-id: https://develop.svn.wordpress.org/trunk@57337 602fd350-edb4-49c9-b593-d223f7449a82
This commit is contained in:
Binary file not shown.
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
return [
|
||||
'messages' =>
|
||||
[
|
||||
'original' => ['translation'],
|
||||
'contextoriginal with context' => ['translation with context'],
|
||||
'plural0' . "\0" . 'plural1' => ['translation0', 'translation1'],
|
||||
'contextplural0 with context' . "\0" . 'plural1 with context' => ['translation0 with context', 'translation1 with context'],
|
||||
],
|
||||
];
|
||||
@@ -0,0 +1,23 @@
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"PO-Revision-Date: 2016-01-05 18:45:32+1000\n"
|
||||
|
||||
msgid "original"
|
||||
msgstr "translation"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "original with context"
|
||||
msgstr "translation with context"
|
||||
|
||||
msgid "plural0"
|
||||
msgid_plural "plural1"
|
||||
msgstr[0] "translation0"
|
||||
msgstr[1] "translation1"
|
||||
|
||||
msgctxt "context"
|
||||
msgid "plural0 with context"
|
||||
msgid_plural "plural1 with context"
|
||||
msgstr[0] "translation0 with context"
|
||||
msgstr[1] "translation1 with context"
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
return ['project-id-version'=>'WordPress 2.6-bleeding','report-msgid-bugs-to'=>'wp-polyglots@lists.automattic.com','messages'=>['baba'=>'dyado','kuku
|
||||
ruku'=>'yes']];
|
||||
@@ -48,6 +48,9 @@ class Tests_L10n_LoadTextdomainJustInTime extends WP_UnitTestCase {
|
||||
|
||||
$wp_textdomain_registry = new WP_Textdomain_Registry();
|
||||
|
||||
unload_textdomain( 'internationalized-plugin' );
|
||||
unload_textdomain( 'internationalized-theme' );
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
|
||||
@@ -21,6 +21,11 @@ class Tests_L10n_wpLocaleSwitcher extends WP_UnitTestCase {
|
||||
*/
|
||||
protected static $user_id;
|
||||
|
||||
/**
|
||||
* @var WP_Locale_Switcher
|
||||
*/
|
||||
protected $orig_instance;
|
||||
|
||||
public static function wpSetUpBeforeClass( WP_UnitTest_Factory $factory ) {
|
||||
self::$user_id = $factory->user->create(
|
||||
array(
|
||||
@@ -42,7 +47,11 @@ class Tests_L10n_wpLocaleSwitcher extends WP_UnitTestCase {
|
||||
|
||||
$wp_textdomain_registry = new WP_Textdomain_Registry();
|
||||
|
||||
remove_filter( 'locale', array( $wp_locale_switcher, 'filter_locale' ) );
|
||||
$this->orig_instance = $wp_locale_switcher;
|
||||
|
||||
remove_all_filters( 'locale' );
|
||||
remove_all_filters( 'determine_locale' );
|
||||
|
||||
$wp_locale_switcher = new WP_Locale_Switcher();
|
||||
$wp_locale_switcher->init();
|
||||
}
|
||||
@@ -58,9 +67,13 @@ class Tests_L10n_wpLocaleSwitcher extends WP_UnitTestCase {
|
||||
// before resetting $wp_locale_switcher.
|
||||
restore_current_locale();
|
||||
|
||||
remove_filter( 'locale', array( $wp_locale_switcher, 'filter_locale' ) );
|
||||
$wp_locale_switcher = new WP_Locale_Switcher();
|
||||
$wp_locale_switcher->init();
|
||||
remove_all_filters( 'locale' );
|
||||
remove_all_filters( 'determine_locale' );
|
||||
|
||||
$wp_locale_switcher = $this->orig_instance;
|
||||
|
||||
unload_textdomain( 'internationalized-plugin' );
|
||||
unload_textdomain( 'custom-internationalized-theme' );
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,356 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @group l10n
|
||||
* @group i18n
|
||||
*/
|
||||
class WP_Translation_Controller_Tests extends WP_UnitTestCase {
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function tear_down() {
|
||||
remove_all_filters( 'translation_file_format' );
|
||||
unload_textdomain( 'wp-tests-domain' );
|
||||
unload_textdomain( 'internationalized-plugin' );
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
* @covers WP_Translation_Controller::get_entries
|
||||
* @covers WP_Translation_Controller::get_headers
|
||||
* @covers WP_Translation_Controller::normalize_header
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain() {
|
||||
global $l10n;
|
||||
|
||||
$loaded_before_load = is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
$load_successful = load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$loaded_after_load = is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$is_loaded = WP_Translation_Controller::instance()->is_textdomain_loaded( 'wp-tests-domain' );
|
||||
$headers = WP_Translation_Controller::instance()->get_headers( 'wp-tests-domain' );
|
||||
$entries = WP_Translation_Controller::instance()->get_entries( 'wp-tests-domain' );
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$loaded_after_unload = is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
$this->assertFalse( $loaded_before_load, 'Text domain was already loaded at beginning of the test' );
|
||||
$this->assertTrue( $load_successful, 'Text domain not successfully loaded' );
|
||||
$this->assertTrue( $loaded_after_load, 'Text domain is not considered loaded' );
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
$this->assertFalse( $loaded_after_unload, 'Text domain still considered loaded after unload' );
|
||||
$this->assertTrue( $is_loaded, 'Text domain not considered loaded' );
|
||||
$this->assertEqualSetsWithIndex(
|
||||
array(
|
||||
'Project-Id-Version' => 'WordPress 2.6-bleeding',
|
||||
'Report-Msgid-Bugs-To' => 'wp-polyglots@lists.automattic.com',
|
||||
),
|
||||
$headers,
|
||||
'Actual translation headers do not match expected ones'
|
||||
);
|
||||
$this->assertEqualSetsWithIndex(
|
||||
array(
|
||||
'baba' => 'dyado',
|
||||
"kuku\nruku" => 'yes',
|
||||
),
|
||||
$entries,
|
||||
'Actual translation entries do not match expected ones'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
* @covers WP_Translation_Controller::get_entries
|
||||
* @covers WP_Translation_Controller::get_headers
|
||||
* @covers WP_Translation_Controller::normalize_header
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_existing_override() {
|
||||
add_filter( 'override_load_textdomain', '__return_true' );
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$is_loaded_wp = is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
$is_loaded = WP_Translation_Controller::instance()->is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
remove_filter( 'override_load_textdomain', '__return_true' );
|
||||
|
||||
$this->assertFalse( $is_loaded_wp );
|
||||
$this->assertFalse( $is_loaded );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_php_files() {
|
||||
$load_php_successful = load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.l10n.php' );
|
||||
|
||||
$unload_php_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertTrue( $load_php_successful, 'PHP file not successfully loaded' );
|
||||
$this->assertTrue( $unload_php_successful );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_reads_php_files_if_filtered_format_is_unsupported() {
|
||||
add_filter(
|
||||
'translation_file_format',
|
||||
static function () {
|
||||
return 'unknown-format';
|
||||
}
|
||||
);
|
||||
|
||||
$load_mo_successful = load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$unload_mo_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$load_php_successful = load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.l10n.php' );
|
||||
|
||||
$unload_php_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertTrue( $load_mo_successful, 'MO file not successfully loaded' );
|
||||
$this->assertTrue( $unload_mo_successful );
|
||||
$this->assertTrue( $load_php_successful, 'PHP file not successfully loaded' );
|
||||
$this->assertTrue( $unload_php_successful );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_existing_translation_is_kept() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/context.mo' );
|
||||
|
||||
$mo = new MO();
|
||||
$mo->import_from_file( DIR_TESTDATA . '/pomo/context.mo' );
|
||||
$mo->merge_with( $l10n['wp-tests-domain'] );
|
||||
$l10n['wp-tests-domain'] = $mo;
|
||||
|
||||
$simple = __( 'baba', 'wp-tests-domain' );
|
||||
$context = _x( 'one dragon', 'not so dragon', 'wp-tests-domain' );
|
||||
|
||||
$this->assertSame( 'dyado', $simple );
|
||||
$this->assertSame( 'oney dragoney', $context );
|
||||
$this->assertInstanceOf( Translations::class, $l10n['wp-tests-domain'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_loads_existing_translation() {
|
||||
global $l10n;
|
||||
|
||||
$mo = new MO();
|
||||
$mo->import_from_file( DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
$l10n['wp-tests-domain'] = $mo;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/context.mo' );
|
||||
|
||||
$simple = __( 'baba', 'wp-tests-domain' );
|
||||
$context = _x( 'one dragon', 'not so dragon', 'wp-tests-domain' );
|
||||
|
||||
$this->assertSame( 'dyado', $simple );
|
||||
$this->assertSame( 'oney dragoney', $context );
|
||||
$this->assertInstanceOf( WP_Translations::class, $l10n['wp-tests-domain'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_loads_existing_translation_mo_files() {
|
||||
global $l10n;
|
||||
|
||||
add_filter(
|
||||
'translation_file_format',
|
||||
static function () {
|
||||
return 'mo';
|
||||
}
|
||||
);
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$mo = new MO();
|
||||
$mo->import_from_file( DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
$l10n['wp-tests-domain'] = $mo;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/context.mo' );
|
||||
|
||||
$simple = __( 'baba', 'wp-tests-domain' );
|
||||
$context = _x( 'one dragon', 'not so dragon', 'wp-tests-domain' );
|
||||
|
||||
$this->assertSame( 'dyado', $simple );
|
||||
$this->assertSame( 'oney dragoney', $context );
|
||||
$this->assertInstanceOf( WP_Translations::class, $l10n['wp-tests-domain'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_textdomain_loads_existing_translation_php_files() {
|
||||
global $l10n;
|
||||
|
||||
// Just to ensure the PHP files exist.
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/context.mo' );
|
||||
unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$mo = new MO();
|
||||
$mo->import_from_file( DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
$l10n['wp-tests-domain'] = $mo;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/context.mo' );
|
||||
|
||||
$simple = __( 'baba', 'wp-tests-domain' );
|
||||
$context = _x( 'one dragon', 'not so dragon', 'wp-tests-domain' );
|
||||
|
||||
$this->assertSame( 'dyado', $simple );
|
||||
$this->assertSame( 'oney dragoney', $context );
|
||||
$this->assertInstanceOf( WP_Translations::class, $l10n['wp-tests-domain'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::unload_textdomain
|
||||
* @covers WP_Translation_Controller::get_entries
|
||||
* @covers WP_Translation_Controller::get_headers
|
||||
* @covers WP_Translation_Controller::normalize_header
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_textdomain() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$loaded_after_unload = is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$is_loaded = WP_Translation_Controller::instance()->is_textdomain_loaded( 'wp-tests-domain' );
|
||||
$headers = WP_Translation_Controller::instance()->get_headers( 'wp-tests-domain' );
|
||||
$entries = WP_Translation_Controller::instance()->get_entries( 'wp-tests-domain' );
|
||||
|
||||
$this->assertNull( $compat_instance, 'Compat instance was not removed' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
$this->assertFalse( $loaded_after_unload, 'Text domain still considered loaded after unload' );
|
||||
$this->assertFalse( $is_loaded, 'Text domain still considered loaded' );
|
||||
$this->assertEmpty( $headers, 'Actual translation headers are not empty' );
|
||||
$this->assertEmpty( $entries, 'Actual translation entries are not empty' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::unload_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_textdomain_existing_override() {
|
||||
add_filter( 'override_unload_textdomain', '__return_true' );
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$is_loaded = WP_Translation_Controller::instance()->is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
remove_filter( 'override_unload_textdomain', '__return_true' );
|
||||
|
||||
$unload_successful_after = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$is_loaded_after = WP_Translation_Controller::instance()->is_textdomain_loaded( 'wp-tests-domain' );
|
||||
|
||||
$this->assertTrue( $unload_successful );
|
||||
$this->assertTrue( $is_loaded );
|
||||
$this->assertTrue( $unload_successful_after );
|
||||
$this->assertFalse( $is_loaded_after );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
* @covers ::unload_textdomain
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_switch_to_locale_translations_stay_loaded_default_textdomain() {
|
||||
switch_to_locale( 'es_ES' );
|
||||
|
||||
$actual = __( 'Invalid parameter.' );
|
||||
|
||||
$this->assertTrue( WP_Translation_Controller::instance()->is_textdomain_loaded() );
|
||||
$this->assertTrue( WP_Translation_Controller::instance()->is_textdomain_loaded( 'default', 'es_ES' ) );
|
||||
|
||||
restore_previous_locale();
|
||||
|
||||
$actual_2 = __( 'Invalid parameter.' );
|
||||
|
||||
$this->assertTrue( WP_Translation_Controller::instance()->is_textdomain_loaded( 'default', 'es_ES' ) );
|
||||
|
||||
$this->assertSame( 'Parámetro no válido. ', $actual );
|
||||
$this->assertSame( 'Invalid parameter.', $actual_2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load_textdomain
|
||||
* @covers ::unload_textdomain
|
||||
* @covers ::change_locale
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_switch_to_locale_translations_stay_loaded_custom_textdomain() {
|
||||
$this->assertSame( 'en_US', WP_Translation_Controller::instance()->get_locale() );
|
||||
|
||||
require_once DIR_TESTDATA . '/plugins/internationalized-plugin.php';
|
||||
|
||||
$before = i18n_plugin_test();
|
||||
|
||||
switch_to_locale( 'es_ES' );
|
||||
|
||||
$actual = i18n_plugin_test();
|
||||
|
||||
$this->assertSame( 'es_ES', WP_Translation_Controller::instance()->get_locale() );
|
||||
$this->assertTrue( WP_Translation_Controller::instance()->is_textdomain_loaded( 'internationalized-plugin', 'es_ES' ) );
|
||||
$this->assertTrue( WP_Translation_Controller::instance()->is_textdomain_loaded( 'default', 'es_ES' ) );
|
||||
$this->assertFalse( WP_Translation_Controller::instance()->is_textdomain_loaded( 'foo-bar', 'es_ES' ) );
|
||||
|
||||
restore_previous_locale();
|
||||
|
||||
$after = i18n_plugin_test();
|
||||
|
||||
$this->assertTrue( WP_Translation_Controller::instance()->is_textdomain_loaded( 'internationalized-plugin', 'es_ES' ) );
|
||||
|
||||
$this->assertSame( 'This is a dummy plugin', $before );
|
||||
$this->assertSame( 'Este es un plugin dummy', $actual );
|
||||
$this->assertSame( 'This is a dummy plugin', $after );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @coversDefaultClass WP_Translations
|
||||
* @group l10n
|
||||
* @group i18n
|
||||
*/
|
||||
class WP_Translations_Tests extends WP_UnitTestCase {
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function tear_down() {
|
||||
unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
parent::tear_down();
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__construct
|
||||
* @covers ::__get
|
||||
* @covers ::make_entry
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_entries() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$entries = $compat_instance ? $compat_instance->entries : array();
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
$this->assertEqualSets(
|
||||
array(
|
||||
new Translation_Entry(
|
||||
array(
|
||||
'singular' => 'baba',
|
||||
'translations' => array( 'dyado' ),
|
||||
)
|
||||
),
|
||||
new Translation_Entry(
|
||||
array(
|
||||
'singular' => "kuku\nruku",
|
||||
'translations' => array( 'yes' ),
|
||||
)
|
||||
),
|
||||
),
|
||||
$entries,
|
||||
'Actual translation entries do not match expected ones'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__get
|
||||
* @covers ::make_entry
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_entries_plural() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/plural.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$entries = $compat_instance ? $compat_instance->entries : array();
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
$this->assertEqualSets(
|
||||
array(
|
||||
new Translation_Entry(
|
||||
array(
|
||||
'singular' => 'one dragon',
|
||||
'plural' => '%d dragons',
|
||||
'translations' => array(
|
||||
'oney dragoney',
|
||||
'twoey dragoney',
|
||||
'manyey dragoney',
|
||||
'manyeyey dragoney',
|
||||
'manyeyeyey dragoney',
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
$entries,
|
||||
'Actual translation entries do not match expected ones'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers ::__get
|
||||
* @covers ::make_entry
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_entries_context() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/context.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$entries = $compat_instance ? $compat_instance->entries : array();
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
$this->assertEqualSets(
|
||||
array(
|
||||
new Translation_Entry(
|
||||
array(
|
||||
'context' => 'not so dragon',
|
||||
'singular' => 'one dragon',
|
||||
'translations' => array( 'oney dragoney' ),
|
||||
)
|
||||
),
|
||||
new Translation_Entry(
|
||||
array(
|
||||
'is_plural' => true,
|
||||
'singular' => 'one dragon',
|
||||
'plural' => '%d dragons',
|
||||
'context' => 'dragonland',
|
||||
'translations' => array(
|
||||
'oney dragoney',
|
||||
'twoey dragoney',
|
||||
'manyey dragoney',
|
||||
),
|
||||
)
|
||||
),
|
||||
),
|
||||
$entries,
|
||||
'Actual translation entries do not match expected ones'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__get
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_headers() {
|
||||
global $l10n;
|
||||
|
||||
$load_successful = load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$headers = $compat_instance ? $compat_instance->headers : array();
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertTrue( $load_successful, 'Text domain not successfully loaded' );
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
$this->assertEqualSetsWithIndex(
|
||||
array(
|
||||
'Project-Id-Version' => 'WordPress 2.6-bleeding',
|
||||
'Report-Msgid-Bugs-To' => 'wp-polyglots@lists.automattic.com',
|
||||
),
|
||||
$headers,
|
||||
'Actual translation headers do not match expected ones'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::__get
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_getter_unsupported_property() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance );
|
||||
|
||||
$this->assertNull( $compat_instance->foo );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::translate
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_translate() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$translation = $compat_instance ? $compat_instance->translate( 'baba' ) : false;
|
||||
$translation_missing = $compat_instance ? $compat_instance->translate( 'does not exist' ) : false;
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertSame( 'dyado', $translation, 'Actual translation does not match expected one' );
|
||||
$this->assertSame( 'does not exist', $translation_missing, 'Actual translation fallback does not match expected one' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::translate_plural
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_translate_plural() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/plural.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$translation_1 = $compat_instance ? $compat_instance->translate_plural( 'one dragon', '%d dragons', 1 ) : false;
|
||||
$translation_2 = $compat_instance ? $compat_instance->translate_plural( 'one dragon', '%d dragons', 2 ) : false;
|
||||
$translation_minus_8 = $compat_instance ? $compat_instance->translate_plural( 'one dragon', '%d dragons', -8 ) : false;
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertSame( 'oney dragoney', $translation_1, 'Actual translation does not match expected one' );
|
||||
$this->assertSame( 'twoey dragoney', $translation_2, 'Actual translation does not match expected one' );
|
||||
$this->assertSame( 'twoey dragoney', $translation_minus_8, 'Actual translation does not match expected one' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::translate_plural
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_translate_plural_missing() {
|
||||
global $l10n;
|
||||
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/plural.mo' );
|
||||
|
||||
$compat_instance = $l10n['wp-tests-domain'] ?? null;
|
||||
|
||||
$translation_1 = $compat_instance ? $compat_instance->translate_plural( '%d house', '%d houses', 1 ) : false;
|
||||
$translation_2 = $compat_instance ? $compat_instance->translate_plural( '%d car', '%d cars', 2 ) : false;
|
||||
|
||||
$unload_successful = unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertInstanceOf( WP_Translations::class, $compat_instance, 'No compat provider instance used' );
|
||||
$this->assertSame( '%d house', $translation_1, 'Actual translation fallback does not match expected one' );
|
||||
$this->assertSame( '%d cars', $translation_2, 'Actual plural translation fallback does not match expected one' );
|
||||
$this->assertTrue( $unload_successful, 'Text domain not successfully unloaded' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::translate
|
||||
* @covers ::translate_plural
|
||||
*
|
||||
* @ticket 41257
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_translate_invalid_edge_cases() {
|
||||
load_textdomain( 'wp-tests-domain', DIR_TESTDATA . '/pomo/simple.mo' );
|
||||
|
||||
// phpcs:disable WordPress.WP.I18n
|
||||
$null_string = __( null, 'wp-tests-domain' );
|
||||
$null_singular = _n( null, 'plural', 1, 'wp-tests-domain' );
|
||||
$null_plural = _n( 'singular', null, 1, 'wp-tests-domain' );
|
||||
$null_both = _n( null, null, 1, 'wp-tests-domain' );
|
||||
$null_context = _x( 'foo', null, 'wp-tests-domain' );
|
||||
$float_number = _n( '%d house', '%d houses', 7.5, 'wp-tests-domain' );
|
||||
// phpcs:enable WordPress.WP.I18n
|
||||
|
||||
unload_textdomain( 'wp-tests-domain' );
|
||||
|
||||
$this->assertNull( $null_string );
|
||||
$this->assertNull( $null_singular );
|
||||
$this->assertSame( 'singular', $null_plural );
|
||||
$this->assertNull( $null_both );
|
||||
$this->assertSame( 'foo', $null_context );
|
||||
$this->assertSame( '%d houses', $float_number );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,598 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @coversDefaultClass WP_Translation_Controller
|
||||
* @group l10n
|
||||
* @group i18n
|
||||
*/
|
||||
class WP_Translation_Controller_Convert_Tests extends WP_UnitTestCase {
|
||||
/**
|
||||
* @covers ::instance
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_instance() {
|
||||
$instance = WP_Translation_Controller::instance();
|
||||
$instance2 = WP_Translation_Controller::instance();
|
||||
|
||||
$this->assertSame( $instance, $instance2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function test_no_files_loaded_returns_false() {
|
||||
$instance = new WP_Translation_Controller();
|
||||
$this->assertFalse( $instance->translate( 'singular' ) );
|
||||
$this->assertFalse( $instance->translate_plural( array( 'plural0', 'plural1' ), 1 ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::unload
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_not_loaded() {
|
||||
$instance = new WP_Translation_Controller();
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertFalse( $instance->unload_textdomain( 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
* @covers ::unload
|
||||
* @covers ::is_textdomain_loaded
|
||||
* @covers ::translate
|
||||
* @covers ::locate_translation
|
||||
* @covers ::get_files
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_entire_textdomain() {
|
||||
$instance = new WP_Translation_Controller();
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertTrue( $instance->load_file( DIR_TESTDATA . '/l10n/example-simple.php', 'unittest' ) );
|
||||
$this->assertTrue( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
|
||||
$this->assertSame( 'translation', $instance->translate( 'original', '', 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $instance->unload_textdomain( 'unittest' ) );
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertFalse( $instance->translate( 'original', '', 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::unload
|
||||
* @covers WP_Translation_File::get_file
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_file_is_not_actually_loaded() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'unittest' ) );
|
||||
$this->assertFalse( $controller->unload_file( DIR_TESTDATA . '/l10n/simple.mo', 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertSame( 'translation', $controller->translate( 'original', '', 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::unload
|
||||
* @covers ::is_textdomain_loaded
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_specific_locale() {
|
||||
$instance = new WP_Translation_Controller();
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertTrue( $instance->load_file( DIR_TESTDATA . '/l10n/example-simple.php', 'unittest' ) );
|
||||
$this->assertTrue( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest', 'es_ES' ) );
|
||||
$this->assertTrue( $instance->load_file( DIR_TESTDATA . '/l10n/example-simple.php', 'unittest', 'es_ES' ) );
|
||||
$this->assertTrue( $instance->is_textdomain_loaded( 'unittest', 'es_ES' ) );
|
||||
|
||||
$this->assertSame( 'translation', $instance->translate( 'original', '', 'unittest' ) );
|
||||
$this->assertSame( 'translation', $instance->translate( 'original', '', 'unittest', 'es_ES' ) );
|
||||
|
||||
$this->assertTrue( $instance->unload_textdomain( 'unittest', $instance->get_locale() ) );
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertFalse( $instance->translate( 'original', '', 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $instance->is_textdomain_loaded( 'unittest', 'es_ES' ) );
|
||||
$this->assertTrue( $instance->unload_textdomain( 'unittest', 'es_ES' ) );
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest', 'es_ES' ) );
|
||||
$this->assertFalse( $instance->translate( 'original', '', 'unittest', 'es_ES' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_invalid_files
|
||||
*
|
||||
* @param string $type
|
||||
* @param string $file_contents
|
||||
* @param string|bool $expected_error
|
||||
* @return void
|
||||
*
|
||||
* @phpstan-param 'mo'|'php' $type
|
||||
*/
|
||||
public function test_invalid_files( string $type, string $file_contents, $expected_error = null ) {
|
||||
$file = $this->temp_filename();
|
||||
|
||||
$this->assertNotFalse( $file );
|
||||
|
||||
file_put_contents( $file, $file_contents );
|
||||
|
||||
$instance = WP_Translation_File::create( $file, $type );
|
||||
|
||||
$this->assertInstanceOf( WP_Translation_File::class, $instance );
|
||||
|
||||
// Not an error condition until it attempts to parse the file.
|
||||
$this->assertNull( $instance->error() );
|
||||
|
||||
// Trigger parsing.
|
||||
$instance->headers();
|
||||
|
||||
$this->assertNotNull( $instance->error() );
|
||||
|
||||
if ( null !== $expected_error ) {
|
||||
$this->assertSame( $expected_error, $instance->error() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{0: array{0: 'mo'|'php', 1: string|false, 2?: string}}
|
||||
*/
|
||||
public function data_invalid_files(): array {
|
||||
return array(
|
||||
array( 'php', '' ),
|
||||
array( 'php', '<?php // This is a php file without a payload' ),
|
||||
array( 'mo', '', 'Invalid data' ),
|
||||
array( 'mo', 'Random data in a file long enough to be a real header', 'Magic marker does not exist' ),
|
||||
array( 'mo', pack( 'V*', 0x950412de ), 'Invalid data' ),
|
||||
array( 'mo', pack( 'V*', 0x950412de ) . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'Unsupported revision' ),
|
||||
array( 'mo', pack( 'V*', 0x950412de, 0x0 ) . 'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA', 'Invalid data' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers WP_Translation_Controller::load
|
||||
* @covers WP_Translation_Controller::is_textdomain_loaded
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_non_existent_file() {
|
||||
$instance = new WP_Translation_Controller();
|
||||
|
||||
$this->assertFalse( $instance->load_file( DIR_TESTDATA . '/l10n/file-that-doesnt-exist.mo', 'unittest' ) );
|
||||
$this->assertFalse( $instance->is_textdomain_loaded( 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers WP_Translation_File::create
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_create_non_existent_file() {
|
||||
$this->assertFalse( WP_Translation_File::create( 'this-file-does-not-exist' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers WP_Translation_File::create
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_create_invalid_filetype() {
|
||||
$file = $this->temp_filename();
|
||||
$this->assertNotFalse( $file );
|
||||
file_put_contents( $file, '' );
|
||||
$this->assertFalse( WP_Translation_File::create( $file, 'invalid' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
* @covers ::is_textdomain_loaded
|
||||
* @covers ::translate
|
||||
* @covers ::translate_plural
|
||||
* @covers ::locate_translation
|
||||
* @covers ::get_files
|
||||
*
|
||||
* @dataProvider data_simple_example_files
|
||||
*
|
||||
* @param string $file
|
||||
* @return void
|
||||
*/
|
||||
public function test_simple_translation_files( string $file ) {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/' . $file, 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertFalse( $controller->is_textdomain_loaded( 'textdomain not loaded' ) );
|
||||
|
||||
$this->assertFalse( $controller->translate( "string that doesn't exist", '', 'unittest' ) );
|
||||
$this->assertFalse( $controller->translate( 'original', '', 'textdomain not loaded' ) );
|
||||
|
||||
$this->assertSame( 'translation', $controller->translate( 'original', '', 'unittest' ) );
|
||||
$this->assertSame( 'translation with context', $controller->translate( 'original with context', 'context', 'unittest' ) );
|
||||
|
||||
$this->assertSame( 'translation1', $controller->translate_plural( array( 'plural0', 'plural1' ), 0, '', 'unittest' ) );
|
||||
$this->assertSame( 'translation0', $controller->translate_plural( array( 'plural0', 'plural1' ), 1, '', 'unittest' ) );
|
||||
$this->assertSame( 'translation1', $controller->translate_plural( array( 'plural0', 'plural1' ), 2, '', 'unittest' ) );
|
||||
|
||||
$this->assertSame( 'translation1 with context', $controller->translate_plural( array( 'plural0 with context', 'plural1 with context' ), 0, 'context', 'unittest' ) );
|
||||
$this->assertSame( 'translation0 with context', $controller->translate_plural( array( 'plural0 with context', 'plural1 with context' ), 1, 'context', 'unittest' ) );
|
||||
$this->assertSame( 'translation1 with context', $controller->translate_plural( array( 'plural0 with context', 'plural1 with context' ), 2, 'context', 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array{0: string}>
|
||||
*/
|
||||
public function data_simple_example_files(): array {
|
||||
return array(
|
||||
array( 'example-simple.mo' ),
|
||||
array( 'example-simple.php' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
* @covers ::unload
|
||||
* @covers ::is_textdomain_loaded
|
||||
* @covers ::translate
|
||||
* @covers ::translate_plural
|
||||
* @covers ::locate_translation
|
||||
* @covers ::get_files
|
||||
* @covers WP_Translation_File::get_plural_form
|
||||
* @covers WP_Translation_File::make_plural_form_function
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_multiple_files() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'unittest' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/simple.mo', 'unittest' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/plural.mo', 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
|
||||
$this->assertFalse( $controller->translate( "string that doesn't exist", '', 'unittest' ) );
|
||||
$this->assertFalse( $controller->translate( 'original', '', 'textdomain not loaded' ) );
|
||||
|
||||
// From example-simple.mo
|
||||
|
||||
$this->assertSame( 'translation', $controller->translate( 'original', '', 'unittest' ) );
|
||||
$this->assertSame( 'translation with context', $controller->translate( 'original with context', 'context', 'unittest' ) );
|
||||
|
||||
$this->assertSame( 'translation1', $controller->translate_plural( array( 'plural0', 'plural1' ), 0, '', 'unittest' ) );
|
||||
$this->assertSame( 'translation0', $controller->translate_plural( array( 'plural0', 'plural1' ), 1, '', 'unittest' ) );
|
||||
$this->assertSame( 'translation1', $controller->translate_plural( array( 'plural0', 'plural1' ), 2, '', 'unittest' ) );
|
||||
|
||||
$this->assertSame( 'translation1 with context', $controller->translate_plural( array( 'plural0 with context', 'plural1 with context' ), 0, 'context', 'unittest' ) );
|
||||
$this->assertSame( 'translation0 with context', $controller->translate_plural( array( 'plural0 with context', 'plural1 with context' ), 1, 'context', 'unittest' ) );
|
||||
$this->assertSame( 'translation1 with context', $controller->translate_plural( array( 'plural0 with context', 'plural1 with context' ), 2, 'context', 'unittest' ) );
|
||||
|
||||
// From simple.mo.
|
||||
|
||||
$this->assertSame( 'dyado', $controller->translate( 'baba', '', 'unittest' ) );
|
||||
|
||||
// From plural.mo.
|
||||
|
||||
$this->assertSame( 'oney dragoney', $controller->translate_plural( array( 'one dragon', '%d dragons' ), 1, '', 'unittest' ), 'Actual translation does not match expected one' );
|
||||
$this->assertSame( 'twoey dragoney', $controller->translate_plural( array( 'one dragon', '%d dragons' ), 2, '', 'unittest' ), 'Actual translation does not match expected one' );
|
||||
$this->assertSame( 'twoey dragoney', $controller->translate_plural( array( 'one dragon', '%d dragons' ), -8, '', 'unittest' ), 'Actual translation does not match expected one' );
|
||||
|
||||
$this->assertTrue( $controller->unload_file( DIR_TESTDATA . '/l10n/simple.mo', 'unittest' ) );
|
||||
|
||||
$this->assertFalse( $controller->translate( 'baba', '', 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::set_locale
|
||||
* @covers ::get_locale
|
||||
* @covers ::load
|
||||
* @covers ::unload
|
||||
* @covers ::is_textdomain_loaded
|
||||
* @covers ::translate
|
||||
* @covers ::translate_plural
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_multiple_locales() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
|
||||
$this->assertSame( 'en_US', $controller->get_locale() );
|
||||
|
||||
$controller->set_locale( 'de_DE' );
|
||||
|
||||
$this->assertSame( 'de_DE', $controller->get_locale() );
|
||||
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'unittest' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/simple.mo', 'unittest', 'es_ES' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/plural.mo', 'unittest', 'en_US' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
|
||||
// From example-simple.mo
|
||||
|
||||
$this->assertSame( 'translation', $controller->translate( 'original', '', 'unittest' ), 'String should be translated in de_DE' );
|
||||
$this->assertFalse( $controller->translate( 'original', '', 'unittest', 'es_ES' ), 'String should not be translated in es_ES' );
|
||||
$this->assertFalse( $controller->translate( 'original', '', 'unittest', 'en_US' ), 'String should not be translated in en_US' );
|
||||
|
||||
// From simple.mo.
|
||||
|
||||
$this->assertFalse( $controller->translate( 'baba', '', 'unittest' ), 'String should not be translated in de_DE' );
|
||||
$this->assertSame( 'dyado', $controller->translate( 'baba', '', 'unittest', 'es_ES' ), 'String should be translated in es_ES' );
|
||||
$this->assertFalse( $controller->translate( 'baba', '', 'unittest', 'en_US' ), 'String should not be translated in en_US' );
|
||||
|
||||
$this->assertTrue( $controller->unload_file( DIR_TESTDATA . '/l10n/plural.mo', 'unittest', 'de_DE' ) );
|
||||
|
||||
$this->assertSame( 'oney dragoney', $controller->translate_plural( array( 'one dragon', '%d dragons' ), 1, '', 'unittest', 'en_US' ), 'String should be translated in en_US' );
|
||||
|
||||
$this->assertTrue( $controller->unload_file( DIR_TESTDATA . '/l10n/plural.mo', 'unittest', 'en_US' ) );
|
||||
|
||||
$this->assertFalse( $controller->translate_plural( array( 'one dragon', '%d dragons' ), 1, '', 'unittest', 'en_US' ), 'String should not be translated in en_US' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::unload
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_unload_with_multiple_locales() {
|
||||
$ginger_mo = new WP_Translation_Controller();
|
||||
|
||||
$ginger_mo->set_locale( 'de_DE' );
|
||||
|
||||
$this->assertSame( 'de_DE', $ginger_mo->get_locale() );
|
||||
$this->assertTrue( $ginger_mo->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'unittest' ) );
|
||||
$ginger_mo->set_locale( 'es_ES' );
|
||||
$this->assertTrue( $ginger_mo->load_file( DIR_TESTDATA . '/l10n/simple.mo', 'unittest' ) );
|
||||
$ginger_mo->set_locale( 'pl_PL' );
|
||||
$this->assertTrue( $ginger_mo->load_file( DIR_TESTDATA . '/l10n/plural.mo', 'unittest' ) );
|
||||
$this->assertSame( 'pl_PL', $ginger_mo->get_locale() );
|
||||
|
||||
$this->assertTrue( $ginger_mo->is_textdomain_loaded( 'unittest' ) );
|
||||
|
||||
$ginger_mo->set_locale( 'en_US' );
|
||||
$this->assertSame( 'en_US', $ginger_mo->get_locale() );
|
||||
|
||||
$this->assertFalse( $ginger_mo->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertTrue( $ginger_mo->is_textdomain_loaded( 'unittest', 'pl_PL' ) );
|
||||
$this->assertTrue( $ginger_mo->is_textdomain_loaded( 'unittest', 'es_ES' ) );
|
||||
$this->assertTrue( $ginger_mo->is_textdomain_loaded( 'unittest', 'de_DE' ) );
|
||||
|
||||
$this->assertTrue( $ginger_mo->unload_textdomain( 'unittest' ) );
|
||||
|
||||
$this->assertFalse( $ginger_mo->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertFalse( $ginger_mo->is_textdomain_loaded( 'unittest', 'pl_PL' ) );
|
||||
$this->assertFalse( $ginger_mo->is_textdomain_loaded( 'unittest', 'es_ES' ) );
|
||||
$this->assertFalse( $ginger_mo->is_textdomain_loaded( 'unittest', 'de_DE' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
* @covers ::locate_translation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_with_default_textdomain() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo' ) );
|
||||
$this->assertFalse( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
$this->assertSame( 'translation', $controller->translate( 'original' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_same_file_twice() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'unittest' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_file_is_already_loaded_for_different_textdomain() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'foo' ) );
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'bar' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'foo' ) );
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'bar' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::load
|
||||
* @covers ::unload
|
||||
* @covers ::is_textdomain_loaded
|
||||
* @covers ::translate
|
||||
* @covers ::translate_plural
|
||||
* @covers ::locate_translation
|
||||
* @covers ::get_files
|
||||
* @covers WP_Translation_File::get_plural_form
|
||||
* @covers WP_Translation_File::make_plural_form_function
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_load_no_plurals() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$this->assertTrue( $controller->load_file( DIR_TESTDATA . '/l10n/fa_IR.mo', 'unittest' ) );
|
||||
|
||||
$this->assertTrue( $controller->is_textdomain_loaded( 'unittest' ) );
|
||||
|
||||
$this->assertFalse( $controller->translate( "string that doesn't exist", '', 'unittest' ) );
|
||||
|
||||
$this->assertSame( 'رونوشتها فعال نشدند.', $controller->translate( 'Revisions not enabled.', '', 'unittest' ) );
|
||||
$this->assertSame( 'افزودن جدید', $controller->translate( 'Add New', 'file', 'unittest' ) );
|
||||
|
||||
$this->assertSame( '%s دیدگاه', $controller->translate_plural( array( '%s comment', '%s comments' ), 0, '', 'unittest' ) );
|
||||
$this->assertSame( '%s دیدگاه', $controller->translate_plural( array( '%s comment', '%s comments' ), 1, '', 'unittest' ) );
|
||||
$this->assertSame( '%s دیدگاه', $controller->translate_plural( array( '%s comment', '%s comments' ), 2, '', 'unittest' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get_headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_headers_no_loaded_translations() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$headers = $controller->get_headers();
|
||||
$this->assertEmpty( $headers );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get_headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_headers_with_default_textdomain() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo' );
|
||||
$headers = $controller->get_headers();
|
||||
$this->assertSame(
|
||||
array(
|
||||
'Po-Revision-Date' => '2016-01-05 18:45:32+1000',
|
||||
),
|
||||
$headers
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get_headers
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_headers_no_loaded_translations_for_domain() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$controller->load_file( DIR_TESTDATA . '/l10n/example-simple.mo', 'foo' );
|
||||
$headers = $controller->get_headers( 'bar' );
|
||||
$this->assertEmpty( $headers );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @covers ::get_entries
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_entries_no_loaded_translations() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$headers = $controller->get_entries();
|
||||
$this->assertEmpty( $headers );
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get_entries
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_entries_with_default_textdomain() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$controller->load_file( DIR_TESTDATA . '/l10n/simple.mo' );
|
||||
$headers = $controller->get_entries();
|
||||
$this->assertSame(
|
||||
array(
|
||||
'baba' => 'dyado',
|
||||
"kuku\nruku" => 'yes',
|
||||
),
|
||||
$headers
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers ::get_entries
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_get_entries_no_loaded_translations_for_domain() {
|
||||
$controller = new WP_Translation_Controller();
|
||||
$controller->load_file( DIR_TESTDATA . '/l10n/simple.mo', 'foo' );
|
||||
$headers = $controller->get_entries( 'bar' );
|
||||
$this->assertEmpty( $headers );
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider data_export_matrix
|
||||
*
|
||||
* @param string $source_file
|
||||
* @param string $destination_format
|
||||
* @return void
|
||||
*
|
||||
* @phpstan-param 'mo'|'php' $destination_format
|
||||
*/
|
||||
public function test_convert_format( string $source_file, string $destination_format ) {
|
||||
$destination_file = $this->temp_filename();
|
||||
|
||||
$this->assertNotFalse( $destination_file );
|
||||
|
||||
$source = WP_Translation_File::create( $source_file );
|
||||
|
||||
$this->assertInstanceOf( WP_Translation_File::class, $source );
|
||||
|
||||
$contents = WP_Translation_File::transform( $source_file, $destination_format );
|
||||
|
||||
$this->assertNotFalse( $contents );
|
||||
|
||||
file_put_contents( $destination_file, $contents );
|
||||
|
||||
$destination = WP_Translation_File::create( $destination_file, $destination_format );
|
||||
|
||||
$this->assertInstanceOf( WP_Translation_File::class, $destination );
|
||||
$this->assertNull( $destination->error() );
|
||||
|
||||
$this->assertTrue( filesize( $destination_file ) > 0 );
|
||||
|
||||
$destination_read = WP_Translation_File::create( $destination_file, $destination_format );
|
||||
|
||||
$this->assertInstanceOf( WP_Translation_File::class, $destination_read );
|
||||
$this->assertNull( $destination_read->error() );
|
||||
|
||||
$source_headers = $source->headers();
|
||||
$destination_headers = $destination_read->headers();
|
||||
|
||||
$this->assertEquals( $source_headers, $destination_headers );
|
||||
|
||||
foreach ( $source->entries() as $original => $translation ) {
|
||||
// Verify the translation is in the destination file
|
||||
$new_translation = $destination_read->translate( $original );
|
||||
$this->assertSame( $translation, $new_translation );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<array{0:string, 1: 'mo'|'php'}>
|
||||
*/
|
||||
public function data_export_matrix(): array {
|
||||
$formats = array( 'mo', 'php' );
|
||||
|
||||
$matrix = array();
|
||||
|
||||
foreach ( $formats as $input_format ) {
|
||||
foreach ( $formats as $output_format ) {
|
||||
$matrix[ "$input_format to $output_format" ] = array( DIR_TESTDATA . '/l10n/example-simple.' . $input_format, $output_format );
|
||||
}
|
||||
}
|
||||
|
||||
return $matrix;
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers WP_Translation_File::transform
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function test_convert_format_invalid_source() {
|
||||
$this->assertFalse( WP_Translation_File::transform( 'this-file-does-not-exist', 'invalid' ) );
|
||||
$this->assertFalse( WP_Translation_File::transform( DIR_TESTDATA . '/l10n/example-simple.mo', 'invalid' ) );
|
||||
$this->assertNotFalse( WP_Translation_File::transform( DIR_TESTDATA . '/l10n/example-simple.mo', 'php' ) );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user