User:Lvl/Devel

From DPWiki

Distributed gettext fixing effort

/Distributed gettext fixing effort

See also /I18n TODO list

Questions awaiting answers on the dev. list

See /Questions pending

Mails

/Mails

Things I would like to work on

I'm listing below various things I whould like to work on. Since our code squirrels have very limited time, I'm giving a list of these here so that they can pick up on which topics they have time to review effective code and accept the code fix.


Fix automatically found gettext markup errors

review the comments I made in the dev list on Coachmike's code, 
because I saw that some of these comments were ignored. e.g. 
dp-devel/pinc/Stage.inc

  echo "<input type='submit' value='". _("Submit Changes") . "'>\n";

should use attr_safe()

- fix the 64 occurrences of similar constructs found by 

 grep -r ' [a-z]\{1,\}=['\''"]\{2\} *\. *_(' dp-devel


run a similar perl program to find deviations to the coding Guidelines:

  while (<>) {
    s/\t/ /g;
    if (/^ *\$(\w+) *=.*_\(/) { $tainted{$1} = $_; }
  
    print if (/ [a-z]+ *= *'[^\\']*" *\. *_\(/);
    while (/ [a-z]+ *= *'[^\\']*\$(\w+)/g) {
        print if (exists $tainted{$1});
    }
    while (/ [a-z]+ *= *'[^\\']*" *\. *\$(\w+)/g) {
        print if (exists $tainted{$1});
    }
  }


Organise a list of files to be checked for gettext markup update

I have created a list on the wiki:

http://www.pgdp.net/wiki/User:Lvl/Devel/Distributed_gettext_fixing_effort

This is now waiting for feedback from code squirrels.


Task:1344 translator center

Implement step 0 of the strategy described in the dev. list.


Fix projectID validation

