542 lines
16 KiB
PHP
542 lines
16 KiB
PHP
<?php
|
|
// This file is part of Moodle - http://moodle.org/
|
|
//
|
|
// Moodle is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Moodle is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
/**
|
|
* Helper functions converting moodle strings to json.
|
|
*/
|
|
|
|
function detect_languages($languages) {
|
|
echo "\n\n\n";
|
|
|
|
$all_languages = glob(LANGPACKSFOLDER.'/*' , GLOB_ONLYDIR);
|
|
function get_lang_from_dir($dir) {
|
|
return str_replace('_', '-', explode('/', $dir)[3]);
|
|
}
|
|
function get_lang_not_wp($langname) {
|
|
return (substr($langname, -3) !== '-wp');
|
|
}
|
|
$all_languages = array_map('get_lang_from_dir', $all_languages);
|
|
$all_languages = array_filter($all_languages, 'get_lang_not_wp');
|
|
|
|
$detect_lang = array_diff($all_languages, $languages);
|
|
$new_langs = [];
|
|
foreach ($detect_lang as $lang) {
|
|
$new = detect_lang($lang);
|
|
if ($new) {
|
|
$new_langs[$lang] = $lang;
|
|
}
|
|
}
|
|
|
|
return $new_langs;
|
|
}
|
|
|
|
function build_languages($languages, $added_langs = []) {
|
|
// Process the languages.
|
|
foreach ($languages as $lang) {
|
|
if (build_lang($lang)) {
|
|
$added_langs[$lang] = $lang;
|
|
}
|
|
}
|
|
|
|
return $added_langs;
|
|
}
|
|
|
|
/**
|
|
* Loads lang index keys.
|
|
*/
|
|
function load_langindex() {
|
|
global $STATS;
|
|
global $LANGINDEX;
|
|
|
|
$local = 0;
|
|
$total = 0;
|
|
// Process the index file, just once.
|
|
$langindexjson = load_json('langindex.json');
|
|
|
|
$LANGINDEX = [];
|
|
foreach ($langindexjson as $appkey => $value) {
|
|
if ($value == APPMODULENAME) {
|
|
$file = $value;
|
|
$lmskey = $appkey;
|
|
$local++;
|
|
} else {
|
|
$exp = explode('/', $value, 2);
|
|
$file = $exp[0];
|
|
if (count($exp) == 2) {
|
|
$lmskey = $exp[1];
|
|
} else {
|
|
$exp = explode('.', $appkey, 3);
|
|
|
|
if (count($exp) == 3) {
|
|
$lmskey = $exp[2];
|
|
} else {
|
|
$lmskey = $exp[1];
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!isset($LANGINDEX[$file])) {
|
|
$LANGINDEX[$file] = [];
|
|
}
|
|
|
|
$LANGINDEX[$file][$appkey] = $lmskey;
|
|
$total++;
|
|
}
|
|
|
|
$STATS = new StdClass();
|
|
$STATS->local = $local;
|
|
$STATS->total = $total;
|
|
|
|
echo "Total strings to translate $total ($local local)\n";
|
|
}
|
|
|
|
/**
|
|
* Add lang names to config file.
|
|
*
|
|
* @param $langs Array of language codes to add.
|
|
* @param $config Loaded config file.
|
|
*/
|
|
function add_langs_to_config($langs, $config) {
|
|
$changed = false;
|
|
$config_langs = get_object_vars($config['languages']);
|
|
foreach ($langs as $lang) {
|
|
if (!isset($config_langs[$lang])) {
|
|
$langfoldername = get_langfolder($lang);
|
|
|
|
$lmsstring = get_translation_strings($langfoldername, 'langconfig');
|
|
$config['languages']->$lang = $lmsstring['thislanguage'];
|
|
$changed = true;
|
|
}
|
|
}
|
|
|
|
if ($changed) {
|
|
// Sort languages by key.
|
|
$config['languages'] = json_decode( json_encode( $config['languages'] ), true );
|
|
ksort($config['languages']);
|
|
$config['languages'] = json_decode( json_encode( $config['languages'] ), false );
|
|
save_json(CONFIG, $config);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Save json data.
|
|
*
|
|
* @param $path Path of the file to load.
|
|
* @param $content Content string to save.
|
|
*/
|
|
function save_json($path, $content) {
|
|
file_put_contents($path, str_replace('\/', '/', json_encode($content, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT))."\n");
|
|
}
|
|
|
|
/**
|
|
* Load json data.
|
|
*
|
|
* @param $path Path of the file to load.
|
|
* @return Associative array obtained from json.
|
|
*/
|
|
function load_json($path) {
|
|
$file = file_get_contents($path);
|
|
return (array) json_decode($file);
|
|
}
|
|
|
|
/**
|
|
* Get's lang folder from lang code.
|
|
*
|
|
* @param $lang Lang code.
|
|
* @return Folder path.
|
|
*/
|
|
function get_langfolder($lang) {
|
|
$folder = LANGPACKSFOLDER.'/'.str_replace('-', '_', $lang);
|
|
if (!is_dir($folder) || !is_file($folder.'/langconfig.php')) {
|
|
return false;
|
|
}
|
|
|
|
return $folder;
|
|
}
|
|
|
|
/**
|
|
* Import translation file from langpack and returns it.
|
|
*
|
|
* @param $langfoldername Lang folder path.
|
|
* @param $file File name (excluding extension).
|
|
* @param $override_folder If needed, the folder of the file to override strings.
|
|
* @return String array.
|
|
*/
|
|
function get_translation_strings($langfoldername, $file, $override_folder = false) {
|
|
$lmsstring = import_translation_strings($langfoldername, $file);
|
|
if ($override_folder) {
|
|
$override = import_translation_strings($override_folder, $file);
|
|
$lmsstring = array_merge($lmsstring, $override);
|
|
}
|
|
|
|
return $lmsstring;
|
|
}
|
|
|
|
/**
|
|
* Import translation file from langpack and returns it.
|
|
*
|
|
* @param $langfoldername Lang folder path.
|
|
* @param $file File name (excluding extension).
|
|
* @return String array.
|
|
*/
|
|
function import_translation_strings($langfoldername, $file) {
|
|
|
|
$path = $langfoldername.'/'.$file.'.php';
|
|
// Apply translations.
|
|
if (!file_exists($path)) {
|
|
return [];
|
|
}
|
|
|
|
$string = [];
|
|
|
|
include($path);
|
|
|
|
return $string;
|
|
}
|
|
|
|
/**
|
|
* Build translations files from langpack.
|
|
*
|
|
* @param lang Language code.
|
|
* @return Wether it succeeded.
|
|
*/
|
|
function build_lang($lang) {
|
|
global $STATS;
|
|
global $LANGINDEX;
|
|
|
|
$langfoldername = get_langfolder($lang);
|
|
if (!$langfoldername) {
|
|
echo "Cannot translate $lang, folder not found";
|
|
|
|
return false;
|
|
}
|
|
|
|
if (OVERRIDE_LANG_SUFIX) {
|
|
$override_langfolder = get_langfolder($lang.OVERRIDE_LANG_SUFIX);
|
|
} else {
|
|
$override_langfolder = false;
|
|
}
|
|
|
|
$total = $STATS->total;
|
|
$local = 0;
|
|
|
|
$langparts = explode('-', $lang, 2);
|
|
$parentname = $langparts[0] ? $langparts[0] : "";
|
|
$parent = "";
|
|
|
|
echo "Processing $lang";
|
|
// Check parent language exists.
|
|
if ($parentname != $lang && get_langfolder($parentname)) {
|
|
echo " ($parentname)";
|
|
$parent = $parentname;
|
|
}
|
|
|
|
$langFile = false;
|
|
if (file_exists(ASSETSPATH.$lang.'.json')) {
|
|
// Load lang files just once.
|
|
$langFile = load_json(ASSETSPATH.$lang.'.json');
|
|
}
|
|
|
|
$translations = [];
|
|
// Add the translation to the array.
|
|
foreach ($LANGINDEX as $file => $keys) {
|
|
$lmsstring = get_translation_strings($langfoldername, $file, $override_langfolder);
|
|
foreach ($keys as $appkey => $lmskey) {
|
|
// Apply translations.
|
|
if (empty($lmsstring)) {
|
|
if ($file == 'donottranslate') {
|
|
// Restore it form the json.
|
|
if ($langFile && is_array($langFile) && isset($langFile[$appkey])) {
|
|
$translations[$appkey] = $langFile[$appkey];
|
|
} else {
|
|
// If not present, do not count it in the total.
|
|
$total--;
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
if (TOTRANSLATE) {
|
|
echo "\n\t\tTo translate $lmskey on $file";
|
|
}
|
|
continue;
|
|
}
|
|
|
|
if (!isset($lmsstring[$lmskey]) || ($lang == 'en' && $file == APPMODULENAME)) {
|
|
// Not yet translated. Do not override.
|
|
if ($langFile && is_array($langFile) && isset($langFile[$appkey])) {
|
|
$translations[$appkey] = $langFile[$appkey];
|
|
|
|
if ($file == APPMODULENAME) {
|
|
$local++;
|
|
}
|
|
}
|
|
if (TOTRANSLATE && !isset($lmsstring[$lmskey])) {
|
|
echo "\n\t\tTo translate $lmskey on $file";
|
|
}
|
|
continue;
|
|
}
|
|
|
|
$text = $lmsstring[$lmskey];
|
|
|
|
if ($file != APPMODULENAME) {
|
|
$text = str_replace('$a->@', '$a.', $text);
|
|
$text = str_replace('$a->', '$a.', $text);
|
|
$text = str_replace('{$a', '{{$a', $text);
|
|
$text = str_replace('}', '}}', $text);
|
|
$text = preg_replace('/@@.+?@@(<br>)?\\s*/', '', $text);
|
|
// Prevent double.
|
|
$text = str_replace(['{{{', '}}}'], ['{{', '}}'], $text);
|
|
} else {
|
|
// @TODO: Remove that line when core.cannotconnect and core.login.invalidmoodleversion are completelly changed to use $a
|
|
if (($appkey == 'core.cannotconnect' || $appkey == 'core.login.invalidmoodleversion') && strpos($text, '2.4')) {
|
|
$text = str_replace('2.4', '{{$a}}', $text);
|
|
}
|
|
$local++;
|
|
}
|
|
|
|
$translations[$appkey] = html_entity_decode($text);
|
|
}
|
|
}
|
|
|
|
if (!empty($parent)) {
|
|
$translations['core.parentlanguage'] = $parent;
|
|
} else if (isset($translations['core.parentlanguage'])) {
|
|
unset($translations['core.parentlanguage']);
|
|
}
|
|
|
|
// Sort and save.
|
|
ksort($translations);
|
|
save_json(ASSETSPATH.$lang.'.json', $translations);
|
|
|
|
$success = count($translations);
|
|
$percentage = floor($success/$total * 100);
|
|
$bar = progressbar($percentage);
|
|
if (strlen($lang) <= 2 && !$parent) {
|
|
echo "\t";
|
|
}
|
|
echo "\t\t$success of $total -> $percentage% $bar ($local local)\n";
|
|
|
|
if ($lang == 'en') {
|
|
generate_local_module_file($LANGINDEX[APPMODULENAME], $translations);
|
|
override_component_lang_files($translations);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Generates an ASCII progress bar.
|
|
*
|
|
* @param $percentage Done part.
|
|
* @param $length Length of the text.
|
|
* @return Text generated.
|
|
*/
|
|
function progressbar($percentage, $length = 10) {
|
|
$done = floor($percentage / $length);
|
|
return "\t".str_repeat('=', $done) . str_repeat('-', $length - $done);
|
|
}
|
|
|
|
/**
|
|
* Check translations on langpack and detects if the language should be added.
|
|
*
|
|
* @param lang Language code.
|
|
* @return If the file should be added to the app.
|
|
*/
|
|
function detect_lang($lang) {
|
|
global $STATS;
|
|
global $LANGINDEX;
|
|
|
|
$langfoldername = get_langfolder($lang);
|
|
if (!$langfoldername) {
|
|
echo "Cannot translate $lang, folder not found";
|
|
|
|
return false;
|
|
}
|
|
|
|
$total = $STATS->total;
|
|
$success = 0;
|
|
$local = 0;
|
|
|
|
$lmsstring = get_translation_strings($langfoldername, 'langconfig');
|
|
$parent = isset($lmsstring['parentlanguage']) ? $lmsstring['parentlanguage'] : "";
|
|
if (!isset($lmsstring['thislanguage'])) {
|
|
echo "Cannot translate $lang, translated name not found";
|
|
return false;
|
|
}
|
|
|
|
$title = $lang;
|
|
if ($parent != "" && $parent != $lang) {
|
|
$title .= " ($parent)";
|
|
}
|
|
$langname = $lmsstring['thislanguage'];
|
|
$title .= " ".$langname." -D";
|
|
|
|
$lmsstring = get_translation_strings($langfoldername, APPMODULENAME);
|
|
if (!empty($lmsstring)) {
|
|
// Add the translation to the array.
|
|
foreach ($LANGINDEX as $file => $keys) {
|
|
$lmsstring = get_translation_strings($langfoldername, $file);
|
|
|
|
// Apply translations.
|
|
if (empty($lmsstring)) {
|
|
// Do not count non translatable in the totals.
|
|
if ($file == 'donottranslate') {
|
|
$total -= count($keys);
|
|
}
|
|
continue;
|
|
}
|
|
|
|
foreach ($keys as $lmskey) {
|
|
if (!isset($lmsstring[$lmskey])) {
|
|
continue;
|
|
}
|
|
|
|
if ($file == APPMODULENAME) {
|
|
$local++;
|
|
}
|
|
|
|
$success++;
|
|
}
|
|
}
|
|
}
|
|
|
|
echo "Checking ".$title.str_repeat("\t", 7 - floor(mb_strlen($title, 'UTF-8')/8));
|
|
|
|
if ($local == 0) {
|
|
echo "\tNo Mobile App strings found\n";
|
|
} else {
|
|
$percentage = floor($success/$total * 100);
|
|
$bar = progressbar($percentage);
|
|
|
|
echo "\t$success of $total -> $percentage% $bar ($local local)";
|
|
if (($percentage > 75 && $local > 50) || ($percentage > 50 && $local > 75)) {
|
|
echo " \t DETECTED\n";
|
|
return true;
|
|
}
|
|
echo "\n";
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Save a key - value pair into a json file.
|
|
*
|
|
* @param key Key of the json object.
|
|
* @param value Value of the json object.
|
|
* @param filePath Path of the json file.
|
|
*/
|
|
function save_key($key, $value, $filePath) {
|
|
$file = load_json($filePath);
|
|
$value = html_entity_decode($value);
|
|
if (!isset($file[$key]) || $file[$key] != $value) {
|
|
$file[$key] = $value;
|
|
ksort($file);
|
|
save_json($filePath, $file);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Take newer ENGLISH translations from the langpacks and applies it to the app lang.json files.
|
|
*
|
|
* @param [array] $translations English translations.
|
|
*/
|
|
function override_component_lang_files($translations) {
|
|
echo "Override component lang files.\n";
|
|
foreach ($translations as $key => $value) {
|
|
$path = '../src/';
|
|
$exp = explode('.', $key, 3);
|
|
|
|
$type = $exp[0];
|
|
if (count($exp) == 3) {
|
|
$component = $exp[1];
|
|
$plainid = $exp[2];
|
|
} else {
|
|
$component = 'moodle';
|
|
$plainid = $exp[1];
|
|
}
|
|
switch($type) {
|
|
case 'core':
|
|
if ($component == 'moodle') {
|
|
$path .= 'core/lang.json';
|
|
} else {
|
|
$path .= 'core/features/'.str_replace('_', '/', $component).'/lang.json';
|
|
}
|
|
break;
|
|
case 'addon':
|
|
$path .= 'addons/'.str_replace('_', '/', $component).'/lang.json';
|
|
break;
|
|
case 'assets':
|
|
$path .= $type.'/'.$component.'.json';
|
|
break;
|
|
default:
|
|
$path .= $type.'/lang.json';
|
|
break;
|
|
|
|
}
|
|
|
|
if (is_file($path)) {
|
|
save_key($plainid, $value, $path);
|
|
} else {
|
|
echo "Cannot override: $path not found.\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Generates local module file to update languages in AMOS.
|
|
*
|
|
* @param [array] $appindex Translation appindex.
|
|
* @param [array] $translations English translations.
|
|
*/
|
|
function generate_local_module_file($appindex, $translations) {
|
|
echo 'Generate '.APPMODULENAME."\n";
|
|
|
|
$lmsstring = "";
|
|
foreach ($appindex as $appkey => $lmskey) {
|
|
if (isset($translations[$appkey])) {
|
|
$lmsstring .= '$string[\''.$appkey.'\'] = \''.str_replace("'", "\'", $translations[$appkey]).'\';'."\n";
|
|
}
|
|
}
|
|
|
|
if (empty($lmsstring)) {
|
|
echo "ERROR, translations not found, you probably didn't run gulp lang!\n";
|
|
|
|
return;
|
|
}
|
|
|
|
$filepath = '../../moodle-'.APPMODULENAME.'/lang/en/'.APPMODULENAME.'.php';
|
|
$filecontents = file_get_contents($filepath);
|
|
|
|
$startcomment = "/* AUTO START */\n";
|
|
$endcomment = '/* AUTO END */';
|
|
|
|
$start = strpos($filecontents, $startcomment);
|
|
$start = $start === false ? 0 : $start + strlen($startcomment);
|
|
|
|
$end = strpos($filecontents, $endcomment, $start);
|
|
$end = $end === false ? strlen($filecontents) : $end;
|
|
|
|
$filecontents = substr_replace($filecontents, $lmsstring, $start, $end - $start);
|
|
|
|
if (substr($filecontents, -2) != "\n\n") {
|
|
$filecontents .= "\n";
|
|
}
|
|
|
|
file_put_contents($filepath, $filecontents);
|
|
}
|