Index: theme/standard/styles_layout.css =================================================================== RCS file: /cvsroot/moodle/moodle/theme/standard/styles_layout.css,v retrieving revision 1.543 diff -u -r1.543 styles_layout.css --- theme/standard/styles_layout.css 19 Dec 2007 18:26:12 -0000 1.543 +++ theme/standard/styles_layout.css 19 Dec 2007 18:38:45 -0000 @@ -959,13 +959,45 @@ border-style: solid; } -#admin-langimport .generalbox { +#admin-lang .generalbox { text-align:center; margin:auto; border-width: 1px; border-style: solid; } +#admin-lang .lang_versionrestricted .lang_version { + background:black; + color:white; + font-weight:bold; + font-size:0.8em; + float:left; + padding:0 2px; + margin-top:0.35em; +} + +#admin-lang table.lang_except { + margin:0 0 0 1em; + cell-spacing:0; +} +#admin-lang table.lang_except th { + padding:5px 4px 2px 0; + font-size:0.75em; +} +#admin-lang table.lang_except td { + padding:0 4px 0 0; +} +#admin-lang .lang_previousvalue { + font-size:0.75em; +} +#admin-lang .lang_except_add { + margin-left:1em; + font-size:0.75em; + vertical-align:bottom; +} + + + #admin-langimport .generalbox table { text-align:center; margin:auto; Index: lang/en_utf8/admin.php =================================================================== RCS file: /cvsroot/moodle/moodle/lang/en_utf8/admin.php,v retrieving revision 1.171 diff -u -r1.171 admin.php --- lang/en_utf8/admin.php 19 Dec 2007 17:35:24 -0000 1.171 +++ lang/en_utf8/admin.php 19 Dec 2007 18:38:44 -0000 @@ -384,6 +384,9 @@ $string['iplookup'] = 'IP address lookup'; $string['keeptagnamecase'] = 'Keep tag name casing'; $string['lang'] = 'Default language'; +$string['lang_exceptadd'] = 'Add except'; +$string['lang_exceptcondition'] = 'Except when'; +$string['lang_exceptvalue'] = 'Value'; $string['lang16notify'] = 'Moodle 1.6 and above allows you to install and update language packs directly from download.moodle.org by following the link below'; $string['langcache'] = 'Cache language menu'; $string['langedit'] = 'Language editing'; Index: lib/moodlelib.php =================================================================== RCS file: /cvsroot/moodle/moodle/lib/moodlelib.php,v retrieving revision 1.978 diff -u -r1.978 moodlelib.php --- lib/moodlelib.php 19 Dec 2007 17:35:27 -0000 1.978 +++ lib/moodlelib.php 19 Dec 2007 18:38:45 -0000 @@ -4963,7 +4963,7 @@ $filetocheck = 'langconfig.php'; $defaultlang = 'en_utf8'; if (in_array($identifier, $langconfigstrs)) { - $module = 'langconfig'; //This strings are under langconfig.php for 1.6 lang packs + $module = 'langconfig'; //This strings are under langconfig.php for 1.6 lang packs } $lang = current_language(); @@ -5028,7 +5028,7 @@ foreach ($locations as $location) { $locallangfile = $location.$lang.'_local'.'/'.$module.'.php'; //first, see if there's a local file if (file_exists($locallangfile)) { - if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5036,7 +5036,7 @@ //if local directory not found, or particular string does not exist in local direcotry $langfile = $location.$lang.'/'.$module.'.php'; if (file_exists($langfile)) { - if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $langfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5054,14 +5054,14 @@ foreach ($locations as $location) { $langfile = $location.$lang.'/'.$filetocheck; if (file_exists($langfile)) { - if ($result = get_string_from_file('parentlanguage', $langfile, "\$parentlang")) { + if ($result = get_string_from_file('parentlanguage', $langfile, "\$parentlang", $a)) { eval($result); if (!empty($parentlang)) { // found it! //first, see if there's a local file for parent $locallangfile = $location.$parentlang.'_local'.'/'.$module.'.php'; if (file_exists($locallangfile)) { - if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5070,7 +5070,7 @@ //if local directory not found, or particular string does not exist in local direcotry $langfile = $location.$parentlang.'/'.$module.'.php'; if (file_exists($langfile)) { - if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $langfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5085,7 +5085,7 @@ foreach ($locations as $location) { $locallangfile = $location.$defaultlang.'_local/'.$module.'.php'; //first, see if there's a local file if (file_exists($locallangfile)) { - if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5095,7 +5095,7 @@ $langfile = $location.$defaultlang.'/'.$module.'.php'; if (file_exists($langfile)) { - if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $langfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5109,7 +5109,7 @@ foreach ($locations as $location) { $locallangfile = $location.$defaultlang.'_local/'.$module.'.php'; //first, see if there's a local file if (file_exists($locallangfile)) { - if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $locallangfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5119,7 +5119,7 @@ $langfile = $location.$defaultlang.'/'.$module.'.php'; if (file_exists($langfile)) { - if ($result = get_string_from_file($identifier, $langfile, "\$resultstring")) { + if ($result = get_string_from_file($identifier, $langfile, "\$resultstring", $a)) { eval($result); return $resultstring; } @@ -5137,18 +5137,21 @@ * @param string $identifier ? * @param string $langfile ? * @param string $destination ? + * @param mixed $a Arbitrary parameter to get_string, used only for expressions * @return string|false ? * @staticvar array $strings Localized strings * @access private * @todo Finish documenting this function. */ -function get_string_from_file($identifier, $langfile, $destination) { +function get_string_from_file($identifier, $langfile, $destination, $a) { static $strings; // Keep the strings cached in memory. if (empty($strings[$langfile])) { $string = array(); + $except = array(); include ($langfile); + $string['__except']=$except; $strings[$langfile] = $string; } else { $string = &$strings[$langfile]; @@ -5157,8 +5160,26 @@ if (!isset ($string[$identifier])) { return false; } + + $selectedstring=null; + + // When there is a conditional string entry for this identifier, it is + // used in preference. The first matching condition is used. If no + // conditions match, the normal $string will be used. + if(array_key_exists($identifier,$string['__except'])) { + foreach($string['__except'][$identifier] as $expression=>$value) { + if(eval("return $expression;")) { + $selectedstring=$value; + break; + } + } + } + + if(is_null($selectedstring)) { + $selectedstring=$string[$identifier]; + } - return $destination .'= sprintf("'. $string[$identifier] .'");'; + return $destination .'= sprintf("'. $selectedstring .'");'; } /** Index: admin/lang.php =================================================================== RCS file: /cvsroot/moodle/moodle/admin/lang.php,v retrieving revision 1.111 diff -u -r1.111 lang.php --- admin/lang.php 19 Dec 2007 17:35:21 -0000 1.111 +++ admin/lang.php 19 Dec 2007 18:38:44 -0000 @@ -439,15 +439,27 @@ } $newstrings = array(); + $newexcepts = array(); foreach ($_POST as $postkey => $postval) { $stringkey = lang_file_string_key($postkey); - $newstrings[$stringkey] = $postval; + @list($id, $stringname) = explode('XXX',$stringkey); + $matches=array(); + if($id=='string') { + $newstrings[$stringname] = $postval; + } else if(preg_match('/^exceptcondition([0-9]+)$/',$id,$matches)) { + if(!array_key_exists($stringname, $newexcepts)) { + $newexcepts[$stringname] = array(); + } + $value = $_POST['exceptvalue'.$matches[1].'XXX'.$stringname]; + if( trim($value) !== '' ) { + $newexcepts[$stringname][$postval] = $value; + } + } } - - unset($newstrings['currentfile']); - + $packstring = array(); + $packexcept = array(); $saveinto = $langdir; if ($uselocal) { if(file_exists($trfilepath)) { @@ -455,12 +467,17 @@ if (isset($string)) { $packstring = $string; } + if (isset($except)) { + $packexcept = $except; + } unset($string); + unset($except); } $saveinto = $locallangdir; } - if (lang_save_file($saveinto, $currentfile, $newstrings, $uselocal, $packstring)) { + if (lang_save_file($saveinto, $currentfile, $newstrings, $newexcepts, + $uselocal, $packstring, $packexcept)) { notify(get_string("changessaved")." ($saveinto/$currentfile)", "notifysuccess"); } else { error("Could not save the file '$saveinto/$currentfile'!", "lang.php?mode=compare&currentfile=$currentfile"); @@ -518,8 +535,10 @@ $o = ''; // stores the HTML output to be echo-ed unset($string); + unset($except); include($enfilepath); $enstring = isset($string) ? $string : array(); + $enexcept = isset($except) ? $except : array(); // // Following strings have moved into langconfig.php, but keep the here for backward compatibility // @@ -530,17 +549,21 @@ $enstring['parentlanguage'] = "<< TRANSLATORS: If your language has a Parent Language that Moodle should use when strings are missing from your language pack, then specify the code for it here. If you leave this blank then English will be used. Example: nl >>"; } unset($string); + unset($except); ksort($enstring); @include($lcfilepath); $localstring = isset($string) ? $string : array(); + $localexcept = isset($except) ? $except : array(); unset($string); + unset($except); ksort($localstring); @include($trfilepath); $string = isset($string) ? $string : array(); + $except = isset($except) ? $except : array(); ksort($string); - + if ($editable) { $o .= "
"; $o .= '
'; @@ -555,10 +578,6 @@ $o .= ''; $o .= '
 '; } - $envalue = nl2br(htmlspecialchars($envalue)); - $envalue = preg_replace('/(\$a\-\>[a-zA-Z0-9]*|\$a)/', '$0', $envalue); // Make variables bold. - $envalue = str_replace("%%","%",$envalue); - $envalue = str_replace("\\","",$envalue); // Delete all slashes $o .= "\n\n".''; $o .= ''; - $o .= ''.$envalue.''; - $o .= '
