Skip to content

Commit c8dd62d

Browse files
committed
Administration: Allow deferring individual translation updates
1 parent 7955a63 commit c8dd62d

File tree

6 files changed

+445
-54
lines changed

6 files changed

+445
-54
lines changed

src/wp-admin/includes/class-language-pack-upgrader.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,10 @@ public static function async_upgrade( $upgrader = false ) {
7070
foreach ( $language_updates as $key => $language_update ) {
7171
$update = ! empty( $language_update->autoupdate );
7272

73+
if ( wp_is_translation_update_deferred( $language_update ) ) {
74+
$update = false;
75+
}
76+
7377
/**
7478
* Filters whether to asynchronously update translation for core, a plugin, or a theme.
7579
*

src/wp-admin/includes/class-wp-automatic-updater.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,10 @@ public function should_update( $type, $item, $context ) {
229229
}
230230
} else {
231231
$update = ! empty( $item->autoupdate );
232+
233+
if ( wp_is_translation_update_deferred( $item ) ) {
234+
$update = false;
235+
}
232236
}
233237

234238
// If the `disable_autoupdate` flag is set, override any user-choice, but allow filters.

src/wp-admin/includes/update.php

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ function get_theme_updates() {
646646
/**
647647
* Gets the display name for a translation update.
648648
*
649-
* @since 6.7.0
649+
* @since 7.1.0
650650
*
651651
* @param object $update Translation update object.
652652
* @return string The translation update name.
@@ -718,7 +718,7 @@ function wp_get_translation_update_name( $update ) {
718718
/**
719719
* Gets the display language for a translation update.
720720
*
721-
* @since 6.7.0
721+
* @since 7.1.0
722722
*
723723
* @param string $locale Translation update locale.
724724
* @return string The translation update language.
@@ -741,11 +741,14 @@ function wp_get_translation_update_language( $locale ) {
741741
/**
742742
* Gets display data for available translation updates.
743743
*
744-
* @since 6.7.0
744+
* @since 7.1.0
745745
*
746746
* @return array[] {
747747
* An array of translation update display data.
748748
*
749+
* @type bool $checked Whether the translation update is selected for installation.
750+
* @type bool $deferred Whether the translation update has been deferred.
751+
* @type string $id Translation update identifier.
749752
* @type string $language Translation update language.
750753
* @type string $language_code Translation update locale.
751754
* @type string $name Translation update name.
@@ -755,12 +758,19 @@ function wp_get_translation_update_language( $locale ) {
755758
* }
756759
*/
757760
function wp_get_translation_update_data() {
758-
$translation_updates = array();
761+
$available_updates = wp_get_translation_updates();
762+
$deferred_translation_updates = wp_get_deferred_translation_updates( $available_updates );
763+
$translation_updates = array();
759764

760-
foreach ( wp_get_translation_updates() as $update ) {
761-
$language = isset( $update->language ) ? $update->language : '';
765+
foreach ( $available_updates as $update ) {
766+
$translation_update_id = wp_get_translation_update_id( $update );
767+
$language = isset( $update->language ) ? $update->language : '';
768+
$deferred = isset( $deferred_translation_updates[ $translation_update_id ] );
762769

763770
$translation_updates[] = array(
771+
'checked' => ! $deferred,
772+
'deferred' => $deferred,
773+
'id' => $translation_update_id,
764774
'language' => wp_get_translation_update_language( $language ),
765775
'language_code' => $language,
766776
'name' => wp_get_translation_update_name( $update ),

src/wp-admin/update-core.php

Lines changed: 118 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -835,24 +835,66 @@ function list_translation_updates() {
835835
?>
836836
</h2>
837837
<form method="post" action="<?php echo esc_url( $form_action ); ?>" name="upgrade-translations" class="upgrade">
838-
<p><?php _e( 'The following translation updates are available. Update Translations to install them.' ); ?></p>
839-
<ul class="ul-disc">
838+
<p><?php _e( 'The following translation updates are available. Leave any translation updates unchecked if you want to install them later, then click &#8220;Update Translations&#8221;.' ); ?></p>
839+
<p><?php _e( 'Translation updates you leave unchecked will remain available until you select them.' ); ?></p>
840+
<?php wp_nonce_field( 'upgrade-translations' ); ?>
841+
<p><input id="upgrade-translations" class="button" type="submit" value="<?php esc_attr_e( 'Update Translations' ); ?>" name="upgrade" /></p>
842+
<table class="widefat updates-table" id="update-translations-table">
843+
<thead>
844+
<tr>
845+
<td class="manage-column check-column"><input type="checkbox" id="translations-select-all" /></td>
846+
<td class="manage-column"><label for="translations-select-all"><?php _e( 'Select All' ); ?></label></td>
847+
</tr>
848+
</thead>
849+
850+
<tbody class="plugins">
840851
<?php foreach ( $translation_updates as $translation_update ) : ?>
841-
<li>
842-
<strong><?php echo esc_html( $translation_update['name'] ); ?></strong>:
843-
<?php
844-
printf(
845-
/* translators: 1: Language name or locale, 2: Version number. */
846-
__( '%1$s translation is available for version %2$s.' ),
847-
esc_html( $translation_update['language'] ),
848-
esc_html( $translation_update['version'] )
849-
);
850-
?>
851-
</li>
852+
<?php $checkbox_id = 'checkbox_' . md5( $translation_update['id'] ); ?>
853+
<tr>
854+
<td class="check-column">
855+
<input type="hidden" name="translations[]" value="<?php echo esc_attr( $translation_update['id'] ); ?>" />
856+
<input type="checkbox" name="checked[]" id="<?php echo esc_attr( $checkbox_id ); ?>" value="<?php echo esc_attr( $translation_update['id'] ); ?>" <?php checked( $translation_update['checked'] ); ?> />
857+
<label for="<?php echo esc_attr( $checkbox_id ); ?>">
858+
<span class="screen-reader-text">
859+
<?php
860+
printf(
861+
/* translators: 1: Project name, 2: Language name or locale. */
862+
esc_html__( 'Select the translation update for %1$s in %2$s' ),
863+
esc_html( $translation_update['name'] ),
864+
esc_html( $translation_update['language'] )
865+
);
866+
?>
867+
</span>
868+
</label>
869+
</td>
870+
<td class="plugin-title"><p>
871+
<strong><?php echo esc_html( $translation_update['name'] ); ?></strong>
872+
<?php
873+
printf(
874+
/* translators: 1: Language name or locale, 2: Version number. */
875+
esc_html__( '%1$s translation is available for version %2$s.' ),
876+
esc_html( $translation_update['language'] ),
877+
esc_html( $translation_update['version'] )
878+
);
879+
880+
if ( $translation_update['deferred'] ) {
881+
echo ' ';
882+
esc_html_e( 'This translation update will remain available until you select it.' );
883+
}
884+
?>
885+
</p></td>
886+
</tr>
852887
<?php endforeach; ?>
853-
</ul>
854-
<?php wp_nonce_field( 'upgrade-translations' ); ?>
855-
<p><input class="button" type="submit" value="<?php esc_attr_e( 'Update Translations' ); ?>" name="upgrade" /></p>
888+
</tbody>
889+
890+
<tfoot>
891+
<tr>
892+
<td class="manage-column check-column"><input type="checkbox" id="translations-select-all-2" /></td>
893+
<td class="manage-column"><label for="translations-select-all-2"><?php _e( 'Select All' ); ?></label></td>
894+
</tr>
895+
</tfoot>
896+
</table>
897+
<p><input id="upgrade-translations-2" class="button" type="submit" value="<?php esc_attr_e( 'Update Translations' ); ?>" name="upgrade" /></p>
856898
</form>
857899
<?php
858900
}
@@ -1026,7 +1068,7 @@ function do_undismiss_core_update() {
10261068
$updates_howto .= '<p>' . __( '<strong>Themes and Plugins</strong> &mdash; To update individual themes or plugins from this screen, use the checkboxes to make your selection, then <strong>click on the appropriate &#8220;Update&#8221; button</strong>. To update all of your themes or plugins at once, you can check the box at the top of the section to select all before clicking the update button.' ) . '</p>';
10271069

10281070
if ( 'en_US' !== get_locale() ) {
1029-
$updates_howto .= '<p>' . __( '<strong>Translations</strong> &mdash; The files translating WordPress into your language are updated for you whenever any other updates occur. But if these files are out of date, you can <strong>click the &#8220;Update Translations&#8221;</strong> button.' ) . '</p>';
1071+
$updates_howto .= '<p>' . __( '<strong>Translations</strong> &mdash; Translation updates are selected for installation by default. Leave any translation updates unchecked if you want to install them later, then <strong>click the &#8220;Update Translations&#8221;</strong> button. Translation updates you leave unchecked will remain available until you select them.' ) . '</p>';
10301072
}
10311073

10321074
get_current_screen()->add_help_tab(
@@ -1116,6 +1158,15 @@ function do_undismiss_core_update() {
11161158
}
11171159
}
11181160

1161+
if ( isset( $_GET['translation_updates'] ) && 'deferred' === $_GET['translation_updates'] ) {
1162+
wp_admin_notice(
1163+
__( 'The unchecked translation updates will remain available until you select them.' ),
1164+
array(
1165+
'type' => 'success',
1166+
)
1167+
);
1168+
}
1169+
11191170
$last_update_check = false;
11201171
$current = get_site_transient( 'update_core' );
11211172

@@ -1299,6 +1350,55 @@ function do_undismiss_core_update() {
12991350

13001351
check_admin_referer( 'upgrade-translations' );
13011352

1353+
if ( empty( $_POST['translations'] ) ) {
1354+
wp_redirect( self_admin_url( 'update-core.php' ) );
1355+
exit;
1356+
}
1357+
1358+
$translation_updates = wp_get_translation_updates_by_id();
1359+
1360+
$translation_update_ids = array_unique(
1361+
array_map(
1362+
'sanitize_text_field',
1363+
wp_unslash( (array) $_POST['translations'] )
1364+
)
1365+
);
1366+
1367+
$translation_updates = array_intersect_key( $translation_updates, array_flip( $translation_update_ids ) );
1368+
1369+
if ( empty( $translation_updates ) ) {
1370+
wp_redirect( self_admin_url( 'update-core.php' ) );
1371+
exit;
1372+
}
1373+
1374+
$selected_translation_updates = array();
1375+
1376+
if ( ! empty( $_POST['checked'] ) ) {
1377+
$selected_translation_update_ids = array_unique(
1378+
array_map(
1379+
'sanitize_text_field',
1380+
wp_unslash( (array) $_POST['checked'] )
1381+
)
1382+
);
1383+
1384+
$selected_translation_updates = array_intersect_key( $translation_updates, array_flip( $selected_translation_update_ids ) );
1385+
}
1386+
1387+
$current_translation_updates = wp_get_translation_updates_by_id();
1388+
$deferred_translation_updates = array_intersect_key(
1389+
$current_translation_updates,
1390+
wp_get_deferred_translation_updates( $current_translation_updates )
1391+
);
1392+
$deferred_translation_updates = array_diff_key( $deferred_translation_updates, $translation_updates );
1393+
$deferred_translation_updates += array_diff_key( $translation_updates, $selected_translation_updates );
1394+
1395+
wp_set_deferred_translation_updates( $deferred_translation_updates );
1396+
1397+
if ( empty( $selected_translation_updates ) ) {
1398+
wp_redirect( add_query_arg( 'translation_updates', 'deferred', self_admin_url( 'update-core.php' ) ) );
1399+
exit;
1400+
}
1401+
13021402
require_once ABSPATH . 'wp-admin/admin-header.php';
13031403
require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
13041404

@@ -1308,7 +1408,7 @@ function do_undismiss_core_update() {
13081408
$context = WP_LANG_DIR;
13091409

13101410
$upgrader = new Language_Pack_Upgrader( new Language_Pack_Upgrader_Skin( compact( 'url', 'nonce', 'title', 'context' ) ) );
1311-
$result = $upgrader->bulk_upgrade();
1411+
$result = $upgrader->bulk_upgrade( array_values( $selected_translation_updates ) );
13121412

13131413
wp_localize_script(
13141414
'updates',

src/wp-includes/update.php

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -920,6 +920,144 @@ function wp_get_translation_updates() {
920920
return $updates;
921921
}
922922

923+
/**
924+
* Gets a stable identifier for a translation update.
925+
*
926+
* @since 7.1.0
927+
*
928+
* @param array|object $update Translation update data.
929+
* @return string Translation update identifier.
930+
*/
931+
function wp_get_translation_update_id( $update ) {
932+
$update = (object) $update;
933+
934+
return md5(
935+
wp_json_encode(
936+
array(
937+
'type' => $update->type ?? '',
938+
'slug' => $update->slug ?? '',
939+
'language' => $update->language ?? '',
940+
'version' => $update->version ?? '',
941+
)
942+
)
943+
);
944+
}
945+
946+
/**
947+
* Gets translation updates keyed by their stable identifiers.
948+
*
949+
* @since 7.1.0
950+
*
951+
* @param object[]|null $updates Optional. Translation update objects. Default null.
952+
* @return object[] Translation updates keyed by identifier.
953+
*/
954+
function wp_get_translation_updates_by_id( $updates = null ) {
955+
if ( null === $updates ) {
956+
$updates = wp_get_translation_updates();
957+
}
958+
959+
$translation_updates = array();
960+
961+
foreach ( (array) $updates as $update ) {
962+
$translation_updates[ wp_get_translation_update_id( $update ) ] = (object) $update;
963+
}
964+
965+
return $translation_updates;
966+
}
967+
968+
/**
969+
* Gets deferred translation updates.
970+
*
971+
* Deferred translation updates remain available for later installation and are
972+
* skipped by background translation updates until they are selected again.
973+
*
974+
* @since 7.1.0
975+
*
976+
* @param object[]|null $updates Optional. Translation update objects used to filter deferred updates
977+
* to currently available updates. Default null.
978+
* @return array[] Deferred translation updates keyed by identifier.
979+
*/
980+
function wp_get_deferred_translation_updates( $updates = null ) {
981+
$stored_updates = get_site_option( 'deferred_translation_updates', array() );
982+
983+
if ( ! is_array( $stored_updates ) ) {
984+
return array();
985+
}
986+
987+
$deferred_updates = array();
988+
989+
foreach ( $stored_updates as $stored_update ) {
990+
if ( ! is_array( $stored_update ) ) {
991+
continue;
992+
}
993+
994+
$stored_update = (object) array(
995+
'type' => $stored_update['type'] ?? '',
996+
'slug' => $stored_update['slug'] ?? '',
997+
'language' => $stored_update['language'] ?? '',
998+
'version' => $stored_update['version'] ?? '',
999+
);
1000+
1001+
$deferred_updates[ wp_get_translation_update_id( $stored_update ) ] = (array) $stored_update;
1002+
}
1003+
1004+
if ( null !== $updates ) {
1005+
$deferred_updates = array_intersect_key( $deferred_updates, wp_get_translation_updates_by_id( $updates ) );
1006+
}
1007+
1008+
return $deferred_updates;
1009+
}
1010+
1011+
/**
1012+
* Determines whether a translation update has been deferred.
1013+
*
1014+
* @since 7.1.0
1015+
*
1016+
* @param array|object $update Translation update data.
1017+
* @param array[]|null $deferred_updates Optional. Deferred translation updates keyed by identifier.
1018+
* Default null.
1019+
* @return bool Whether the translation update has been deferred.
1020+
*/
1021+
function wp_is_translation_update_deferred( $update, $deferred_updates = null ) {
1022+
if ( null === $deferred_updates ) {
1023+
$deferred_updates = wp_get_deferred_translation_updates();
1024+
}
1025+
1026+
return isset( $deferred_updates[ wp_get_translation_update_id( $update ) ] );
1027+
}
1028+
1029+
/**
1030+
* Stores deferred translation updates.
1031+
*
1032+
* @since 7.1.0
1033+
*
1034+
* @param object[]|array[] $updates Translation updates to defer.
1035+
* @return void
1036+
*/
1037+
function wp_set_deferred_translation_updates( $updates ) {
1038+
$deferred_updates = array();
1039+
1040+
foreach ( (array) $updates as $update ) {
1041+
$update = (object) $update;
1042+
1043+
$translation_update = array(
1044+
'type' => $update->type ?? '',
1045+
'slug' => $update->slug ?? '',
1046+
'language' => $update->language ?? '',
1047+
'version' => $update->version ?? '',
1048+
);
1049+
1050+
$deferred_updates[ wp_get_translation_update_id( $translation_update ) ] = $translation_update;
1051+
}
1052+
1053+
if ( empty( $deferred_updates ) ) {
1054+
delete_site_option( 'deferred_translation_updates' );
1055+
return;
1056+
}
1057+
1058+
update_site_option( 'deferred_translation_updates', $deferred_updates );
1059+
}
1060+
9231061
/**
9241062
* Collects counts and UI strings for available updates.
9251063
*

0 commit comments

Comments
 (0)