PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/core/lang_api.php

https://github.com/fusenigk/mantisbt-1
PHP | 404 lines | 199 code | 60 blank | 145 comment | 54 complexity | adf5c4db807fe82b8118013b7064f5f4 MD5 | raw file
  1. <?php
  2. # MantisBT - A PHP based bugtracking system
  3. # MantisBT is free software: you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation, either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # MantisBT is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with MantisBT. If not, see <http://www.gnu.org/licenses/>.
  15. /**
  16. * Language (Internationalization) API
  17. *
  18. * @package CoreAPI
  19. * @subpackage LanguageAPI
  20. * @copyright Copyright (C) 2000 - 2002 Kenzaburo Ito - kenito@300baud.org
  21. * @copyright Copyright (C) 2002 - 2011 MantisBT Team - mantisbt-dev@lists.sourceforge.net
  22. * @link http://www.mantisbt.org
  23. *
  24. * @uses authentication_api.php
  25. * @uses config_api.php
  26. * @uses constant_inc.php
  27. * @uses error_api.php
  28. * @uses plugin_api.php
  29. * @uses user_pref_api.php
  30. */
  31. require_api( 'authentication_api.php' );
  32. require_api( 'config_api.php' );
  33. require_api( 'constant_inc.php' );
  34. require_api( 'error_api.php' );
  35. require_api( 'plugin_api.php' );
  36. require_api( 'user_pref_api.php' );
  37. # Cache of localization strings in the language specified by the last
  38. # lang_load call
  39. $g_lang_strings = array();
  40. # stack for language overrides
  41. $g_lang_overrides = array();
  42. # To be used in custom_strings_inc.php :
  43. $g_active_language = '';
  44. /**
  45. * Loads the specified language and stores it in $g_lang_strings, to be used by lang_get
  46. * @param string $p_lang
  47. * @param string $p_dir
  48. * @return null
  49. */
  50. function lang_load( $p_lang, $p_dir = null ) {
  51. global $g_lang_strings, $g_active_language;
  52. $g_active_language = $p_lang;
  53. if( isset( $g_lang_strings[$p_lang] ) && is_null( $p_dir ) ) {
  54. return;
  55. }
  56. if( !lang_language_exists( $p_lang ) ) {
  57. return;
  58. }
  59. // Step 1 - Load Requested Language file
  60. // @@ and if file doesn't exist???
  61. if( $p_dir === null ) {
  62. include_once( config_get( 'language_path' ) . 'strings_' . $p_lang . '.txt' );
  63. } else {
  64. if( is_file( $p_dir . 'strings_' . $p_lang . '.txt' ) ) {
  65. include_once( $p_dir . 'strings_' . $p_lang . '.txt' );
  66. }
  67. }
  68. // Step 2 - Allow overriding strings declared in the language file.
  69. // custom_strings_inc.php can use $g_active_language
  70. // 2 formats:
  71. // $s_* - old format
  72. // $s_custom_strings array - new format
  73. // NOTE: it's not expected that you'd mix/merge old/new formats within this file.
  74. $t_custom_strings = config_get( 'custom_strings_file' ) ;
  75. if( file_exists( $t_custom_strings ) ) {
  76. # this may be loaded multiple times, once per language
  77. require( $t_custom_strings );
  78. }
  79. // Step 3 - New Language file format
  80. // Language file consists of an array
  81. if( isset( $s_messages ) ) {
  82. // lang strings array entry can only be set if $p_dir is not null - i.e. in a plugin
  83. if( isset( $g_lang_strings[$p_lang] ) ) {
  84. if( isset( $s_custom_messages[$p_lang] ) ) {
  85. // Step 4 - handle merging in custom strings:
  86. // Possible states:
  87. // 4.a - new string format + new custom string format
  88. $g_lang_strings[$p_lang] = array_replace( ((array)$g_lang_strings[$p_lang]), (array)$s_messages, (array)$s_custom_messages[$p_lang]);
  89. return;
  90. } else {
  91. $g_lang_strings[$p_lang] = array_replace( ((array)$g_lang_strings[$p_lang]), (array)$s_messages);
  92. }
  93. } else {
  94. // new language loaded
  95. $g_lang_strings[$p_lang] = $s_messages;
  96. if( isset( $s_custom_messages[$p_lang] ) ) {
  97. // 4.a - new string format + new custom string format
  98. $g_lang_strings[$p_lang] = array_replace( ((array)$g_lang_strings[$p_lang]), (array)$s_custom_messages[$p_lang]);
  99. return;
  100. }
  101. }
  102. }
  103. // 4.b new string format + old custom string format
  104. // 4.c - old string format + old custom string format
  105. if( !isset( $s_messages ) || file_exists( $t_custom_strings ) ) {
  106. $t_vars = get_defined_vars();
  107. foreach( array_keys( $t_vars ) as $t_var ) {
  108. $t_lang_var = preg_replace( '/^s_/', '', $t_var );
  109. if( $t_lang_var != $t_var ) {
  110. $g_lang_strings[$p_lang][$t_lang_var] = $$t_var;
  111. }
  112. else if( 'MANTIS_ERROR' == $t_var ) {
  113. if( isset( $g_lang_strings[$p_lang][$t_lang_var] ) ) {
  114. foreach( $$t_var as $key => $val ) {
  115. $g_lang_strings[$p_lang][$t_lang_var][$key] = $val;
  116. }
  117. } else {
  118. $g_lang_strings[$p_lang][$t_lang_var] = $$t_var;
  119. }
  120. }
  121. }
  122. // 4.d old string format + new custom string format
  123. // merge new custom strings into array in same way we merge in 4.a
  124. if( isset( $s_custom_messages[$p_lang] ) ) {
  125. $g_lang_strings[$p_lang] = array_replace( ((array)$g_lang_strings[$p_lang]), (array)$s_custom_messages[$p_lang]);
  126. }
  127. }
  128. }
  129. /**
  130. * Determine the preferred language
  131. * @return string
  132. */
  133. function lang_get_default() {
  134. global $g_active_language;
  135. $t_lang = false;
  136. # Confirm that the user's language can be determined
  137. if( function_exists( 'auth_is_user_authenticated' ) && auth_is_user_authenticated() ) {
  138. $t_lang = user_pref_get_language( auth_get_current_user_id() );
  139. }
  140. # Otherwise fall back to default
  141. if( !$t_lang ) {
  142. $t_lang = config_get_global( 'default_language' );
  143. }
  144. if( $t_lang == 'auto' ) {
  145. $t_lang = lang_map_auto();
  146. }
  147. # Remember the language
  148. $g_active_language = $t_lang;
  149. return $t_lang;
  150. }
  151. /**
  152. *
  153. * @return string
  154. */
  155. function lang_map_auto() {
  156. $t_lang = config_get( 'fallback_language' );
  157. if( isset( $_SERVER['HTTP_ACCEPT_LANGUAGE'] ) ) {
  158. $t_accept_langs = explode( ',', $_SERVER['HTTP_ACCEPT_LANGUAGE'] );
  159. $t_auto_map = config_get( 'language_auto_map' );
  160. # Expand language map
  161. $t_auto_map_exp = array();
  162. foreach( $t_auto_map as $t_encs => $t_enc_lang ) {
  163. $t_encs_arr = explode( ',', $t_encs );
  164. foreach( $t_encs_arr as $t_enc ) {
  165. $t_auto_map_exp[trim( $t_enc )] = $t_enc_lang;
  166. }
  167. }
  168. # Find encoding
  169. foreach( $t_accept_langs as $t_accept_lang ) {
  170. $t_tmp = explode( ';', utf8_strtolower( $t_accept_lang ) );
  171. if( isset( $t_auto_map_exp[trim( $t_tmp[0] )] ) ) {
  172. $t_valid_langs = config_get( 'language_choices_arr' );
  173. $t_found_lang = $t_auto_map_exp[trim( $t_tmp[0] )];
  174. if( in_array( $t_found_lang, $t_valid_langs, true ) ) {
  175. $t_lang = $t_found_lang;
  176. break;
  177. }
  178. }
  179. }
  180. }
  181. return $t_lang;
  182. }
  183. /**
  184. * Ensures that a language file has been loaded
  185. * @param string $p_lang the language name
  186. * @return null
  187. */
  188. function lang_ensure_loaded( $p_lang ) {
  189. global $g_lang_strings;
  190. if( !isset( $g_lang_strings[$p_lang] ) ) {
  191. lang_load( $p_lang );
  192. }
  193. }
  194. /**
  195. * Check if the given language exists
  196. *
  197. * @param string $p_lang the language name
  198. * @return boolean
  199. */
  200. function lang_language_exists( $p_lang ) {
  201. $t_valid_langs = config_get( 'language_choices_arr' );
  202. $t_valid = in_array( $p_lang, $t_valid_langs, true );
  203. return $t_valid;
  204. }
  205. /**
  206. * language stack implementation
  207. * push a language onto the stack
  208. * @param string $p_lang
  209. * @return null
  210. */
  211. function lang_push( $p_lang = null ) {
  212. global $g_lang_overrides;
  213. # If no specific language is requested, we'll
  214. # try to determine the language from the users
  215. # preferences
  216. $t_lang = $p_lang;
  217. if( null === $t_lang ) {
  218. $t_lang = config_get( 'default_language' );
  219. }
  220. # don't allow 'auto' as a language to be pushed onto the stack
  221. # The results from auto are always the local user, not what the
  222. # override wants, unless this is the first language setting
  223. if(( 'auto' == $t_lang ) && ( 0 < count( $g_lang_overrides ) ) ) {
  224. $t_lang = config_get( 'fallback_language' );
  225. }
  226. $g_lang_overrides[] = $t_lang;
  227. # Remember the language
  228. $g_active_language = $t_lang;
  229. # make sure it's loaded
  230. lang_ensure_loaded( $t_lang );
  231. }
  232. /**
  233. * pop a language onto the stack and return it
  234. * @return string
  235. */
  236. function lang_pop() {
  237. global $g_lang_overrides;
  238. return array_pop( $g_lang_overrides );
  239. }
  240. /**
  241. * return value on top of the language stack
  242. * return default if stack is empty
  243. * @return string
  244. */
  245. function lang_get_current() {
  246. global $g_lang_overrides;
  247. $t_count_overrides = count( $g_lang_overrides );
  248. if( $t_count_overrides > 0 ) {
  249. $t_lang = $g_lang_overrides[$t_count_overrides - 1];
  250. } else {
  251. $t_lang = lang_get_default();
  252. }
  253. return $t_lang;
  254. }
  255. /**
  256. * Retrieves an internationalized string
  257. * This function will return one of (in order of preference):
  258. * 1. The string in the current user's preferred language (if defined)
  259. * 2. The string in English
  260. * @param string $p_string
  261. * @param string $p_lang
  262. * @param bool $p_error default: true - error if string not found
  263. * @return string
  264. */
  265. function lang_get( $p_string, $p_lang = null, $p_error = true ) {
  266. global $g_lang_strings;
  267. # If no specific language is requested, we'll
  268. # try to determine the language from the users
  269. # preferences
  270. $t_lang = $p_lang;
  271. if( null === $t_lang ) {
  272. $t_lang = lang_get_current();
  273. }
  274. // Now we'll make sure that the requested language is loaded
  275. lang_ensure_loaded( $t_lang );
  276. // Step 1 - see if language string exists in requested language
  277. if( lang_exists( $p_string, $t_lang ) ) {
  278. return $g_lang_strings[$t_lang][$p_string];
  279. } else {
  280. // Language string doesn't exist in requested language
  281. // Step 2 - See if language string exists in current plugin
  282. $t_plugin_current = plugin_get_current();
  283. if( !is_null( $t_plugin_current ) ) {
  284. // Step 3 - Plugin exists: load language file
  285. lang_load( $t_lang, config_get( 'plugin_path' ) . $t_plugin_current . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR );
  286. if( lang_exists( $p_string, $t_lang ) ) {
  287. return $g_lang_strings[$t_lang][$p_string];
  288. }
  289. // Step 4 - Localised language entry didn't exist - fallback to english for plugin
  290. lang_load( 'english', config_get( 'plugin_path' ) . $t_plugin_current . DIRECTORY_SEPARATOR . 'lang' . DIRECTORY_SEPARATOR );
  291. if( lang_exists( $p_string, $t_lang ) ) {
  292. return $g_lang_strings[$t_lang][$p_string];
  293. }
  294. }
  295. // Step 5 - string didn't exist, try fall back to english:
  296. if( $t_lang == 'english' ) {
  297. if( $p_error ) {
  298. error_parameters( $p_string );
  299. trigger_error( ERROR_LANG_STRING_NOT_FOUND, WARNING );
  300. }
  301. return '';
  302. } else {
  303. // if string is not found in a language other than english, then retry using the english language.
  304. return lang_get( $p_string, 'english' );
  305. }
  306. }
  307. }
  308. /**
  309. * Check the language entry, if found return true, otherwise return false.
  310. * @param string $p_string
  311. * @param string $p_lang
  312. * @return bool
  313. */
  314. function lang_exists( $p_string, $p_lang ) {
  315. global $g_lang_strings;
  316. return( isset( $g_lang_strings[$p_lang] ) && isset( $g_lang_strings[$p_lang][$p_string] ) );
  317. }
  318. /**
  319. * Get language:
  320. * - If found, return the appropriate string (as lang_get()).
  321. * - If not found, no default supplied, return the supplied string as is.
  322. * - If not found, default supplied, return default.
  323. * @param string $p_string
  324. * @param string $p_default
  325. * @param string $p_lang
  326. * @return string
  327. */
  328. function lang_get_defaulted( $p_string, $p_default = null, $p_lang = null ) {
  329. $t_lang = $p_lang;
  330. if( null === $t_lang ) {
  331. $t_lang = lang_get_current();
  332. }
  333. # Now we'll make sure that the requested language is loaded
  334. lang_ensure_loaded( $t_lang );
  335. if( lang_exists( $p_string, $t_lang ) ) {
  336. return lang_get( $p_string );
  337. } else {
  338. if( null === $p_default ) {
  339. return $p_string;
  340. } else {
  341. return $p_default;
  342. }
  343. }
  344. }