/** * Get an array of all the INI language entries in the specified language. * * @param LANGUAGE_NAME The language * @param ID_TEXT The language file * @param boolean Force usage of original file * @return array The language entries */ function get_lang_file_map($lang, $file, $non_custom = false) { $a = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $file . '.ini'; if (!file_exists($a)) { $a = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $file . '.po'; if (!file_exists($a)) { $a = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $file . '-' . strtolower($lang) . '.po'; } } if (get_custom_file_base() != get_file_base() && !file_exists($a)) { $a = get_file_base() . '/lang_custom/' . $lang . '/' . $file . '.ini'; if (!file_exists($a)) { $a = get_file_base() . '/lang_custom/' . $lang . '/' . $file . '.po'; if (!file_exists($a)) { $a = get_file_base() . '/lang_custom/' . $lang . '/' . $file . '-' . strtolower($lang) . '.po'; } } } if (!file_exists($a) || $non_custom) { $b = get_custom_file_base() . '/lang/' . $lang . '/' . $file . '.ini'; if (!file_exists($b)) { $b = get_custom_file_base() . '/lang/' . $lang . '/' . $file . '.po'; if (!file_exists($b)) { $b = get_custom_file_base() . '/lang/' . $lang . '/' . $file . '-' . strtolower($lang) . '.po'; } } if (file_exists($b)) { $a = $b; } else { if ($non_custom) { return array(); } } } $target = array(); _get_lang_file_map($a, $target); return $target; }
/** * The actualiser to create a .po TAR. * * @return tempcode The UI */ function export_po() { $lang = filter_naughty(get_param('id')); // Send header header('Content-Type: application/octet-stream' . '; authoritative=true;'); if (strstr(ocp_srv('HTTP_USER_AGENT'), 'MSIE') !== false) { header('Content-Disposition: filename="ocportal-' . $lang . '.tar"'); } else { header('Content-Disposition: attachment; filename="ocportal-' . $lang . '.tar"'); } require_code('tar'); require_code('lang_compile'); require_code('character_sets'); $tempfile = ocp_tempnam('po'); $tar = tar_open($tempfile, 'wb'); $dh = @opendir(get_custom_file_base() . '/lang_custom/' . $lang); if ($dh !== false) { $charset = do_lang('charset', NULL, NULL, NULL, $lang); $english_charset = do_lang('charset', NULL, NULL, NULL, fallback_lang()); while (($f = readdir($dh)) !== false) { if (substr($f, -4) == '.ini') { $path = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $f; $entries = array(); _get_lang_file_map($path, $entries, false, false); $mtime = filemtime($path); $data = ' msgid "" msgstr "" "Project-Id-Version: ocportal\\n" "PO-Revision-Date: ' . gmdate('Y-m-d H:i', $mtime) . '+0000\\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n" "Language-Team: FULL NAME <EMAIL@ADDRESS>\\n" "MIME-Version: 1.0\\n" "Content-Type: text/plain; charset=UTF-8\\n" "Content-Transfer-Encoding: 8bit\\n" "X-ocPortal-Export-Date: ' . gmdate('Y-m-d H:i', $mtime) . '+0000\\n" "X-Generator: ocPortal (' . ocp_version_full() . ')\\n" '; $entries2 = array(); $en_seen_before = array(); foreach ($entries as $key => $val) { $english = do_lang($key, NULL, NULL, NULL, fallback_lang(), false); if (is_null($english)) { continue; } if ($english == '') { continue; } $val = convert_to_internal_encoding($val, $charset, 'utf-8'); $val = str_replace(chr(10), '\\n', $val); $english = convert_to_internal_encoding($english, $english_charset, 'utf-8'); $english = str_replace(chr(10), '\\n', $english); $seen_before = false; if (isset($en_seen_before[$val])) { $seen_before = true; foreach ($entries2 as $_key => $_val) { if ($entries2[$_key][2] == $val) { $entries2[$_key][1] = true; } } } $entries2[$key] = array($val, $seen_before, $english); $en_seen_before[$val] = 1; } require_code('support2'); foreach ($entries2 as $key => $_val) { list($val, $seen_before, $english) = $_val; $data .= '#: [strings]' . $key . chr(10); if ($seen_before) { $data .= 'msgctxt "[strings]' . $key . '"' . chr(10); } $wrapped = preg_replace('#"\\n"$#', '', ocp_mb_chunk_split(str_replace('"', '\\"', $english), 76, '"' . chr(10) . '"')); if (strpos($wrapped, chr(10)) !== false) { $data .= 'msgid ""' . chr(10) . '"' . $wrapped . '"' . chr(10); } else { $data .= 'msgid "' . $wrapped . '"' . chr(10); } $wrapped = preg_replace('#"\\n"$#', '', ocp_mb_chunk_split(str_replace('"', '\\"', $val), 76, '"' . chr(10) . '"')); if (strpos($wrapped, chr(10)) !== false) { $data .= 'msgstr ""' . chr(10) . '"' . $wrapped . '"' . chr(10); } else { $data .= 'msgstr "' . $wrapped . '"' . chr(10); } $data .= chr(10); } tar_add_file($tar, basename($f, '.ini') . '/' . basename($f, '.ini') . '-' . strtolower($lang) . '.po', $data, 0666, $mtime); } } } tar_close($tar); readfile($tempfile); @unlink($tempfile); $GLOBALS['SCREEN_TEMPLATE_CALLED'] = ''; exit; return new ocp_tempcode(); // For code quality checker }
function testLangMistakes() { $verbose = false; $dh = opendir(get_file_base() . '/lang/EN/'); while (($file = readdir($dh)) !== false) { if ($file[0] == '.') { continue; } $input = array(); _get_lang_file_map(get_file_base() . '/lang/EN/' . $file, $input, NULL, false); foreach ($input as $key => $string) { $output2 = ''; if ($this->str_ipos($string, 'thankyou') !== false) { $this->assertTrue(false, 'The word \'thankyou\' was used in ' . $file . '. This should be changed to \'thank you\'.'); } if ($this->str_ipos($string, 'unvalidated') !== false) { $this->assertTrue(false, 'The word \'unvalidated\' was used in ' . $file . '. This should be changed to \'non-validated\'.'); } if ($this->str_ipos($string, 'add-on') !== false) { $this->assertTrue(false, 'The word \'add-on\' was used in ' . $file . '. This should be changed to \'addon\'.'); } if ($this->str_ipos($string, 'preceeding') !== false) { $this->assertTrue(false, 'The word \'preceeding\' was used in ' . $file . '. This should be changed to \'proceeding\'.'); } if ($this->str_ipos($string, 'publically') !== false) { $this->assertTrue(false, 'The word \'publically\' was used in ' . $file . '. This should be changed to \'publicly\'.'); } if ($this->str_ipos($string, 'seperate') !== false) { $this->assertTrue(false, 'The word \'seperate\' was used in ' . $file . '. This should be changed to \'separate\'.'); } if ($this->str_ipos($string, 'chat room') !== false) { $this->assertTrue(false, 'The phrase \'chat room\' was used in ' . $file . '. This should be changed to \'chatroom\'.'); } if ($this->str_ipos($string, 'URL\'s') !== false) { $this->assertTrue(false, 'The acronym \'URLs\' was used in ' . $file . '. This should be changed to \'URLs\'.'); } if ($this->str_ipos($string, 'user-group') !== false) { $this->assertTrue(false, 'The term \'user-group\' was used in ' . $file . '. This should be changed to \'usergroup\'.'); } if ($this->str_ipos($string, 'supermember') !== false) { $this->assertTrue(false, 'The term \'supermember\' was used in ' . $file . '. This should be changed to \'super-member\'.'); } if ($this->str_ipos($string, 'user name') !== false) { $this->assertTrue(false, 'The term \'user name\' was used in ' . $file . '. This should be changed to \'username\'.'); } if ($this->str_ipos($string, 'built in') !== false) { $this->assertTrue(false, 'The phrase \'built in\' was used in ' . $file . '. This should be changed to \'built-in\'.'); } if ($this->str_ipos($string, 'email') !== false && $this->str_ipos($string, '/') === false) { $this->assertTrue(false, 'The term \'email\' was used in ' . $file . '. This should be changed to \'e-mail\'.'); } if ($this->str_ipos($string, 'web site') !== false) { $this->assertTrue(false, 'The phrase \'web site\' was used in ' . $file . '. This should be changed to \'website\'.'); } if ($this->str_ipos($string, 'ID\'s') !== false) { $this->assertTrue(false, 'The term \'ID\'s\' was used in ' . $file . '. This should be changed to \'IDs\'.'); } if ($this->str_ipos($string, 'comma separated') !== false) { $this->assertTrue(false, 'The phrase \'comma separated\' was used in ' . $file . '. This should be changed to \'comma-separated\'.'); } //if($this->str_ipos($string,'center')!==false) $this->assertTrue(false,'The word \'center\' was used in '.$file.'. This should be changed to \'centre\'.'); if ($file != 'upgrade.ini' && $key != 'NO_PHP_IN_TEMPLATES' && $key != 'WHAT_TO_EXPECT' && $key != 'DESCRIPTION_INCLUDE_OCP_ADVERT' && $key != 'INCLUDE_OCP_ADVERT' && $key != 'UNINSTALL_WARNING' && $key != 'OCP_CHAT_EXTRA' && strpos($key, 'SETUP_WIZARD') === false && $file != 'lang.ini' && $file != 'recommend.ini' && $file != 'version.ini' && $file != 'tips.ini' && $file != 'debrand.ini' && $file != 'import.ini' && $file != 'installer.ini' && $file != 'occle.ini' && $file != 'addons.ini' && strpos($string, 'ocPortal') !== false) { $this->assertTrue(false, 'The word \'ocPortal\' was used in ' . $file . '. This should probably be changed to \'the software\'.'); } if (preg_match('#([^A-Za-z"\\_]+)comcode([^A-Za-z"]+)#', $string) != 0) { $this->assertTrue(false, 'The term \'comcode\' was used in ' . $file . '. This should be changed to \'Comcode\'.'); } if (strpos($string, 'seedy') !== false) { $this->assertTrue(false, 'The term \'seedy\' was used in ' . $file . '. This should be changed to \'SEEDY\'.'); } if (strpos($string, 'admin centre') !== false) { $this->assertTrue(false, 'The phrase \'admin centre\' was used in ' . $file . '. This should be changed to \'Admin Zone\'.'); } if ($verbose && $this->str_ipos($string, 'user') !== false) { $this->assertTrue(false, 'The term \'user\' was used in ' . $file . '. This might need to be changed to \'member\', depending on the circumstances.'); } if ($this->str_ipos($string, 'set-up') !== false) { $this->assertTrue(false, 'The phrase \'set-up\' was used in ' . $file . '. This might need to be changed to \'setup\', depending on the usage.'); } if ($verbose && strpos($string, '\\n') !== false) { $this->assertTrue(false, 'The \'\\n\' linebreak character was used in ' . $file . ' in the language string. This should be checked, to make sure it is really necessary.'); } if (preg_match('#([^A-Za-z]+)tar([^A-Za-z]+)#', $string) != 0) { $this->assertTrue(false, 'The filetype \'tar\' was used in ' . $file . '. This should be changed to \'TAR\'.'); } if (preg_match('#([^A-Za-z]>+)id([^A-Za-z=<]+)#', $string) != 0) { $this->assertTrue(false, 'The acronym \'id\' was used in ' . $file . '. This should be changed to \'ID\'.'); } if (preg_match('#([^A-Za-z\\[\\]></\']+)url([^\\}A-Za-z=\']+)#', $string) != 0) { $this->assertTrue(false, 'The acronym \'url\' was used in ' . $file . '. This should be changed to \'URL\'.'); } if (preg_match('#([^A-Za-z]+)zip([^A-Za-z]+)#', $string) != 0) { $this->assertTrue(false, 'The filetype \'zip\' was used in ' . $file . '. This should be changed to \'ZIP\'.'); } if ($verbose && preg_match('#([A-Za-z]+)s( |-)#', $string) != 0) { $this->assertTrue(false, 'A word ended with an \'s\', but did not contain an apostrophe. This might be a case of mistaken plurality.'); } if ($verbose && preg_match('#([a-z]+)( |-)([A-Z]{1})([a-z]+)#', $string) != 0) { $this->assertTrue(false, 'A word that was in the middle of the string started with a capital letter. This might be a badly capitalised string.'); } if ($verbose && preg_match('#<([A-Za-z]+)>#', $string) != 0) { $this->assertTrue(false, 'An HTML tag was used in ' . $file . ' in the language string. This should be checked, to make sure it is really necessary; HTML should be confined to the templates.'); } } } }
/** * Get an array of all the INI description entries in the specified language. * * @param LANGUAGE_NAME The language * @param ?ID_TEXT The language file (NULL: all non-custom language files) * @return array The language descriptions */ function get_lang_file_descriptions($lang, $file = NULL) { if (is_null($file)) { $dh = opendir(get_file_base() . '/lang/' . $lang); $descriptions = array(); while (($f = readdir($dh)) !== false) { if (substr($f, -4) == '.ini') { $descriptions = array_merge($descriptions, get_lang_file_descriptions($lang, basename($f, '.ini'))); } } return $descriptions; } $a = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $file . '.ini'; if (get_custom_file_base() != get_file_base() && !is_file($a)) { $a = get_file_base() . '/lang_custom/' . $lang . '/' . $file . '.ini'; } $b = is_file($a) ? $a : get_file_base() . '/lang/' . $lang . '/' . $file . '.ini'; if (!is_file($b)) { $b = get_file_base() . '/lang/' . fallback_lang() . '/' . $file . '.ini'; } $target = array(); require_code('lang_compile'); _get_lang_file_map($b, $target, true); return $target; }
/** * Load up a language file, compiling it (it's not cached yet). * * @param ID_TEXT The language file name * @param ?LANGUAGE_NAME The language (NULL: uses the current language) * @param ?string The language type (lang_custom, or custom) (NULL: normal priorities are used) * @set lang_custom custom * @param PATH Where we are cacheing too * @param boolean Whether to just return if there was a loading error * @return boolean Whether we FAILED to load */ function require_lang_compile($codename, $lang, $type, $cache_path, $ignore_errors = false) { global $LANGUAGE, $REQUIRE_LANG_LOOP, $LANG_LOADED_LANG; $desire_cache = function_exists('get_option') && (get_option('is_on_lang_cache', true) == '1' || get_param_integer('keep_cache', 0) == 1 || get_param_integer('cache', 0) == 1) && get_param_integer('keep_cache', NULL) !== 0 && get_param_integer('cache', NULL) !== 0; if ($desire_cache) { if ($GLOBALS['IN_MINIKERNEL_VERSION'] == 0) { global $DECACHED_COMCODE_LANG_STRINGS; // Cleanup language strings if (!$DECACHED_COMCODE_LANG_STRINGS) { $DECACHED_COMCODE_LANG_STRINGS = true; $comcode_lang_strings = $GLOBALS['SITE_DB']->query_select('cached_comcode_pages', array('string_index'), array('the_zone' => '!'), '', NULL, NULL, true); if (!is_null($comcode_lang_strings)) { $GLOBALS['SITE_DB']->query_delete('cached_comcode_pages', array('the_zone' => '!')); foreach ($comcode_lang_strings as $comcode_lang_string) { delete_lang($comcode_lang_string['string_index']); } } } } $load_target = array(); } else { $load_target =& $LANGUAGE[$lang]; } global $FILE_ARRAY; if (@is_array($FILE_ARRAY) && file_array_exists('lang/' . $lang . '/' . $codename . '.ini')) { $lang_file = 'lang/' . $lang . '/' . $codename . '.ini'; $file = file_array_get($lang_file); _get_lang_file_map($file, $load_target, NULL, true); $bad = true; } else { $bad = true; $dirty = false; // Load originals $lang_file = get_file_base() . '/lang/' . $lang . '/' . filter_naughty($codename) . '.ini'; if (file_exists($lang_file)) { _get_lang_file_map($lang_file, $load_target, NULL, false); $bad = false; } // Load overrides now if they are there if ($type != 'lang') { $lang_file = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $codename . '.ini'; if (!file_exists($lang_file) && get_file_base() != get_custom_file_base()) { $lang_file = get_file_base() . '/lang_custom/' . $lang . '/' . $codename . '.ini'; } if (!file_exists($lang_file)) { $lang_file = get_custom_file_base() . '/lang_custom/' . $lang . '/' . $codename . '.po'; if (!file_exists($lang_file)) { $lang_file = get_file_base() . '/lang_custom/' . $lang . '/' . $codename . '-' . strtolower($lang) . '.po'; } } } if ($type != 'lang' && file_exists($lang_file)) { _get_lang_file_map($lang_file, $load_target, NULL, false); $bad = false; $dirty = true; // Tainted from the official pack, so can't store server wide } // NB: Merge op doesn't happen in require_lang. It happens when do_lang fails and then decides it has to force a recursion to do_lang(xx,fallback_lang()) which triggers require_lang(xx,fallback_lang()) when it sees it's not loaded if ($bad && $lang != fallback_lang()) { require_lang($codename, fallback_lang(), $type, $ignore_errors); $REQUIRE_LANG_LOOP--; $fallback_cache_path = get_custom_file_base() . '/lang_cached/' . fallback_lang() . '/' . $codename . '.lcd'; if (file_exists($fallback_cache_path)) { require_code('files'); $fallback_map = unserialize(file_get_contents($fallback_cache_path)); $sep = '<span class="notranslate">----</span>'; $to_translate = ''; $i = 0; $from = 0; $lang_codes = array_keys($fallback_map); foreach ($fallback_map as $value) { if (strlen($to_translate . $sep . $to_translate) >= 3000) { $translated = preg_split('#<span class="notranslate">[^<>]*----[^<>]*</span>#', google_translate($to_translate, $lang)); foreach ($translated as $j => $t_value) { if (strtolower($lang_codes[$from + $j]) == $lang_codes[$from + $j]) { $t_value = $fallback_map[$lang_codes[$from + $j]]; } if ($lang_codes[$from + $j] == 'locale') { $t_value = strtolower($lang) . '_' . strtoupper($lang); } $fallback_map[$lang_codes[$from + $j]] = $t_value; $load_target[$lang_codes[$from + $j]] = $t_value; } $from = $i; $to_translate = ''; } if ($to_translate != '') { $to_translate .= $sep; } $to_translate .= $value; $i++; } $translated = preg_split('#<span class="notranslate">[^<>]*----[^<>]*</span>#', google_translate($to_translate, $lang)); foreach ($translated as $j => $t_value) { if (strtolower($lang_codes[$from + $j]) == $lang_codes[$from + $j]) { $t_value = $fallback_map[$lang_codes[$from + $j]]; } if ($lang_codes[$from + $j] == 'locale') { $t_value = strtolower($lang) . '_' . strtoupper($lang); } $fallback_map[$lang_codes[$from + $j]] = $t_value; $load_target[$lang_codes[$from + $j]] = $t_value; } if (function_exists('ocp_mb_substr') && $codename == 'dates') { foreach (array_keys($fallback_map) as $key) { if (substr($key, 0, 3) == 'FC_') { $test = ocp_mb_substr(trim($fallback_map[substr($key, 3)]), 0, 1, true); if ($test !== false) { $fallback_map[$key] = $test; } } } } $myfile = fopen($cache_path, 'wb'); fwrite($myfile, serialize($fallback_map)); fclose($myfile); fix_permissions($cache_path); } if (!array_key_exists($lang, $LANG_LOADED_LANG)) { $LANG_LOADED_LANG[$lang] = array(); } $LANG_LOADED_LANG[$lang][$codename] = 1; if (!$bad) { $LANGUAGE[$lang] += $fallback_map; } return $bad; } if ($bad) { if ($ignore_errors) { return true; } if ($codename != 'critical_error' || $lang != get_site_default_lang()) { fatal_exit(do_lang_tempcode('MISSING_LANG_FILE', escape_html($codename), escape_html($lang))); } else { critical_error('CRIT_LANG'); } } } if (is_null($GLOBALS['MEM_CACHE'])) { // Cache if ($desire_cache) { $file = @fopen($cache_path, 'wt'); // Will fail if cache dir missing .. e.g. in quick installer if ($file) { if (fwrite($file, serialize($load_target)) > 0) { // Success fclose($file); require_code('files'); fix_permissions($cache_path); } else { // Failure fclose($file); @unlink($cache_path); } } } } else { persistant_cache_set(array('LANG', $lang, $codename), $load_target, !$dirty); } if ($desire_cache) { $LANGUAGE[$lang] += $load_target; } return $bad; }