'."\n"; + $o .= lang_display_item($key,'stren',$enstring,$enexcept); $o .= ''.$key.''; + $o .= ''."\n"; - + // Missing array keys are not bugs here but missing strings error_reporting(E_ALL ^ E_NOTICE); if ($uselocal) { $value = lang_fix_value_from_file($localstring[$key]); $value2 = lang_fix_value_from_file($string[$key]); + $display2 = lang_display_item($key,'lang_previousvalue',$string,$except); + if(array_key_exists($key,$localexcept)) { + $valueexcept=$localexcept[$key]; + } else { + $valueexcept=null; + } + if(array_key_exists($key,$except)) { + $valueexcept2=$except[$key]; + } else { + $valueexcept2=null; + } if ($value == '') { $value = $value2; + $valueexcept = $valueexcept2; // Note you can't have except without a string } } else { $value = lang_fix_value_from_file($string[$key]); $value2 = lang_fix_value_from_file($localstring[$key]); + $display2 = lang_display_item($key,'lang_previousvalue',$localstring,$localexcept); + if(array_key_exists($key,$except)) { + $valueexcept=$except[$key]; + } else { + $valueexcept=null; + } + if(array_key_exists($key,$localexcept)) { + $valueexcept2=$localexcept[$key]; + } else { + $valueexcept2=null; + } } error_reporting($CFG->debug); - + // Color highlighting: // red #ef6868 - translation missing in both system and local pack // yellow #feff7f - translation missing in system pack but is translated in local @@ -612,7 +654,8 @@ $missingprev = ''; } } else { - if ($value <> $value2 && $value2 <> '') { + if (lang_values_are_different_and_not_blank( + $value,$valueexcept,$value2,$valueexcept2)) { $cellcolour = 'class="localdifferent"'; $usetabindex = true; } else { @@ -650,8 +693,31 @@ } $o .= ''; } + $o .= ''; + $o .= ''; + if($valueexcept) { + $count=0; + foreach($valueexcept as $condition=>$conditionvalue) { + + $o .= ''; + $o .= ''; + $o .= ''; + $count++; + } + } + $o .= ''; + if ($value2 <> '' && $value <> $value2) { - $o .= '
'.$value2.''; + $o .= $display2; } $o .= $missingnext . ''; @@ -684,8 +750,13 @@ print_heading($strnomissingstrings, '', 4, 'notifysuccess'); } } + + $o .= ''. + ''; + echo $o; - } else { // no $currentfile specified // no useful information to display - maybe some help? instructions? @@ -912,11 +983,14 @@ * @param string $path Full pathname to the directory to use * @param string $file File to overwrite * @param array $strings Array of strings to write + * @param array $excepts Array of excepts to write * @param bool $local Should *_local version be saved? * @param array $packstrings Array of default langpack strings (needed if $local) - * @return bool Created successfully? + * @param array $packexcepts Array of excepts to write + * @return bool Created successfully? */ -function lang_save_file($path, $file, $strings, $local, $packstrings) { +function lang_save_file($path, $file, $strings, $excepts, $local, + $packstrings, $packexcepts) { global $CFG, $USER; if (LANG_KEEP_ORPHANS) { // let us load the current content of the file @@ -928,6 +1002,12 @@ } else { $orphans = array(); } + if (isset($except)) { + $exceptorphans = $except; + unset($except); + } else { + $exceptorphans = array(); + } } // let us rewrite the file if (!$f = @fopen("$path/$file","w")) { @@ -941,25 +1021,25 @@ } fwrite($f, "\n\n"); ksort($strings); - foreach ($strings as $key => $value) { - @list($id, $stringname) = explode('XXX',$key); + foreach ($strings as $stringname => $value) { $value = lang_fix_value_before_save($value); - if ($id == "string" and $value != ""){ - if ((!$local) || (!isset($packstrings[$stringname])) || (lang_fix_value_from_file($packstrings[$stringname]) <> lang_fix_value_from_file($value))) { + if ($value != "") { + if (!$local || !lang_items_are_the_same( + $stringname, $strings, $excepts, $packstrings, $packexcepts)) { // Either we are saving the master language pack - // or the string is not saved in packstring - fixes PHP notices about missing key // or we are saving local language pack and the strings differ. - fwrite($f,"\$string['$stringname'] = '$value';\n"); + lang_write_item_to_file($f,$stringname,$strings,$excepts); } if (LANG_KEEP_ORPHANS && isset($orphans[$stringname])) { unset($orphans[$stringname]); + unset($exceptorphans[$stringname]); } } } if (LANG_KEEP_ORPHANS) { // let us add orphaned strings, i.e. already translated strings without the English referential source foreach ($orphans as $key => $value) { - fwrite($f,"\$string['$key'] = '".lang_fix_value_before_save($value)."'; // ORPHANED\n"); + lang_write_item_to_file($f,$key,$orphans,$exceptorphans,' // ORPHANED'); } } fwrite($f,"\n?>\n"); @@ -968,6 +1048,30 @@ } /** + * Writes a language string, and any associated 'except' conditions, to a file. + * @param object $f File handle + * @param string $key Key of string + * @param array &$string Array including the string + * @param array &$except Array possibly including except conditions + * @param string $note Optional note to add to end of line + */ +function lang_write_item_to_file(&$f,$key,$string,$except,$note='') { + fwrite($f,"\$string['$key'] = '". + lang_fix_value_before_save($string[$key])."';$note\n"); + if(array_key_exists($key,$except) && count($except[$key])>0) { + fwrite($f,"\$except['$key'] = array("); + $first=true; + foreach($except[$key] as $condition=>$value) { + fwrite($f,($first ? '' : ',')."\n '$condition'=>'". + lang_fix_value_before_save($value)."'"); + $first=false; + } + fwrite($f,");\n"); + } +} + + +/** * Fix value of the translated string after it is load from the file. * * These modifications are typically necessary to work with the same string coming from two sources. @@ -991,6 +1095,115 @@ } /** + * Converts a language string value for display by changing special characters + * and bolding any variables. + * @param string $value Language string + * @return string String correctly escaped and converted for HTML + */ +function lang_display_string($value) { + $value = nl2br(htmlspecialchars($value)); + $value = preg_replace('/(\$a\-\>[a-zA-Z0-9_]*|\$a)/', '$0', $value); // Make variables bold. + $value = str_replace("%%","%",$value); + $value = str_replace("\\","",$value); // Delete all slashes + return $value; +} + +/** + * Displays a language 'item' including the string and any exceptions. + * @param string $key Array key + * @param string $class HTML class= value + * @param array &$string Basic string array + * @param array &$except Exceptions array + */ +function lang_display_item($key,$class,&$string,&$except) { +if(!is_array($except)) { + debugging('oops'); + print_object($except); +} + $result = '
'; + $result .= lang_display_string($string[$key]); + if(array_key_exists($key,$except)) { + $result .= ''; + foreach($except[$key] as $condition=>$conditionstring) { + $result .= ''; + } + $result .= '
'. + htmlspecialchars($condition).''. + lang_display_string($conditionstring).'
'; + } + $result .= '
'."\n"; + return $result; +} + +/** + * Compares two language items, including the basic string plus any + * 'except' conditions. + * @param string $key Array key + * @param array &$string1 Array of basic strings from source 1 + * @param array &$except1 Array of except from source 1 + * @param array &$string2 Array of basic strings from source 2 + * @param array &$except2 Array of except from source 2 + * @return bool True if they are essentially the same (ignoring minor + * differences such as CRLF, whitespace at ends, etc.) + */ +function lang_items_are_the_same($key,&$string1,&$except1,&$string2,&$except2) { + + return lang_values_are_the_same( + array_key_exists($key,$string1) ? $string1[$key] : null, + array_key_exists($key,$except1) ? $except1[$key] : null, + array_key_exists($key,$string2) ? $string2[$key] : null, + array_key_exists($key,$except2) ? $except2[$key] : null); +} + +function lang_values_are_different_and_not_blank( + $oldvalue, $oldexcept, $newvalue, $newexcept) { + // Special case: if new values are blank, return false + if($newvalue==='' && ($newexcept===null || implode('',$newexcept)==='')) { + return false; + } + return !lang_values_are_the_same($oldvalue,$oldexcept,$newvalue,$newexcept); +} + +function lang_values_are_the_same($oldvalue, $oldexcept, $newvalue, $newexcept) { + // If string doesn't exist, must also not exist in second one + if($oldvalue===null) { + return $newvalue===null; + } + + // Compare strings + if(lang_fix_value_from_file($oldvalue) !== + lang_fix_value_from_file($newvalue)) { + return false; + } + + // Strings are the same. Now do same check for except + if($oldexcept===null) { + return $newexcept===null; + } else if($newexcept===null) { + return false; + } + + // Except exists in both, compare except + if(count($oldexcept)!=count($newexcept)) { + return false; + } + + // Compare each condition and value + foreach($oldexcept as $condition=>$value) { + if(!array_key_exists($condition,$newexcept)) { + return false; + } + if(lang_fix_value_from_file($value) !== + lang_fix_value_from_file($newexcept[$condition])) { + return false; + } + } + + // OK, I guess they're the same! + return true; +} + +/** * Fix value of the translated string before it is saved into the file * * @uses $CFG Index: admin/lang.js =================================================================== RCS file: admin/lang.js diff -N admin/lang.js --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ admin/lang.js 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,91 @@ +// JavaScript for dynamic HTML editing of 'except' conditions on language page + +var lang_delete_src,lang_delete_alt; + +function lang_init_js(addText,deleteSrc,deleteAlt) { + lang_delete_src=deleteSrc; + lang_delete_alt=deleteAlt; + var inputs=document.getElementsByTagName('input'); + for(var i=0;i