Skip to content

Commit

Permalink
Add Pontoon links to QA views, improve accesskeys view (#884)
Browse files Browse the repository at this point in the history
* Add edit link to variables view
* Add edit link to Empty strings
* Improve accesskeys view
  • Loading branch information
flodolo committed Sep 18, 2017
1 parent 219f82a commit 48d9039
Show file tree
Hide file tree
Showing 11 changed files with 281 additions and 119 deletions.
10 changes: 8 additions & 2 deletions app/classes/Transvision/ShowResults.php
Expand Up @@ -240,15 +240,21 @@ public static function formatEntity($entity, $highlight = false)
/** /**
* Return link to edit a message on external tool used by requested locale * Return link to edit a message on external tool used by requested locale
* *
* @param string $tool Tool name
* @param string $repo Repository * @param string $repo Repository
* @param string $key Key of the current string * @param string $key Key of the current string
* @param string $text Text of the current strings * @param string $text Text of the current strings
* @param string $locale Current locale * @param string $locale Current locale
* *
* @return string HTML link to edit the string inside the tool used by this locale * @return string HTML link to edit the string inside the tool used by this locale
*/ */
public static function getEditLink($repo, $key, $text, $locale) public static function getEditLink($tool, $repo, $key, $text, $locale)
{ {
// Return if it's not a supported tool
if (! in_array($tool, ['pontoon'])) {
return '';
}

$component = explode('/', $key)[0]; $component = explode('/', $key)[0];
$fileAndRawString = explode(':', $key); $fileAndRawString = explode(':', $key);


Expand Down Expand Up @@ -414,7 +420,7 @@ public static function resultsTable($search_object, $search_results, $page)
$transliterate = $locale2 == 'sr' && ! $extra_locale && $target_string && $target_string != '@@missing@@'; $transliterate = $locale2 == 'sr' && ! $extra_locale && $target_string && $target_string != '@@missing@@';


$edit_link = $toolUsedByTargetLocale != '' $edit_link = $toolUsedByTargetLocale != ''
? self::getEditLink($current_repo, $key, $target_string, $locale2) ? self::getEditLink($toolUsedByTargetLocale, $current_repo, $key, $target_string, $locale2)
: ''; : '';


if ($transliterate) { if ($transliterate) {
Expand Down
46 changes: 0 additions & 46 deletions app/classes/Transvision/Utils.php
Expand Up @@ -82,52 +82,6 @@ public static function checkboxState($str, $extra = '')
return $str ? ' checked="checked"' : ''; return $str ? ' checked="checked"' : '';
} }


/**
* Print a simple table, used in the accesskeys view, needs rework
*
* @param array $arr First column of data
* @param array $arr2 Optional. A second column of data
* @param array $titles Column titles, by default 4 columns
* @param string $cssclass optional css class to apply to the table
*
* @return void
*/
public static function printSimpleTable(
$arr,
$arr2 = false,
$titles = ['Column1', 'Column2', 'Column3', 'Column4'],
$cssclass = ''
) {
if ($cssclass != '') {
echo "<table class='{$cssclass}'>";
} else {
echo '<table>';
}
echo "<thead>\n <tr class='column_headers'>\n" .
" <th>{$titles[0]}</th><th>{$titles[1]}</th>\n";

if ($arr2) {
echo " <th>{$titles[2]}</th><th>{$titles[3]}</th>\n";
}

echo " </tr>\n</thead>\n<tbody>\n";

foreach ($arr as $key => $val) {
echo '<tr>';
if ($arr2) {
echo "<td><span class='celltitle'>{$titles[0]}</span><div class='string'>" . ShowResults::formatEntity($val) . '</div></td>';
echo "<td><span class='celltitle'>{$titles[1]}</span><div class='string'>" . $arr2[$val] . '</div></td>';
echo "<td><span class='celltitle'>{$titles[2]}</span><div class='string'>" . str_replace(' ', '<span class="highlight-red"> </span>', $arr2[$key]) . '</div></td>';
echo "<td><span class='celltitle'>{$titles[3]}</span><div class='string'>" . ShowResults::formatEntity($key) . '</div></td>';
} else {
echo "<td>{$key}</td>";
echo "<td>{$val}</td>";
}
echo '</tr>';
}
echo "</tbody>\n</table>\n";
}

/** /**
* Split a sentence in words from longest to shortest, ignoring * Split a sentence in words from longest to shortest, ignoring
* words shorter than 2 characters. * words shorter than 2 characters.
Expand Down
8 changes: 8 additions & 0 deletions app/controllers/accesskeys.php
@@ -0,0 +1,8 @@
<?php
namespace Transvision;

// Get requested repo and locale
require_once INC . 'l10n-init.php';

include MODELS . 'accesskeys.php';
include VIEWS . 'accesskeys.php';
3 changes: 2 additions & 1 deletion app/inc/dispatcher.php
Expand Up @@ -35,9 +35,10 @@
$js_files[] = '/assets/jQuery-Autocomplete/dist/jquery.autocomplete.min.js'; $js_files[] = '/assets/jQuery-Autocomplete/dist/jquery.autocomplete.min.js';
break; break;
case 'accesskeys': case 'accesskeys':
$view = 'accesskeys'; $controller = 'accesskeys';
$page_title = 'Access Keys'; $page_title = 'Access Keys';
$page_descr = 'Check your access keys.'; $page_descr = 'Check your access keys.';
$js_files[] = '/js/component_filter.js';
$js_files[] = '/js/sorttable.js'; $js_files[] = '/js/sorttable.js';
break; break;
case Strings::StartsWith($url['path'], 'api'): case Strings::StartsWith($url['path'], 'api'):
Expand Down
94 changes: 94 additions & 0 deletions app/models/accesskeys.php
@@ -0,0 +1,94 @@
<?php
namespace Transvision;

$error_messages = [];
$reference_locale = Project::getReferenceLocale($repo);
$supported_locales = Project::getRepositoryLocales($repo, [$reference_locale]);
// If the requested locale is not available, fall back to the first
if (! in_array($locale, $supported_locales)) {
$locale = array_shift($supported_locales);
}
// Build the target locale switcher
$target_locales_list = Utils::getHtmlSelectOptions($supported_locales, $locale);

/*
Only use desktop repositories. If the requested repository is not
available, fall back to the first key.
*/
$channels = array_intersect_key(
Project::getSupportedRepositories(),
array_flip($desktop_repos)
);
if (! isset($channels[$repo])) {
$repo = current(array_keys($channels));
$error_messages[] = "The selected repository is not supported. Falling back to <em>{$repo}</em>.";
}
$channel_selector = Utils::getHtmlSelectOptions($channels, $repo, true);

// Get strings
$source = Utils::getRepoStrings($reference_locale, $repo);
$target = Utils::getRepoStrings($locale, $repo);

// Get strings with 'accesskey' in the string ID
$ak_string_ids = array_filter(
array_keys($target),
function ($entity) {
return strpos($entity, '.accesskey') !== false;
}
);

// Possible labels associated to an access key
$ak_labels = ['.label', '.title', '.message', ''];

// Known false positives
$ignored_ids = [
'suite/chrome/mailnews/messenger.dtd:searchButton.title',
];

$ak_results = [];
foreach ($ak_string_ids as $ak_string_id) {
foreach ($ak_labels as $ak_label) {
/*
Replace 'accesskey' with one of the known IDs used for labels.
E.g.:
* foo.accesskey -> foo.label
* foo.accesskey -> foo.title
* foo.accesskey -> foo.message
* foo.accesskey -> foo (common in devtools)
*/
$entity = str_replace('.accesskey', $ak_label, $ak_string_id);
$current_ak = $target[$ak_string_id];

/*
Ignore:
* Strings not available or empty in target locale.
* Empty access keys in source locale.
*/
if (isset($target[$entity]) && ! empty($target[$entity]) && ! empty($source[$ak_string_id]) ) {
// Ignore known false positives
if (in_array($entity, $ignored_ids)) {
continue;
}
/*
Store the string if the access key is empty or using a
character not available in the label.
*/
if (($current_ak == '') || (mb_stripos($target[$entity], $current_ak) === false)) {
$ak_results[$ak_string_id] = $entity;
}
}
}
}

// Add component filter
if (in_array($repo, $desktop_repos)) {
// Build logic to filter components
$components = Project::getComponents(array_flip($ak_results));
$filter_block = '';
foreach ($components as $value) {
$filter_block .= " <a href='#{$value}' id='{$value}' class='filter'>{$value}</a>";
}
}

// RTL support
$direction = RTLSupport::getDirection($locale);
158 changes: 102 additions & 56 deletions app/views/accesskeys.php
@@ -1,63 +1,109 @@
<?php <?php
namespace Transvision; namespace Transvision;


require_once INC . 'l10n-init.php'; // Include the common simple search form

include __DIR__ . '/simplesearchform.php';
$strings[$repo] = Utils::getRepoStrings($locale, $repo);
$strings_english[$repo] = Utils::getRepoStrings('en-US', $repo); if (! empty($ak_results)) {

$search_id = 'accesskeys';
$channel_selector = Utils::getHtmlSelectOptions( $content = '';
array_intersect_key( if (! empty($error_messages)) {
$repos_nice_names, $content .= '<p class="error">' .
array_flip($desktop_repos) implode('<br/>', $error_messages) .
), '</p>';
$repo,
true
);

// Get the locale list
$loc_list = Project::getRepositoryLocales($repo);

// Build the target locale switcher
$target_locales_list = Utils::getHtmlSelectOptions($loc_list, $locale);

$akeys = array_filter(
array_keys($strings[$repo]),
function ($entity) {
return substr($entity, -9) == 'accesskey';
} }
); $content .= "<h2><span class=\"results_count_{$search_id}\">"

. Utils::pluralize(count($ak_results), 'potential access key error')
$ak_labels = ['.label', '.title', '.title2']; . "</span> found</h2>\n";
$ak_results = [];

if (isset($filter_block)) {
foreach ($akeys as $akey) { $content .= "<div id='filters'>" .
$entity = substr($akey, 0, -10); " <h4>Filter by folder:</h4>\n" .
$akey_value = $strings[$repo][$akey]; " <a href='#showall' id='showall' class='filter'>Show all results</a>\n" .

$filter_block .
foreach ($ak_labels as $ak_label) { "</div>\n";
if (isset($strings[$repo][$entity . $ak_label]) }
&& !empty($strings[$repo][$entity . $ak_label])
&& isset($strings_english[$repo][$akey]) $content .= "
&& !empty($strings_english[$repo][$akey]) <table class='collapsable results_table sortable {$search_id}'>
) { <thead>
if ($akey_value == '') { <tr class='column_headers'>
$ak_results[$akey] = $entity . $ak_label; <th>Entity</th>
} elseif (mb_stripos($strings[$repo][$entity . $ak_label], $akey_value) === false) { <th>Label</th>
$ak_results[$akey] = $entity . $ak_label; <th>Access&nbsp;key</th>
} else { <th>Access&nbsp;key entity</th>
break; </tr>
} </thead>
} <tbody>\n";

// Get the tool used to edit strings for the target locale
$toolUsedByTargetLocale = Project::getLocaleTool($locale);

foreach ($ak_results as $ak_string => $ak_label) {
// Link to entity
$ak_link = "?sourcelocale={$reference_locale}" .
"&locale={$locale}" .
"&repo={$repo}" .
"&search_type=entities&recherche={$ak_string}" .
'&entire_string=entire_string';
$label_link = "?sourcelocale={$reference_locale}" .
"&locale={$locale}" .
"&repo={$repo}" .
"&search_type=entities&recherche={$ak_label}" .
'&entire_string=entire_string';

$path_ak = VersionControl::hgPath($locale, $repo, $ak_string);
$path_label = VersionControl::hgPath($locale, $repo, $ak_label);

$edit_link_ak = $toolUsedByTargetLocale != ''
? ShowResults::getEditLink($toolUsedByTargetLocale, $repo, $ak_string, $target[$ak_string], $locale)
: '';
$edit_link_label = $toolUsedByTargetLocale != ''
? ShowResults::getEditLink($toolUsedByTargetLocale, $repo, $ak_label, $target[$ak_label], $locale)
: '';

$ak_value = ! empty($target[$ak_string])
? Utils::secureText($target[$ak_string])
: '<em class="error">(empty)</em>';
$label_value = ! empty($target[$ak_label])
? Utils::secureText($target[$ak_label])
: '<em class="error">(empty)</em>';

$component = explode('/', $ak_string)[0];
$content .= "<tr class='{$component} {$search_id}'>
<td>
<span class='celltitle'>Entity</span>
<span class='link_to_entity'>
<a href=\"/{$label_link}\">" . ShowResults::formatEntity($ak_label) . "</a>
</span>
</td>
<td dir='{$direction}'>
<span class='celltitle'>Label</span>
<div class='string'>{$label_value}</div>
<div dir='ltr' class='result_meta_link'>
<a class='source_link' href='{$path_label}'>&lt;source&gt;</a>
{$edit_link_label}
</div>
</td>
<td dir='{$direction}'>
<span class='celltitle'>Access&nbsp;key</span>
<div class='string'>{$ak_value}</div>
<div dir='ltr' class='result_meta_link'>
<a class='source_link' href='{$path_ak}'>&lt;source&gt;</a>
{$edit_link_ak}
</div>
</td>
<td>
<span class='celltitle'>Access&nbsp;key entity</span>
<span class='link_to_entity'>
<a href=\"/{$ak_link}\">" . ShowResults::formatEntity($ak_string) . "</a>
</span>
</td>
</tr>\n";
} }
$content .= "</tbody>\n</table>\n";
} else {
$content = '<h2>Congratulations, no errors found.</h2>';
} }
// Include the common simple search form
include __DIR__ . '/simplesearchform.php';


echo '<h2>' . count($ak_results) . ' potential accesskey errors</h2>'; print $content;
Utils::printSimpleTable(
$ak_results,
$strings[$repo],
['Label entity', 'Label value', 'Access&nbsp;key', 'Access key entity'],
'collapsable sortable'
);

0 comments on commit 48d9039

Please sign in to comment.