www.mageia.org report about differences between Transifex and our git repository

Languages translation progress report for web pages is available here.

'help', // Mageia Installer Help 'tx_name' => 'doc_installer', 'git_path' => 'http://gitweb.mageia.org/software/i18n/tools/plain/docs/installer', ), array( 'pot_name' => 'mcc-help', // Mageia Control Center Help 'tx_name' => 'mcc-help', 'git_path' => 'http://gitweb.mageia.org/software/i18n/tools/plain/docs/mcc-help', ), ); } else if ('Cauldron' == $resource_type) { $git_resources = array( array( 'pot_name' => 'drakconf', // Mageia Control Center 'tx_name' => 'control-center', 'git_path' => 'http://gitweb.mageia.org/software/control-center/plain/po', ), array( 'pot_name' => 'copyiso2usb', 'tx_name' => 'copyiso2usb', 'git_path' => 'http://gitweb.mageia.org/software/copyiso2usb/plain/po', ), array( 'pot_name' => 'desktop-common-data', 'tx_name' => 'desktop-common-data', 'git_path' => 'http://gitweb.mageia.org/software/desktop/common-data/plain/po', ), array( 'pot_name' => 'drak3d', 'tx_name' => 'drak3d', 'git_path' => 'http://gitweb.mageia.org/software/drak3d/plain/po', ), array( 'pot_name' => 'drakguard', 'tx_name' => 'drakguard', 'git_path' => 'http://gitweb.mageia.org/software/drakguard/plain/po', ), array( 'pot_name' => 'draklive-install', 'tx_name' => 'draklive-install', 'git_path' => 'http://gitweb.mageia.org/software/draklive-install/plain/po', ), array( 'pot_name' => 'drakmenustyle', 'tx_name' => 'drakmenustyle', 'git_path' => 'http://gitweb.mageia.org/software/drakmenustyle/plain/po', ), array( 'pot_name' => 'drakpxelinux', 'tx_name' => 'drakpxelinux', 'git_path' => 'http://gitweb.mageia.org/software/drakpxelinux/plain/po', ), array( 'pot_name' => 'drakwizard', 'tx_name' => 'drakwizard', 'git_path' => 'http://gitweb.mageia.org/software/drakwizard/plain/po', ), array( 'pot_name' => 'drakx-kbd-mouse-x11', 'tx_name' => 'drakx-kbd-mouse-x11', 'git_path' => 'http://gitweb.mageia.org/software/drakx-kbd-mouse-x11/plain/po', ), array( 'pot_name' => 'drakx-net', 'tx_name' => 'drakx-net', 'git_path' => 'http://gitweb.mageia.org/software/drakx-net/plain/po', ), array( 'pot_name' => 'DrakX', 'tx_name' => 'drakx_install', 'git_path' => 'http://gitweb.mageia.org/software/drakx/plain/perl-install/install/share/po', ), array( 'pot_name' => 'libDrakX', 'tx_name' => 'drakx_share', 'git_path' => 'http://gitweb.mageia.org/software/drakx/plain/perl-install/share/po', ), array( 'pot_name' => 'libDrakX-standalone', 'tx_name' => 'drakx_standalone', 'git_path' => 'http://gitweb.mageia.org/software/drakx/plain/perl-install/standalone/po', ), array( 'pot_name' => 'indexhtml', 'tx_name' => 'indexhtml', 'git_path' => 'http://gitweb.mageia.org/software/indexhtml/plain/po', ), array( 'pot_name' => 'kde4-splash-mga', 'tx_name' => 'kde4-splash-mga', 'git_path' => 'http://gitweb.mageia.org/software/desktop/kde/splash/plain/po', ), array( 'pot_name' => 'bootloader', 'tx_name' => 'mageia-gfxboot-theme', 'git_path' => 'http://gitweb.mageia.org/software/design/bootloader-theme/plain/po', ), array( 'pot_name' => 'mageia-kde-translation', 'tx_name' => 'mageia-kde-translation', 'git_path' => 'http://gitweb.mageia.org/software/i18n/kde/plain/po', ), array( 'pot_name' => 'mageiawelcome', // 'tx_name' => 'Mageia Welcome', 'tx_name' => 'mageia-welcome', 'git_path' => 'http://gitweb.mageia.org/software/mageiawelcome/plain/po', ), array( 'pot_name' => 'mgaonline', 'tx_name' => 'mgaonline', 'git_path' => 'http://gitweb.mageia.org/software/mgaonline/plain/po', ), array( 'pot_name' => 'msec', 'tx_name' => 'msec', 'git_path' => 'http://gitweb.mageia.org/software/msec/plain/po', ), array( 'pot_name' => 'net_monitor', 'tx_name' => 'net_monitor', 'git_path' => 'http://gitweb.mageia.org/software/net_monitor/plain/po', ), array( 'pot_name' => 'rpmdrake', 'tx_name' => 'rpmdrake', 'git_path' => 'http://gitweb.mageia.org/software/rpmdrake/plain/po', ), array( 'pot_name' => 'system-config-printer', 'tx_name' => 'system-config-printer', 'git_path' => 'http://gitweb.mageia.org/software/i18n/system-config-printer/plain/po', ), array( 'pot_name' => 'transfugdrake', 'tx_name' => 'transfugdrake', 'git_path' => 'http://gitweb.mageia.org/software/transfugdrake/plain/po', ), array( 'pot_name' => 'urpmi', 'tx_name' => 'urpmi', 'git_path' => 'http://gitweb.mageia.org/software/rpm/urpmi/plain/po', ), array( 'pot_name' => 'userdrake', 'tx_name' => 'userdrake2', 'git_path' => 'http://gitweb.mageia.org/software/userdrake/plain/po', ), ); // identity-catdap, indexhtml_about, isodumper } /** * Transifex API implementation in php detailed on http://docs.transifex.com/developer/api/projects * * Returns $tx_result_array from Transifex request * * @param string $tx_request request * @param string $project default project * * @return array */ function tx_call($tx_request, $project = 'project/mageia/') { global $errors; $tx_url_prefix = "www.transifex.com/api/2/"; $tx_url = $tx_url_prefix . $project . $tx_request; $user = "filip_mageia"; $pass = "report"; $tx_result = @file_get_contents("http://$user:$pass@$tx_url"); $tx_result_array = json_decode($tx_result, TRUE); $json_last_error = json_last_error(); if (JSON_ERROR_NONE !== $json_last_error) { $error = "There was an error during API call to Transifex $tx_request ($json_last_error)."; $errors['tx_json_error'] = "$error Please reload the page and report this on mailing list if it persist."; $tx_result_array = array(); } else if (FALSE === $tx_result) { $errors['tx_call'] = "API call to Transifex $tx_request failed. Please reload the page and report this on mailing list if it persist."; $tx_result_array = array(); } return $tx_result_array; } /** * Build Transifex and git links with numbers of untranslated strings * * Returns text string * * @param string $git_resource_name like 'about/constitution' * @param string $language_code like 'sl' * @param string $resource_type like 'Webpages' * @param array $stat_data with numbers of untranslated strings * * @return string */ function build_links($git_resource_name, $language_code, $resource_type, $stat_data) { $tx_resource_name = str_replace(array('/', 'mageia-welcome'), array('-', 'Mageia%20Welcome'), $git_resource_name); $locale_name = locale_underscore_to_hyphen($language_code); if ('Webpages' == $resource_type) { if ('nav' == $git_resource_name) { $git_link = sprintf('http://gitweb.mageia.org/web/nav/tree/langs/%s.po', $locale_name); } else { $git_link = sprintf('http://gitweb.mageia.org/web/www/tree/langs/%s/%s.po', $locale_name, $git_resource_name); } } else { $git_link = sprintf('%s/%s.po', $stat_data['git_path'], $language_code); } $links_and_num = "Tx: "; $links_and_num .= $stat_data['tx_untran']; $links_and_num .= (0 == $stat_data['tx_untran'] ? ' - full' : ''); $links_and_num .= ', git: '; $links_and_num .= $stat_data['git_untran']; $links_and_num .= ($stat_data['num_of_all'] == $stat_data['git_untran'] ? ' - empty' : ''); return $links_and_num; } /** * Generating report about git resources statistics * * @param array $language_codes list * @param array $resource_names list * @param string $path to the git, otherwise NULL * * @return array */ function generating_report($language_codes, $resource_names, $path = NULL, $pot_name = NULL) { $report = array(); foreach ($resource_names as $f) { $source_strings = NULL; foreach ($language_codes as $l) { $references = ''; if (is_null($pot_name)) { $resource = _extract_resource($f); } else { $resource = $pot_name; } $langF = _po_file_switch($f, $l); if (strstr($f, '../_nav/langs/en.') !== FALSE) { $langF = '../_nav/langs/' . $l . '.po' . (($l == 'en') ? 't' : ''); } if (!is_null($path) || file_exists($langF)) { $stat = _po_diff($l, $resource, $source_strings, $path); $num_of_fuzzy_or_missing = count($stat['fuzzy_or_missing']); } else { // file $langF doesn't exists in 'Webpages' $resource_type $stat = _po_diff('en', $resource, $source_strings); $num_of_fuzzy_or_missing = 0; } $num_of_untranslated = count($stat['notrans']); $source_strings = $stat['source_strings']; // unify resource names, navigation is a special exception $resource_name = str_replace(array('../_nav/langs/en', 'en/', '.pot'), array('nav', '', ''), $f); // create pt_BR from pt-br and alike to unify languages $web_language_code = locale_hyphen_underscore($l, true); $num_of_not_fully_trans = $num_of_fuzzy_or_missing + $num_of_untranslated; $report[] = array( 'num_of_all_strings' => $stat['a'], 'resource_name' => $resource_name, 'web_language_code' => $web_language_code, 'num_of_not_fully_trans' => $num_of_not_fully_trans, 'webgit_path' => $path, ); } } return $report; } /** * Returns native language name from Mageia web site if exists otherwise English name from Transifex * * @param string $language_code for language * * @return string */ function get_language_name($language_code) { global $langs; static $tx_languages_details = NULL; $web_language_code = locale_underscore_to_hyphen($language_code); if (array_key_exists($web_language_code, $langs)) { $language_name = $langs[$web_language_code]; } else { if (is_null($tx_languages_details)) { $tx_languages_details = tx_call("languages", ''); } $key_exists = recursive_array_search($language_code, $tx_languages_details); // is language code in the $tx_languages_details array? if ($key_exists !== FALSE) { $language_name = $tx_languages_details[$key_exists]['name']; } else { $language_name = $language_code; } } return $language_name; } // get resources data from TX $tx_resources = tx_call("resources"); // create separate array ($tx_resources_info) and add statistics to it from TX $tx_resources_info = array(); foreach ($tx_resources as $one_resource) { $tx_resource_name = $one_resource['slug']; $category = $one_resource['categories'][0]; // limit resource type only on one if ($category == $resource_type) { // add statistic $tx_stat_for_resource = tx_call("resource/$tx_resource_name/stats"); $tx_resource_name = str_replace('page-', '', $tx_resource_name); // unify resource names $one_resource['tx_resource_name'] = $tx_resource_name; $one_resource['statistic'] = $tx_stat_for_resource; $tx_resources_info[] = $one_resource; } } // create array ($report) with statistics from git $report = array(); if ('Webpages' == $resource_type) { $enFiles = array_merge(array('../_nav/langs/en.pot'), get_lang_references('*.pot')); // added navigation file $report = generating_report(get_other_langs(), $enFiles); } else { foreach ($git_resources as $git_resource_details) { $git_path = $git_resource_details['git_path']; $tx_name = $git_resource_details['tx_name']; $pot_name = $git_resource_details['pot_name']; $raw_html_dump = file_get_contents($git_path); // list all po files from links within $raw_html_dump preg_match_all("/('>)([a-z_A-Z]+)(\.po<)/", $raw_html_dump, $language_codes); $one_report = generating_report(array_values($language_codes[2]), array($tx_name), $git_path, $pot_name); $report = array_merge($one_report, $report); } } // core part: building the data $tx_lang_completed_treshold = 90; // report new languages above this treshold from 0 to 100 (%) $langs_and_res_names_done = FALSE; $tx_all_languages = array(); $tx_all_langs_above_treshold = array(); $git_all_languages = array(); $tx_all_resource_names = array(); $git_all_resource_names = array(); $git_compare_resources = array(); $tx_git_difference = array(); $parse_errors = array(); $nonequal_num_of_all_strings = array(); foreach ($tx_resources_info as $tx_resource_info) { $tx_resource_name = $tx_resource_info['tx_resource_name']; if (!in_array($tx_resource_name, $tx_all_resource_names)) { $tx_all_resource_names[] = $tx_resource_name; } foreach ($tx_resource_info['statistic'] as $tx_resource_language => $tx_resource_language_stat) { $completed = sprintf("%d", $tx_resource_language_stat['completed']); if (!in_array($tx_resource_language, $tx_all_languages)) { $tx_all_languages[] = $tx_resource_language; } if ($tx_lang_completed_treshold <= $completed && 'en' != $tx_resource_language) { $tx_all_langs_above_treshold[$tx_resource_language][] = $tx_resource_name; } foreach ($report as $git_resource_info) { $git_resource_name = $git_resource_info['resource_name']; $git_compare_resource_name = str_replace('/', '-', $git_resource_name); $git_resource_language = $git_resource_info['web_language_code']; if (!$langs_and_res_names_done) { $git_all_languages[] = $git_resource_language; $git_all_resource_names[] = $git_resource_name; $git_compare_resources[] = $git_compare_resource_name; } // if names and languages match but skip English as a source language if ($tx_resource_language == $git_resource_language && 'en' != $git_resource_language && $tx_resource_name == $git_compare_resource_name) { $tx_resource_untrans_in_lang = $tx_resource_language_stat['untranslated_entities']; $tx_resource_all_strings_in_lang = $tx_resource_untrans_in_lang + $tx_resource_language_stat['translated_entities']; $git_resource_num_of_all_strings = $git_resource_info['num_of_all_strings']; $git_resource_untrans_in_lang = $git_resource_info['num_of_not_fully_trans']; $git_resource_path = $git_resource_info['webgit_path']; // compare l10n level if ($tx_resource_untrans_in_lang != $git_resource_untrans_in_lang) { $tx_git_difference[$tx_resource_language][$git_resource_name]['tx_num_of_all_strings'] = $tx_resource_all_strings_in_lang; $tx_git_difference[$tx_resource_language][$git_resource_name]['tx_untranslated'] = $tx_resource_untrans_in_lang; $tx_git_difference[$tx_resource_language][$git_resource_name]['git_untranslated'] = $git_resource_untrans_in_lang; $tx_git_difference[$tx_resource_language][$git_resource_name]['webgit_path'] = $git_resource_path; } // it seems like a parse error if (0 == $git_resource_num_of_all_strings) { $parse_errors[$git_resource_name][] = $git_resource_language; // this bellow should normaly only happen inside of a tx sync window so remember it } else if ($tx_resource_all_strings_in_lang != $git_resource_num_of_all_strings) { if (!array_key_exists($git_resource_name, $nonequal_num_of_all_strings)) { $nonequal_num_of_all_strings[$git_resource_name] = "$git_resource_name git:$git_resource_num_of_all_strings/tx:$tx_resource_all_strings_in_lang"; } } } } if (!$langs_and_res_names_done) { $git_all_languages = array_unique($git_all_languages); $git_all_resource_names = array_unique($git_all_resource_names); $git_compare_resources = array_unique($git_compare_resources); $langs_and_res_names_done = TRUE; } } }; // sorting data sort($tx_all_resource_names, SORT_STRING); sort($git_all_resource_names, SORT_STRING); sort($git_compare_resources, SORT_STRING); sort($tx_all_languages); ksort($tx_all_langs_above_treshold); // sort by lang sort($git_all_languages); sort($nonequal_num_of_all_strings, SORT_STRING); $tx_only_resources = array_diff($tx_all_resource_names, $git_compare_resources); $git_only_resources = array_diff($git_compare_resources, $tx_all_resource_names); $tx_only_languages = array_diff(array_keys($tx_all_langs_above_treshold), $git_all_languages); $git_only_languages = array_diff($git_all_languages, $tx_all_languages); // preparing text for languages not present yet in our git repositories $tx_only_languages_details = ''; if (0 < count($tx_only_languages)) { $tx_only_languages_details = "

