Skip to content

Commit

Permalink
Merge pull request #198 from WordPress/event-strings
Browse files Browse the repository at this point in the history
Show the strings of a translation event
  • Loading branch information
akirk authored Apr 30, 2024
2 parents 7624474 + 5f127d8 commit 5910bf5
Show file tree
Hide file tree
Showing 11 changed files with 486 additions and 11 deletions.
8 changes: 8 additions & 0 deletions assets/css/translation-events.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
.event-details-stats table {
margin: 1rem;
}

.event-details-stats table {
width: 100%;
table-layout: fixed;
Expand Down Expand Up @@ -348,13 +349,19 @@ a.event-page-edit-link:hover {
border-bottom: var(--gp-color-btn-primary-bg) thin solid;
text-decoration: none;
}

ul.text-snippets {
padding: 0;
margin-left: 160px;
}
.first-time-contributor-tada::after {
content: ' 🎉';
}

ul#translation-links li {
margin-bottom: .5em;
}

.icons li .name {
display: none;
}
Expand All @@ -365,6 +372,7 @@ ul.text-snippets {
cursor: pointer;
display: inline-block;
}

/* show the event-details-right below instead of on the right on mobile */
@media (max-width: 768px) {

Expand Down
1 change: 1 addition & 0 deletions autoload.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require_once __DIR__ . '/includes/routes/event/details.php';
require_once __DIR__ . '/includes/routes/event/edit.php';
require_once __DIR__ . '/includes/routes/event/list.php';
require_once __DIR__ . '/includes/routes/event/translations.php';
require_once __DIR__ . '/includes/routes/user/attend-event.php';
require_once __DIR__ . '/includes/routes/user/host-event.php';
require_once __DIR__ . '/includes/routes/user/my-events.php';
Expand Down
178 changes: 178 additions & 0 deletions includes/routes/event/translations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
<?php

namespace Wporg\TranslationEvents\Routes\Event;

use GP;
use GP_Locales;
use GP_Original;
use Translation_Entry;
use Wporg\TranslationEvents\Routes\Route;
use Wporg\TranslationEvents\Translation_Events;
use Wporg\TranslationEvents\Event\Event_Repository_Interface;

/**
* Displays the event details page.
*/
class Translations_Route extends Route {
private Event_Repository_Interface $event_repository;

public function __construct() {
parent::__construct();
$this->event_repository = Translation_Events::get_event_repository();
}

public function handle( string $event_slug, string $locale, string $status = 'any' ): void {
$user = wp_get_current_user();
$event = get_page_by_path( $event_slug, OBJECT, Translation_Events::CPT );
if ( ! $event ) {
$this->die_with_404();
}
$event = $this->event_repository->get_event( $event->ID );
if ( ! $event ) {
$this->die_with_404();
}

global $wpdb, $gp_table_prefix;

// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery
// phpcs:disable WordPress.DB.DirectDatabaseQuery.NoCaching
$translation_sets = $wpdb->get_results(
$wpdb->prepare(
"
SELECT DISTINCT ts.id as translation_set_id, ts.name, o.project_id as project_id
FROM {$gp_table_prefix}event_actions ea
JOIN {$gp_table_prefix}originals o ON ea.original_id = o.id
JOIN {$gp_table_prefix}translation_sets ts ON o.project_id = ts.project_id AND ea.locale = ts.locale
WHERE ea.event_id = %d
AND ea.locale = %s
",
$event->id(),
$locale
)
);
$projects = array();
$translations = array();
$locale = GP_Locales::by_slug( $locale );
foreach ( $translation_sets as $ts ) {
$projects[ $ts->translation_set_id ] = GP::$project->get( $ts->project_id );

}
gp_tmpl_load( 'event-translations-header', get_defined_vars(), $this->template_path );

foreach ( $translation_sets as $ts ) {
$rows = $wpdb->get_results(
$wpdb->prepare(
"
SELECT
t.*,
o.*,
t.id as id,
o.id as original_id,
t.status as translation_status,
o.status as original_status,
t.date_added as translation_added,
o.date_added as original_added
FROM {$gp_table_prefix}event_actions ea
JOIN {$gp_table_prefix}originals o ON ea.original_id = o.id
JOIN {$gp_table_prefix}translations t ON t.original_id = ea.original_id
WHERE ea.event_id = %d
AND t.translation_set_id = %d
AND t.user_id = ea.user_id
AND t.status LIKE %s
",
$event->id(),
$ts->translation_set_id,
trim( $status, '/' ) === 'waiting' ? 'waiting' : '%'
)
);
// phpcs:enable
if ( empty( $rows ) ) {
echo '<style>li#translations_link_', esc_html( $ts->translation_set_id ), ' { display: none; }</style>';
continue;
}
$translations = array();
$project = $projects[ $ts->translation_set_id ];
$translation_set = GP::$translation_set->get( $ts->translation_set_id );
$filters = array();
$sort = array();
$glossary = GP::$glossary->get( $project->id, $locale );
$page = 1;
$per_page = 10000;
$total_translations_count = 0;
$text_direction = 'ltr';
$locale_slug = $translation_set->locale;
$translation_set_slug = $translation_set->slug;
$word_count_type = $locale->word_count_type;
$can_edit = $this->can( 'edit', 'translation-set', $translation_set->id );
$can_write = $this->can( 'write', 'project', $project->id );
$can_approve = $this->can( 'approve', 'translation-set', $translation_set->id );
$can_import_current = $can_approve;
$can_import_waiting = $can_approve || $this->can( 'import-waiting', 'translation-set', $translation_set->id );
$url = gp_url_project( $project, gp_url_join( $translation_set->locale, $translation_set->slug ) );
$set_priority_url = gp_url( '/originals/%original-id%/set_priority' );
$discard_warning_url = gp_url_project( $project, gp_url_join( $translation_set->locale, $translation_set->slug, '-discard-warning' ) );
$set_status_url = gp_url_project( $project, gp_url_join( $translation_set->locale, $translation_set->slug, '-set-status' ) );
$bulk_action = gp_url_join( $url, '-bulk' );

$editor_options[ $translation_set->id ] = compact( 'can_approve', 'can_write', 'url', 'discard_warning_url', 'set_priority_url', 'set_status_url', 'word_count_type' );

foreach ( (array) $rows as $row ) {
$row->user = null;
$row->user_last_modified = null;

if ( $row->user_id ) {
$user = get_userdata( $row->user_id );
if ( $user ) {
$row->user = (object) array(
'ID' => $user->ID,
'user_login' => $user->user_login,
'display_name' => $user->display_name,
'user_nicename' => $user->user_nicename,
);
}
}

if ( $row->user_id_last_modified ) {
$user = get_userdata( $row->user_id_last_modified );
if ( $user ) {
$row->user_last_modified = (object) array(
'ID' => $user->ID,
'user_login' => $user->user_login,
'display_name' => $user->display_name,
'user_nicename' => $user->user_nicename,
);
}
}

$row->translations = array();
for ( $i = 0; $i < $locale->nplurals; $i++ ) {
$row->translations[] = $row->{'translation_' . $i};
}
$row->references = $row->references ? preg_split( '/\s+/', $row->references, -1, PREG_SPLIT_NO_EMPTY ) : array();
$row->extracted_comments = $row->comment;
$row->warnings = $row->warnings ? maybe_unserialize( $row->warnings ) : null;
unset( $row->comment );

// Reduce range by one since we're starting at 0, see GH#516.
foreach ( range( 0, 5 ) as $i ) {
$member = "translation_$i";
unset( $row->$member );
}

$row->row_id = $row->original_id . ( $row->id ? "-$row->id" : '' );

if ( '0' !== $row->priority ) {
$row->flags = array(
'gp-priority: ' . GP_Original::$priorities[ $row->priority ],
);
}

$translations[ $row->row_id ] = new Translation_Entry( (array) $row );
}
gp_tmpl_load( 'translations', get_defined_vars(), $this->template_path );
}

gp_tmpl_load( 'event-translations-footer', get_defined_vars(), $this->template_path );
}
}
16 changes: 13 additions & 3 deletions includes/stats/stats-calculator.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
class Stats_Row {
public int $created;
public int $reviewed;
public int $waiting;
public int $users;
public ?GP_Locale $language = null;

public function __construct( $created, $reviewed, $users, ?GP_Locale $language = null ) {
public function __construct( $created, $reviewed, $waiting, $users, ?GP_Locale $language = null ) {
$this->created = $created;
$this->reviewed = $reviewed;
$this->waiting = $waiting;
$this->users = $users;
$this->language = $language;
}
Expand Down Expand Up @@ -103,8 +105,10 @@ public function for_event( int $event_id ): Event_Stats {
select locale,
sum(action = 'create') as created,
count(*) as total,
count(distinct user_id) as users
from {$gp_table_prefix}event_actions
sum(t.status = 'waiting') as waiting,
count(distinct ea.user_id) as users
from {$gp_table_prefix}event_actions ea
left join {$gp_table_prefix}translations t ON ea.original_id = t.original_id and ea.user_id = t.user_id
where event_id = %d
group by locale with rollup
",
Expand All @@ -130,9 +134,15 @@ public function for_event( int $event_id ): Event_Stats {
$lang = null;
}

if ( is_null( $row->waiting ) ) {
// The corresponding translations are missing. Could be a unit test or data corruption.
$row->waiting = 0;
}

$stats_row = new Stats_Row(
$row->created,
$row->total - $row->created,
$row->waiting,
$row->users,
$lang
);
Expand Down
4 changes: 4 additions & 0 deletions includes/urls.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public static function event_details_absolute( int $event_id ): string {
return get_site_url() . gp_url( wp_make_link_relative( $permalink ) );
}

public static function event_translations( int $event_id, string $locale, string $status = '' ): string {
return gp_url_join( self::event_details( $event_id ), 'translations', $locale, $status );
}

public static function event_edit( int $event_id ): string {
return gp_url( '/events/edit/' . $event_id );
}
Expand Down
36 changes: 36 additions & 0 deletions templates/event-translations-footer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
</div>
<div class="clear"></div>
<script type="text/javascript">
jQuery( function($) {
var hooks_installed = {};
var current_event_translations_table = false;
<?php
foreach ( $editor_options as $translation_set_id => $options ) {
?>
$('#translations_<?php echo esc_html( $translation_set_id ); ?>' ).click( set_translation_table_<?php echo esc_html( $translation_set_id ); ?> );
$('#translations_<?php echo esc_html( $translation_set_id ); ?>' ).mousemove( function() {
if ( ! $( '#translations', this ).length ) {
set_translation_table_<?php echo esc_html( $translation_set_id ); ?>();
}
});
function set_translation_table_<?php echo esc_html( $translation_set_id ); ?>() {
if ( current_event_translations_table === <?php echo esc_html( $translation_set_id ); ?> ) {
return;
}
current_event_translations_table = <?php echo esc_html( $translation_set_id ); ?>;
$gp_editor_options = <?php echo wp_json_encode( $options ); ?>;
$( '#translations' ).attr( 'id', null );
$( '#translations_<?php echo esc_html( $translation_set_id ); ?> table' ).attr( 'id', 'translations' );
$gp.editor.table = $( '#translations' );
if ( typeof hooks_installed[<?php echo esc_html( $translation_set_id ); ?>] === 'undefined' ) {
$gp.editor.install_hooks();
hooks_installed[<?php echo esc_html( $translation_set_id ); ?>] = true;
}
$gp_translation_helpers_editor = $gp_translation_helpers_editor_<?php echo esc_html( $translation_set_id ); ?>;
}
<?php } ?>
} );
</script>
<?php
gp_enqueue_script( 'wporg-translate-editor' );
gp_tmpl_footer(); ?>
63 changes: 63 additions & 0 deletions templates/event-translations-header.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
<?php

namespace Wporg\TranslationEvents;

use GP;
use Wporg\TranslationEvents\Event\Event;

/** @var Event $event */

/* translators: %s: Event title. */
gp_title( sprintf( __( 'Translation Events - %s' ), esc_html( $event->title() ) ) );
gp_breadcrumb_translation_events( array( '<a href="' . esc_url( Urls::event_details( $event->id() ) ) . '">' . esc_html( $event->title() ) . '</a>', __( 'Translations', 'glotpress' ), $locale->english_name ) );
gp_enqueue_scripts( array( 'gp-editor', 'gp-translations-page' ) );
wp_localize_script(
'gp-translations-page',
'$gp_translations_options',
array(
'sort' => __( 'Sort', 'glotpress' ),
'filter' => __( 'Filter', 'glotpress' ),
)
);

gp_tmpl_header();
?>

<div class="event-list-top-bar">
<h2 class="event-page-title">
<?php echo esc_html( $event->title() ); ?>
<?php if ( isset( $event ) && 'draft' === $event->status() ) : ?>
<span class="event-label-draft"><?php echo esc_html( $event->status() ); ?></span>
<?php endif; ?>
</h2>
</div>
<div class="event-page-wrapper">
<h4>
<?php
echo esc_html(
sprintf(
// Translators: %s is the locale name.
__( 'Translations to %s', 'glotpress' ),
$locale->english_name
)
);
?>
</h4>
<ul id="translation-links">
<?php foreach ( $translation_sets as $translation_set ) : ?>
<li id="translations_link_<?php echo esc_attr( $translation_set->translation_set_id ); ?>"><a href="#translations_<?php echo esc_attr( $translation_set->translation_set_id ); ?>"><?php echo esc_html( gp_project_names_from_root( $projects[ $translation_set->translation_set_id ] ) ); ?></a></li>
<?php endforeach; ?>
</ul>

<?php
if ( trim( $status, '/' ) !== 'waiting' ) {
?>
<a href="<?php echo esc_url( Urls::event_translations( $event->id(), $locale->slug, 'waiting' ) ); ?>"><?php esc_html_e( 'Show only waiting translations', 'glotpress' ); ?></a>
<?php
} else {
?>
<a href="<?php echo esc_url( Urls::event_translations( $event->id(), $locale->slug ) ); ?>"><?php esc_html_e( 'Show all contributed translations', 'glotpress' ); ?></a>
<?php
}
?>
<hr>
Loading

0 comments on commit 5910bf5

Please sign in to comment.