internationalization.lib.php 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. <?php
  2. /**
  3. * ==============================================================================
  4. * File: internationalization.lib.php
  5. * Main API extension library for Dokeos 1.8.6+ LMS
  6. * A library implementing internationalization related functions.
  7. * License: GNU/GPL version 2 or later (Free Software Foundation)
  8. * @author: Ivan Tcholakov, ivantcholakov@gmail.com
  9. * August 2009 - initial implementation.
  10. * @package dokeos.library
  11. * ==============================================================================
  12. */
  13. /**
  14. * ----------------------------------------------------------------------------
  15. * Constants
  16. * ----------------------------------------------------------------------------
  17. */
  18. // Predefined date formats in Dokeos provided by the language sub-system.
  19. // To be used as a parameter for the function api_format_date().
  20. define('TIME_NO_SEC_FORMAT', 0); // 15:23
  21. define('DATE_FORMAT_SHORT', 1); // 25.08.2009
  22. define('DATE_FORMAT_LONG', 2); // Aug 25, 09
  23. define('DATE_TIME_FORMAT_LONG', 3); // August 25, 2009 at 03:28 PM
  24. // Formatting person's name.
  25. define('PERSON_NAME_COMMON_CONVENTION', 0); // Formatting a person's name using the pattern as it has been
  26. // configured in the internationalization database for every language.
  27. // This (default) option would be the most used.
  28. // The followind options may be used in limited number of places for overriding the common convention:
  29. define('PERSON_NAME_WESTERN_ORDER', 1); // Formatting a person's name in Western order: first_name last_name
  30. define('PERSON_NAME_EASTERN_ORDER', 2); // Formatting a person's name in Eastern order: last_name first_name
  31. define('PERSON_NAME_LIBRARY_ORDER', 3); // Contextual: formatting person's name in library order: last_name, first_name
  32. define('PERSON_NAME_EMAIL_ADDRESS', PERSON_NAME_WESTERN_ORDER); // Contextual: formatting a person's name assotiated with an email-address. Ivan: I am not sure how seems email servers an clients would interpret name order, so I assign the Western order.
  33. define('PERSON_NAME_DATA_EXPORT', PERSON_NAME_EASTERN_ORDER); // Contextual: formatting a person's name for data-exporting operarions. For backward compatibility this format has been set to Eastern order.
  34. /**
  35. * ----------------------------------------------------------------------------
  36. * Language support
  37. * ----------------------------------------------------------------------------
  38. */
  39. /**
  40. * Whenever the server type in the Dokeos Config settings is
  41. * @param string $variable This is the identificator (name) of the translated string to be retrieved.
  42. * @param string $notrans This parameter directs whether a link to DLTT to be shown for untranslated strings
  43. * ($notrans = 'DLTT' means "yes", any other value means "no").
  44. * @param string $language (optional) Language indentificator. If it is omited, the current interface language is assumed.
  45. * @return string Returns the requested string in the correspondent language.
  46. *
  47. * @author Roan Embrechts
  48. * @author Patrick Cool
  49. * @author Ivan Tcholakov, April-August 2009 (caching functionality, additional parameter $language).
  50. *
  51. * Notes:
  52. * 1. If the name of a given language variable has the prefix "lang" it may be omited,
  53. * i.e. get_lang('langYes') == get_lang('Yes').
  54. * 2. Whenever the server type in the Dokeos Config settings is set to
  55. * test/development server you will get an indication that a language variable
  56. * is not translated and a link to a suggestions form of DLTT.
  57. * 3. DLTT means Dokeos Language Translation Tool.
  58. * @link http://www.dokeos.com/DLTT/
  59. */
  60. function get_lang($variable, $notrans = 'DLTT', $language = null) {
  61. // We introduced the possibility to request specific language
  62. // by the aditional parameter $language to this function.
  63. // By manipulating this global variable the translation
  64. // may be done in different languages too (not the elegant way).
  65. global $language_interface;
  66. // Because of possibility for manipulations of the global variable
  67. // $language_interface, we need its initial value.
  68. global $language_interface_initial_value;
  69. // This is a cache for already translated language variables.
  70. // By using it we will avoid repetitive translations.
  71. static $cache = array();
  72. // Combining both ways for requesting specific language.
  73. if (empty($language)) {
  74. $language = $language_interface;
  75. }
  76. // This is a flag for showing the link to the Dokeos Language Translation Tool
  77. // when the requested variable has no translation within the language files.
  78. $dltt = $notrans == 'DLTT' ? true : false;
  79. // Cache initialization.
  80. if (!is_array($cache[$language])) {
  81. $cache[$language] = array(false => array(), true => array());
  82. }
  83. // Looking up into the cache for existing translation.
  84. if (isset($cache[$language][$dltt][$variable])) {
  85. // There is a previously saved translation, returning it.
  86. return $cache[$language][$dltt][$variable];
  87. }
  88. // There is no saved translation, we have to extract it.
  89. // If the language files have been reloaded, then the language
  90. // variables should be accessed as local ones.
  91. $seek_local_variables = false;
  92. // We reload the language variables when the requested language is different to
  93. // the language of the interface or when the server is in testing mode.
  94. if ($language != $language_interface_initial_value || api_get_setting('server_type') == 'test') {
  95. $seek_local_variables = true;
  96. global $language_files;
  97. $langpath = api_get_path(SYS_CODE_PATH).'lang/';
  98. if (isset ($language_files)) {
  99. if (!is_array($language_files)) {
  100. @include $langpath.$language.'/'.$language_files.'.inc.php';
  101. } else {
  102. foreach ($language_files as $index => $language_file) {
  103. @include $langpath.$language.'/'.$language_file.'.inc.php';
  104. }
  105. }
  106. }
  107. }
  108. $ot = '[='; //opening tag for missing vars
  109. $ct = '=]'; //closing tag for missing vars
  110. if (api_get_setting('hide_dltt_markup') == 'true') {
  111. $ot = '';
  112. $ct = '';
  113. }
  114. // Translation mode for production servers.
  115. if (api_get_setting('server_type') != 'test') {
  116. if (!$seek_local_variables) {
  117. $lvv = isset ($GLOBALS['lang'.$variable]) ? $GLOBALS['lang'.$variable] : (isset ($GLOBALS[$variable]) ? $GLOBALS[$variable] : $ot.$variable.$ct);
  118. } else {
  119. @eval('$lvv = $'.$variable.';');
  120. if (!isset($lvv)) {
  121. @eval('$lvv = $lang'.$variable.';');
  122. if (!isset($lvv)) {
  123. $lvv = $ot.$variable.$ct;
  124. }
  125. }
  126. }
  127. if (!is_string($lvv)) {
  128. $cache[$language][$dltt][$variable] = $lvv;
  129. return $lvv;
  130. }
  131. $lvv = str_replace("\\'", "'", $lvv);
  132. $lvv = _get_lang_purify($lvv, $language);
  133. $cache[$language][$dltt][$variable] = $lvv;
  134. return $lvv;
  135. }
  136. // Translation mode for test/development servers.
  137. if (!is_string($variable)) {
  138. $cache[$language][$dltt][$variable] = $ot.'get_lang(?)'.$ct;
  139. return $cache[$language][$dltt][$variable];
  140. }
  141. @ eval ('$langvar = $'.$variable.';'); // Note (RH): $$var doesn't work with arrays, see PHP doc
  142. if (isset ($langvar) && is_string($langvar) && strlen($langvar) > 0) {
  143. $langvar = str_replace("\\'", "'", $langvar);
  144. $langvar = _get_lang_purify($langvar, $language);
  145. $cache[$language][$dltt][$variable] = $langvar;
  146. return $langvar;
  147. }
  148. @ eval ('$langvar = $lang'.$variable.';');
  149. if (isset ($langvar) && is_string($langvar) && strlen($langvar) > 0) {
  150. $langvar = str_replace("\\'", "'", $langvar);
  151. $langvar = _get_lang_purify($langvar, $language);
  152. $cache[$language][$dltt][$variable] = $langvar;
  153. return $langvar;
  154. }
  155. if (!$dltt) {
  156. $cache[$language][$dltt][$variable] = $ot.$variable.$ct;
  157. return $cache[$language][$dltt][$variable];
  158. }
  159. if (!is_array($language_files)) {
  160. $language_file = $language_files;
  161. } else {
  162. $language_file = implode('.inc.php', $language_files);
  163. }
  164. $cache[$language][$dltt][$variable] =
  165. $ot.$variable.$ct."<a href=\"http://www.dokeos.com/DLTT/suggestion.php?file=".$language_file.".inc.php&amp;variable=$".$variable."&amp;language=".$language_interface."\" target=\"_blank\" style=\"color:#FF0000\"><strong>#</strong></a>";
  166. return $cache[$language][$dltt][$variable];
  167. }
  168. /**
  169. * Gets the current interface language.
  170. * @param bool $purified (optional) When it is true, a purified (refined) language value will be returned, for example 'french' instead of 'french_unicode'.
  171. * @return string The current language of the interface.
  172. */
  173. function api_get_interface_language($purified = false) {
  174. global $language_interface;
  175. if (empty($language_interface)) {
  176. return 'english';
  177. }
  178. if ($purified) {
  179. return api_refine_language_id($language_interface);
  180. }
  181. return $language_interface;
  182. }
  183. /**
  184. * ----------------------------------------------------------------------------
  185. * Date and time formats
  186. * ----------------------------------------------------------------------------
  187. */
  188. /**
  189. * Returns formated date/time format correspondent to a given language.
  190. * @author Patrick Cool <patrick.cool@UGent.be>, Ghent University
  191. * @author Christophe Gesche<gesche@ipm.ucl.ac.be>
  192. * originally inspired from from PhpMyAdmin
  193. * @author Ivan Tcholakov, 2009, code refactoring, adding support for predefined date/time formats.
  194. * @param string/int $date_format The date pattern. See the php-manual about the function strftime().
  195. * Note: For $date_format the following integer constants may be used for using predefined date/time
  196. * formats in the Dokeos system: TIME_NO_SEC_FORMAT, DATE_FORMAT_SHORT, DATE_FORMAT_LONG, DATE_TIME_FORMAT_LONG.
  197. * @param int $time_stamp (optional) Time as an integer value. The default value -1 means now, the function time() is called internally.
  198. * @param string $language (optional) Language indentificator. If it is omited, the current interface language is assumed.
  199. * @return string Returns the formatted date.
  200. * @link http://php.net/manual/en/function.strftime.php
  201. */
  202. function api_format_date($date_format, $time_stamp = -1, $language = null) {
  203. if ($time_stamp == -1) {
  204. $time_stamp = time();
  205. }
  206. if (is_int($date_format)) {
  207. switch ($date_format) {
  208. case TIME_NO_SEC_FORMAT:
  209. $date_format = get_lang('timeNoSecFormat', '', $language);
  210. break;
  211. case DATE_FORMAT_SHORT:
  212. $date_format = get_lang('dateFormatShort', '', $language);
  213. break;
  214. case DATE_FORMAT_LONG:
  215. $date_format = get_lang('dateFormatShort', '', $language);
  216. break;
  217. case DATE_TIME_FORMAT_LONG:
  218. $date_format = get_lang('dateTimeFormatLong', '', $language);
  219. break;
  220. default:
  221. $date_format = get_lang('dateTimeFormatLong', '', $language);
  222. }
  223. }
  224. // We replace %a %A %b %B masks of date format with translated strings.
  225. $translated = &_api_get_day_month_names($language);
  226. $date_format = str_replace(array('%A', '%a', '%B', '%b'),
  227. array($translated['days_long'][(int)strftime('%w', $time_stamp)],
  228. $translated['days_short'][(int)strftime('%w', $time_stamp)],
  229. $translated['months_long'][(int)strftime('%m', $time_stamp) - 1],
  230. $translated['months_short'][(int)strftime('%m', $time_stamp) - 1]),
  231. $date_format);
  232. return strftime($date_format, $time_stamp);
  233. }
  234. /**
  235. * Returns an array of translated week days in short names.
  236. * @param string $language (optional) Language indentificator. If it is omited, the current interface language is assumed.
  237. * @return string Returns an array of week days (short names).
  238. * Example: api_get_week_days_short('english') means array('Sun', 'Mon', ... 'Sat').
  239. * Note: For all languges returned days are in the English order.
  240. */
  241. function api_get_week_days_short($language = null) {
  242. $days = &_api_get_day_month_names($language);
  243. return $days['days_short'];
  244. }
  245. /**
  246. * Returns an array of translated week days.
  247. * @param string $language (optional) Language indentificator. If it is omited, the current interface language is assumed.
  248. * @return string Returns an array of week days.
  249. * Example: api_get_week_days_long('english') means array('Sunday, 'Monday', ... 'Saturday').
  250. * Note: For all languges returned days are in the English order.
  251. */
  252. function api_get_week_days_long($language = null) {
  253. $days = &_api_get_day_month_names($language);
  254. return $days['days_long'];
  255. }
  256. /**
  257. * Returns an array of translated months in short names.
  258. * @param string $language (optional) Language indentificator. If it is omited, the current interface language is assumed.
  259. * @return string Returns an array of months (short names).
  260. * Example: api_get_months_short('english') means array('Jan', 'Feb', ... 'Dec').
  261. */
  262. function api_get_months_short($language = null) {
  263. $months = &_api_get_day_month_names($language);
  264. return $months['months_short'];
  265. }
  266. /**
  267. * Returns an array of translated months.
  268. * @param string $language (optional) Language indentificator. If it is omited, the current interface language is assumed.
  269. * @return string Returns an array of months.
  270. * Example: api_get_months_long('english') means array('January, 'February' ... 'December').
  271. */
  272. function api_get_months_long($language = null) {
  273. $months = &_api_get_day_month_names($language);
  274. return $months['months_long'];
  275. }
  276. /**
  277. * ----------------------------------------------------------------------------
  278. * Name order conventions
  279. * ----------------------------------------------------------------------------
  280. */
  281. /**
  282. * Builds a person (full) name depending on the convention for a given language.
  283. * @param string $first_name The first name of the preson.
  284. * @param string $last_name The last name of the person.
  285. * @param string $title The title of the person.
  286. * @param int/string $format (optional) The person name format. It may be a pattern-string (for example '%t. %l, %f') or some of the constants PERSON_NAME_COMMON_CONVENTION (default), PERSON_NAME_WESTERN_ORDER, PERSON_NAME_EASTERN_ORDER, PERSON_NAME_LIBRARY_ORDER.
  287. * @param string $language (optional) The language indentificator. If it is omited, the current interface language is assumed. This parameter has meaning with the format PERSON_NAME_COMMON_CONVENTION only.
  288. * @return bool The result is sort of full name of the person.
  289. * Sample results:
  290. * Peter Ustinoff or Dr. Peter Ustinoff - the Western order
  291. * Ustinoff Peter or Dr. Ustinoff Peter - the Eastern order
  292. * Ustinoff, Peter or - Dr. Ustinoff, Peter - the library order
  293. * Note: See the file dokeos/main/inc/lib/internationalization_database/name_order_conventions.php where you can revise the convention for your language.
  294. * @author Carlos Vargas <carlos.vargas@dokeos.com> - initial implementation.
  295. * @author Ivan Tcholakov
  296. */
  297. function api_get_person_name($first_name, $last_name, $title = null, $format = null, $language = null) {
  298. static $valid = array();
  299. if (empty($format)) {
  300. $format = PERSON_NAME_COMMON_CONVENTION;
  301. }
  302. if (empty($language)) {
  303. $language = api_get_interface_language();
  304. }
  305. if (!isset($valid[$format][$language])) {
  306. if (is_int($format)) {
  307. switch ($format) {
  308. case PERSON_NAME_COMMON_CONVENTION:
  309. $valid[$format][$language] = _api_get_person_name_convention($language, 'format');
  310. break;
  311. case PERSON_NAME_WESTERN_ORDER:
  312. $valid[$format][$language] = '%t %f %l';
  313. break;
  314. case PERSON_NAME_EASTERN_ORDER:
  315. $valid[$format][$language] = '%t %l %f';
  316. break;
  317. case PERSON_NAME_LIBRARY_ORDER:
  318. $valid[$format][$language] = '%t %l, %f';
  319. break;
  320. default:
  321. $valid[$format][$language] = '%t %f %l';
  322. }
  323. } else {
  324. $valid[$format][$language] = _api_validate_person_name_format($format);
  325. }
  326. }
  327. return _api_clean_person_name(str_replace(array('%f', '%l', '%t'), array($first_name, $last_name, $title), $valid[$format][$language]));
  328. }
  329. /**
  330. * Checks whether a given format represents person name in Western order (for which first name is first).
  331. * @param int/string $format (optional) The person name format. It may be a pattern-string (for example '%t. %l, %f') or some of the constants PERSON_NAME_COMMON_CONVENTION (default), PERSON_NAME_WESTERN_ORDER, PERSON_NAME_EASTERN_ORDER, PERSON_NAME_LIBRARY_ORDER.
  332. * @param string $language (optional) The language indentificator. If it is omited, the current interface language is assumed. This parameter has meaning with the format PERSON_NAME_COMMON_CONVENTION only.
  333. * @return bool The result TRUE means that the order is first_name last_name, FALSE means last_name first_name.
  334. * Note: You may use this function for determing the order of the fields or columns "First name" and "Last name" in forms, tables and reports.
  335. * @author Ivan Tcholakov
  336. */
  337. function api_is_western_name_order($format = null, $language = null) {
  338. static $order = array();
  339. if (empty($format)) {
  340. $format = PERSON_NAME_COMMON_CONVENTION;
  341. }
  342. if (empty($language)) {
  343. $language = api_get_interface_language();
  344. }
  345. if (!isset($order[$format][$language])) {
  346. $test_name = api_get_person_name('%f', '%l', '%t', $format, $language);
  347. $order[$format][$language] = strpos($test_name, '%f') <= strpos($test_name, '%l');
  348. }
  349. return $order[$format][$language];
  350. }
  351. /**
  352. * Returns a directive for sorting person names depending on a given language and based on the options in the internationalization "database".
  353. * @param string $language (optional) The input language. If it is omited, the current interface language is assumed.
  354. * @return bool Returns boolean value. TRUE means ORDER BY first_name, last_name; FALSE means ORDER BY last_name, first_name.
  355. * Note: You may use this function:
  356. * 2. for constructing the ORDER clause of SQL queries, related to first_name and last_name;
  357. * 3. for adjusting php-implemented sorting in tables and reports.
  358. * @author Ivan Tcholakov
  359. */
  360. function api_sort_by_first_name($language = null) {
  361. static $sort_by_first_name = array();
  362. if (empty($language)) {
  363. $language = api_get_interface_language();
  364. }
  365. if (!isset($sort_by_first_name[$language])) {
  366. $sort_by_first_name[$language] = _api_get_person_name_convention($language, 'sort_by');
  367. }
  368. return $sort_by_first_name[$language];
  369. }
  370. /**
  371. * ----------------------------------------------------------------------------
  372. * Functions for internal use behind this API.
  373. * ----------------------------------------------------------------------------
  374. */
  375. require_once dirname(__FILE__).'/internationalization_internal.lib.php';