Permalink
Browse files

Create QA view for Empty strings (fixes #813) (#814)

  • Loading branch information...
flodolo authored and TheoChevalier committed Sep 27, 2016
1 parent 1075320 commit 17373b2a2e366a693ef15831c8d93be6f904b675
@@ -49,6 +49,12 @@ public static function reportErrorLink($locale, $entity, $source_string, $target
{
$bug_summary = rawurlencode("[{$locale}] Translation update proposed for {$entity}");
$transvision_url = "https://transvision.mozfr.org/{$entity_link}";
+ $source_string = $source_string != ''
+ ? $source_string
+ : '(empty string)';
+ $target_string = $target_string != ''
+ ? $target_string
+ : '(empty string)';
$bug_message = rawurlencode(
html_entity_decode(
"The string:\n{$source_string}\n\n"
@@ -115,11 +115,11 @@ public static function multipleStringReplace($replacements, $string)
public static function highlightSpecial($string, $exclude_whitespaces = true)
{
$replacements = [
- ' ' => '<span class="highlight-space" title="White space"> </span>',
- ' ' => '<span class="highlight-gray" title="Non breakable space"> </span>',
- '' => '<span class="highlight-red" title="Narrow no-break space"> </span>',
- '' => '<span class="highlight-gray" title="Real ellipsis">…</span>',
- '&hellip;' => '<span class="highlight-red" title="HTML ellipsis">…</span>',
+ ' ' => '<span class="highlight-special highlight-space" title="White space"> </span>',
+ ' ' => '<span class="highlight-special highlight-gray" title="Non breakable space"> </span>',
+ '' => '<span class="highlight-special highlight-red" title="Narrow no-break space"> </span>',
+ '' => '<span class="highlight-special highlight-gray" title="Real ellipsis">…</span>',
+ '&hellip;' => '<span class="highlight-special highlight-red" title="HTML ellipsis">…</span>',
];
if ($exclude_whitespaces) {
@@ -0,0 +1,8 @@
+<?php
+namespace Transvision;
+
+// Get requested repo and locale
+require_once INC . 'l10n-init.php';
+
+include MODELS . 'empty_strings.php';
+include VIEWS . 'empty_strings.php';
View
@@ -71,6 +71,14 @@
$css_files[] = 'tmx.css';
$js_files[] = '/js/select_all.js';
break;
+ case 'empty-strings':
+ $experimental = true;
+ $controller = 'empty_strings';
+ $page_title = 'Empty Strings';
+ $page_descr = '';
+ $js_files[] = '/js/component_filter.js';
+ $js_files[] = '/js/sorttable.js';
+ break;
case 'news':
$controller = 'changelog';
$page_title = 'Transvision News and Release Notes';
View
@@ -2,22 +2,23 @@
$urls = [
'/' => 'root',
- 'news' => 'changelog',
- 'rss' => 'rss',
- 'stats' => 'stats',
+ '3locales' => '3locales',
+ 'accesskeys' => 'keys',
+ 'api' => 'api',
'channelcomparison' => 'channelcomp',
'consistency' => 'consistency',
- 'accesskeys' => 'keys',
'credits' => 'credits',
'downloads' => 'downloads',
+ 'empty-strings' => 'empty_strings',
+ 'news' => 'changelog',
+ 'productization' => 'productization',
+ 'rss' => 'rss',
'showrepos' => 'showrepos',
+ 'stats' => 'stats',
+ 'string' => 'onestring',
'unchanged' => 'unchangedstrings',
- 'unlocalized' => 'unlocalized',
'unlocalized-all' => 'unlocalized_all',
'unlocalized-json' => 'unlocalized_json',
+ 'unlocalized' => 'unlocalized',
'variables' => 'checkvariables',
- '3locales' => '3locales',
- 'string' => 'onestring',
- 'productization' => 'productization',
- 'api' => 'api',
];
@@ -0,0 +1,65 @@
+<?php
+namespace Transvision;
+
+// Build arrays for the search form, ignore mozilla.org and iOS
+$channel_selector = Utils::getHtmlSelectOptions(
+ array_intersect_key(
+ $repos_nice_names,
+ array_flip($desktop_repos)
+ ),
+ $repo,
+ true
+);
+
+$target_locales_list = Utils::getHtmlSelectOptions(
+ Project::getRepositoryLocales($repo),
+ $locale
+);
+
+$reference_locale = Project::getReferenceLocale($repo);
+
+$reference_strings = Utils::getRepoStrings($reference_locale, $repo);
+$locale_strings = Utils::getRepoStrings($locale, $repo);
+
+/*
+ Identify empty strings in reference locale, store the translation
+ only if locale has a non empty string for that ID. Then repeat the
+ process for the locale.
+*/
+$empty_strings = [];
+
+$empty_reference = array_filter($reference_strings, function ($string) {
+ return strlen($string) == 0;
+});
+foreach ($empty_reference as $string_id => $value) {
+ if (isset($locale_strings[$string_id]) && $locale_strings[$string_id] != '') {
+ $empty_strings[$string_id] = [
+ 'reference' => $value,
+ 'translation' => $locale_strings[$string_id],
+ ];
+ }
+}
+
+$empty_locale = array_filter($locale_strings, function ($string) {
+ return strlen($string) == 0;
+});
+foreach ($empty_locale as $string_id => $value) {
+ if (isset($reference_strings[$string_id]) && $reference_strings[$string_id] != '') {
+ $empty_strings[$string_id] = [
+ 'reference' => $reference_strings[$string_id],
+ 'translation' => $value,
+ ];
+ }
+}
+
+unset($reference_strings);
+unset($locale_strings);
+
+if (count($empty_strings) > 0) {
+ ksort($empty_strings);
+ $components = Project::getComponents($empty_strings);
+ $filter_block = '';
+ foreach ($components as $value) {
+ $filter_block .= " <a href='#{$value}' id='{$value}' class='filter'>{$value}</a>";
+ }
+}
View
@@ -0,0 +1,131 @@
+<?php
+namespace Transvision;
+
+?>
+<p class="intro">This view displays strings that are empty in the reference language
+ but have a translation in the requested language, and viceversa.
+ It can be used to identify strings that should have been localized and
+ are empty by mistake, and strings that should actually remain empty.
+</p>
+<form name="searchform" id="simplesearchform" method="get" action="">
+ <fieldset id="main_search">
+
+ <?php if (isset($target_locales_list)) : ?>
+ <fieldset>
+ <label>Locale</label>
+ <div class="select-style">
+ <select name="locale" title="Locale" id="simplesearch_locale">
+ <?=$target_locales_list?>
+ </select>
+ </div>
+ </fieldset>
+ <?php endif; ?>
+
+ <?php if (isset($channel_selector)) : ?>
+ <fieldset>
+ <label>Repository</label>
+ <div class="select-style">
+ <select name="repo" title="Repository" id="simplesearch_repository">
+ <?=$channel_selector?>
+ </select>
+ </div>
+ </fieldset>
+ <?php endif; ?>
+
+ <input type="submit" value="Go" alt="Go" />
+ </fieldset>
+</form>
+<?php if (isset($filter_block)) {
+ ?>
+<div id="filters">
+ <h4>Filter by folder:</h4>
+ <a href="#showall" id="showall" class="filter">Show all results</a>
+ <?=$filter_block; ?>
+</div>
+<?php
+
+}
+
+if (count($empty_strings) == 0) {
+ echo "<div class=\"message\"><p>No strings found.</p></div>";
+} else {
+ $text_direction = RTLSupport::getDirection($locale);
+ $table = "<table class='collapsable results_table sortable'>
+ <thead>
+ <tr class='column_headers'>
+ <th>Entity</th>
+ <th>{$reference_locale}</th>
+ <th>{$locale}</th>
+ </tr>
+ </thead>
+ <tbody>\n";
+
+ foreach ($empty_strings as $key => $strings) {
+ $entity = ShowResults::formatEntity($key);
+ $component = explode('/', $key)[0];
+ $reference_string = htmlspecialchars($strings['reference']);
+ $locale_string = Strings::highlightSpecial(htmlspecialchars($strings['translation']), false);
+
+ $entity_link = "?sourcelocale={$reference_locale}"
+ . "&locale={$locale}"
+ . "&repo={$repo}"
+ . "&search_type=entities&recherche={$key}"
+ . "&perfect_match=perfect_match";
+
+ $bugzilla_link = [Bugzilla::reportErrorLink(
+ $locale, $key, $reference_string, $locale_string, $repo, $entity_link
+ )];
+
+ $reference_path = VersionControl::hgPath($reference_locale, $repo, $key);
+ $locale_path = VersionControl::hgPath($locale, $repo, $key);
+
+ if (! $reference_string) {
+ $reference_string = '<em class="error">(empty)</em>';
+ }
+ if ($locale_string == '@@missing@@') {
+ $locale_string = '<em class="error">Missing string</em>';
+ } elseif ($locale_string == '') {
+ $locale_string = '<em class="error">(empty)</em>';
+ }
+
+ // Replace / and : in the key name and use it as an anchor name
+ $anchor_name = str_replace(['/', ':'], '_', $key);
+
+ $table .= "
+ <tr class='{$component}'>
+ <td>
+ <span class='celltitle'>Entity</span>
+ <a class='resultpermalink tag' id='{$anchor_name}' href='#{$anchor_name}' title='Permalink to this string'>link</a>
+ <a class='l10n tag' href='/string/?entity={$key}&amp;repo={$repo}' title='List all translations for this entity'>l10n</a>
+ <a class='link_to_entity' href=\"/{$entity_link}\">{$entity}</a>
+ </td>
+ <td dir='ltr' lang='{$reference_locale}'>
+ <span class='celltitle'>{$reference_locale}</span>
+ <div class='string'>
+ {$reference_string}
+ </div>
+ <div dir='ltr' class='result_meta_link'>
+ <a class='source_link' href='{$reference_path}'>
+ &lt;source&gt;
+ </a>
+ </div>
+ </td>
+ <td dir='{$text_direction}' lang='{$locale}'>
+ <span class='celltitle'>{$locale}</span>
+ <div class='string'>{$locale_string}</div>
+ <div dir='ltr' class='result_meta_link'>
+ <a class='source_link' href='{$locale_path}'>
+ &lt;source&gt;
+ </a>
+ &nbsp;
+ <a class='bug_link' target='_blank' href='{$bugzilla_link[0]}'>
+ &lt;report a bug&gt;
+ </a>
+ </div>
+ </td>
+ </tr>";
+ }
+ $table .= " </tbody>\n</table>\n";
+
+ echo $table;
+}
@@ -45,6 +45,7 @@
<ul>
{$li_link('keys', 'Check your access keys', 'Access Keys')}
{$li_link('checkvariables', 'Check what variable differences there are from English', 'Check Variables')}
+ {$li_link('empty_strings', 'Display empty strings in English or locale', 'Empty Strings')}
{$li_link('unchangedstrings', 'Display all strings identical to English', 'Unchanged Strings')}
{$li_link('unlocalized_all', 'Display common words remaining in English', 'Unlocalized Words')}
</ul>
@@ -7,6 +7,7 @@
['consistency/?locale=fr&repo=central', 200, 'English String', 'Available Translations'],
['consistency/?locale=en-US&repo=central', 200, 'No inconsistent translations found.', 'Analyze translation consistency across repositories.'],
['credits/', 200, 'Transvision 1.0 was created', 'Transvision is a community project under the MozFR umbrella'],
+ ['empty-strings/', 200, 'Empty Strings', 'Repository'],
['downloads/', 200, 'Select which strings', 'Generate the TMX'],
['news/', 200, 'Version 4.0', 'End user visible changes'],
['productization/', 200, 'Show productization', 'firefox'],
@@ -96,13 +96,13 @@ public function multipleStringReplaceDP()
return [
[
[
- ' ' => '<span class="highlight-gray" title="Non breakable space"> </span>', // Nbsp highlight
- '' => '<span class="highlight-red" title="Thin space"> </span>', // Thin space highlight
- '' => '<span class="highlight-gray">…</span>', // Right ellipsis highlight
- '&hellip;' => '<span class="highlight-gray">…</span>', // Right ellipsis highlight
+ ' ' => '<span class="highlight-special highlight-gray" title="Non breakable space"> </span>', // Nbsp highlight
+ '' => '<span class="highlight-special highlight-red" title="Thin space"> </span>', // Thin space highlight
+ '' => '<span class="highlight-special highlight-gray">…</span>', // Right ellipsis highlight
+ '&hellip;' => '<span class="highlight-special highlight-gray">…</span>', // Right ellipsis highlight
],
'&hellip;  …',
- '<span class="highlight-gray">…</span><span class="highlight-gray" title="Non breakable space"> </span><span class="highlight-red" title="Thin space"> </span><span class="highlight-gray">…</span>',
+ '<span class="highlight-special highlight-gray">…</span><span class="highlight-special highlight-gray" title="Non breakable space"> </span><span class="highlight-special highlight-red" title="Thin space"> </span><span class="highlight-special highlight-gray">…</span>',
],
];
}
@@ -123,10 +123,10 @@ public function testHighlightSpecial()
$obj = new _Strings();
$this
->string($obj->highlightSpecial('Foo is bar ; Bar is Foo…'))
- ->isEqualTo('Foo is bar<span class="highlight-gray" title="Non breakable space"> </span>;<span class="highlight-gray" title="Non breakable space"> </span>Bar is Foo<span class="highlight-gray" title="Real ellipsis">…</span>');
+ ->isEqualTo('Foo is bar<span class="highlight-special highlight-gray" title="Non breakable space"> </span>;<span class="highlight-special highlight-gray" title="Non breakable space"> </span>Bar is Foo<span class="highlight-special highlight-gray" title="Real ellipsis">…</span>');
$this
->string($obj->highlightSpecial('Foo is bar ; Bar is Foo…', false))
- ->isEqualTo('Foo<span class="highlight-space" title="White space"> </span>is<span class="highlight-space" title="White space"> </span>bar<span class="highlight-gray" title="Non breakable space"> </span>;<span class="highlight-gray" title="Non breakable space"> </span>Bar<span class="highlight-space" title="White space"> </span>is<span class="highlight-space" title="White space"> </span>Foo<span class="highlight-gray" title="Real ellipsis">…</span>');
+ ->isEqualTo('Foo<span class="highlight-special highlight-space" title="White space"> </span>is<span class="highlight-special highlight-space" title="White space"> </span>bar<span class="highlight-special highlight-gray" title="Non breakable space"> </span>;<span class="highlight-special highlight-gray" title="Non breakable space"> </span>Bar<span class="highlight-special highlight-space" title="White space"> </span>is<span class="highlight-special highlight-space" title="White space"> </span>Foo<span class="highlight-special highlight-gray" title="Real ellipsis">…</span>');
}
public function markStringDP()
View
@@ -947,6 +947,18 @@ input[type="checkbox"]:disabled + label {
margin-top: -10px;
}
+/* Empty strings view */
+#empty_strings .intro,
+#empty_strings .message {
+ margin: 0 auto;
+ text-align: center;
+ width: 75%;
+}
+
+#empty_strings .highlight-special {
+ min-width: 0.5em;
+}
+
/* Glossary view */
#glossary_matches {
width: 80%;

0 comments on commit 17373b2

Please sign in to comment.