Languages with at least one resource for $resource_type translated over treshold "; $tx_only_languages_details .= "($tx_lang_completed_treshold %) but not present yet in our git:

'; } // preparing error texts if (0 < count($git_only_languages)) { $error = "Note that some languages (" . implode(", ", $git_only_languages) . ") are present in our git"; $errors['git_only_languages'] = "$error but they are bellow treshold ($tx_lang_completed_treshold %) in Transifex."; } if (0 < count($tx_only_resources)) { $error = "Some resources (" . implode(", ", $tx_only_resources) . ") are present only in Transifex"; $errors['tx_only_resources'] = "$error but not in our git. Please report that."; } if (0 < count($git_only_resources)) { $error = "Some resources (" . implode(", ", $git_only_resources) . ") are present only in our git"; $errors['git_only_resources'] = "$error but not in Transifex. Please report that."; } if (0 < count($parse_errors)) { $errors = array(); foreach ($parse_errors as $single_git_resource_name => $git_resource_languages) { $errors[] = "$single_git_resource_name.po (languages: " . implode(", ", $git_resource_languages) . ")"; } $errors['po_file_parse'] = "It seems that parsing of some resources failed: " . implode(", ", $errors) . "."; } if (0 < count($nonequal_num_of_all_strings)) { $error = "Some resources (" . implode(", ", $nonequal_num_of_all_strings) . ") have different number of all strings"; $bug = "Note that there is a bug which influence proper parsing of msec and mageia-kde-translation."; $errors['nonequal_num_of_all_strings'] = "$error between our git and Transifex. Please report that on the mailing list if it happens across several days. $bug"; } // making a list of resources with Tx/git differences ksort($tx_git_difference); $all_languages_with_tx_git_diff = array(); $all_resources_with_tx_git_diff = array(); foreach ($tx_git_difference as $one_language_of_tx_git_difference => $resources_with_tx_git_difference) { $all_languages_with_tx_git_diff[] = $one_language_of_tx_git_difference; foreach ($resources_with_tx_git_difference as $one_resource_with_tx_git_difference => $details) { $all_resources_with_tx_git_diff[] = $one_resource_with_tx_git_difference; } } $all_resources_with_tx_git_diff = array_unique($all_resources_with_tx_git_diff); sort($all_resources_with_tx_git_diff, SORT_STRING); $num_of_resources_w_difference = count($all_resources_with_tx_git_diff); $table_difference = ''; $num_for_switch_table_to_list = 15; if (0 < $num_of_resources_w_difference && $num_for_switch_table_to_list > $num_of_resources_w_difference) { // preparing a table represantation of Tx/git differences $i = 0; $table_rows = array(); $table_rows[] = "" . PHP_EOL; $table_rows[] = "" . PHP_EOL; $first_row_pass = TRUE; foreach ($tx_git_difference as $one_language => $one_language_array) { $j = 0; $row = array(); $first_col_pass = TRUE; if ($first_row_pass || 0 == $i % 12) { $array_chunks = array_chunk($all_resources_with_tx_git_diff, $col_repeat = 8, TRUE); foreach ($array_chunks as $array_chunk) { $row = array_merge($row, array(' '), $array_chunk); } $table_rows[] = "" . PHP_EOL; // add header row $row = array(); } foreach ($all_resources_with_tx_git_diff as $resource_with_tx_git_diff) { if ($first_col_pass || 0 == $j % $col_repeat) { // left cell $language_name = get_language_name($one_language); $row[] = "
$language_name - $one_language
"; $first_col_pass = FALSE; } if (array_key_exists($resource_with_tx_git_diff, $one_language_array)) { $stat_data = array(); $stat_data['num_of_all'] = $one_language_array[$resource_with_tx_git_diff]['tx_num_of_all_strings']; $stat_data['tx_untran'] = $one_language_array[$resource_with_tx_git_diff]['tx_untranslated']; $stat_data['git_untran'] = $one_language_array[$resource_with_tx_git_diff]['git_untranslated']; $stat_data['git_path'] = $one_language_array[$resource_with_tx_git_diff]['webgit_path']; $cell = ""; $cell .= build_links($resource_with_tx_git_diff, $one_language, $resource_type, $stat_data); $cell .= ""; $row[] = $cell; } else { $row[] = ' '; // there is no differences } $j++; } $table_rows[] = "" . PHP_EOL; if ($first_row_pass) { $table_rows[] = "" . PHP_EOL; $table_rows[] = "" . PHP_EOL; $first_row_pass = FALSE; } $i++; } $table_rows[] = "" . PHP_EOL; $table_rows[] = "
" . implode("", $row) . "
" . implode("", $row) . "
" . PHP_EOL; $table_difference = implode($table_rows); } $list_of_lang_diff = ''; $list_of_resource_diff = ''; if (0 < $num_of_resources_w_difference) { // preparing a list represantation of Tx/git differences by language $list_of_lang_diff .= '' . PHP_EOL; // preparing a list represantation of Tx/git differences by resources $list_of_resource_diff .= '' . PHP_EOL; } // print links for diferent reports if ('Webpages' != $resource_type) { $links[] = 'website translations'; } if ('Documentation' != $resource_type) { $links[] = 'documentation translations'; } if ('Cauldron' != $resource_type) { // $links[] = 'software translations'; } $reports_links = '

You can also see reports about differences in ' . implode(" or ", $links) . '. And please don\'t forget great '; $reports_links .= 'wiki page about Transifex and git syncing.

'; echo $reports_links . PHP_EOL; // print out any errors if (0 < count($errors)) { $error_text = ''; echo $error_text . PHP_EOL; } // print any languages present only in Transifex echo $tx_only_languages_details . PHP_EOL; if (0 < $num_of_resources_w_difference) { // print any differences between Transifex and our git repository echo '

Languages bellow have some differences between Transifex and our git repository.

'; echo '

To avoid furter alienation and confusion please synchronise them.

'; echo '

They differs on number of untranslated strings in resources:

'; // print table if there are only a few resources with differences otherwise print a list if ($num_for_switch_table_to_list > $num_of_resources_w_difference) { echo $table_difference . PHP_EOL; } else { echo $list_of_lang_diff . PHP_EOL; echo '

Same list but arranged by resources:

'; echo $list_of_resource_diff . PHP_EOL; } } ?>

Source code for this website is available on git.

' ?>