123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588 |
- <?php
- namespace Elgg\I18n;
- /**
- * WARNING: API IN FLUX. DO NOT USE DIRECTLY.
- *
- * @access private
- *
- * @since 1.10.0
- */
- class Translator {
-
- /**
- * Global Elgg configuration
- *
- * @var \stdClass
- */
- private $CONFIG;
- /**
- * Initializes new translator
- */
- public function __construct() {
- global $CONFIG;
- $this->CONFIG = $CONFIG;
- $this->defaultPath = dirname(dirname(dirname(dirname(__DIR__)))) . "/languages/";
- }
-
- /**
- * Given a message key, returns an appropriately translated full-text string
- *
- * @param string $message_key The short message code
- * @param array $args An array of arguments to pass through vsprintf().
- * @param string $language Optionally, the standard language code
- * (defaults to site/user default, then English)
- *
- * @return string Either the translated string, the English string,
- * or the original language string.
- */
- function translate($message_key, $args = array(), $language = "") {
-
-
- static $CURRENT_LANGUAGE;
-
- // old param order is deprecated
- if (!is_array($args)) {
- elgg_deprecated_notice(
- 'As of Elgg 1.8, the 2nd arg to elgg_echo() is an array of string replacements and the 3rd arg is the language.',
- 1.8
- );
-
- $language = $args;
- $args = array();
- }
-
- if (!isset($this->CONFIG->translations)) {
- // this means we probably had an exception before translations were initialized
- $this->registerTranslations($this->defaultPath);
- }
-
- if (!$CURRENT_LANGUAGE) {
- $CURRENT_LANGUAGE = $this->getLanguage();
- }
- if (!$language) {
- $language = $CURRENT_LANGUAGE;
- }
- if (!isset($this->CONFIG->translations[$language])) {
- // The language being requested is not the same as the language of the
- // logged in user, so we will have to load it separately. (Most likely
- // we're sending a notification and the recipient is using a different
- // language than the logged in user.)
- _elgg_load_translations_for_language($language);
- }
- if (isset($this->CONFIG->translations[$language][$message_key])) {
- $string = $this->CONFIG->translations[$language][$message_key];
- } else if (isset($this->CONFIG->translations["en"][$message_key])) {
- $string = $this->CONFIG->translations["en"][$message_key];
- _elgg_services()->logger->notice(sprintf('Missing %s translation for "%s" language key', $language, $message_key));
- } else {
- $string = $message_key;
- _elgg_services()->logger->notice(sprintf('Missing English translation for "%s" language key', $message_key));
- }
-
- // only pass through if we have arguments to allow backward compatibility
- // with manual sprintf() calls.
- if ($args) {
- $string = vsprintf($string, $args);
- }
-
- return $string;
- }
-
- /**
- * Add a translation.
- *
- * Translations are arrays in the Zend Translation array format, eg:
- *
- * $english = array('message1' => 'message1', 'message2' => 'message2');
- * $german = array('message1' => 'Nachricht1','message2' => 'Nachricht2');
- *
- * @param string $country_code Standard country code (eg 'en', 'nl', 'es')
- * @param array $language_array Formatted array of strings
- *
- * @return bool Depending on success
- */
- function addTranslation($country_code, $language_array) {
-
- if (!isset($this->CONFIG->translations)) {
- $this->CONFIG->translations = array();
- }
-
- $country_code = strtolower($country_code);
- $country_code = trim($country_code);
- if (is_array($language_array) && $country_code != "") {
- if (sizeof($language_array) > 0) {
- if (!isset($this->CONFIG->translations[$country_code])) {
- $this->CONFIG->translations[$country_code] = $language_array;
- } else {
- $this->CONFIG->translations[$country_code] = $language_array + $this->CONFIG->translations[$country_code];
- }
- }
- return true;
- }
- return false;
- }
-
- /**
- * Detect the current language being used by the current site or logged in user.
- *
- * @return string The language code for the site/user or "en" if not set
- */
- function getCurrentLanguage() {
- $language = $this->getLanguage();
-
- if (!$language) {
- $language = 'en';
- }
-
- return $language;
- }
-
- /**
- * Gets the current language in use by the system or user.
- *
- * @return string The language code (eg "en") or false if not set
- */
- function getLanguage() {
- $url_lang = _elgg_services()->input->get('hl');
- if ($url_lang) {
- return $url_lang;
- }
-
- $user = _elgg_services()->session->getLoggedInUser();
- $language = false;
-
- if (($user) && ($user->language)) {
- $language = $user->language;
- }
-
- if ((!$language) && (isset($this->CONFIG->language)) && ($this->CONFIG->language)) {
- $language = $this->CONFIG->language;
- }
-
- if ($language) {
- return $language;
- }
-
- return false;
- }
-
- /**
- * @access private
- */
- function loadTranslations() {
-
-
- if ($this->CONFIG->system_cache_enabled) {
- $loaded = true;
- $languages = array_unique(array('en', $this->getCurrentLanguage()));
- foreach ($languages as $language) {
- $data = elgg_load_system_cache("$language.lang");
- if ($data) {
- $this->addTranslation($language, unserialize($data));
- } else {
- $loaded = false;
- }
- }
-
- if ($loaded) {
- $this->CONFIG->i18n_loaded_from_cache = true;
- // this is here to force
- $this->CONFIG->language_paths[$this->defaultPath] = true;
- return;
- }
- }
-
- // load core translations from languages directory
- $this->registerTranslations($this->defaultPath);
- }
-
-
-
- /**
- * When given a full path, finds translation files and loads them
- *
- * @param string $path Full path
- * @param bool $load_all If true all languages are loaded, if
- * false only the current language + en are loaded
- *
- * @return bool success
- */
- function registerTranslations($path, $load_all = false) {
- $path = sanitise_filepath($path);
-
- // Make a note of this path just incase we need to register this language later
- if (!isset($this->CONFIG->language_paths)) {
- $this->CONFIG->language_paths = array();
- }
- $this->CONFIG->language_paths[$path] = true;
-
- // Get the current language based on site defaults and user preference
- $current_language = $this->getCurrentLanguage();
- _elgg_services()->logger->info("Translations loaded from: $path");
- // only load these files unless $load_all is true.
- $load_language_files = array(
- 'en.php',
- "$current_language.php"
- );
-
- $load_language_files = array_unique($load_language_files);
-
- $handle = opendir($path);
- if (!$handle) {
- _elgg_services()->logger->error("Could not open language path: $path");
- return false;
- }
-
- $return = true;
- while (false !== ($language = readdir($handle))) {
- // ignore bad files
- if (substr($language, 0, 1) == '.' || substr($language, -4) !== '.php') {
- continue;
- }
-
- if (in_array($language, $load_language_files) || $load_all) {
- $result = include_once($path . $language);
- if ($result === false) {
- $return = false;
- continue;
- } elseif (is_array($result)) {
- $this->addTranslation(basename($language, '.php'), $result);
- }
- }
- }
-
- return $return;
- }
-
- /**
- * Reload all translations from all registered paths.
- *
- * This is only called by functions which need to know all possible translations.
- *
- * @todo Better on demand loading based on language_paths array
- *
- * @return void
- */
- function reloadAllTranslations() {
-
-
- static $LANG_RELOAD_ALL_RUN;
- if ($LANG_RELOAD_ALL_RUN) {
- return;
- }
-
- if ($this->CONFIG->i18n_loaded_from_cache) {
- $cache = elgg_get_system_cache();
- $cache_dir = $cache->getVariable("cache_path");
- $filenames = elgg_get_file_list($cache_dir, array(), array(), array(".lang"));
- foreach ($filenames as $filename) {
- // Look for files matching for example 'en.lang', 'cmn.lang' or 'pt_br.lang'.
- // Note that this regex is just for the system cache. The original language
- // files are allowed to have uppercase letters (e.g. pt_BR.php).
- if (preg_match('/(([a-z]{2,3})(_[a-z]{2})?)\.lang$/', $filename, $matches)) {
- $language = $matches[1];
- $data = elgg_load_system_cache("$language.lang");
- if ($data) {
- $this->addTranslation($language, unserialize($data));
- }
- }
- }
- } else {
- foreach ($this->CONFIG->language_paths as $path => $dummy) {
- $this->registerTranslations($path, true);
- }
- }
-
- $LANG_RELOAD_ALL_RUN = true;
- }
-
- /**
- * Return an array of installed translations as an associative
- * array "two letter code" => "native language name".
- *
- * @return array
- */
- function getInstalledTranslations() {
-
-
- // Ensure that all possible translations are loaded
- $this->reloadAllTranslations();
-
- $installed = array();
-
- $admin_logged_in = _elgg_services()->session->isAdminLoggedIn();
-
- foreach ($this->CONFIG->translations as $k => $v) {
- $installed[$k] = $this->translate($k, array(), $k);
- if ($admin_logged_in && ($k != 'en')) {
- $completeness = $this->getLanguageCompleteness($k);
- if ($completeness < 100) {
- $installed[$k] .= " (" . $completeness . "% " . $this->translate('complete') . ")";
- }
- }
- }
-
- return $installed;
- }
-
- /**
- * Return the level of completeness for a given language code (compared to english)
- *
- * @param string $language Language
- *
- * @return int
- */
- function getLanguageCompleteness($language) {
-
-
- // Ensure that all possible translations are loaded
- $this->reloadAllTranslations();
-
- $language = sanitise_string($language);
-
- $en = count($this->CONFIG->translations['en']);
-
- $missing = $this->getMissingLanguageKeys($language);
- if ($missing) {
- $missing = count($missing);
- } else {
- $missing = 0;
- }
-
- //$lang = count($this->CONFIG->translations[$language]);
- $lang = $en - $missing;
-
- return round(($lang / $en) * 100, 2);
- }
-
- /**
- * Return the translation keys missing from a given language,
- * or those that are identical to the english version.
- *
- * @param string $language The language
- *
- * @return mixed
- */
- function getMissingLanguageKeys($language) {
-
-
- // Ensure that all possible translations are loaded
- $this->reloadAllTranslations();
-
- $missing = array();
-
- foreach ($this->CONFIG->translations['en'] as $k => $v) {
- if ((!isset($this->CONFIG->translations[$language][$k]))
- || ($this->CONFIG->translations[$language][$k] == $this->CONFIG->translations['en'][$k])) {
- $missing[] = $k;
- }
- }
-
- if (count($missing)) {
- return $missing;
- }
-
- return false;
- }
-
- /**
- * Check if a give language key exists
- *
- * @param string $key The translation key
- * @param string $language The specific language to check
- *
- * @return bool
- * @since 1.11
- */
- function languageKeyExists($key, $language = 'en') {
- if (empty($key)) {
- return false;
- }
-
- if (($language !== 'en') && !array_key_exists($language, $this->CONFIG->translations)) {
- // Ensure that all possible translations are loaded
- $this->reloadAllTranslations();
- }
-
- if (!array_key_exists($language, $this->CONFIG->translations)) {
- return false;
- }
-
- return array_key_exists($key, $this->CONFIG->translations[$language]);
- }
-
- /**
- * Returns an array of language codes.
- *
- * @return array
- */
- public static function getAllLanguageCodes() {
- return [
- "aa", // "Afar"
- "ab", // "Abkhazian"
- "af", // "Afrikaans"
- "am", // "Amharic"
- "ar", // "Arabic"
- "as", // "Assamese"
- "ay", // "Aymara"
- "az", // "Azerbaijani"
- "ba", // "Bashkir"
- "be", // "Byelorussian"
- "bg", // "Bulgarian"
- "bh", // "Bihari"
- "bi", // "Bislama"
- "bn", // "Bengali; Bangla"
- "bo", // "Tibetan"
- "br", // "Breton"
- "ca", // "Catalan"
- "cmn", // "Mandarin Chinese" // ISO 639-3
- "co", // "Corsican"
- "cs", // "Czech"
- "cy", // "Welsh"
- "da", // "Danish"
- "de", // "German"
- "dz", // "Bhutani"
- "el", // "Greek"
- "en", // "English"
- "eo", // "Esperanto"
- "es", // "Spanish"
- "et", // "Estonian"
- "eu", // "Basque"
- "eu_es", // "Basque (Spain)"
- "fa", // "Persian"
- "fi", // "Finnish"
- "fj", // "Fiji"
- "fo", // "Faeroese"
- "fr", // "French"
- "fy", // "Frisian"
- "ga", // "Irish"
- "gd", // "Scots / Gaelic"
- "gl", // "Galician"
- "gn", // "Guarani"
- "gu", // "Gujarati"
- "he", // "Hebrew"
- "ha", // "Hausa"
- "hi", // "Hindi"
- "hr", // "Croatian"
- "hu", // "Hungarian"
- "hy", // "Armenian"
- "ia", // "Interlingua"
- "id", // "Indonesian"
- "ie", // "Interlingue"
- "ik", // "Inupiak"
- "is", // "Icelandic"
- "it", // "Italian"
- "iu", // "Inuktitut"
- "iw", // "Hebrew (obsolete)"
- "ja", // "Japanese"
- "ji", // "Yiddish (obsolete)"
- "jw", // "Javanese"
- "ka", // "Georgian"
- "kk", // "Kazakh"
- "kl", // "Greenlandic"
- "km", // "Cambodian"
- "kn", // "Kannada"
- "ko", // "Korean"
- "ks", // "Kashmiri"
- "ku", // "Kurdish"
- "ky", // "Kirghiz"
- "la", // "Latin"
- "ln", // "Lingala"
- "lo", // "Laothian"
- "lt", // "Lithuanian"
- "lv", // "Latvian/Lettish"
- "mg", // "Malagasy"
- "mi", // "Maori"
- "mk", // "Macedonian"
- "ml", // "Malayalam"
- "mn", // "Mongolian"
- "mo", // "Moldavian"
- "mr", // "Marathi"
- "ms", // "Malay"
- "mt", // "Maltese"
- "my", // "Burmese"
- "na", // "Nauru"
- "ne", // "Nepali"
- "nl", // "Dutch"
- "no", // "Norwegian"
- "oc", // "Occitan"
- "om", // "(Afan) Oromo"
- "or", // "Oriya"
- "pa", // "Punjabi"
- "pl", // "Polish"
- "ps", // "Pashto / Pushto"
- "pt", // "Portuguese"
- "pt_br", // "Portuguese (Brazil)"
- "qu", // "Quechua"
- "rm", // "Rhaeto-Romance"
- "rn", // "Kirundi"
- "ro", // "Romanian"
- "ro_ro", // "Romanian (Romania)"
- "ru", // "Russian"
- "rw", // "Kinyarwanda"
- "sa", // "Sanskrit"
- "sd", // "Sindhi"
- "sg", // "Sangro"
- "sh", // "Serbo-Croatian"
- "si", // "Singhalese"
- "sk", // "Slovak"
- "sl", // "Slovenian"
- "sm", // "Samoan"
- "sn", // "Shona"
- "so", // "Somali"
- "sq", // "Albanian"
- "sr", // "Serbian"
- "sr_latin", // "Serbian (Latin)"
- "ss", // "Siswati"
- "st", // "Sesotho"
- "su", // "Sundanese"
- "sv", // "Swedish"
- "sw", // "Swahili"
- "ta", // "Tamil"
- "te", // "Tegulu"
- "tg", // "Tajik"
- "th", // "Thai"
- "ti", // "Tigrinya"
- "tk", // "Turkmen"
- "tl", // "Tagalog"
- "tn", // "Setswana"
- "to", // "Tonga"
- "tr", // "Turkish"
- "ts", // "Tsonga"
- "tt", // "Tatar"
- "tw", // "Twi"
- "ug", // "Uigur"
- "uk", // "Ukrainian"
- "ur", // "Urdu"
- "uz", // "Uzbek"
- "vi", // "Vietnamese"
- "vo", // "Volapuk"
- "wo", // "Wolof"
- "xh", // "Xhosa"
- "yi", // "Yiddish"
- "yo", // "Yoruba"
- "za", // "Zuang"
- "zh", // "Chinese"
- "zh_hans", // "Chinese Simplified"
- "zu", // "Zulu"
- ];
- }
- /**
- * Normalize a language code (e.g. from Transifex)
- *
- * @param string $code Language code
- *
- * @return string
- */
- public static function normalizeLanguageCode($code) {
- $code = strtolower($code);
- $code = preg_replace('~[^a-z0-9]~', '_', $code);
- return $code;
- }
- }
|