- check cases of $_GET['project and $POST_['project which are not 
validated with the new function validate_projectID()

- consider testing using is_string() that $value is a real string 
(and not an array) in validate_projectID()?


htmlspecialchars without ENT_QUOTES

look for cases of using htmlspecialchars without ENT_QUOTES.


Get rid of addslashes()

- Many cases of addslashes inside SQL queries should be replaced 
with mysql_real_escape_string. 

- In other cases, there is just a confusion. Document the variables
that are encoded specifically using addslashes in the database, in 
a separate documentation file, and for any variable not documented 
as using a special format, remove these addslashes calls.


Task:749 disallow binary characters and tabs in txt files

in function _normalize_page_text, file pinc/DPage.inc, add a regexp 
to replace rows of illegal characters with a single space char. Add 
possibly other regexps that will convert Windows special chars into 
our markup. make that dependent upon whether the site is in utf-8.

Also replace addslashes with mysql_real_escape_string in file_content_expr()

=> check code by Michael in tools/project_manager/add_files.php and pinc/DPage.inc


Task:1201 Illustration tag button should remove the colon and space if nothing highlighted

This is a duplicate of 1300; close [[Task:1300]].

insert in dp_proof.js:
   // standard tag selection
 function surroundSelectionOrInsert(wOT,wCT,text)
 {
    markRef.markBox.value=wOT;
    markRef.markBoxEnd.value=wCT;

    insertTags(wOT,wCT,text,false);
 }

and in toolbox.inc, replace
       "top.surroundSelection('[Illustration: ',']')"
with
       "top.surroundSelectionOrInsert('[Illustration: ',']','[Illustration]')"


Translate popup help

([[Task:594]] faq/pophelp should be localized and "theme-able")

At present popups are stand-alone html files grouped in directory.
The idea is to replace each directory with one php file containing 
a big switch, depending on $_GET['id'], to branch to code that 
displays the popup help, using _(...).
I have written a shell script that converts the html files into the
relevant php code, and I suggest to fix pinc/js_newpophelp.inc so 
that the generated javascript function no longer links to a standalone 
html file, but to that php file, i.e. replace

    return "
    function newHelpWin(wFile)
        {
        var newFeatures='toolbar=0,status=0,location=0,directories=0,menubar=0,scrollbars=1,resizable=1,width=400,height=300,top=$top,left=$left';
        window.open('$popHelpDir'+wFile+'.html','popHelp',newFeatures);
    }
    ";

with

    $pop_help_php = "$popHelpDir?id=";
    $pop_title = attr_safe(_("popHelp"));

    return "
    function newHelpWin(wFile)
        {
        var newFeatures='toolbar=0,status=0,location=0,directories=0,menubar=0,scrollbars=1,resizable=1,width=400,height=300,top=$top,left=$left';
        window.open('$pop_help_php'+wFile,'$pop_title',newFeatures);
    }
    ";

The various popup php files will include file pophelp.inc:

 <?php 
 include_once("site_vars.php");   // $charset ?
 include_once("gettext_setup.inc");
 
 function do_popup($title, $content)
 {
    global $charset;
 
    echo "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n";
    echo "<html " . lang_html_header() . ">\n";
    echo "<head>\n";
    echo "<title>" . sprintf(_("%s Help"), $title) . "</title>";
    echo "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=$charset\" />\n";
    echo "</meta>";
    echo "<body>";
    echo "<h2 style='text-align: center;'>$title</h2>";
    echo $content;
    echo "<p style='text-align: center;'><b><a href='Javascript:window.close();'>"
        . _("Close Window") . "</a></b></p>";
    echo "</body></html>"
 }
 ?>


Fix missing quotes in html attributes

Things like <tag attribute=value> are not supported in XHTML, and 
cause display problems in some browsers. I suggest to convert them 
to use quotes, e.g. <tag attribute="value">  or <tag attribute='value'>


cleaner handling of backslashes in page text inner interfaces

DPage.inc, PPage.inc, LPage.inc and processtext.php: 
change the interface for saveAsInProgress() and saveAsDone()
so that page text is passed unslashed, and 
mysql_real_escape_string is used directly close to the building of 
the SQL query.


minor optimisations in page_table.inc

in tools/project_manager/page_table.inc,

- replace all $code_url/tools/project_manager/ with ""
- replace  style='text-align: right' with class='r'

and add this in function echo_pagetable_stylesheet()

    table.pagedetail td.r {
        text-align: right;
    }

- remove space in        echo "<td $cell_class_attr>
  and put the space in $cell_class_attr

- cache values of gettext for frequent links _("Edit"), _("no diff"),
and so on.

- href=$url => put quotes around it.

- cache the value of the correct bad state for the current
round, instead of
            // Bad Page
            $page_is_in_bad_state = page_state_is_a_bad_state($page_state);

- cache the value of the cell describing the url to send 
message + number of pages proofed by a user in a round.


fix html ampersand in urls

tidy complains about things like &foo=... (should be &amp;foo=)
But beware of functions handling urls in misc.inc 

translate dates

check calls to date() and replace them with calls to strftime() 


deprecated functions

Deprecated functions in PHP 5.3.0: 

 mysql_escape_string() 
 POSIX regex => replace that with pcre regex.
   affected functions: ereg(), eregi(), ereg_replace(), eregi_replace()
   (we don't seem to call split, spliti or sql_regcase)
 dl()  (used by the difference engine)
 and of course the magic quotes stuff.


get rid of \w and \W which locale dependant

- re PHP manual: 

"The definition of letters and digits is controlled by PCRE's 
character tables, and may vary if locale-specific matching is 
taking place. For example, in the "fr" (French) locale, some 
character codes greater than 128 are used for accented letters, 
and these are matched by \w." 

=> find all occurrences of \W and \w and replace them with the actual 
meanings in the C locale. Theoretically \b and \B are affected too. 


latin-1 upper/lowercase in javascript

javascript functions to convert to lowercase or uppercase, taking
care of the latin-1 accented characters.

 function translit(left, right, str)
 {
    for ( var i = 0, l = right.length; i < l; i++ )
    {
        var repl = new RegExp(left.charAt(i), "g")
        var subs = right.charAt(i);

        str = str.replace(repl, subs);
    }
    return str;
 }

 function uppercase(str)
 {
    return translit(
        "àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ", 
        "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ",
        str.toupper()) . replace(/ÿ/g, "[\"Y]");
 }

 function lowercase(str)
 {
    return translit(
        "ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞ",
        "àáâãäåæçèéêëìíîïðñòóôõöøùúûüýþ", 
        str.replace(/\["Y\]/g, "ÿ").tolower()) ;
 }


minor fix

page_table.inc,
line 369

$page_is_in_bad_state = page_state_is_a_bad_state($page_state);

this calls a loop for each page; would be better to compute first
the bad state for this round, out of the loop, and within the loop 
test if the page state is equal to that bad state.


fix to adapt to number of rounds > 2

automodify.php

    // In round 2, if it has any bad pages
    // and no available pages, it's bad.
    //
    if ($round->round_number == 2)

put a number >= 2


Task:1181 Add a link to change the proofreading preferences

add the link in ctrl_frame.php, something like

 <?php
 $url = "...";
 echo "<a style=\"color:#0000FF; text-decoration: underline;\" href='$url'  target='_blank'>";
 echo _('Proofreading Preferences')."</i>\n"; 
 echo "</a>\n" ?>


htmlspecialchars missing

pinc/filter_project_list.inc

in function _build_project_filter_select, protect the variables 
using htmlspecialchars(..., ENT_QUOTES) in these two lines:

            $return.="value='$value'";
            $return.="value='$option'";


translatable genres

genre should be made an associative array, for translating purposes.

pinc/filter_project_list.inc:

1) put near the top of file:
include_once("genres.inc");

2) replace around line 225 with
        if($field == "special_code" || $field=="difficulty" || $field=="genre")

3) in function _load_project_filter_field_values, put 
    global $GENRES;
and add the three lines below inside the while loop:
        else if ($field == "genre")
            $return[$a_res[0]] = array_key_exists($a_res[0], $GENRES))
                ? $GENRES[$a_res[0]] : $a_res[0];        


Task:546 change the font in the dropdown menus.

in tools/proofers/ctrl_frame.php, after 
 .dropchars {
  background-color:#EEDFCC;

insert the result of function css_for_font_pref() to be defined in PPage.inc:

 function css_for_font_pref()
 {
    $css = "";
    if ( $userP['i_layout']==1 )
    {
        // "vertical"
        $font_face_i = $userP['v_fntf'];
        $font_size_i = $userP['v_fnts'];
    }
    else
    {
        // "horizontal"
        $font_face_i = $userP['h_fntf'];
        $font_size_i = $userP['h_fnts'];
    }
    $font_face = $f_f[$font_face_i];
    $font_size = $f_s[$font_size_i];
    if ( $font_face != '' && $font_face != BROWSER_DEFAULT_STR )
        $css .= "font-family: $font_face; ";
    if ( $font_size != '' && $font_size != BROWSER_DEFAULT_STR )
        $css .= "font-size: $font_size;";
    return $css
 }


Task:630 Suppress/fix Mentor Projects display when no projects available

pinc/mentorbanner.inc

comment:  "correctly display singular v. plural of days when age 
is one day (task #630)"

replace

    printf(_("Oldest English %sMENTORS ONLY%s book in %s is %d days old."),
         "<a href='$wiki_url/Mentoring'>",
         "</a>",
         $round_id,
         $oldest);
with

    printf( ngettext(
        "Oldest English <a href="%1\$s"MENTORS ONLY</a> book in %2\$s is %3\$d day old."
        "Oldest English <a href="%1\$s"MENTORS ONLY</a> book in %2\$s is %3\$d days old."
        $oldest), '$wiki_url/Mentoring', $round_id, $oldest);


and implement a replacement for ngettext if not present, in pinc/gettext_setup.inc
    function ngettext($singular, $plural, $count) 
    { 
        // 0 days, 1 day, 2 days.
        return ($count == 1) ? $singular : $plural; 
    }


Task:187 Allow to move a page status to avail even if it is not in save

  => suggested implementation is to use Page_Reclaim()
  instead of Page_clearRound() on these pages.

  => modify page_operations.inc, function page_clear(), 
  and page_details.inc


Task:580 Glottal stop in team name not supported

Actually team stuff is pretty buggy. The [i] and [b] markup seems to 
be implemented rather inconsistently. I suggest to:
- check the number of teams using [b] and [i], 
- remove that functionality in team names
- use the proper escaping mechanism instead of stripAllString


Task:662 Count smoothreading uploads & icon for smoothreaders

Icon: I've drafted an icon representing a comfortable seat. Will open 
a topic on the general forum to allow other, more talented users, to 
agree on a specific icon.
  
tallies:

Do we want to count the number of projects, or to count the cumulative 
number of pages in these projects? 
I'm assuming we also want to keep the dates, and not only the 
cumulative number of pages/projects.

If it's the number of pages, then we can reuse the page statistics 
stuff and also display neighbours, average page per day, and diagrams
easily. But it looks a bit weird.

So, I suggest rather to count the number of projects. Displaying the
average number of projects smoothread per day would be a bit silly... 
So then I suggest to count statistics per months instead, reusing part 
of the page_tally.inc code that is still relevant (e.g. neighbours),
and create new code to handle monthly statistics instead. 

(note that these new monthly project statistics could also later 
include PP and PPV statistics)

There is no need to add a field in table smoothread to indicate if a
project was already uploaded; we can determine that in the filesystem.

In tools/upload_text.php, if the field is not set then update a book tally:

  if ($stage == 'smooth_done') 
  {
    if (... not uploading the second version of the same project ...) 
    {
      $users_SR_tallyboard = new TallyBoard( 'SR', 'U' );
      $users_SR_tallyboard->add_to_tally( $userP['user_id'], 1 );
    }
    then set the field to 1.
  }

In stats/include/member.inc, function showMbrRoles(), add this to 
display a smoothreader icon (displayed when one book has been uploaded)

    $users_SR_tallyboard = new TallyBoard( 'SR', 'U' );
    if ($users_SR_tallyboard->get_current_tally($curMbr['u_id']) > 0)
    {
        $roles[] = array( 'sr', _("Smooth reader"), 25 );
    }

Show the PP, PPV and SR statistics also, counted as number of pages 
or number of books?
Change showMbrTallySelector()
Add also a 

  echo _("Display user stats for different activities:") . ' ' . $choices2;
    
where choices2 contains also PP, PPV, SR?


Task:709 layout of diff page / links to images

Suggest adding checkboxes on top of page, showing possible rounds and 
displayed rounds; and to only display by default the current and 
previous round. That would save bandwidth and time for 95% of uses imho.
  
I'm not sure suppressing the dates for completed rounds is a good idea, 
because often you're interested in finding out if a particular proofer 
has been click-throughing the pages.
  
Implementation notes:
move the
  $rounds_to_display = get_rounds_with_data( $projectid );
out of tools/project_manager/page_table.inc, and pass $rounds_to_display 
as argument to function echo_page_table().
In tools/project_manager/page_detail.php, add the checkbox stuff with 
a button that refreshes the display.


Task:728 Show number of books available for Smooth Reading on activity hub

Implementation suggestion:

in pinc/Stage.inc, add an other parameter which is a SQL where clause 
on the project table.

        $project_where_clause
            // The optional SQL where clause on project table for projects 
            // in this stage. (put NULL if not relevant)

in the creators for Round and Pool, supply NULL for this parameter.

in pinc/stages.inc, in the definition of stage "SR", put:

  "state = 'proj_post_first_checked_out' 
  AND smoothread_deadline > UNIX_TIMESTAMP()"

in activity_hub.php, function summarize_stage(), if the stage is 
neither a Pool nor a Round, and if $project_where_clause is set, run 
the SQL query, possibly with the filter, in order to calculate the 
total number of projects, instead of the code currently between
  // Calculate the total number of projects.
and 
  // Output the table row.


Task:839 Greek translit. box - rho misread as psi - small font

Trivial.
tools/proofers/greek2ascii.php
replace 'h' and 'r' with '<code>h</code>' and '<code>r</code>';
replace <emp> (which doesn't exist) with <em>.


Task:858 Monitor file sizes in add_files.php

(need a site setting, warn at a large size, prevent at a still larger size?)

in tools/project_manager/add_files.php, replace
                if ( $action == 'error' )
                {
                    $this->n_errors++;
                    $error_msgs .= "$error_msg\n";
                }

with
                if ( $action == 'error' )
                {
                    $this->n_errors++;
                }
                if ( $error_msg != '' )
                {
                    $error_msgs .= "$error_msg\n";
                }

and have the function _get_action report warning messages for big sizes.

replace in _check_file()

        else
        {
            if ( $ext != ".txt" && (filesize($filename) < 100) )
            {
                return _('image file is small and probably bad');
            }
        }

with:

 if ($ext != ".txt") 
 {
    $filesize = filesize($filename);
    if ($filesize < 100) ...
    else if ($filesize > SOME_LIMIT)
    {
        return sprintf(_("Image file is too big (more than %d kb)"), SOME_LIMIT);
    }
 }

in _get_action(),
after

       else
        {
            assert( FALSE );
        }

put 
 $warning = '';
 if (filesize($filename) > SOME_LIMIT)
    {
        $warning = sprintf(_("Warning: Image file is very big (more than %d kb)"), SOME_LIMIT);
    }
 }


** consider also to whom whould a warning be issued? A mailing list?


Task:918 Typo in german interface textes

The task center is not the right place to address issues with 
translations in a particular language.
 
Implementation suggestion: 
in pinc/languages.inc, and pinc/lang_data.inc, in addition to
  $lang_forum_data=array(
  );
add an array storing the forum topic to report bugs with the translation
  $lang_translation_issue_forum_data=array(
  );

in pinc/theme.inc, after the code to display "Report a bug", add code
to display a _("Report an issue with the current translation")
if that link exists for that language.

Ideally the code for creating or editing a language in 
locale/translators should be able to edit these fields, so ideally 
the file lang_data.inc should be outside CVS?

Task:926 Show rounds in which pages have been proofed

Implementation suggestion, in project.php, at the end of function 
do_page_summary()

  $rounds_with_data = get_rounds_with_data( $projectid );
  echo "<p>" . _("<p>The project gone through the following rounds:") 
     . " " . implode(" ", $rounds_with_data) . "</p>";

(perhaps later add a summary of rounds and possibly user names?)


Task:1015 Repeat the "in progress" pages near the "start proofreading"

A simpler solution is to not display the "start proofreading" link 
on top if there are pages in progress.
  
add this function before function recentlyproofed( $wlist )

 function user_has_pages_in_progress()
 {
    global $project, $pguser;
 
    $round = get_Round_for_project_state($project->state);
    assert($round);
    $state_condition = "(state='{$round->page_temp_state}' 
        OR state='{$round->page_out_state}')";
        
    return mysql_query("SELECT 1
        FROM $project->projectid
        WHERE {$round->user_column_name}='$pguser' AND $state_condition
        LIMIT 0");
 }

and add something like this test case before line 354

  else if ( user_has_pages_in_progress() )
  {
      // Even though we assume the user has read the new comments,
      // user is probably willing to finish pages in progress first.
      $top_blurb =
          _("You may wish to finish pages which are in progress before proofreading new pages.");
          . "<br>"
          . $please_scroll_down
          . "<br>"
          . $comments_last_modified_blurb
          . "<br>"
          . _("The 'Start Proofreading' link and the list of your recent pages in progress appear below the Project Comments");

            


Task:1106 Make "catalog" page pageable or remove it

Suggest to remove entire catalog/index and catalog/get_page_text.
Unlinked from our CVS code, virtually useless, and bugged.


Task:1147 possibility of deleting some of "my projects"

(related to Task 1208).

Implementation suggestion:   
store 0 in t_latest_home_visit when a user wants to "forget" about 
a project.
A user forgets a project by clicking in a checkbox in his my projects 
page, and then a button _("Do not show selected projects any more").
Only do that when the user has no pages in progress or out for that project.
add 
  AND user_project_info.t_latest_home_visit <> 0 
in the SQL query for "my project" 
(excluding the special PF/admin feature of "my projects").


Task:1207 Show how many people have already Returned Page to Round

(7 votes)

If we add in page_events an index on 
(projectid, username, image, round, event_type), I don't see why the 
request should be extremely slow.
    
It would also enable to avoid proposing the same page to the same user 
when already returned to the round

Question: would the queries be faster if the user numerical ID were 
stored in table page_events instead of user name?

On the other hand, we could implement a degraded version of the feature: 
when returning a page to the round, increase a counter stored in field 
b_user (that field is unused when the page is not marked as bad).
Saving a page as done does reset this counter. The counter would then 
hold the number of times people (possibly the same user) have returned 
that page to the round. Run a cron job to fetch the pages having this 
counter set to a high value periodically?


Task:1208 Projects incorrectly added to My Projects

Implementation suggestion: in pinc/DPage.inc, in Page_returnToRound, and possibly also Page_reclaim and Page_markAsBad, if there are no other pages by this user in this project, then set t_latest_page_event to zero for that project, so that the project will not appear in the "My Projects" list for that user.

I considered doing it also for Page_clearRound, but I suppose the proofer might be interested in going back to that project when the PM has notified that pages have been cleared.


Task:1263 search/replace undo also undoes other formatting

Well, what is clear is that it is not possible in all cases to revert 
the changes made by the search/replace while keeping the other changes 
made. This is because the system does not keep a history of changes 
made, it just changes the entire text window.

What can be implemented is to ask for confirmation if the text has 
been further edited (i.e. is different) after the replace took place.


Task:1282 Zipped image file creation fails when project has 2048+ image files

suggest replacing in file tools/download_images.php
  exec(
    "zip -n .png:.jpg -q -j $zipfile_path $projectpath/*.png $projectpath/*.jpg",
    $output,
    $return_code );
with
  exec(
    "find $projectpath -name '*.png' -or -name '*.jpg' | xargs zip -n .png:.jpg -q -j $zipfile_path",
    $output,
    $return_code );


Task:1304 Option of downloading just the proofing images for a project.

In project.php, add after
    if ( $discriminator == 'images' )
    {
        ...
    }
    else if ( $discriminator == 'page_images' )
        // Generate images zip on the fly, so it's not taking up space on the disk.

        $url = "$code_url/tools/download_images.php?projectid=$projectid"
  . "&pages_only=1"
  . "&dummy={$projectid}_page_images.zip";
        // The 'dummy' parameter is for the benefit of download-software that
        // names the resulting file after the last component of the request URL.

        // To gain speed, images shall not be compressed in the zip,
        // so the sum of their individual filesizes is a fair approximation of
        // the size of the resulting zip.
        $filesize_b = 0;

  $result = mysql_query("
        SELECT image
        FROM $projectid
        ORDER BY image
    ");
  while($row = mysql_fetch_row($result))
  {
    filesize_b += filesize("$project->dir/$row[0]");
  }


and put this in download_images.php.

  if (isset($_GET['pages_only']))
  {
    $result = mysql_query("
        SELECT image
        FROM $projectid
        ORDER BY image
    ");
    $zip_cmd = "zip -n .png:.jpg -q -j $zipfile_path ";
    $zip_args = "";
    $n_args = 0;
    while ($row = mysql_fetch_row($result))
    {
        if ($nargs > 100) 
        {
            exec("$zip_cmd$zip_args");
            $n_args = 0;
            $zip_args = "";
        }
        $zip_args .= " $projectpath/$row[0]";
        $nargs ++;
    }
    if ($nargs != 0) 
        exec("$zip_cmd$zip_args");
  } 
  else 
  {
  ...
  }


Task:1318 Concatenated text download - only own pages

add in project.php:

        echo "Export only my pages?    ";
        echo "<input type='radio' name='this_user_only' value='1' />";
        echo "Yes    ";
        echo "<input type='radio' name='this_user_only' value='0' CHECKED />";
        echo "No<br />\n";

in tools/project_manager/generate_post_files.php, add

  $this_user_only = get enumerated parameter ... @$_REQUEST['this_user_only'];

  generate_interim_file( $projectid, $round_id, $which_text, $include_proofers, $this_user_only);

in tools/project_manager/post_files.inc, add parameter $this_user_only to 
  function generate_interim_file($project, $limit_round_id, $which_text, $include_proofers)

replace
    $pages_res = page_info_query($project, $limit_round_id, $which_text);
with
    $pages_res = page_info_query($project, $limit_round_id, $which_text, $this_user_only);

replace
  function page_info_query( $projectid, $limit_round_id, $which_text )
with
  function page_info_query( $projectid, $limit_round_id, $which_text, $this_user_only = 0 )

and put

    if ($this_user_only != 0) 
    {   
        $where = "WHERE '$pguser' IN ("
        for ( $rn = 1; $rn <= $limit_round->round_number; $rn++ )
            $where .= ($rn > 1? ", " : "") . $round->user_column_name;
        $where .= ")"
    }
    else
        $where = "";

    $res = mysql_query("
        SELECT $text_column_expr, image $user_fields
        FROM $projectid
        $where
        ORDER BY image
    ");

at the end of page_info_query.


Task:1338 Allow PPer to use the skip recommendation tool on their projects

(I don't remember if this has been implemented yet)

In noncvs/project_retread_skip_recommendations.php, replace
  // confirm the user can edit the project
  $ucep_result = user_can_edit_project($projectid);
  if(!($ucep_result == USER_CAN_EDIT_PROJECT || $pguser == 'piggy'))

with
  // confirm the user may run the script
  $user_allowed = (user_can_edit_project($projectid) == USER_CAN_EDIT_PROJECT);
  // also allow the reserved PPer. That will also include PPVers when the project
  // is in PPV, but it doesn't matter.
  $user_allowed = $user_allowed || mysql_query("SELECT 1 FROM projects 
    WHERE projectid = '$projectid' 
    AND checkedoutby = '$pguser'
    LIMIT 0");
  if(!($user_allowed || $pguser == 'piggy'))


pinc/SettingsClass.inc

Given this code:

        switch($settingCode)
        {
            default:
                return true;
            case 'sitemanager':
            case 'manager':
            case 'postprocessor':
                return false;
        }

use an alternate logic so that sitemanager, manager and postprocessor can be
set using the same function (using table users instead of table usersettings)


field postprocessor in users table

That field appears to be unused (superseded with PP.access in usersettings)
Suggest to remove it in the next release.


Translate emails

In theory when a mail is being sent to someone else, we should proceed thus:

  $temp = mysql_query("SELECT email, u_intlang FROM users WHERE username = '...'");
  $email = mysql_result($temp, 0, "email");
  $temp_intlang = mysql_result($temp, 0, "u_intlang");
  // temporarily change the current locale to the recipient's language.
  setlocale(LC_ALL, $temp_intlang);
            
  // build the mail subject and body, in the current localt
  $body = _("...");
  $subject = _("...");
 
  // Send the mail using $subject and $body 

  // restore the current locale
  global $intlang;
  setlocale(LC_ALL, $intlang);

So, check all use of function maybe_mail() and distinguish two cases:
1) mail is sent to a mailing list: then in conjunction with
the email address global variable, add an email language global variable,
e.g. in addition to

  $email_addr = $promotion_requests_email_addr;

add

  $email_lang = $promotion_requests_intlang;

and then use setlocale(LC_ALL, $email_lang) before building the body 
and subject. (that allows in theory another site to have its mailing 
lists in a different language, while sharing the same code)

Or to simplify we could use the same intlang value for all 
administrative purposes, and define a global variable $site_admin_intlang;

2) mail is sent to an individual (a proofreader, project manager, etc.);
use function 
  $email = get_email_and_setlocale($username)
before building the subject and body.

Similarly one could define a function
  get_email_and_setlocale_project_manager($project)
if needed.

And do not forget to restore the language after maybe_mail().


gettext ersatz

Unless nobody objects, I intend to move the replacement for _() 
that is currently in pinc/site_vars.php into pinc/gettext_setup.inc,
and also to add there a replacement for ngettext() in case the 
gettext extension is not installed.

userprefs and real name

- strip slashes on the user real name and user htmlspecialchars(, ENT_QUOTES) around $current_value in userprefs.php function _show_textfield

special colors

pinc/special_colors.inc actually dumps the entire special color database in an associative array, merely to check if a key exists in that array, and this for each books listed in the round pages. This array should be cached for efficiency.

tools/proofer/diff.php

creates a new Project for the same project ID several times. Should pass the Project object along for efficiency.