ocPortal Developer's Guide: Language: code and content
» Return to Contents
We define a difference between 'code' (the translation of the site usage process, in language string form) and 'content' (the translation of the content that is added to the site).
Some language guidelines:
- Don't split up phrases, use {1} {2} and {3} to insert variables instead. There is no guarantee that different languages assemble together in the same way. It is also a lot cleaner like this. HTML is allowed, where supported and where the string'll solely be used in HTML
- Don't translate technical terms. These include: cookie, localhost, comcode, CEDI, ocPortal, chmod, FTP, SQL, PHP, XHTML, HTML, SMTP, GD, SUEXEC, Gzipped, POP3
- charset is a special entry, and is the character set of the language
- Also when needed, add comments to define context
- Try to reuse strings as much as possible. Don't add new strings unless it is really needed, as they need to be translated into potentially dozens of languages
- Good grammar is important. We Don't Capitalise Like This. We do it nicely like this. Consistency! Sometimes multi-word proper nouns are given hyphens, sometimes concatenation is used, sometimes CamelCase is used, sometimes abbreviation is used by just using the first letters placed together as capitals, and sometimes each word is given in capitals - this inconsistency is ingrained in English, but for any single term, reference it in a uniform way
- Plurality-Wrong: Apple's. Plurality-Right: Apples. Possession-Wrong: Pauls. Possession-Right: Paul's. Compaction-Wrong: Its. Compaction-Right: It's. S-Ending-Pocession-Wrong: Chris' (unless there is more than one Chris). S-Ending-Pocession-Right: Chris's.
- Phrases should be phrased as generally as possible… i.e. without using context or tense; this allows reuse
- If phrases are not general, then put them in a language file that can be individually included by a module
- Language strings must not include html symbols like ' " < > and &. These should be turned into HTML entities, such as & or <
sources/lang.php
Global_functions_lang.php
Function summary
|
void
|
init__lang ()
|
|
?mixed
|
do_lang (ID_TEXT codename, ?mixed token1, ?mixed token2, ?mixed token3, ?LANGUAGE_NAME lang, boolean require_result)
|
|
void
|
open_page_cache_file ()
|
|
LANGUAGE_NAME
|
fallback_lang ()
|
|
LANGUAGE_NAME
|
user_lang ()
|
|
?LANGUAGE_NAME
|
get_lang_browser ()
|
|
boolean
|
does_lang_exist (LANGUAGE_NAME lang)
|
|
LANGUAGE_NAME
|
get_site_default_lang ()
|
|
?LANGUAGE_NAME
|
get_lang_forum_user (MEMBER member)
|
|
LANGUAGE_NAME
|
get_lang (?MEMBER member)
|
|
void
|
require_lang (ID_TEXT codename, ?LANGUAGE_NAME lang, ?string type, boolean ignore_errors)
|
|
void
|
require_all_lang (?LANGUAGE_NAME lang, boolean only_if_for_lang)
|
|
integer
|
lang_code_to_default_content (ID_TEXT code, boolean comcode, integer level)
|
|
void
|
require_all_open_lang_files (?LANGUAGE_NAME lang)
|
|
tempcode
|
urlise_lang (string string, mixed url, string title, boolean new_window)
|
|
tempcode
|
protect_from_escaping (mixed in)
|
|
?mixed
|
_do_lang (ID_TEXT codename, ?mixed token1, ?mixed token2, ?mixed token3, ?LANGUAGE_NAME lang, boolean require_result)
|
|
array
|
find_all_langs (boolean even_empty_langs)
|
|
tempcode
|
nice_get_langs (?LANGUAGE_NAME select_lang, boolean show_unset)
|
|
integer
|
insert_lang_comcode (string text, integer level, ?object connection, boolean insert_as_admin, ?string pass_id, integer wrap_pos, boolean preparse_mode, boolean save_as_volatile)
|
|
integer
|
insert_lang (string text, integer level, ?object connection, boolean comcode, ?integer id, ?LANGUAGE_NAME lang, boolean insert_as_admin, ?string pass_id, ?string text2, integer wrap_pos, boolean preparse_mode, boolean save_as_volatile)
|
|
integer
|
lang_remap_comcode (integer id, string text, ?object connection, ?string pass_id, ?MEMBER source_member, boolean as_admin)
|
|
integer
|
lang_remap (integer id, string text, ?object connection, boolean comcode, ?string pass_id, ?MEMBER source_member, boolean as_admin, boolean backup_string)
|
|
void
|
delete_lang (integer id, ?object connection)
|
|
?tempcode
|
get_translated_tempcode (integer entry, ?object connection, ?LANGUAGE_NAME lang, boolean force, boolean as_admin, boolean clear_away_from_cache)
|
|
?string
|
get_translated_text (integer entry, ?object connection, ?LANGUAGE_NAME lang, boolean force)
|
|
tempcode
|
comcode_lang_string (ID_TEXT lang_code)
|
|
mixed
|
choose_language (tempcode title, boolean tip, boolean allow_all_selection)
|
void init__lang()
Standard code module initialisation function.
Parameters…
(No return value)
function init__lang()
{
if (!function_exists('do_lang'))
{
/**
* Get the human-readable form of a language id, or a language entry from a language INI file.
*
* @param ID_TEXT The language id
* @param ?mixed The first token [string or tempcode] (replaces {1}) (NULL: none)
* @param ?mixed The second token [string or tempcode] (replaces {2}) (NULL: none)
* @param ?mixed The third token (replaces {3}). May be an array of [of string], to allow any number of additional args (NULL: none)
* @param ?LANGUAGE_NAME The language to use (NULL: users language)
* @param boolean Whether to cause ocPortal to exit if the lookup does not succeed
* @return ?mixed The human-readable content (NULL: not found). String normally. Tempcode if tempcode parameters.
*/
function do_lang($codename,$token1=NULL,$token2=NULL,$token3=NULL,$lang=NULL,$require_result=true)
{
return _do_lang($codename,$token1,$token2,$token3,$lang,$require_result);
}
}
global $COMCODE_LANG_STRING_CACHE;
$COMCODE_LANG_STRING_CACHE=array();
global $LANG;
$LANG=array();
global $LANG_LOADED,$LANG_LOADED_LANG,$LANG_REQUESTED_LANG,$LANGS_REQUESTED;
// Tracks what has already been require'd, although loading may have been deferred.
$LANG_REQUESTED_LANG=array(); // By lang pack and lang file
$LANGS_REQUESTED=array(); // Just by lang file
// Tracks what has already been require'd and not deferred. This will not track all require_lang calls, as ocPortal will try and use the page's own lang cache first.
$LANG_LOADED_LANG=array(); // By lang pack and lang file
$LANG_LOADED=array(); // Just by lang file
global $LANGUAGE;
$LANGUAGE=array();
global $LANGS_MAP;
$LANGS_MAP=NULL;
global $USER_LANG_CACHED,$USER_LANG_EARLY_CACHED,$USER_LANG_LOOP,$REQUIRE_LANG_LOOP;
global $RECORD_LANG_STRINGS,$RECORDED_LANG_STRINGS,$RECORD_LANG_STRINGS_CONTENT,$RECORDED_LANG_STRINGS_CONTENT;
$RECORD_LANG_STRINGS=false;
$RECORDED_LANG_STRINGS=array();
$RECORD_LANG_STRINGS_CONTENT=false;
$RECORDED_LANG_STRINGS_CONTENT=array();
$USER_LANG_LOOP=0;
$USER_LANG_CACHED=NULL;
$USER_LANG_EARLY_CACHED=NULL;
$REQUIRE_LANG_LOOP=0;
global $REQUIRED_ALL_LANG;
$REQUIRED_ALL_LANG=array();
// Lazy loading code: learning algorithm to cache strings against different pages without loading all, unless we get a cache miss in the page's pool
global $PAGE_CACHE_FILE,$PAGE_CACHE_LANG_LOADED,$PAGE_CACHE_LAZY_LOAD,$PAGE_CACHE_LANGS_REQUESTED;
$PAGE_CACHE_FILE=mixed();
$PAGE_CACHE_LANG_LOADED=array();
$PAGE_CACHE_LAZY_LOAD=false;
$PAGE_CACHE_LANGS_REQUESTED=array();
if (((function_exists('get_option')) && (get_option('is_on_lang_cache')=='1') && ((!array_key_exists('page',$_GET)) || (/*(is_string($_GET['page'])) && */(strpos($_GET['page'],'..')===false))))/* && (!is_null($GLOBALS['MEM_CACHE']))*/)
{
if (running_script('index'))
{
$key='page__'.get_zone_name().'__'.get_page_name();
} else
{
$key='script__'.md5(serialize(ocp_srv('PHP_SELF')));
}
$cache_path=get_custom_file_base().'/lang_cached/'.user_lang().'/'.filter_naughty($key,true).'.lcd';
if (!is_null($GLOBALS['MEM_CACHE']))
{
$PAGE_CACHE_LANG_LOADED=persistant_cache_get($cache_path);
if (is_array($PAGE_CACHE_LANG_LOADED))
{
$PAGE_CACHE_LAZY_LOAD=true;
$LANGUAGE=$PAGE_CACHE_LANG_LOADED;
}
$PAGE_CACHE_FILE=$cache_path;
} else
{
$contents=@file_get_contents($cache_path,FILE_TEXT);
if ($contents!==false)
{
$PAGE_CACHE_LANG_LOADED=@unserialize($contents);
if (is_array($PAGE_CACHE_LANG_LOADED))
{
$PAGE_CACHE_LAZY_LOAD=true;
$LANGUAGE=$PAGE_CACHE_LANG_LOADED;
}
}
$PAGE_CACHE_FILE=$cache_path;
}
}
require_lang('critical_error');
require_lang('global');
global $SEARCH__CONTENT_BITS;
$SEARCH__CONTENT_BITS=NULL;
if (strtolower(get_charset())=='utf-8')
{
global $HTML_ESCAPE_1_STRREP,$HTML_ESCAPE_2;
$HTML_ESCAPE_1_STRREP=array('&'/*,'ì','î'*/,'"','\'','<','>'/*,'£'*/);
$HTML_ESCAPE_2=array('&'/*,'"','"'*/,'"',''','<','>'/*,'£'*/);
}
global $OPTIONS;
if (isset($OPTIONS))
{
if (user_lang()!=get_site_default_lang())
{
foreach ($OPTIONS as $name=>$option)
{
unset($OPTIONS[$name]['config_value_translated']);
}
}
}
}
?mixed do_lang(ID_TEXT codename, ?mixed token1, ?mixed token2, ?mixed token3, ?LANGUAGE_NAME lang, boolean require_result)
Get the human-readable form of a language id, or a language entry from a language INI file.
Parameters…
| Name |
codename |
| Description |
The language id |
| Type |
ID_TEXT |
| Name |
token1 |
| Description |
The first token [string or tempcode] (replaces {1}) (NULL: none) |
| Default value |
|
| Type |
?mixed |
| Name |
token2 |
| Description |
The second token [string or tempcode] (replaces {2}) (NULL: none) |
| Default value |
|
| Type |
?mixed |
| Name |
token3 |
| Description |
The third token (replaces {3}). May be an array of [of string], to allow any number of additional args (NULL: none) |
| Default value |
|
| Type |
?mixed |
| Name |
lang |
| Description |
The language to use (NULL: users language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
require_result |
| Description |
Whether to cause ocPortal to exit if the lookup does not succeed |
| Default value |
boolean-true |
| Type |
boolean |
Returns…
| Description |
The human-readable content (NULL: not found). String normally. Tempcode if tempcode parameters. |
| Type |
?mixed |
function do_lang($codename,$token1=NULL,$token2=NULL,$token3=NULL,$lang=NULL,$require_result=true)
{
return _do_lang($codename,$token1,$token2,$token3,$lang,$require_result);
}
void open_page_cache_file()
Open up our language cache file for appending.
Parameters…
(No return value)
function open_page_cache_file()
{
if ($GLOBALS['MEM_CACHE']===NULL)
{
global $PAGE_CACHE_FILE,$PAGE_CACHE_LAZY_LOAD;
if ($PAGE_CACHE_FILE===NULL) return;
if (!is_string($PAGE_CACHE_FILE)) return;
$cache_path=$PAGE_CACHE_FILE;
$PAGE_CACHE_FILE=@fopen($cache_path,'at');
if ($PAGE_CACHE_FILE!==false)
{
if (!$PAGE_CACHE_LAZY_LOAD)
{
require_code('files');
fix_permissions($cache_path,0666);
}
} else
{
$PAGE_CACHE_FILE=NULL;
}
}
}
LANGUAGE_NAME fallback_lang()
This function is called when no other language works, and it will return the original default language - 'EN'. You may change this to another language, but this is not advised, as ocPortal is being shipped with the EN language complete and unabridged as standard - hence you cannot go wrong if you leave it as EN.In theory, this is the only hook to English that there is.
Parameters…
Returns…
| Description |
The fallback language |
| Type |
LANGUAGE_NAME |
function fallback_lang()
{
return 'EN';
}
LANGUAGE_NAME user_lang()
Get the user's currently selected language.
Parameters…
Returns…
| Description |
The user's current language |
| Type |
LANGUAGE_NAME |
function user_lang()
{
global $USER_LANG_CACHED;
if ($USER_LANG_CACHED!==NULL) return $USER_LANG_CACHED;
global $MEMBER_CACHED,$USER_LANG_LOOP,$IN_MINIKERNEL_VERSION;
if ($IN_MINIKERNEL_VERSION==1)
{
return get_site_default_lang();
}
// In URL?
$lang='';
$special_page_type=get_param('special_page_type','');
if ($special_page_type!='' && substr($special_page_type,0,5)=='lang_')
{
if (substr($special_page_type,0,13)=='lang_content_')
{
$lang=substr($special_page_type,13);
} else
{
$lang=substr($special_page_type,5);
}
}
if ($lang=='')
{
$lang=filter_naughty(either_param('lang',get_param('keep_lang','')));
}
if ((!function_exists('get_member')) || ($USER_LANG_LOOP==1) || ($MEMBER_CACHED===NULL))
{
global $USER_LANG_EARLY_CACHED;
if ($USER_LANG_EARLY_CACHED!==NULL) return $USER_LANG_EARLY_CACHED;
if (($lang!='') && (does_lang_exist($lang))) return $lang;
if ((array_key_exists('GET_OPTION_LOOP',$GLOBALS)) && ($GLOBALS['GET_OPTION_LOOP']==0) && (function_exists('get_option')) && (get_option('detect_lang_browser',true)=='1'))
{
// In browser?
$lang=get_lang_browser();
if ($lang!==NULL)
{
$USER_LANG_EARLY_CACHED=$lang;
return $lang;
}
}
$lang=get_site_default_lang();
$USER_LANG_EARLY_CACHED=$lang;
return $lang; // Booting up and we don't know the user yet
}
$USER_LANG_LOOP=1;
// In URL?
if (($lang!='') && (does_lang_exist($lang)))
{
$USER_LANG_CACHED=$lang;
} else
{
if (((get_forum_type()=='ocf') || (get_option('detect_lang_forum',true)=='1') || (get_option('detect_lang_browser',true)=='1')) && ((!$GLOBALS['DEBUG_MODE']) || (get_site_default_lang()!='Gibb')))
{
// In forum?
if (($USER_LANG_CACHED===NULL) && (get_option('detect_lang_forum',true)=='1'))
{
$USER_LANG_CACHED=get_lang_forum_user(get_member());
}
if (($USER_LANG_CACHED===NULL) && (get_option('detect_lang_browser',true)=='1'))
{
$USER_LANG_CACHED=get_lang_browser();
}
}
}
if ($USER_LANG_CACHED===NULL)
{
$USER_LANG_CACHED=get_site_default_lang();
}
$USER_LANG_LOOP=0;
return $USER_LANG_CACHED;
}
?LANGUAGE_NAME get_lang_browser()
Get the closest fit language code to what the browser is requesting.
Parameters…
Returns…
| Description |
The closest-fit language to what the browser wants (NULL: browser doesn't ask) |
| Type |
?LANGUAGE_NAME |
function get_lang_browser()
{
// In browser?
if (array_key_exists('HTTP_ACCEPT_LANGUAGE',$_SERVER)) $http_lang=$_SERVER['HTTP_ACCEPT_LANGUAGE'];
elseif (array_key_exists('HTTP_ACCEPT_LANGUAGE',$_ENV)) $http_lang=$_ENV['HTTP_ACCEPT_LANGUAGE'];
else $http_lang='';
if (strlen($http_lang)>0)
{
$http_langs=explode(',',$http_lang);
foreach ($http_langs as $lang)
{
// Clean up
$lang=strtoupper(trim($lang));
$pos=strpos($lang,';');
if ($pos!==false) $lang=substr($lang,0,$pos);
$pos=strpos($lang,'-');
if ($pos!==false) $lang=substr($lang,0,$pos);
if (does_lang_exist($lang))
{
return $lang;
}
}
}
return NULL;
}
boolean does_lang_exist(LANGUAGE_NAME lang)
Find whether the specified language exists.
Parameters…
| Name |
lang |
| Description |
The language |
| Type |
LANGUAGE_NAME |
Returns…
| Description |
Whether the language exists |
| Type |
boolean |
function does_lang_exist($lang)
{
if ($lang=='') return false;
if ($lang=='Gibb') return true; // Test language
if ($lang=='xxx') return true; // Test language
$file_a=get_file_base().'/lang/'.$lang;
$file_b=get_custom_file_base().'/lang_custom/'.$lang;
$file_c=get_file_base().'/lang_custom/'.$lang;
return is_dir($file_a) || is_dir($file_b) || is_dir($file_c);
}
LANGUAGE_NAME get_site_default_lang()
Get the site's default language, with support for URL overrides.
Parameters…
Returns…
| Description |
The site's default language |
| Type |
LANGUAGE_NAME |
function get_site_default_lang()
{
// Site default then
global $SITE_INFO;
if (!array_key_exists('default_lang',$SITE_INFO)) // We must be installing
{
global $IN_MINIKERNEL_VERSION;
if ($IN_MINIKERNEL_VERSION==1)
{
if (array_key_exists('lang',$_POST)) return $_POST['lang'];
if (array_key_exists('lang',$_GET)) return $_GET['lang'];
}
return fallback_lang();
}
return $SITE_INFO['default_lang'];
}
?LANGUAGE_NAME get_lang_forum_user(MEMBER member)
Get what language the given member uses. The language is sent through a mapping to ensure it is in the right format, or dumped if it will not map.
Parameters…
| Name |
member |
| Description |
The member id |
| Type |
MEMBER |
Returns…
| Description |
The language used by the member (NULL: the language will not map) |
| Type |
?LANGUAGE_NAME |
function get_lang_forum_user($member)
{
// In forum?
$lang=$GLOBALS['FORUM_DRIVER']->forum_get_lang($member);
if ((!is_null($lang)) && (strlen($lang)>0))
{
$_lang=strtoupper($lang);
if ((!is_dir(get_file_base().'/lang/'.$_lang)) && (!is_dir(get_custom_file_base().'/lang_custom/'.$_lang)) && (!is_dir(get_file_base().'/lang_custom/'.$_lang)))
{
$map_file_a=get_file_base().'/lang/map.ini';
$map_file_b=get_custom_file_base().'/lang_custom/map.ini';
if (!is_file($map_file_b)) $map_file_b=$map_file_a;
$map=better_parse_ini_file($map_file_b);
if (!array_key_exists($lang,$map))
{
//fatal_exit('The specified language ('.$lang.') is missing. The language needs installing/creating in ocPortal, or the language map file needs updating (to map this language to a known ocPortal one), or both.');
$_lang=NULL; // Instead of the above, let's just fallback to default! So people's weird forum integration doesn't make ocPortal die
} else
{
$_lang=$map[$lang];
if ((!is_dir(get_file_base().'/lang/'.$_lang)) && (!is_dir(get_custom_file_base().'/lang_custom/'.$_lang)) && (!is_dir(get_file_base().'/lang_custom/'.$_lang)))
$_lang=NULL;
}
}
if (!is_null($_lang)) return $_lang;
}
return NULL;
}
LANGUAGE_NAME get_lang(?MEMBER member)
Get the current language.First it tries to get the GET or POST language values, then it tries the user's language, then site default, then it resorts to EN.
Parameters…
| Name |
member |
| Description |
The member id (NULL: site default language, although better just to call get_site_default_lang directly) |
| Default value |
|
| Type |
?MEMBER |
Returns…
| Description |
The current language |
| Type |
LANGUAGE_NAME |
function get_lang($member=NULL)
{
if ($member!==NULL)
{
if ($member==get_member()) return user_lang();
$lang=get_lang_forum_user($member);
if ($lang!==NULL) return $lang;
}
return get_site_default_lang();
}
void require_lang(ID_TEXT codename, ?LANGUAGE_NAME lang, ?string type, boolean ignore_errors)
Includes a language file for use in the script.If $type is not null, then this specifies whether to use 'lang_custom' or 'custom' (otherwise, normal priorities occur).
Parameters…
| Name |
codename |
| Description |
The language file name |
| Type |
ID_TEXT |
| Name |
lang |
| Description |
The language (NULL: uses the current language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
type |
| Description |
The language type (lang_custom, or custom) (NULL: normal priorities are used) |
| Default value |
|
| Type |
?string |
| Values restricted to |
lang_custom custom |
| Name |
ignore_errors |
| Description |
Whether to just return if there was a loading error |
| Default value |
boolean-false |
| Type |
boolean |
(No return value)
function require_lang($codename,$lang=NULL,$type=NULL,$ignore_errors=false) // $type is for efficiency only - to avoid needing to doubly-search when requiring all
{
// So we can keep track of what code loads what langs
global $LANGS_REQUESTED,$LANG_REQUESTED_LANG,$REQUIRE_LANG_LOOP,$PAGE_CACHE_LAZY_LOAD,$PAGE_CACHE_LANGS_REQUESTED,$LANG_LOADED_LANG,$LANGUAGE;
$LANGS_REQUESTED[$codename]=1;
if ($lang===NULL) $lang=user_lang();
if ((isset($LANG_REQUESTED_LANG[$lang])) && (isset($LANG_REQUESTED_LANG[$lang][$codename])))
return;
$LANG_REQUESTED_LANG[$lang][$codename]=1;
$cfb=get_custom_file_base();
$fb=get_file_base();
$codename=filter_naughty($codename);
if ($PAGE_CACHE_LAZY_LOAD)
{
global $SITE_INFO;
$support_smart_decaching=(!isset($SITE_INFO['disable_smart_decaching'])) || ($SITE_INFO['disable_smart_decaching']=='0');
if ($support_smart_decaching)
{
$cache_path=$cfb.'/lang_cached/'.$lang.'/'.$codename.'.lcd';
$lang_file_default=$fb.'/lang/'.$lang.'/'.$codename.'.ini';
if (!is_file($lang_file_default))
{
$lang_file_default=$fb.'/lang/'.fallback_lang().'/'.$codename.'.ini';
}
$lang_file=$fb.'/lang_custom/'.$lang.'/'.$codename.'.ini';
if (!is_file($lang_file))
{
$lang_file=$fb.'/lang_custom/'.$lang.'/'.$codename.'.po';
if (!is_file($lang_file))
{
$lang_file=$fb.'/lang_custom/'.$lang.'/'.filter_naughty($codename).'-'.strtolower($lang).'.po';
if (!is_file($lang_file))
{
$lang_file=$lang_file_default;
} else
{
if (!is_file($lang_file_default)) $lang_file_default=$lang_file;
}
} else
{
if (!is_file($lang_file_default)) $lang_file_default=$lang_file;
}
} else
{
if (!is_file($lang_file_default)) $lang_file_default=$lang_file;
}
}
if ((!$support_smart_decaching) || ((is_file($cache_path)) && (is_file($lang_file)) && (@/*race conditions*/filemtime($cache_path)>filemtime($lang_file)) && (@/*race conditions*/filemtime($cache_path)>filemtime($lang_file_default))))
{
if ($lang===NULL) $lang=user_lang();
$PAGE_CACHE_LANGS_REQUESTED[]=array($codename,$lang);
return;
} else // Invalidate it, as our .lcd cache was dirty
{
global $PAGE_CACHE_FILE;
open_page_cache_file();
$LANGUAGE=array();
@rewind($PAGE_CACHE_FILE);
@ftruncate($PAGE_CACHE_FILE,0);
$PAGE_CACHE_LAZY_LOAD=false;
$LANG_LOADED_LANG=array();
$PAGE_CACHE_LANGS_REQUESTED[]=array($codename,$lang);
foreach ($PAGE_CACHE_LANGS_REQUESTED as $request)
{
list($that_codename,$that_lang)=$request;
unset($LANG_REQUESTED_LANG[$that_lang][$that_codename]);
require_lang($that_codename,$that_lang,NULL,$ignore_errors);
}
}
}
if ((isset($LANG_LOADED_LANG[$lang])) && (isset($LANG_LOADED_LANG[$lang][$codename])))
return;
$REQUIRE_LANG_LOOP++;
if ((function_exists('memory_get_usage')) && (isset($_GET['keep_show_loading'])) && ($_GET['keep_show_loading']=='1'))
{
print('<!-- require_lang: '.htmlentities($codename).' ('.integer_format(memory_get_usage()).' before) -->'."\n");
flush();
}
$bad=false;
$done=false;
if (!isset($LANGUAGE[$lang])) $LANGUAGE[$lang]=array();
$cache_path=$cfb.'/lang_cached/'.$lang.'/'.$codename.'.lcd';
// Try lang_cached
if ($GLOBALS['MEM_CACHE']!==NULL)
{
$desire_cache=true;
global $SITE_INFO;
$support_smart_decaching=(!isset($SITE_INFO['disable_smart_decaching'])) || ($SITE_INFO['disable_smart_decaching']=='0');
if ($support_smart_decaching)
{
$lang_file=$fb.'/lang/'.$lang.'/'.$codename.'.ini';
if (!is_file($lang_file))
{
$lang_file=$fb.'/lang/'.$lang.'/'.$codename.'.po';
if (!is_file($lang_file)) $lang_file=$fb.'/lang/'.$lang.'/'.filter_naughty($codename).'-'.strtolower($lang).'.po';
}
$pcache=persistant_cache_get(array('LANG',$lang,$codename),is_file($lang_file)?filemtime($lang_file):NULL);
} else
{
$pcache=persistant_cache_get(array('LANG',$lang,$codename));
}
if (is_array($pcache))
{
$LANGUAGE[$lang]+=$pcache;
$done=true;
}
} else
{
$desire_cache=(function_exists('get_option')) && ((get_option('is_on_lang_cache',true)=='1') || (get_param_integer('keep_cache',0)==1) || (get_param_integer('cache',0)==1)) && (get_param_integer('keep_cache',NULL)!==0) && (get_param_integer('cache',NULL)!==0);
if ($desire_cache)
{
$cache_path=$cfb.'/lang_cached/'.$lang.'/'.$codename.'.lcd';
$lang_file_default=$fb.'/lang/'.$lang.'/'.$codename.'.ini';
if (!is_file($lang_file_default))
{
$lang_file_default=$fb.'/lang/'.fallback_lang().'/'.$codename.'.ini';
}
$lang_file=$fb.'/lang_custom/'.$lang.'/'.$codename.'.ini';
if (!is_file($lang_file))
{
$lang_file=$fb.'/lang_custom/'.$lang.'/'.$codename.'.po';
if (!is_file($lang_file))
{
$lang_file=$fb.'/lang_custom/'.$lang.'/'.filter_naughty($codename).'-'.strtolower($lang).'.po';
if (!is_file($lang_file))
{
$lang_file=$lang_file_default;
}
}
}
if (!is_file($lang_file_default)) $lang_file_default=$lang_file;
if ((is_file($cache_path)) && ((!is_file($lang_file)) || ((@/*race conditions*/filemtime($cache_path)>filemtime($lang_file)) && (@/*race conditions*/filemtime($cache_path)>filemtime($lang_file_default)))))
{
$tmp=@file_get_contents($cache_path,FILE_TEXT);
if ($tmp!='')
{
$unserialized=@unserialize($tmp);
if ($unserialized!==false)
{
$LANGUAGE[$lang]+=$unserialized;
$done=true;
}
}
}
}
}
if (!$done)
{
if (($desire_cache) && (is_file($cache_path))) // Must have been dirty cache, so we need to kill compiled templates too (as lang is compiled into them)
{
require_code('view_modes');
global $ERASED_TEMPLATES_ONCE;
if (!$ERASED_TEMPLATES_ONCE)
erase_cached_templates();
}
require_code('lang_compile');
$bad=$bad || require_lang_compile($codename,$lang,$type,$cache_path,$ignore_errors);
}
global $LANG_LOADED;
$LANG_LOADED[$codename]=$type;
if (!isset($LANG_LOADED_LANG[$lang])) $LANG_LOADED_LANG[$lang]=array();
$LANG_LOADED_LANG[$lang][$codename]=1;
}
void require_all_lang(?LANGUAGE_NAME lang, boolean only_if_for_lang)
Include all the language files for use in the script.NOTE: This may reduce performance, so you should only use it if you really have to.
Parameters…
| Name |
lang |
| Description |
The language to include files from (NULL: use current users language). |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
only_if_for_lang |
| Description |
Only load it up if it is specifically defined for our language. |
| Default value |
boolean-false |
| Type |
boolean |
(No return value)
function require_all_lang($lang=NULL,$only_if_for_lang=false)
{
if (is_null($lang))
{
global $REQUIRED_ALL_LANG;
if (array_key_exists($lang,$REQUIRED_ALL_LANG)) return;
$REQUIRED_ALL_LANG[$lang]=true;
}
if (is_null($lang)) $lang=user_lang();
require_code('lang2');
$lang_files=get_lang_files(fallback_lang());
foreach (array_keys($lang_files) as $file)
{
if ((!$only_if_for_lang) || (is_file(get_custom_file_base().'/lang_custom/'.$lang.'/'.$file.'.ini')) || (is_file(get_custom_file_base().'/lang/'.$lang.'/'.$file.'.ini')) || (is_file(get_custom_file_base().'/lang_custom/'.$lang.'/'.$file.'.po')) || (is_file(get_custom_file_base().'/lang_custom/'.$lang.'/'.$file.'-'.strtolower($lang).'.po')))
require_lang($file,$lang,NULL,true);
}
}
integer lang_code_to_default_content(ID_TEXT code, boolean comcode, integer level)
Convert the specified language codename to the default content, and return the language key.
Parameters…
| Name |
code |
| Description |
The language codename |
| Type |
ID_TEXT |
| Name |
comcode |
| Description |
Whether the given codes value is to be parsed as comcode |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
level |
| Description |
The level of importance this language string holds |
| Default value |
2 |
| Type |
integer |
Returns…
| Description |
The language ID |
| Type |
integer |
function lang_code_to_default_content($code,$comcode=false,$level=2)
{
$lang_key=insert_lang(do_lang($code),$level,NULL,$comcode);
$langs=find_all_langs();
foreach ($langs as $lang=>$lang_type)
{
if ($lang!=user_lang())
{
if (is_file(get_file_base().'/'.$lang_type.'/'.$lang.'/critical_error.ini')) // Make sure it's a reasonable looking pack, not just a stub (Google Translate addon can be made to go nuts otherwise)
insert_lang(do_lang($code,'','','',$lang),$level,NULL,true,$lang_key,$lang);
}
}
return $lang_key;
}
void require_all_open_lang_files(?LANGUAGE_NAME lang)
Require all the open language files. This doesn't hurt performance a lot.
Parameters…
| Name |
lang |
| Description |
The language to require open files from (NULL: uses the current language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
(No return value)
function require_all_open_lang_files($lang=NULL)
{
global $LANG_LOADED,$PAGE_CACHE_LAZY_LOAD,$LANGS_REQUESTED;
$PAGE_CACHE_LAZY_LOAD=false;
global $LANG_REQUESTED_LANG,$LANG_LOADED_LANG;
$LANG_LOADED_LANG=array();
$LANG_REQUESTED_LANG=array();
$langs_requested_copy=$LANGS_REQUESTED;
$LANGS_REQUESTED=array();
foreach (array_keys($langs_requested_copy) as $toload)
{
require_lang($toload,$lang,NULL,true);
}
// Block cacheing might have hidden that we loaded these
require_lang('global',$lang,NULL,true);
require_lang('critical_error',$lang,NULL,true);
}
tempcode urlise_lang(string string, mixed url, string title, boolean new_window)
URL'ise specially encoded text-acceptance language strings.
Parameters…
| Name |
string |
| Description |
The language string |
| Type |
string |
| Name |
url |
| Description |
The URL (either tempcode or string) |
| Type |
mixed |
| Name |
title |
| Description |
The title of the hyperlink |
| Default value |
|
| Type |
string |
| Name |
new_window |
| Description |
Whether to use a new window |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The encoded version |
| Type |
tempcode |
function urlise_lang($string,$url,$title='',$new_window=false)
{
require_code('lang_urlise');
return _urlise_lang($string,$url,$title,$new_window);
}
tempcode protect_from_escaping(mixed in)
Stop some text being escapable by the Tempcode layer.
Parameters…
| Name |
in |
| Description |
Text |
| Type |
mixed |
Returns…
| Description |
Text that can't be escaped |
| Type |
tempcode |
function protect_from_escaping($in)
{
return do_lang_tempcode('dont_escape_trick',$in);
}
?mixed _do_lang(ID_TEXT codename, ?mixed token1, ?mixed token2, ?mixed token3, ?LANGUAGE_NAME lang, boolean require_result)
Get the human-readable form of a language id, or a language entry from a language INI file.
Parameters…
| Name |
codename |
| Description |
The language id |
| Type |
ID_TEXT |
| Name |
token1 |
| Description |
The first token [string or tempcode] (replaces {1}) (NULL: none) |
| Default value |
|
| Type |
?mixed |
| Name |
token2 |
| Description |
The second token [string or tempcode] (replaces {2}) (NULL: none) |
| Default value |
|
| Type |
?mixed |
| Name |
token3 |
| Description |
The third token (replaces {3}). May be an array of [of string], to allow any number of additional args (NULL: none) |
| Default value |
|
| Type |
?mixed |
| Name |
lang |
| Description |
The language to use (NULL: users language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
require_result |
| Description |
Whether to cause ocPortal to exit if the lookup does not succeed |
| Default value |
boolean-true |
| Type |
boolean |
Returns…
| Description |
The human-readable content (NULL: not found). String normally. Tempcode if tempcode parameters. |
| Type |
?mixed |
function _do_lang($codename,$token1=NULL,$token2=NULL,$token3=NULL,$lang=NULL,$require_result=true)
{
global $LANGUAGE,$USER_LANG_CACHED,$RECORD_LANG_STRINGS,$XSS_DETECT,$PAGE_CACHE_FILE,$PAGE_CACHE_LANG_LOADED;
if ($lang===NULL)
{
$lang=($USER_LANG_CACHED===NULL)?user_lang():$USER_LANG_CACHED;
}// else // This else assumes we initially load all language files in the users language. Reasonable. EDIT: Actually, no it is not - the user_lang() initially is not accurate until ocPortal gets past a certain startup position
{
if ($GLOBALS['SEMI_DEBUG_MODE']) // Special syntax for easily inlining language strings
{
$pos=strpos($codename,'=');
if ($pos!==false)
{
// Find loaded file with smallest levenstein distance to current page
$best=mixed();
$best_for=NULL;
global $LANGS_REQUESTED;
foreach (array_keys($LANGS_REQUESTED) as $possible)
{
$dist=levenshtein(get_page_name(),$possible);
if ((is_null($best)) || ($best>$dist))
{
$best=$dist;
$best_for=$possible;
}
}
$save_path=get_file_base().'/lang/'.fallback_lang().'/'.$best_for.'.ini';
if (!is_file($save_path))
$save_path=get_file_base().'/lang_custom/'.fallback_lang().'/'.$best_for.'.ini';
// Tack language strings onto this file
list($codename,$value)=explode('=',$codename,2);
$myfile=fopen($save_path,'at');
fwrite($myfile,"\n".$codename.'='.$value);
fclose($myfile);
// Fake-load the string
$LANGUAGE[$lang][$codename]=$value;
// Go through all required files, doing a string replace if needed
$included_files=get_included_files();
foreach ($included_files as $inc)
{
$orig_contents=file_get_contents($inc);
$contents=str_replace("'".$codename.'='.$value."'","'".$codename."'",$orig_contents);
if ($orig_contents!=$contents)
{
$myfile=fopen($inc,'wt');
fwrite($myfile,$contents);
fclose($myfile);
}
}
}
}
$there=isset($LANGUAGE[$lang][$codename]);
if (!$there)
{
$pos=strpos($codename,':');
if ($pos!==false)
{
require_lang(substr($codename,0,$pos),NULL,NULL,!$require_result);
$codename=substr($codename,$pos+1);
}
$there=isset($LANGUAGE[$lang][$codename]);
}
if ($RECORD_LANG_STRINGS)
{
global $RECORDED_LANG_STRINGS;
$RECORDED_LANG_STRINGS[$codename]=1;
}
if ((!$there) && ((!isset($LANGUAGE[$lang])) || (!array_key_exists($codename,$LANGUAGE[$lang]))))
{
global $PAGE_CACHE_LAZY_LOAD,$PAGE_CACHE_LANGS_REQUESTED,$LANG_REQUESTED_LANG;
if ($PAGE_CACHE_LAZY_LOAD)
{
$PAGE_CACHE_LAZY_LOAD=false; // We can't be lazy any more, but we will keep growing our pool so hopefully CAN be lazy the next time
foreach ($PAGE_CACHE_LANGS_REQUESTED as $request)
{
list($that_codename,$that_lang)=$request;
unset($LANG_REQUESTED_LANG[$that_lang][$that_codename]);
require_lang($that_codename,$that_lang,NULL,!$require_result);
}
$ret=_do_lang($codename,$token1,$token2,$token3,$lang,$require_result);
if ($ret===NULL)
{
$PAGE_CACHE_LANG_LOADED[$lang][$codename]=NULL;
if ($GLOBALS['MEM_CACHE']!==NULL)
{
persistant_cache_set($PAGE_CACHE_FILE,$PAGE_CACHE_LANG_LOADED);
} else
{
open_page_cache_file();
@rewind($PAGE_CACHE_FILE);
@ftruncate($PAGE_CACHE_FILE,0);
@fwrite($PAGE_CACHE_FILE,serialize($PAGE_CACHE_LANG_LOADED));
}
}
return $ret;
}
require_all_open_lang_files($lang);
}
}
if ($lang=='xxx') return 'xxx'; // Helpful for testing language compliancy. We don't expect to see non x's if we're running this language
if ((!isset($LANGUAGE[$lang][$codename])) && (($require_result) || (!isset($LANGUAGE[$lang])) || (!array_key_exists($codename,$LANGUAGE[$lang]))))
{
if ($lang!=fallback_lang())
{
$ret=do_lang($codename,$token1,$token2,$token3,fallback_lang(),$require_result);
if ($PAGE_CACHE_FILE!==NULL)
{
if ((!isset($PAGE_CACHE_LANG_LOADED[$lang][$codename])) && (isset($PAGE_CACHE_LANG_LOADED[fallback_lang()][$codename])))
{
$PAGE_CACHE_LANG_LOADED[$lang][$codename]=$PAGE_CACHE_LANG_LOADED[fallback_lang()][$codename]; // Will have been cached into fallback_lang() from the nested do_lang call, we need to copy it into our cache bucket for this language
if ($GLOBALS['MEM_CACHE']!==NULL)
{
persistant_cache_set($PAGE_CACHE_FILE,$PAGE_CACHE_LANG_LOADED);
} else
{
open_page_cache_file();
@rewind($PAGE_CACHE_FILE);
@ftruncate($PAGE_CACHE_FILE,0);
@fwrite($PAGE_CACHE_FILE,serialize($PAGE_CACHE_LANG_LOADED));
}
}
}
return $ret;
} else
{
if ($require_result)
{
global $USER_LANG_LOOP,$REQUIRE_LANG_LOOP;
//print_r(debug_backtrace());
if ($USER_LANG_LOOP==1) critical_error('RELAY','Missing language code: '.$codename.'. This language code is required to produce error messages, and thus a critical error was prompted by the non-ability to show less-critical error messages. It is likely the source language files (lang/'.fallback_lang().'/*.ini) for ocPortal on this website have been corrupted.');
if ($REQUIRE_LANG_LOOP>=2) return ''; // Probably failing to load global.ini, so just output with some text missing
require_code('view_modes');
erase_cached_language();
fatal_exit(do_lang_tempcode('MISSING_LANG_ENTRY',escape_html($codename)));
} else return NULL;
}
}
if ($PAGE_CACHE_FILE!==NULL)
{
if ((!isset($PAGE_CACHE_LANG_LOADED[$lang][$codename])) && ((!isset($PAGE_CACHE_LANG_LOADED[$lang])) || (!array_key_exists($codename,$PAGE_CACHE_LANG_LOADED[$lang]))))
{
$PAGE_CACHE_LANG_LOADED[$lang][$codename]=$LANGUAGE[$lang][$codename];
if ($GLOBALS['MEM_CACHE']!==NULL)
{
persistant_cache_set($PAGE_CACHE_FILE,$PAGE_CACHE_LANG_LOADED);
} else
{
open_page_cache_file();
@rewind($PAGE_CACHE_FILE);
@ftruncate($PAGE_CACHE_FILE,0);
@fwrite($PAGE_CACHE_FILE,serialize($PAGE_CACHE_LANG_LOADED));
}
}
}
// Put in parameters
static $non_plural_non_vowel=array('1','b','c','d','f','g','h','j','k','l','m','n','p','q','r','s','t','v','w','x','y','z');
$looked_up=$LANGUAGE[$lang][$codename];
if ($looked_up===NULL) return NULL; // Learning cache pool has told us this string definitely does not exist
$out=str_replace('\n',"\n",$looked_up);
$plural_or_vowel_check=strpos($out,'|')!==false;
if ($XSS_DETECT) ocp_mark_as_escaped($out);
if ($token1!==NULL)
{
if (((is_object($token1)) && ($token2===NULL)) || (($token2!==NULL) && (is_object($token2)))) // Tempcode only supported in first two
{
$bits=preg_split('#\{\d[^\}]*\}#',$out,2,PREG_SPLIT_OFFSET_CAPTURE);
$ret=new ocp_tempcode();
foreach ($bits as $bit)
{
if ($XSS_DETECT) ocp_mark_as_escaped($bit[0]);
$at=$bit[1];
if ($at!=0)
{
if ($out[$at-2]=='1') $ret->attach($token1);
elseif ($out[$at-2]=='2') $ret->attach($token2);
elseif (($plural_or_vowel_check) && (substr($out[$at-2],0,2)=='1|'))
{
$exploded=explode('|',$out[$at-2]);
$_token=$token1->evaluate();
$ret->attach((in_array(is_numeric($_token)?$_token:strtolower(substr($_token,0,1)),$non_plural_non_vowel))?$exploded[1]:$exploded[2]);
}
elseif (($plural_or_vowel_check) && (substr($out[$at-2],0,2)=='2|'))
{
$exploded=explode('|',$out[$at-2]);
$_token=$token2->evaluate();
$ret->attach((in_array(is_numeric($_token)?$_token:strtolower(substr($_token,0,1)),$non_plural_non_vowel))?$exploded[1]:$exploded[2]);
}
}
$ret->attach($bit[0]);
}
return $ret;
} elseif ($token1!==NULL)
{
$out=str_replace('{1}',$token1,$out);
if ($plural_or_vowel_check) $out=preg_replace('#\{1\|(.*)\|(.*)\}#U',(in_array(is_numeric($token1)?$token1:strtolower(substr($token1,0,1)),$non_plural_non_vowel))?'\\1':'\\2',$out);
if (($XSS_DETECT) && (ocp_is_escaped($token1))) ocp_mark_as_escaped($out);
}
if ($token2!==NULL)
{
if ($XSS_DETECT) $escaped=ocp_is_escaped($out);
$out=str_replace('{2}',$token2,$out);
if ($plural_or_vowel_check) $out=preg_replace('#\{2\|(.*)\|(.*)\}#U',(in_array(is_numeric($token2)?$token2:strtolower(substr($token2,0,1)),$non_plural_non_vowel))?'\\1':'\\2',$out);
if (($XSS_DETECT) && (ocp_is_escaped($token2)) && ($escaped)) ocp_mark_as_escaped($out);
if ($token3!==NULL)
{
$i=3;
if (!is_array($token3)) $token3=array($token3);
foreach ($token3 as $token)
{
if ($XSS_DETECT) $escaped=ocp_is_escaped($out);
$out=str_replace('{'.strval($i).'}',$token,$out);
if ($plural_or_vowel_check) $out=preg_replace('#\{'.strval($i).'\|(.*)\|(.*)\}#U',(in_array(is_numeric($token)?$token:strtolower(substr($token,0,1)),$non_plural_non_vowel))?'\\1':'\\2',$out);
if (($XSS_DETECT) && (ocp_is_escaped($token)) && ($escaped)) ocp_mark_as_escaped($out);
$i++;
}
}
}
}
return $out;
}
array find_all_langs(boolean even_empty_langs)
Get an array of all the installed languages that can be found in root/lang/ and root/lang_custom/
Parameters…
| Name |
even_empty_langs |
| Description |
Whether to even find empty languages |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The installed languages (map, lang=>type) |
| Type |
array |
function find_all_langs($even_empty_langs=false)
{
require_code('lang3');
return _find_all_langs($even_empty_langs);
}
tempcode nice_get_langs(?LANGUAGE_NAME select_lang, boolean show_unset)
Get a nice formatted XHTML listed language selector.
Parameters…
| Name |
select_lang |
| Description |
The language to have selected by default (NULL: uses the current language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
show_unset |
| Description |
Whether to show languages that have no language details currently defined for them |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The language selector |
| Type |
tempcode |
function nice_get_langs($select_lang=NULL,$show_unset=false)
{
require_code('lang3');
return _nice_get_langs($select_lang,$show_unset);
}
integer insert_lang_comcode(string text, integer level, ?object connection, boolean insert_as_admin, ?string pass_id, integer wrap_pos, boolean preparse_mode, boolean save_as_volatile)
Insert a comcode language entry into the translation table, and returns the id.
Parameters…
| Name |
text |
| Description |
The text |
| Type |
string |
| Name |
level |
| Description |
The level of importance this language string holds |
| Type |
integer |
| Values restricted to |
1 2 3 4 |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
insert_as_admin |
| Description |
Whether to insert it as an admin (any comcode parsing will be carried out with admin privileges) |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
pass_id |
| Description |
The special identifier for this lang code on the page it will be displayed on; this is used to provide an explicit binding between languaged elements and greater templated areas (NULL: none) |
| Default value |
|
| Type |
?string |
| Name |
wrap_pos |
| Description |
Comcode parser wrap position |
| Default value |
60 |
| Type |
integer |
| Name |
preparse_mode |
| Description |
Whether to generate a fatal error if there is invalid Comcode |
| Default value |
boolean-true |
| Type |
boolean |
| Name |
save_as_volatile |
| Description |
Whether we are saving as a 'volatile' file extension (used in the XML DB driver, to mark things as being non-syndicated to subversion) |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The id of the newly added language entry |
| Type |
integer |
function insert_lang_comcode($text,$level,$connection=NULL,$insert_as_admin=false,$pass_id=NULL,$wrap_pos=60,$preparse_mode=true,$save_as_volatile=false)
{
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
return insert_lang($text,$level,$connection,true,NULL,NULL,$insert_as_admin,$pass_id,NULL,$wrap_pos,$preparse_mode,$save_as_volatile);
}
integer insert_lang(string text, integer level, ?object connection, boolean comcode, ?integer id, ?LANGUAGE_NAME lang, boolean insert_as_admin, ?string pass_id, ?string text2, integer wrap_pos, boolean preparse_mode, boolean save_as_volatile)
Insert a language entry into the translation table, and returns the id.
Parameters…
| Name |
text |
| Description |
The text |
| Type |
string |
| Name |
level |
| Description |
The level of importance this language string holds |
| Type |
integer |
| Values restricted to |
1 2 3 4 |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
comcode |
| Description |
Whether it is to be parsed as comcode |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
id |
| Description |
The id to use for the language entry (NULL: work out next available) |
| Default value |
|
| Type |
?integer |
| Name |
lang |
| Description |
The language (NULL: uses the current language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
insert_as_admin |
| Description |
Whether to insert it as an admin (any comcode parsing will be carried out with admin privileges) |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
pass_id |
| Description |
The special identifier for this lang code on the page it will be displayed on; this is used to provide an explicit binding between languaged elements and greater templated areas (NULL: none) |
| Default value |
|
| Type |
?string |
| Name |
text2 |
| Description |
Assembled Tempcode portion (NULL: work it out) |
| Default value |
|
| Type |
?string |
| Name |
wrap_pos |
| Description |
Comcode parser wrap position |
| Default value |
60 |
| Type |
integer |
| Name |
preparse_mode |
| Description |
Whether to generate a fatal error if there is invalid Comcode |
| Default value |
boolean-true |
| Type |
boolean |
| Name |
save_as_volatile |
| Description |
Whether we are saving as a 'volatile' file extension (used in the XML DB driver, to mark things as being non-syndicated to subversion) |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The id of the newly added language entry |
| Type |
integer |
function insert_lang($text,$level,$connection=NULL,$comcode=false,$id=NULL,$lang=NULL,$insert_as_admin=false,$pass_id=NULL,$text2=NULL,$wrap_pos=60,$preparse_mode=true,$save_as_volatile=false)
{
require_code('lang3');
return _insert_lang($text,$level,$connection,$comcode,$id,$lang,$insert_as_admin,$pass_id,$text2,$wrap_pos,$preparse_mode,$save_as_volatile);
}
integer lang_remap_comcode(integer id, string text, ?object connection, ?string pass_id, ?MEMBER source_member, boolean as_admin)
Remap the specified comcode language id, and return the id again - the id isn't changed.
Parameters…
| Name |
id |
| Description |
The language entries id |
| Type |
integer |
| Name |
text |
| Description |
The text to remap to |
| Type |
string |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
pass_id |
| Description |
The special identifier for this lang code on the page it will be displayed on; this is used to provide an explicit binding between languaged elements and greater templated areas (NULL: none) |
| Default value |
|
| Type |
?string |
| Name |
source_member |
| Description |
The member performing the change (NULL: current member) |
| Default value |
|
| Type |
?MEMBER |
| Name |
as_admin |
| Description |
Whether to generate Comcode as arbitrary admin |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The language entries id |
| Type |
integer |
function lang_remap_comcode($id,$text,$connection=NULL,$pass_id=NULL,$source_member=NULL,$as_admin=false)
{
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
return lang_remap($id,$text,$connection,true,$pass_id,$source_member,$as_admin);
}
integer lang_remap(integer id, string text, ?object connection, boolean comcode, ?string pass_id, ?MEMBER source_member, boolean as_admin, boolean backup_string)
Remap the specified language id, and return the id again - the id isn't changed.
Parameters…
| Name |
id |
| Description |
The language entries id |
| Type |
integer |
| Name |
text |
| Description |
The text to remap to |
| Type |
string |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
comcode |
| Description |
Whether it is to be parsed as comcode |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
pass_id |
| Description |
The special identifier for this lang code on the page it will be displayed on; this is used to provide an explicit binding between languaged elements and greater templated areas (NULL: none) |
| Default value |
|
| Type |
?string |
| Name |
source_member |
| Description |
The member performing the change (NULL: current member) |
| Default value |
|
| Type |
?MEMBER |
| Name |
as_admin |
| Description |
Whether to generate Comcode as arbitrary admin |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
backup_string |
| Description |
Whether to backup the language string before changing it |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The language entries id |
| Type |
integer |
function lang_remap($id,$text,$connection=NULL,$comcode=false,$pass_id=NULL,$source_member=NULL,$as_admin=false,$backup_string=false)
{
require_code('lang3');
return _lang_remap($id,$text,$connection,$comcode,$pass_id,$source_member,$as_admin,$backup_string);
}
void delete_lang(integer id, ?object connection)
Delete the specified language entry from the translation table.
Parameters…
| Name |
id |
| Description |
The id |
| Type |
integer |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
(No return value)
function delete_lang($id,$connection=NULL)
{
if (is_null($connection)) $connection=$GLOBALS['SITE_DB'];
$connection->query_delete('translate',array('id'=>$id));
}
?tempcode get_translated_tempcode(integer entry, ?object connection, ?LANGUAGE_NAME lang, boolean force, boolean as_admin, boolean clear_away_from_cache)
This function is an offshoot of get_translated_text, it instead returns parsed comcode that is linked to the specified language id.
Parameters…
| Name |
entry |
| Description |
The id |
| Type |
integer |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
lang |
| Description |
The language (NULL: uses the current language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
force |
| Description |
Whether to force it to the specified language |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
as_admin |
| Description |
Whether to force as_admin, even if the lang string isn't stored against an admin (designed for comcode page cacheing) |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
clear_away_from_cache |
| Description |
Whether to remove from the Tempcode cache when we're done, for performance reasons (normally don't bother with this, but some code knows it won't be needed again – esp Comcode cache layer – and saves RAM by removing it) |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The parsed comcode (NULL: the text couldn't be looked up) |
| Type |
?tempcode |
function get_translated_tempcode($entry,$connection=NULL,$lang=NULL,$force=false,$as_admin=false,$clear_away_from_cache=false)
{
if ($entry==0) return paragraph(do_lang_tempcode('FAILED_ENTRY'),'rtgtedgrgd');
if ($connection===NULL) $connection=$GLOBALS['SITE_DB'];
global $RECORD_LANG_STRINGS_CONTENT;
if ($RECORD_LANG_STRINGS_CONTENT)
{
global $RECORDED_LANG_STRINGS_CONTENT;
$RECORDED_LANG_STRINGS_CONTENT[$entry]=($connection->connection_write!=$GLOBALS['SITE_DB']->connection_write);
}
if ($lang===NULL) $lang=user_lang();
if ($lang=='xxx') return make_string_tempcode('!!!'); // Helpful for testing language compliancy. We don't expect to see non x's/!'s if we're running this language
if ((isset($connection->text_lookup_cache[$entry])) && ($lang==user_lang()))
{
$ret=$connection->text_lookup_cache[$entry];
if ($ret!=='')
{
if (is_string($ret))
{
$connection->text_lookup_cache[$entry]=new ocp_tempcode();
$connection->text_lookup_cache[$entry]->from_assembly($ret);
$ret=$connection->text_lookup_cache[$entry];
}
if ($clear_away_from_cache)
{
unset($connection->text_lookup_cache[$entry]);
unset($connection->text_lookup_original_cache[$entry]);
}
return $ret;
}
}
global $SEARCH__CONTENT_BITS;
if ($SEARCH__CONTENT_BITS!==NULL) // Doing a search so we need to reparse, with highlighting on
{
$_result=$connection->query_select('translate',array('text_original','source_user'),array('id'=>$entry,'language'=>$lang),'',1);
if (array_key_exists(0,$_result))
{
global $LAX_COMCODE;
$temp=$LAX_COMCODE;
$LAX_COMCODE=true;
$result=$_result[0];
$ret=comcode_to_tempcode($result['text_original'],$result['source_user'],$as_admin,60,NULL,$connection,false,false,false,false,false,$SEARCH__CONTENT_BITS);
$LAX_COMCODE=$temp;
return $ret;
}
}
$_result=$connection->query_select('translate',array('text_parsed','text_original'),array('id'=>$entry,'language'=>$lang),'',1);
$result=isset($_result[0])?$_result[0]['text_parsed']:NULL;
if (isset($_result[0]))
{
if ($lang==user_lang())
{
$connection->text_lookup_original_cache[$entry]=$_result[0]['text_original'];
}
}
if (($result===NULL) || ($result=='') || (is_browser_decacheing())) // Not cached
{
require_code('lang3');
return parse_translated_text($entry,$connection,$lang,$force,$as_admin);
}
$parsed=new ocp_tempcode();
if (!$parsed->from_assembly($result,true))
{
require_code('lang3');
return parse_translated_text($entry,$connection,$lang,$force,$as_admin);
}
if ($lang==user_lang())
{
$connection->text_lookup_cache[$entry]=$parsed;
}
return $parsed;
}
?string get_translated_text(integer entry, ?object connection, ?LANGUAGE_NAME lang, boolean force)
Try to return the human-readable version of the language id, passed in as $entry.
Parameters…
| Name |
entry |
| Description |
The id |
| Type |
integer |
| Name |
connection |
| Description |
The database connection to use (NULL: standard site connection) |
| Default value |
|
| Type |
?object |
| Name |
lang |
| Description |
The language (NULL: uses the current language) |
| Default value |
|
| Type |
?LANGUAGE_NAME |
| Name |
force |
| Description |
Whether to force it to the specified language |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The human-readable version (NULL: could not look up when $force was on) |
| Type |
?string |
function get_translated_text($entry,$connection=NULL,$lang=NULL,$force=false)
{
if ($entry==0) return do_lang('FAILED_ENTRY');
if ($entry===NULL) fatal_exit(do_lang_tempcode('NULL_LANG_STRING'));
if ($connection===NULL) $connection=$GLOBALS['SITE_DB'];
global $RECORD_LANG_STRINGS_CONTENT;
if ($RECORD_LANG_STRINGS_CONTENT)
{
global $RECORDED_LANG_STRINGS_CONTENT;
$RECORDED_LANG_STRINGS_CONTENT[$entry]=($connection->connection_write!=$GLOBALS['SITE_DB']->connection_write);
}
if ($lang===NULL) $lang=user_lang();
if ((isset($connection->text_lookup_original_cache[$entry])) && ($lang==user_lang()))
{
return $connection->text_lookup_original_cache[$entry];
}
if ($lang=='xxx') return '!!!'; // Helpful for testing language compliancy. We don't expect to see non x's/!'s if we're running this language
$result=$connection->query_select('translate',array('text_original','text_parsed'),array('id'=>$entry,'language'=>$lang),'',1);
if (!isset($result[0]))
{
if ($force) return NULL;
$result=$connection->query_select('translate',array('*'),array('id'=>$entry),'',1);
if (!isset($result[0]))
{
$result=$connection->query_select('translate',array('*'),array('id'=>$entry),'',1);
}
if (isset($result[0]))
{
$connection->query_insert('translate',array('broken'=>1,'language'=>$lang)+$result[0]);
}
}
if (!isset($result[0]))
{
$member_id=function_exists('get_member')?get_member():$GLOBALS['FORUM_DRIVER']->get_guest_id();
$connection->query_insert('translate',array('id'=>$entry,'source_user'=>$member_id,'broken'=>0,'importance_level'=>3,'text_original'=>'','text_parsed'=>'','language'=>$lang));
$msg=do_lang('LANGUAGE_CORRUPTION',strval($entry));
if (preg_match('#^localhost[\.\:$]#',ocp_srv('HTTP_HOST'))!=0) fatal_exit($msg);
require_code('site');
attach_message(make_string_tempcode($msg),'warn');
return '';
}
if ($lang==user_lang())
{
$connection->text_lookup_original_cache[$entry]=$result[0]['text_original'];
$connection->text_lookup_cache[$entry]=$result[0]['text_parsed'];
}
return $result[0]['text_original'];
}
tempcode comcode_lang_string(ID_TEXT lang_code)
Convert a language string that is Comcode to tempcode, with potential cacheing in the db.
Parameters…
| Name |
lang_code |
| Description |
The language string ID |
| Type |
ID_TEXT |
Returns…
| Description |
The parsed Comcode |
| Type |
tempcode |
function comcode_lang_string($lang_code)
{
require_code('lang3');
return _comcode_lang_string($lang_code);
}
mixed choose_language(tempcode title, boolean tip, boolean allow_all_selection)
UI to choose a language.
Parameters…
| Name |
title |
| Description |
Title for the form |
| Type |
tempcode |
| Name |
tip |
| Description |
Whether to give a tip about edit order |
| Default value |
boolean-false |
| Type |
boolean |
| Name |
allow_all_selection |
| Description |
Whether to add an 'all' entry to the list |
| Default value |
boolean-false |
| Type |
boolean |
Returns…
| Description |
The UI (tempcode) or the language to use (string/LANGUAGE_NAME) |
| Type |
mixed |
function choose_language($title,$tip=false,$allow_all_selection=false)
{
if (!multi_lang()) return user_lang();
$lang=either_param('lang',/*get_param('keep_lang',NULL)*/NULL);
if (!is_null($lang)) return filter_naughty($lang);
if (!$tip)
{
$text=do_lang_tempcode('CHOOSE_LANG_DESCRIP');
} else
{
global $LANGS_MAP;
if ($LANGS_MAP===NULL)
{
$map_a=get_file_base().'/lang/langs.ini';
$map_b=get_custom_file_base().'/lang_custom/langs.ini';
if (!is_file($map_b)) $map_b=$map_a;
$LANGS_MAP=better_parse_ini_file($map_b);
}
$lang_name=get_site_default_lang();
if (array_key_exists($lang_name,$LANGS_MAP)) $lang_name=$LANGS_MAP[$lang_name];
$text=do_lang_tempcode('CHOOSE_LANG_DESCRIP_ADD_TO_MAIN_LANG_FIRST',escape_html($lang_name));
}
$langs=new ocp_tempcode();
if ($allow_all_selection)
{
$langs->attach(form_input_list_entry('',false,do_lang_tempcode('_ALL')));
}
$langs->attach(nice_get_langs());
require_code('form_templates');
$fields=form_input_list(do_lang_tempcode('LANGUAGE'),do_lang_tempcode('DESCRIPTION_LANGUAGE'),'lang',$langs,NULL,true);
$hidden=build_keep_post_fields();
$url=get_self_url();
return do_template('FORM_SCREEN',array('_GUID'=>'1a2823d450237aa299c095bf9c689a2a','GET'=>false,'SKIP_VALIDATION'=>true,'HIDDEN'=>$hidden,'SUBMIT_NAME'=>do_lang_tempcode('PROCEED'),'TITLE'=>$title,'FIELDS'=>$fields,'URL'=>$url,'TEXT'=>$text));
}
All translateable attributes in ocPortal are given priorities. The scheme for these priorities at the time of writing is as follows…
1 (absolutely crucial and permanent/featured)
- zones.header_text
- cached_comcode_pages.string_index
- catalogues.c_title
- galleries.fullname
- news.title
- news.news
- news.news_article
- news_categories.nc_title
- poll.question
- poll.option1
- poll.option2
- poll.option3
- poll.option4
- poll.option5
- ticket_types.ticket_type
- f_custom_fields.cf_name
2 (pretty noticeable: titles, descriptions of very-important)
- seo_meta.meta_keywords
- seo_meta.meta_description
- galleries.description
- catalogues.c_description
- iotd.caption
- text.the_message
- catalogue_categories.cc_title
- banners.caption
- download_categories.category
- download_downloads.name
- seedy_posts.the_message
- seedy_pages.title
- seedy_pages.description
- download_categories.description
- catalogue_fields.cf_name
- catalogue_fields.cf_description
- f_custom_fields.cf_description
3 (full body descriptions)
- authors.description
- authors.skills
- catalogue_categories.cc_description
- filedump.description
- images.comments
- download_downloads.description
- download_downloads.comments
- catalogue_entry_field_values_long_trans.cv_value
- catalogue_entry_field_values_short_trans.cv_value
- f_multi_moderations.mm_name
4 (for individual members, or very low level)
- chargelog.reason
- gifts.reason
- f_posts.p_post
- f_members.m_signature
0 reviews: Unrated (average)
There have been no comments yet