Language: Add sub-languages using gettext for symfony and vue - refs BT#20922

pull/5000/head
christian 2 years ago
parent 6bfe2f3934
commit 2dee11ec95
  1. 324
      public/main/admin/sub_language.php
  2. 189
      public/main/admin/sub_language_add.php
  3. 88
      public/main/admin/sub_language_ajax.inc.php
  4. 28
      public/main/inc/lib/internationalization.lib.php
  5. 503
      public/main/inc/lib/sub_language.class.php
  6. 35
      src/CoreBundle/Command/UpdateVueTranslations.php

@ -1,8 +1,6 @@
<?php
/* For licensing terms, see /license.txt */
exit;
/**
* Script for sub-language administration.
*/
@ -14,43 +12,38 @@ $this_section = SECTION_PLATFORM_ADMIN;
api_protect_admin_script();
$htmlHeadXtra[] = '<script>
$(function () {
$(".save").click(function() {
var button_name=$(this).attr("name");
var button_array=button_name.split("|");
var button_name=button_array[1];
var file_id=button_array[2];
var is_variable_language="$"+button_name;
var is_new_language = $("#txtid_"+file_id+"_"+button_name).val();
if (is_new_language == undefined) {
is_new_language="_";
}
if (is_new_language.length>0 && is_new_language!="_" && file_id!="" && button_name!="") {
$.ajax({
contentType: "application/x-www-form-urlencoded",
beforeSend: function(myObject) {
$("#div_message_information_id").html("<div class=\"alert alert-info\"><img src=\'../inc/lib/javascript/indicator.gif\' /></div>");
$(".save").on("click", function() {
var $this = $(this);
var buttonId = $this.attr("id");
var textareaId = "txtid_" + buttonId.split("_")[1] + "_" + buttonId.split("_")[2];
var content = $("#" + textareaId).val();
var filename = $this.data("filename");
var msgidEncoded = $this.data("msgid");
$this.prop("disabled", true).text("'.get_lang('Loading').'...");
try {
$.post(
"' . api_get_path(WEB_CODE_PATH) . 'admin/sub_language_ajax.inc.php",
{
content: content,
filename: filename,
msgidEncoded: msgidEncoded
},
type: "POST",
url: "../admin/sub_language_ajax.inc.php",
data: {
\'new_language\': is_new_language,
\'variable_language\': is_variable_language,
\'file_id\': file_id,
\'id\': '.intval($_REQUEST['id']).',
\'sub\': '.intval($_REQUEST['sub_language_id']).',
\'sub_language_id\': '.intval($_REQUEST['sub_language_id']).'
},
success: function(datos) {
if (datos == "1") {
$("#div_message_information_id").html(\''.Display::return_message(get_lang('The new word has been added'), 'success').'\');
function(data) {
if (data.success) {
localStorage.setItem("redirectTo", textareaId);
window.location.reload(true);
} else {
$("#div_message_information_id").html("<div class=\"alert alert-warning\">" + datos +"</div>");
}
alert("Error: " + (data.error || "'.get_lang('Error, try it again').'"));
$this.prop("disabled", false).text("'.get_lang('Save').'");
}
});
} else {
$("#div_message_information_id").html(\''.Display::return_message(get_lang('The form contains incorrect or incomplete data. Please check your input.'), 'error').'\');
},
"json"
);
} catch (e) {
console.error("Error to check JSON:", e);
$this.prop("disabled", false).text("'.get_lang('Save').'");
}
});
});
@ -72,11 +65,6 @@ if (isset($_GET['id']) && $_GET['id'] == strval(intval($_GET['id']))) {
$sub_language_name = SubLanguageManager::get_name_of_language_by_id($_GET['sub_language_id']);
$all_data_of_language = SubLanguageManager::get_all_information_of_language($_GET['id']);
$all_data_of_sublanguage = SubLanguageManager::get_all_information_of_language($_GET['sub_language_id']);
$sub_language_file = api_get_path(SYS_LANG_PATH).$all_data_of_sublanguage['dokeos_folder'];
if (!file_exists($sub_language_file) || !is_writable($sub_language_file)) {
$sublanguage_folder_error = $sub_language_file.' '.get_lang('is not writeable');
}
if (true === SubLanguageManager::check_if_exist_language_by_id($_GET['id'])) {
$language_id_exist = true;
} else {
@ -88,11 +76,6 @@ if (isset($_GET['id']) && $_GET['id'] == strval(intval($_GET['id']))) {
}
$intro = sprintf(get_lang('Define new terms for sub-language %s by searching some term, then save each translation by clicking the save button. You will then have to switch your own user language to see the new terms appear.'), strtolower($sub_language_name));
$path_folder = api_get_path(SYS_LANG_PATH).$all_data_of_language['dokeos_folder'];
if (!is_dir($path_folder) || 0 == strlen($all_data_of_language['dokeos_folder'])) {
api_not_allowed(true);
}
Display :: display_header($language_name);
@ -121,237 +104,61 @@ if (!empty($sublanguage_folder_error)) {
echo '<div id="div_message_information_id">&nbsp;</div>';
/**
* @param $term The term to search
* @param bool $search_in_variable The search will include the variable definition of the term
* @param bool $search_in_english The search will include the english language variables
* @param bool $search_in_parent The search will include the parent language variables of the sub language
* @param bool $search_in_sub_language The search will include the sub language variables
* Searches for a term in language files and returns results.
*
* @param string $term The term to search for.
* @param int $subLanguageId The ID of the sub-language to search in.
*
* @author Julio Montoya
*
* @return array
*/
function search_language_term(
$term,
$search_in_variable = true,
$search_in_english = true,
$search_in_parent = true,
$search_in_sub_language = true
) {
//These the $_REQUEST['id'] and the $_REQUEST['sub_language_id'] variables are process in global.inc.php (LOAD LANGUAGE FILES SECTION)
/*
These 4 arrays are set in global.inc.php with the condition that will be load from sub_language.php or sub_language_ajax.inc.php
$english_language_array
$parent_language_array
$sub_language_array
$language_files_to_load
* @return array An array containing search results.
*/
global $language_files_to_load, $sub_language_array, $english_language_array, $parent_language_array;
$language_files_to_load_keys = array_flip($language_files_to_load);
$array_to_search = $parent_language_array;
$list_info = [];
$term = '/'.Security::remove_XSS(trim($_REQUEST['txt_search_word'])).'/i';
//@todo optimize this foreach
foreach ($language_files_to_load as $lang_file) {
//searching in parent language of the sub language
if ($search_in_parent) {
$variables = $parent_language_array[$lang_file];
foreach ($variables as $parent_name_variable => $parent_variable_value) {
//arrays are avoided
if (is_array($parent_variable_value)) {
continue;
}
$founded = false;
// searching the item in the parent tool
if (0 !== preg_match($term, $parent_variable_value)) {
$founded = true;
}
if ($founded) {
//loading variable from the english array
$sub_language_name_variable = isset($sub_language_array[$lang_file][$parent_name_variable])
? $sub_language_array[$lang_file][$parent_name_variable]
: '';
//loading variable from the english array
$english_name_variable = $english_language_array[$lang_file][$parent_name_variable];
//config buttons
/*if (strlen($english_name_variable)>1500) {
$size =20;
} else {
$size =4;
}*/
$obj_text = Display::tag(
function search_language_term($term, $subLanguageId)
{
$translations = SubLanguageManager::searchTranslations($term, $subLanguageId);
$listInfo = [];
if (!empty($translations)) {
$i = 0;
foreach ($translations as $trans) {
$keys = array_keys($trans);
$firstTranslationKey = $keys[4];
$secondTranslationKey = $keys[5];
$langFile = "messages.$secondTranslationKey.po";
$objText = Display::tag(
'textarea',
$sub_language_name_variable,
$trans[$secondTranslationKey],
[
'rows' => 10,
'cols' => 40,
'name' => 'txt|'.$parent_name_variable.'|'.$language_files_to_load_keys[$lang_file],
'id' => 'txtid_'.$language_files_to_load_keys[$lang_file].'_'.$parent_name_variable,
'name' => 'txt|'.$trans['phpVarName'].'|'.$i,
'id' => 'txtid_'.$i.'_'.$trans['phpVarName'],
]
);
$obj_button = Display::button(
'btn|'.$parent_name_variable.'|'.$language_files_to_load_keys[$lang_file],
$objButton = Display::button(
'btn|'.$trans['phpVarName'].'|'.$i,
get_lang('Save'),
[
'class' => 'save btn btn--plain btn-sm',
'type' => 'button',
'id' => 'btnid_'.$parent_name_variable,
'id' => 'btnid_'.$i.'_'.$trans['phpVarName'],
'data-filename' => $langFile,
'data-msgid' => base64_encode($trans['variable']),
]
);
$list_info[$parent_name_variable] = [
$lang_file.'.inc.php',
$parent_name_variable,
htmlentities($english_name_variable),
htmlentities($parent_variable_value),
$obj_text,
$obj_button,
$listInfo[$i] = [
$langFile,
$trans['variable'],
htmlentities($trans['en']),
htmlentities($trans[$firstTranslationKey]),
$objText,
$objButton,
];
}
}
}
//search in english
if ($search_in_english || $search_in_variable) {
$variables = $english_language_array[$lang_file];
foreach ($variables as $name_variable => $variable_value) {
if (isset($list_info[$name_variable])) {
continue;
}
if (is_array($variable_value)) {
continue;
}
if (is_array($variable_value)) {
echo $lang_file;
}
$founded = false;
if ($search_in_english && $search_in_variable) {
// searching the item in the parent tool
if (0 !== preg_match($term, $variable_value) || 0 !== preg_match($term, $name_variable)) {
$founded = true;
}
} else {
if ($search_in_english) {
if (0 !== preg_match($term, $variable_value)) {
$founded = true;
}
} else {
if (0 !== preg_match($term, $name_variable)) {
$founded = true;
}
}
}
if ($founded) {
//loading variable from the english array
$sub_language_name_variable = null;
if (isset($sub_language_array[$lang_file][$name_variable])) {
$sub_language_name_variable = $sub_language_array[$lang_file][$name_variable];
$i++;
}
$parent_variable_value = null;
if (isset($parent_language_array[$lang_file][$name_variable])) {
$parent_variable_value = $parent_language_array[$lang_file][$name_variable];
}
//config buttons
$obj_text = Display::tag(
'textarea',
$sub_language_name_variable,
[
'rows' => 10,
'cols' => 40,
'name' => 'txt|'.$name_variable.'|'.$language_files_to_load_keys[$lang_file],
'id' => 'txtid_'.$language_files_to_load_keys[$lang_file].'_'.$name_variable,
]
);
$obj_button = Display::button(
'btn|'.$name_variable.'|'.$language_files_to_load_keys[$lang_file],
get_lang('Save'),
[
'class' => 'save btn btn--plain btn-sm',
'type' => 'button',
'id' => 'btnid_'.$name_variable,
]
);
//loading variable from the english array
$english_name_variable = $english_language_array[$lang_file][$name_variable];
$list_info[] = [
$lang_file.'.inc.php',
$name_variable,
htmlentities($english_name_variable),
htmlentities($parent_variable_value),
$obj_text,
$obj_button,
];
}
}
}
// Search in sub language
if ($search_in_sub_language) {
$variables = $sub_language_array[$lang_file];
foreach ($variables as $name_variable => $variable_value) {
if (is_array($parent_variable_value)) {
continue;
}
if (is_array($variable_value)) {
continue;
}
$founded = false;
// searching the item in the parent tool
if (0 !== preg_match($term, $variable_value)) {
$founded = true;
}
if ($founded) {
//loading variable from the english array
$sub_language_name_variable = isset($sub_language_array[$lang_file][$name_variable])
? $sub_language_array[$lang_file][$name_variable]
: '';
$parent_variable_value = isset($parent_language_array[$lang_file][$name_variable])
? $parent_language_array[$lang_file][$name_variable]
: '';
//config buttons
$obj_text = Display::tag(
'textarea',
$sub_language_name_variable,
[
'rows' => 10,
'cols' => 40,
'name' => 'txt|'.$name_variable.'|'.$language_files_to_load_keys[$lang_file],
'id' => 'txtid_'.$language_files_to_load_keys[$lang_file].'_'.$name_variable,
]
);
$obj_button = Display::button(
'btn|'.$name_variable.'|'.$language_files_to_load_keys[$lang_file],
get_lang('Save'),
[
'class' => 'save btn btn--plain btn-sm',
'type' => 'button',
'id' => 'btnid_'.$name_variable,
]
);
//loading variable from the english array
$english_name_variable = $english_language_array[$lang_file][$name_variable];
$list_info[] = [$lang_file.'.inc.php',
$name_variable,
$english_name_variable,
$parent_variable_value, $obj_text, $obj_button, ];
}
}
}
}
$list_info = array_unique_dimensional($list_info);
return $list_info;
return $listInfo;
}
// Allow see data in sort table
@ -361,10 +168,7 @@ if (isset($_REQUEST['txt_search_word'])) {
if (strlen(trim($_REQUEST['txt_search_word'])) > 2) {
$list_info = search_language_term(
$_REQUEST['txt_search_word'],
true,
true,
true,
true
$_GET['sub_language_id'],
);
}
}

@ -20,149 +20,10 @@ $tool_name = get_lang('Create sub-language');
$interbreadcrumb[] = ['url' => 'index.php', 'name' => get_lang('Administration')];
$interbreadcrumb[] = ['url' => 'languages.php', 'name' => get_lang('Chamilo Portal Languages')];
/**
* Add sub-language.
*
* @deprecated
*
* @param string Original language name (Occitan, Wallon, Vlaams)
* @param string English language name (occitan, wallon, flanders)
* @param string ISO code (fr_FR, ...)
* @param int Whether the sublanguage is published (0=unpublished, 1=published)
* @param int ID del idioma padre
*
* @return false|string New sub language ID or false on error
*/
function add_sub_language($original_name, $english_name, $isocode, $sublanguage_available, $parent_id)
{
$tbl_admin_languages = Database::get_main_table(TABLE_MAIN_LANGUAGE);
$original_name = Database::escape_string($original_name);
$english_name = Database::escape_string($english_name);
$isocode = Database::escape_string($isocode);
$sublanguage_available = Database::escape_string($sublanguage_available);
$parent_id = intval($parent_id);
$sql = 'INSERT INTO '.$tbl_admin_languages.'(original_name,english_name,isocode,dokeos_folder,available,parent_id)
VALUES ("'.$original_name.'","'.$english_name.'","'.$isocode.'","'.$english_name.'","'.$sublanguage_available.'","'.$parent_id.'")';
$res = Database::query($sql);
if (false === $res) {
return false;
}
return Database::insert_id();
}
/**
* Check if language exists.
*
* @param string Original language name (Occitan, Wallon, Vlaams)
* @param string English language name (occitan, wallon, flanders)
* @param string ISO code (fr_FR, ...)
* @param int Whether the sublanguage is published (0=unpublished, 1=published)
*
* @return array Array describing the number of items found that match the
* current language insert attempt (original_name => true,
* english_name => true, isocode => true,
* execute_add => true/false). If execute_add is true, then we
* can proceed.
*
* @todo This function is not transaction-safe and should probably be included
* inside the add_sub_language function.
*/
function check_if_language_exist($original_name, $english_name, $isocode, $sublanguage_available)
{
$tbl_admin_languages = Database::get_main_table(TABLE_MAIN_LANGUAGE);
$sql_original_name = 'SELECT count(*) AS count_original_name FROM '.$tbl_admin_languages.'
WHERE original_name="'.Database::escape_string($original_name).'" ';
$sql_english_name = 'SELECT count(*) AS count_english_name FROM '.$tbl_admin_languages.'
WHERE english_name="'.Database::escape_string($english_name).'" ';
$rs_original_name = Database::query($sql_original_name);
$rs_english_name = Database::query($sql_english_name);
$count_original_name = Database::result($rs_original_name, 0, 'count_original_name');
$count_english_name = Database::result($rs_english_name, 0, 'count_english_name');
$has_error = false;
$message_information = [];
if (1 == $count_original_name) {
$has_error = true;
$message_information['original_name'] = true;
}
if (1 == $count_english_name) {
$has_error = true;
$message_information['english_name'] = true;
}
$iso_list = api_get_platform_isocodes();
$iso_list = array_values($iso_list);
if (!in_array($isocode, $iso_list)) {
$has_error = true;
$message_information['isocode'] = true;
}
if (true === $has_error) {
$message_information['execute_add'] = false;
}
if (false === $has_error) {
$message_information['execute_add'] = true;
}
return $message_information;
}
/**
* Check if language exist, given its ID. This is just a wrapper for the
* SubLanguageManager::check_if_exist_language_by_id() method and should not exist.
*
* @param int Language ID
*
* @return bool
*
* @todo deprecate this function and use the static method directly
*/
function check_if_exist_language_by_id($language_id)
{
return SubLanguageManager::check_if_exist_language_by_id($language_id);
}
/**
* Check if the given language is a parent of any sub-language.
*
* @param int Language ID of the presumed parent
*
* @return bool True if this language has children, false otherwise
*/
function ckeck_if_is_parent_of_sub_language($parent_id)
{
$sql = 'SELECT count(*) AS count FROM language WHERE parent_id= '.intval($parent_id);
$rs = Database::query($sql);
if (Database::num_rows($rs) > 0 && 1 == Database::result($rs, 0, 'count')) {
return true;
} else {
return false;
}
}
/**
* Get all information of sub-language.
*
* @param int Parent language ID
* @param int Child language ID
*
* @return array
*/
function allow_get_all_information_of_sub_language($parent_id, $sub_language_id)
{
return SubLanguageManager::get_all_information_of_sub_language($parent_id, $sub_language_id);
}
/*end declare functions*/
//add data
if (isset($_GET['sub_language_id']) && $_GET['sub_language_id'] == strval(intval($_GET['sub_language_id']))) {
$language_name = SubLanguageManager::get_name_of_language_by_id($_GET['sub_language_id']);
if (true === check_if_exist_language_by_id($_GET['sub_language_id'])) {
if (true === SubLanguageManager::languageExistsById($_GET['sub_language_id'])) {
$sub_language_id = $_GET['sub_language_id'];
$sub_language_id_exist = true;
} else {
@ -174,8 +35,8 @@ $language_name = '';
if (isset($_GET['id']) && $_GET['id'] == strval(intval($_GET['id']))) {
$language_details = SubLanguageManager::get_all_information_of_language($_GET['id']);
$language_name = $language_details['original_name'];
if (true === check_if_exist_language_by_id($_GET['id'])) {
$parent_id = $_GET['id'];
if (true === SubLanguageManager::languageExistsById($_GET['id'])) {
$parent_id = (int) $_GET['id'];
$language_id_exist = true;
} else {
$language_id_exist = false;
@ -189,8 +50,8 @@ if (isset($_GET['id']) && $_GET['id'] == strval(intval($_GET['id']))) {
if ((isset($_GET['id']) && $_GET['id'] == strval(intval($_GET['id']))) &&
(isset($_GET['sub_language_id']) && $_GET['sub_language_id'] == strval(intval($_GET['sub_language_id'])))
) {
if (true === check_if_exist_language_by_id($_GET['id']) && true === check_if_exist_language_by_id($_GET['sub_language_id'])) {
$get_all_information = allow_get_all_information_of_sub_language($_GET['id'], $_GET['sub_language_id']);
if (true === SubLanguageManager::languageExistsById($_GET['id']) && true === SubLanguageManager::languageExistsById($_GET['sub_language_id'])) {
$get_all_information = SubLanguageManager::getAllInformationOfSubLanguage((int) $_GET['id'], (int) $_GET['sub_language_id']);
$original_name = $get_all_information['original_name'];
$english_name = $get_all_information['english_name'];
$isocode = $get_all_information['isocode'];
@ -199,7 +60,7 @@ if ((isset($_GET['id']) && $_GET['id'] == strval(intval($_GET['id']))) &&
$language_name = get_lang('Create sub-languageForLanguage').' ( '.strtolower($language_name).' )';
if (true === ckeck_if_is_parent_of_sub_language($parent_id) &&
if (true === SubLanguageManager::isParentOfSubLanguage($parent_id) &&
isset($_GET['action']) && 'deletesublanguage' == $_GET['action']
) {
$language_name = get_lang('Delete sub-language');
@ -214,9 +75,9 @@ if (isset($_POST['SubmitAddNewLanguage'])) {
$english_name = str_replace(' ', '_', $english_name);
$isocode = str_replace(' ', '_', $isocode);
$sublanguage_available = $_POST['sub_language_is_visible'];
$sublanguage_available = isset($_POST['sub_language_is_visible']) ? (int) $_POST['sub_language_is_visible'] : 0;
$check_information = [];
$check_information = check_if_language_exist($original_name, $english_name, $isocode, $sublanguage_available);
$check_information = SubLanguageManager::checkIfLanguageExists($original_name, $english_name, $isocode);
foreach ($check_information as $index_information => $value_information) {
$allow_insert_info = false;
if ('original_name' == $index_information) {
@ -248,20 +109,17 @@ if (isset($_POST['SubmitAddNewLanguage'])) {
$isocode = str_replace(' ', '_', $isocode);
$str_info = '<br/>'.get_lang('Original name').' : '.$original_name.'<br/>'.get_lang('English name').' : '.$english_name.'<br/>'.get_lang('Character set').' : '.$isocode;
$mkdir_result = SubLanguageManager::add_language_directory($english_name);
$mkdir_result = SubLanguageManager::addPoFileForSubLanguage($english_name);
if ($mkdir_result) {
$sl_id = add_sub_language($original_name, $english_name, $isocode, $sublanguage_available, $parent_id);
$sl_id = SubLanguageManager::addSubLanguage($original_name, $english_name, $sublanguage_available, $parent_id);
if (false === $sl_id) {
SubLanguageManager::remove_language_directory($english_name);
SubLanguageManager::removePoFileForSubLanguage($english_name);
$msg .= Display::return_message(get_lang('The /main/lang directory, used on this portal to store the languages, is not writable. Please contact your platform administrator and report this message.'), 'error');
} else {
Display::addFlash(
Display::return_message(get_lang('The new sub-language has been added').$str_info, null, false)
);
unset($interbreadcrumb);
$_GET['sub_language_id'] = $_REQUEST['sub_language_id'] = $sl_id;
require 'sub_language.php';
exit();
api_location(api_get_path(WEB_CODE_PATH).'admin/languages.php?sub_language_id='.$sl_id);
}
} else {
$msg .= Display::return_message(get_lang('The /main/lang directory, used on this portal to store the languages, is not writable. Please contact your platform administrator and report this message.'), 'error');
@ -276,19 +134,24 @@ if (isset($_POST['SubmitAddNewLanguage'])) {
}
}
if (isset($_POST['SubmitAddDeleteLanguage'])) {
$removed = SubLanguageManager::removeSubLanguage($_GET['id'], $_GET['sub_language_id']);
if ($removed) {
Display::addFlash(
Display::return_message(
get_lang(
'The sub language has been removed.'
)
)
);
api_location(api_get_path(WEB_CODE_PATH).'admin/languages.php');
}
}
Display:: display_header($language_name);
echo $msg;
if (isset($_POST['SubmitAddDeleteLanguage'])) {
$rs = SubLanguageManager::remove_sub_language($_GET['id'], $_GET['sub_language_id']);
if (true === $rs) {
echo Display::return_message(get_lang('The sub language has been removed'), 'confirm');
} else {
echo Display::return_message(get_lang('The sub-language has not been removed.'), 'error');
}
}
// ckeck_if_is_parent_of_sub_language($parent_id)===false
if (isset($_GET['action']) && 'definenewsublanguage' == $_GET['action']) {
$text = $language_name;
$form = new FormValidator(

@ -2,90 +2,20 @@
/* For licensing terms, see /license.txt */
exit;
use Chamilo\CoreBundle\Entity\ExtraField;
/**
* Sub language AJAX script to update variables.
*/
$this_script = 'sub_language';
require_once __DIR__.'/../inc/global.inc.php';
require_once __DIR__ . '/../inc/global.inc.php';
api_protect_admin_script();
$new_language = Security::remove_XSS($_REQUEST['new_language']);
$language_variable = Security::remove_XSS($_REQUEST['variable_language']);
$file_id = intval($_REQUEST['file_id']);
if (isset($new_language) && isset($language_variable) && isset($file_id)) {
$file_language = $language_files_to_load[$file_id].'.inc.php';
$id_language = intval($_REQUEST['id']);
$sub_language_id = intval($_REQUEST['sub']);
$all_data_of_language = SubLanguageManager::get_all_information_of_sub_language($id_language, $sub_language_id);
$path_folder = api_get_path(SYS_LANG_PATH).$all_data_of_language['dokeos_folder'].'/'.$file_language;
$all_file_of_directory = SubLanguageManager::get_all_language_variable_in_file($path_folder);
$return_value = SubLanguageManager::add_file_in_language_directory($path_folder);
//update variable language
// Replace double quotes to avoid parse errors
$new_language = str_replace('"', '\"', $new_language);
// Replace new line signs to avoid parse errors - see #6773
$new_language = str_replace("\n", "\\n", $new_language);
$all_file_of_directory[$language_variable] = "\"".$new_language."\";";
$result_array = [];
foreach ($all_file_of_directory as $key_value => $value_info) {
$result_array[$key_value] = SubLanguageManager::write_data_in_file($path_folder, $value_info, $key_value);
}
$variables_with_problems = '';
if (!empty($result_array)) {
foreach ($result_array as $key => $result) {
if (false == $result) {
$variables_with_problems .= $key.' <br />';
}
}
}
if (isset($_REQUEST['redirect'])) {
$message = Display::return_message(get_lang('The new word has been added'), 'success');
if (!empty($variables_with_problems)) {
Display::return_message(
$path_folder.' '.get_lang('is not writeable').'<br /> '.api_ucwords(get_lang('errors found'))
.': <br />'.$variables_with_problems,
'error'
);
}
Display::addFlash($message);
if (isset($_REQUEST['item_type'])) {
$redirectUrl = api_get_path(WEB_CODE_PATH).'admin/extra_fields.php';
switch ($_REQUEST['item_type']) {
case ExtraField::USER_FIELD_TYPE:
header("Location: {$redirectUrl}?type=user");
exit;
case ExtraField::COURSE_FIELD_TYPE:
header("Location: {$redirectUrl}?type=course");
exit;
case ExtraField::SESSION_FIELD_TYPE:
header("Location: {$redirectUrl}?type=session");
exit;
}
}
if (isset($_REQUEST['skill'])) {
header('Location: '.api_get_path(WEB_CODE_PATH).'skills/skill_list.php');
exit;
}
}
if (isset($_POST['content'], $_POST['filename'], $_POST['msgidEncoded'])) {
$content = $_POST['content'];
$filename = $_POST['filename'];
$msgid = base64_decode($_POST['msgidEncoded']);
if (!empty($variables_with_problems)) {
echo $path_folder.' '.get_lang('is not writeable').'<br /> '.api_ucwords(get_lang('errors found')).': <br />'.$variables_with_problems;
} else {
echo 1;
}
$response = SubLanguageManager::updateOrAddMsgid($filename, $msgid, $content);
echo json_encode($response);
} else {
echo json_encode(["success" => false, "error" => get_lang('POST data missing')]);
}

@ -66,6 +66,8 @@ function get_lang($variable)
return $variable;
}
$defaultLocale = 'en';
$locale = api_get_language_isocode();
$userInfo = api_get_user_info();
if (is_array($userInfo) && !empty($userInfo['language'])) {
@ -79,12 +81,36 @@ function get_lang($variable)
// Using symfony
$defaultDomain = 'messages';
return $translator->trans(
$translated = $translator->trans(
$variable,
[],
$defaultDomain,
$locale
);
if ('true' === api_get_setting('language.allow_use_sub_language')) {
$parentLocale = null;
if ($translated === $variable && $locale !== $defaultLocale) {
$parentLocale = SubLanguageManager::getParentLocale($locale);
$translated = $translator->trans(
$variable,
[],
$defaultDomain,
$parentLocale
);
}
if ($translated === $variable && $parentLocale !== $defaultLocale) {
$translated = $translator->trans(
$variable,
[],
$defaultDomain,
$defaultLocale
);
}
}
return $translated;
}
/**

@ -1,11 +1,17 @@
<?php
/* For licensing terms, see /license.txt */
use Chamilo\CoreBundle\Entity\Language;
/**
* This is used in some scripts inside tests.
*/
class SubLanguageManager
{
const SUBLANGUAGE_TRANS_PATH = '../var/translations/';
const LANGUAGE_TRANS_PATH = '../translations/';
public function __construct()
{
}
@ -64,32 +70,6 @@ class SubLanguageManager
return $content_dir;
}
/**
* Get all information of sub-language.
*
* @param int $parent_id The parent id(Language father id)
* @param int $sub_language_id The sub language id
*
* @return array All information about sub-language
*/
public static function get_all_information_of_sub_language($parent_id, $sub_language_id)
{
$table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
$parent_id = intval($parent_id);
$sub_language_id = intval($sub_language_id);
$sql = "SELECT * FROM $table
WHERE
parent_id = $parent_id AND
id = $sub_language_id";
$rs = Database::query($sql);
$all_information = [];
while ($row = Database::fetch_array($rs, 'ASSOC')) {
$all_information = $row;
}
return $all_information;
}
/**
* Get all information of language.
*
@ -183,92 +163,39 @@ class SubLanguageManager
}
/**
* Add directory for sub-language.
* Add a .po file for a sub-language using its ISO code.
*
* @param string $sub_language_dir The sub-language directory ( e.g. 'spanish_corporate' )
* @param string $subLanguageIsoCode The ISO code of the sub-language (e.g., 'es_CO')
*
* @return bool True on success, false on failure
*/
public static function add_language_directory($sub_language_dir)
public static function addPoFileForSubLanguage($subLanguageIsoCode)
{
if (empty($sub_language_dir)) {
if (empty($subLanguageIsoCode)) {
return false;
}
$dir = api_get_path(SYS_LANG_PATH).$sub_language_dir;
if (is_dir($dir)) {
return true;
} //even if the dir already exists, we reach the objective of having the directory there
return @mkdir($dir, api_get_permissions_for_new_directories());
}
// Path for the .po file you want to create
$poFilePath = api_get_path(SYS_PATH) . self::SUBLANGUAGE_TRANS_PATH . 'messages.' . $subLanguageIsoCode . '.po';
$translationsDir = dirname($poFilePath);
/**
* Delete sub-language.
* In order to avoid deletion of main laguages, we check the existence of a parent.
*
* @deprecated
*
* @param int $parent_id The parent id
* @param bool $sub_language_id
*
* @return mixed True on success, false on error
*/
public static function remove_sub_language($parent_id, $sub_language_id)
{
if (empty($parent_id) ||
(intval($parent_id) != $parent_id) ||
empty($sub_language_id) ||
(intval($sub_language_id) != $sub_language_id)
) {
return false;
}
$table = Database::get_main_table(TABLE_MAIN_LANGUAGE);
$sql = 'SELECT dokeos_folder FROM '.$table.'
WHERE parent_id = '.$parent_id.' and id = '.$sub_language_id;
$res = Database::query($sql);
if (false === $res or Database::num_rows($res) < 1) {
return false;
// Check if the translations directory is writable
if (!is_writable($translationsDir)) {
// Attempt to set writable permissions
if (!@chmod($translationsDir, 0775)) { // You might adjust the permission level as needed
return false; // Failed to set writable permissions
}
$row = Database::fetch_assoc($res);
$res = self::remove_language_directory($row['dokeos_folder']);
if (false === $res) {
return false;
} //can't delete dir, so do not delete language record
$sql = 'DELETE FROM '.$table.'
WHERE id= '.intval($sub_language_id);
$res = Database::query($sql);
return $res;
}
/**
* Remove directory for sub-language.
*
* @param string $sub_language_dir The sub-language path directory ( e.g. 'spanish_corporate'' )
*
* @return bool True on success, false on failure
*/
public static function remove_language_directory($sub_language_dir)
{
if (empty($sub_language_dir)) {
return false;
// If the .po file doesn't exist, create it
if (!file_exists($poFilePath)) {
$initialContent = "# Translation file for $subLanguageIsoCode\nmsgid \"\"\nmsgstr \"\"\n";
if (false === file_put_contents($poFilePath, $initialContent)) {
return false; // Failed to write the file
}
$dir = api_get_path(SYS_LANG_PATH).$sub_language_dir;
if (!is_dir($dir)) {
return true;
} //even if the dir does not exist, we reach the objective of not having the directory there
$content = self::get_lang_folder_files_list($dir);
if (count($content) > 0) {
foreach ($content as $value_content) {
$path_file = $dir.'/'.$value_content;
unlink($path_file);
}
return @rmdir($dir);
} else {
return @rmdir($dir);
}
return true;
}
/**
@ -552,4 +479,386 @@ class SubLanguageManager
return false;
}
/**
* Convert a string to a valid PHP camelCase variable name.
*
* @param string $string
* @return string
*/
public static function stringToCamelCaseVariableName($string)
{
$varName = preg_replace('/[^a-z0-9_]/i', '_', $string); // Replace invalid characters with '_'
$varName = trim($varName, '_'); // Trim any '_' from the beginning and end
$varName = ucwords(str_replace('_', ' ', $varName)); // Convert to camel case
$varName = lcfirst(str_replace(' ', '', $varName)); // Remove spaces and convert the first character to lowercase
return substr($varName, 0, 25); // Limit to 15 characters
}
/**
* Retrieve the iso_code for a given language ID and its parent.
*
* @param int $languageId
* @return array [childIsoCode, parentIsoCode]
*/
public static function getIsoCodes($languageId)
{
$em = Database::getManager();
$language = $em->getRepository('Chamilo\CoreBundle\Entity\Language')->find($languageId);
if (!$language) {
return [null, null];
}
$childIsoCode = $language->getIsoCode();
$parentIsoCode = null;
if ($language->getParent()) {
$parentLanguage = $em->getRepository('Chamilo\CoreBundle\Entity\Language')->find($language->getParent());
if ($parentLanguage) {
$parentIsoCode = $parentLanguage->getIsoCode();
}
}
return [$childIsoCode, $parentIsoCode];
}
/**
* Search for translations based on a term and language ID.
*
* @param string $term The term to search for.
* @param int $languageId The ID of the language to search in.
*
* @return array An array of matched translations.
*/
public static function searchTranslations($term, $languageId): array
{
// Retrieve the ISO codes for the provided language ID.
list($childIsoCode, $parentIsoCode) = self::getIsoCodes($languageId);
// Define the files to search in based on the ISO codes.
$files = ['en' => 'messages.en.po', $parentIsoCode => "messages.$parentIsoCode.po", $childIsoCode => "messages.$childIsoCode.po"];
$results = [];
// Step 1: Search for all matches in messages.en.po.
$matchedMsgids = self::searchMsgidInFile($term, $files['en']);
// Step 2: For each matched msgid, search for its translation in the other files.
foreach ($matchedMsgids as $msgid) {
$entry = [
'file' => $files['en'],
'variable' => $msgid,
'phpVarName' => self::stringToCamelCaseVariableName($msgid),
'en' => self::getTranslationForVariable($msgid, $files['en'])
];
$entry[$parentIsoCode] = self::getTranslationForVariable($msgid, $files[$parentIsoCode]);
$entry[$childIsoCode] = self::getTranslationForVariable($msgid, $files[$childIsoCode], true);
$results[] = $entry;
}
return $results;
}
/**
* Search for a specific term inside a given .po file and return the msgids that match.
*
* @param string $term The term to search for.
* @param string $filename The name of the .po file to search in.
*
* @return array An array of msgids that match the given term.
*/
private static function searchMsgidInFile($term, $filename)
{
$poFilePath = api_get_path(SYS_PATH) . self::LANGUAGE_TRANS_PATH . $filename;
$matchedMsgids = [];
if (file_exists($poFilePath)) {
$lines = file($poFilePath, FILE_IGNORE_NEW_LINES);
$currentVariable = null;
foreach ($lines as $line) {
if (strpos($line, 'msgid "') === 0) {
$currentVariable = str_replace('msgid "', '', $line);
$currentVariable = rtrim($currentVariable, '"');
if (stripos($currentVariable, $term) !== false) {
$matchedMsgids[] = $currentVariable;
}
}
}
}
return $matchedMsgids;
}
/**
* Retrieve the translation (msgstr) for a given variable (msgid) from a specified .po file.
*
* @param string $variable The variable (msgid) to search for.
* @param string $filename The name of the .po file to retrieve the translation from.
*
* @return string The translation (msgstr) for the provided variable, or an empty string if not found.
*/
private static function getTranslationForVariable(string $variable, string $filename, $checkSubLanguagePath = false): string
{
$poFilePath = api_get_path(SYS_PATH) . self::LANGUAGE_TRANS_PATH . $filename;
if ($checkSubLanguagePath) {
$poFilePath = api_get_path(SYS_PATH) . self::SUBLANGUAGE_TRANS_PATH . $filename;
}
if (file_exists($poFilePath)) {
$content = file_get_contents($poFilePath);
$pattern = '/msgid "' . preg_quote($variable, '/') . '"\nmsgstr "(.*?)"/';
if (preg_match($pattern, $content, $match)) {
return $match[1];
}
}
return '';
}
/**
* Updates or adds a msgid in the specified .po file.
*
* @param string $filename Name of the .po file
* @param string $msgid Message identifier to search or add
* @param string $content Associated message content
*
* @return array Returns true if the operation was successful, otherwise returns false
*/
public static function updateOrAddMsgid($filename, $msgid, $content): array
{
$filePath = api_get_path(SYS_PATH) . self::SUBLANGUAGE_TRANS_PATH . $filename;
if (!file_exists($filePath)) {
return ['success' => false, 'error' => 'File does not exist'];
}
if (!is_writable($filePath)) {
try {
if (!chmod($filePath, 0664)) {
return ['success' => false, 'error' => 'Unable to set the file to writable'];
}
} catch (Exception $e) {
return ['success' => false, 'error' => 'Failed to change file permissions: ' . $e->getMessage()];
}
}
$fileContents = file_get_contents($filePath);
if ($fileContents === false) {
return ['success' => false, 'error' => 'Failed to read file contents'];
}
$pattern = '/msgid "' . preg_quote($msgid, '/') . '"' . PHP_EOL . 'msgstr "(.*?)"/';
if (preg_match($pattern, $fileContents)) {
$replacement = 'msgid "' . $msgid . '"' . PHP_EOL . 'msgstr "' . $content . '"';
$fileContents = preg_replace($pattern, $replacement, $fileContents);
} else {
$appendString = PHP_EOL . PHP_EOL . 'msgid "' . $msgid . '"' . PHP_EOL . 'msgstr "' . $content . '"';
$fileContents .= $appendString;
}
if (file_put_contents($filePath, $fileContents) === false) {
return ['success' => false, 'error' => 'Failed to write to file'];
}
return ['success' => true];
}
/**
* Delete sub-language.
* In order to avoid deletion of main languages, we check the existence of a parent.
*/
public static function removeSubLanguage(int $parentId, int $subLanguageId): bool
{
$entityManager = Database::getManager();
$subLanguage = $entityManager->getRepository(Language::class)->find($subLanguageId);
$parentLanguage = $subLanguage ? $subLanguage->getParent() : null;
if (!$subLanguage || !$parentLanguage || $parentLanguage->getId() != $parentId) {
return false;
}
// Locate and delete the .po file of the sub-language
$subLanguageIsoCode = $subLanguage->getIsocode();
$poFilePath = api_get_path(SYS_PATH) . self::SUBLANGUAGE_TRANS_PATH . "messages.$subLanguageIsoCode.po";
if (file_exists($poFilePath)) {
unlink($poFilePath);
}
$entityManager->remove($subLanguage);
$entityManager->flush();
return true;
}
/**
* Add a sub-language.
*/
public static function addSubLanguage(string $originalName, string $englishName, bool $isAvailable, int $parentId): bool|int
{
$entityManager = Database::getManager();
$parentLanguage = $entityManager->getRepository(Language::class)->find($parentId);
if (!$parentLanguage) {
return false;
}
$subLanguage = new Language();
$subLanguage->setOriginalName($originalName)
->setEnglishName($englishName)
->setIsocode($englishName)
->setAvailable($isAvailable)
->setParent($parentLanguage);
try {
$entityManager->persist($subLanguage);
$entityManager->flush();
} catch (\Exception $e) {
// Handle exception if needed
return false;
}
return $subLanguage->getId();
}
/**
* Remove a .po file for a sub-language.
*
* @param string $isoCode The ISO code of the sub-language (e.g., 'es_CO')
*
* @return bool True on success, false on failure
*/
public static function removePoFileForSubLanguage(string $isoCode): bool
{
if (empty($isoCode)) {
return false;
}
// Path for the .po file you want to remove
$poFilePath = api_get_path(SYS_PATH) . self::SUBLANGUAGE_TRANS_PATH . "messages.$isoCode.po";
if (file_exists($poFilePath)) {
return unlink($poFilePath);
}
// File does not exist, consider it a successful removal
return true;
}
/**
* Check if a language exists by its ID.
*/
public static function languageExistsById(int $languageId): bool
{
$entityManager = Database::getManager();
$language = $entityManager->getRepository(Language::class)->find($languageId);
return $language !== null;
}
/**
* Check if the given language is a parent of any sub-language.
*/
public static function isParentOfSubLanguage(int $parentId): bool
{
$entityManager = Database::getManager();
$languageRepository = $entityManager->getRepository(Language::class);
$childrenCount = $languageRepository->count(['parent' => $parentId]);
return $childrenCount > 0;
}
/**
* Get all information of a sub-language.
*/
public static function getAllInformationOfSubLanguage(int $parentId, int $subLanguageId): array
{
$entityManager = Database::getManager();
$languageRepository = $entityManager->getRepository(Language::class);
$subLanguage = $languageRepository->findOneBy([
'parent' => $parentId,
'id' => $subLanguageId
]);
return $subLanguage ? self::convertLanguageToArray($subLanguage) : [];
}
/**
* Convert a Language entity to an array.
*/
private static function convertLanguageToArray(Language $language): array
{
return [
'id' => $language->getId(),
'original_name' => $language->getOriginalName(),
'english_name' => $language->getEnglishName(),
'isocode' => $language->getIsocode(),
'available' => $language->getAvailable(),
// Add other fields as needed
];
}
/**
* Check if a language exists.
*/
public static function checkIfLanguageExists(string $originalName, string $englishName, string $isoCode): array
{
$entityManager = Database::getManager();
$languageRepository = $entityManager->getRepository(Language::class);
$messageInformation = [
'original_name' => false,
'english_name' => false,
'isocode' => false,
'execute_add' => true
];
if ($languageRepository->count(['originalName' => $originalName]) > 0) {
$messageInformation['original_name'] = true;
$messageInformation['execute_add'] = false;
}
if ($languageRepository->count(['englishName' => $englishName]) > 0) {
$messageInformation['english_name'] = true;
$messageInformation['execute_add'] = false;
}
$isoList = api_get_platform_isocodes(); // Assuming this is an existing function
if (!in_array($isoCode, array_values($isoList))) {
$messageInformation['isocode'] = true;
$messageInformation['execute_add'] = false;
}
return $messageInformation;
}
/**
* Gets the ISO code of the parent language for a given language.
*/
public static function getParentLocale(string $childIsoCode): ?string
{
$em = Database::getManager();
$languageRepository = $em->getRepository('Chamilo\CoreBundle\Entity\Language');
// Find the language by its ISO code
$language = $languageRepository->findOneBy(['isocode' => $childIsoCode]);
if (!$language) {
return null; // Language not found
}
// Get the parent language if it exists
$parentLanguage = $language->getParent();
if ($parentLanguage) {
return $parentLanguage->getIsocode();
}
return null; // No parent language
}
}

@ -6,6 +6,7 @@ declare(strict_types=1);
namespace Chamilo\CoreBundle\Command;
use Chamilo\CoreBundle\Entity\Language;
use Chamilo\CoreBundle\Repository\LanguageRepository;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
@ -69,7 +70,8 @@ class UpdateVueTranslations extends Command
$newLanguage = [];
foreach ($translations as $variable => $translation) {
$translated = $this->translator->trans($variable, [], null, $iso);
//$translated = $this->translator->trans($variable, [], null, $iso);
$translated = $this->getTranslationWithFallback($variable, $language);
$newLanguage[$variable] = $this->replaceMarkers($translated);
}
$newLanguageToString = json_encode($newLanguage, JSON_PRETTY_PRINT);
@ -83,6 +85,37 @@ class UpdateVueTranslations extends Command
return Command::SUCCESS;
}
/**
* Gets the translation for a given variable with fallbacks to parent language and base language.
*
* @param string $variable The variable to be translated.
* @param Language $language The Language entity for the current language.
*
* @return string The translated string.
*/
private function getTranslationWithFallback(string $variable, Language $language): string {
// Get the ISO code of the current language
$iso = $language->getIsocode();
// Try to translate the variable in the current language
$translated = $this->translator->trans($variable, [], 'messages', $iso);
// Check if the translation is not found and if there is a parent language
if ($translated === $variable && $language->getParent()) {
// Get the parent language entity and its ISO code
$parentLanguage = $language->getParent();
$parentIso = $parentLanguage->getIsocode();
// Try to translate the variable in the parent language
$translated = $this->translator->trans($variable, [], 'messages', $parentIso);
// Check if translation is still not found and use the base language (English)
if ($translated === $variable) {
$translated = $this->translator->trans($variable, [], 'messages', 'en');
}
}
return $translated;
}
/**
* Replace specifiers in a string to allow rendering them by i18n.
*

Loading…
Cancel
Save