summaryrefslogblamecommitdiffstats
path: root/inc/dictionary.inc.php
blob: 3a2f9c2b848a06237909343d6f9d33582a37b609 (plain) (tree)
1
2
3
4
5
6
7
8
9
10

     

                        


                


                                                                                   
                                       
           
                                                                                      
           

                                             
 
                                           
         
                                                                  

                                                                                                   








                                                                           

                                                                           
                                                   
                                                                                
                                                                






                                                                                           




















                                                                                              

         
           
























                                                                                                 



                                                                        
                                                                       

                                                                                    
                                                                                                  
         
                                   
                                     
                                                                                      

                                                                 


                                                         
                                  
                                                    

                                                                             
                 
                                                    
                                       
                                   
                 
                                                         

         









                                                                                                                            
                                                                                                                                
         
                                                            
                                             


                                                          
                                     
                 

                                      








                                                                                                                            
                                                                                                        
         

                                                                                                                                    
                                                                                                                       

         






                                                                                                                            
                                                                                      
         
                                                                     

                                       



                                                                                 

         




                                                                                          
           
                                                                             
         
                                                                              
                                        
                                                                    


                               



                                                 
                                                                          

                                                                                          
                                                                        
         




                                                                                            
                 
                                                            
                                                 

                               

         
           

                                                
                                                                                                      

                                                                     
           
                                                                           
         

                                                

                                                    

                                                                         
                                                                                         

                                                      

                                                                       

                                                      
                                                          
                                                      

                                                        


                                            
         



                                                           
           
                                                                      








                                                                           
 






                                                                                 
                                                                                                 
                                                           
           
                                                                                                
         
                                       














                                                                                                      


                   
 
<?php

declare(strict_types=1);

class Dictionary
{

	/**
	 * @var string[] Array of languages, numeric index, two letter CC as values
	 */
	private static $languages = [];
	/**
	 * @var array{'name': string, 'cc': string}|null Long name of language, and CC
	 */
	private static $languagesLong = null;
	private static $stringCache = [];

	public static function init(): void
	{
		foreach (glob('lang/??', GLOB_ONLYDIR) as $lang) {
			if (!file_exists($lang . '/name.txt') && !file_exists($lang . '/flag.png'))
				continue;
			$lang = basename($lang);
			if ($lang === '..')
				continue;
			self::$languages[] = $lang;
		}

		//Changes the language in case there is a request to
		$lang = Request::get('lang');
		if ($lang !== false && in_array($lang, self::$languages)) {
			Util::clearCookie('lang');
			setcookie('lang', $lang, time() + 86400 * 30 * 12);
			$url = Request::get('url');
			if ($url === false && isset($_SERVER['HTTP_REFERER'])) {
				$url = $_SERVER['HTTP_REFERER'];
			}
			$parts = parse_url($url);
			if ($url === false || $parts === false || empty($parts['query'])) {
				$url = '?do=main';
			} else {
				$url = '?' . $parts['query'];
			}
			Util::redirect($url);
		}

		//Default language
		$language = 'en';

		if (isset($_COOKIE['lang']) && in_array($_COOKIE['lang'], self::$languages)) {
			// Did user override language?
			$language = $_COOKIE['lang'];
		} else if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
			$langs = preg_split('/[,\s]+/', $_SERVER['HTTP_ACCEPT_LANGUAGE']);
			foreach ($langs as $lang) {
				$lang = substr($lang, 0, 2);
				if (in_array($lang, self::$languages)) {
					$language = $lang;
					break;
				}
			}
		}

		define('LANG', $language);
	}

	/**
	 * Format given number using country-specific decimal point and thousands
	 * separator.
	 * @param float $num Number to format
	 * @param int $decimals How many decimals to display
	 */
	public static function number(float $num, int $decimals = 0): string
	{
		static $dec = null, $tho = null;
		if ($dec === null) {
			if (LANG === 'de') {
				$dec = ',';
				$tho = '.';
			} elseif (LANG !== 'en' && file_exists("lang/" . LANG . "/format.txt")) {
				$tmp = file_get_contents("lang/" . LANG . "/format.txt");
				$dec = $tmp[0];
				$tho = $tmp[1];
			} else {
				$dec = '.';
				$tho = ',';
			}
		}
		return number_format($num, $decimals, $dec, $tho);
	}

	/**
	 * Get complete key=>value list for given module, file, language
	 *
	 * @param string $module Module name
	 * @param string $file Dictionary name
	 * @param ?string $lang Language CC, false === current language
	 * @return array assoc array mapping language tags to the translated strings
	 */
	public static function getArray(string $module, string $file, ?string $lang = null): array
	{
		if ($lang === null)
			$lang = LANG;
		$path = Util::safePath("modules/{$module}/lang/{$lang}/{$file}.json");
		if ($path === null)
			ErrorHandler::traceError("Invalid path");
		if (isset(self::$stringCache[$path]))
			return self::$stringCache[$path];
		if (!file_exists($path))
			return [];
		$content = file_get_contents($path);
		if ($content === false) { // File does not exist for language
			$content = '[]';
		}
		$json = json_decode($content, true);
		if (!is_array($json)) {
			$json = [];
		}
		return self::$stringCache[$path] = $json;
	}

	/**
	 * Translate a tag from a dictionary of a module. The current
	 * language will be used.
	 *
	 * @param string $moduleId The module in question
	 * @param string $file Dictionary name
	 * @param string $tag Tag name
	 * @param bool $returnTagOnMissing If true, the tag name enclosed in {{}} will be returned if the tag does not exist
	 * @return string|false The requested tag's translation, or false if not found and $returnTagOnMissing === false
	 */
	public static function translateFileModule(string $moduleId, string $file, string $tag, bool $returnTagOnMissing = true)
	{
		$strings = self::getArray($moduleId, $file);
		if (!isset($strings[$tag])) {
			if ($returnTagOnMissing) {
				return '{{' . $tag . '}}';
			}
			return false;
		}
		return $strings[$tag];
	}

	/**
	 * Translate a tag from a dictionary of the current module, using the current language.
	 *
	 * @param string $file Dictionary name
	 * @param string $tag Tag name
	 * @param bool $returnTagOnMissing If true, the tag name enclosed in {{}} will be returned if the tag does not exist
	 * @return string|false The requested tag's translation, or false if not found and $returnTagOnMissing === false
	 */
	public static function translateFile(string $file, string $tag, bool $returnTagOnMissing = true)
	{
		if (!class_exists('Page') || Page::getModule() === false)
			return false; // We have no page - return false for now, as we're most likely running in api or install mode
		return self::translateFileModule(Page::getModule()->getIdentifier(), $file, $tag, $returnTagOnMissing);
	}

	/**
	 * Translate a tag from the current module's default dictionary, using the current language.
	 *
	 * @param string $tag Tag name
	 * @param bool $returnTagOnMissing If true, the tag name enclosed in {{}} will be returned if the tag does not exist
	 * @return string|false The requested tag's translation, or false if not found and $returnTagOnMissing === false
	 */
	public static function translate(string $tag, bool $returnTagOnMissing = true)
	{
		$string = self::translateFile('module', $tag, false);
		if ($string !== false)
			return $string;
		$string = self::translateFileModule('main', 'global-tags', $tag);
		if ($string !== false || !$returnTagOnMissing)
			return $string;
		return '{{' . $tag . '}}';
	}

	/**
	 * Translate the given message id, reading the given module's messages dictionary.
	 *
	 * @param string $module Module the message belongs to
	 * @param string $id Message id
	 */
	public static function getMessage(string $module, string $id): string
	{
		$string = self::translateFileModule($module, 'messages', $id);
		if ($string === false) {
			return "($id) ({{0}}, {{1}}, {{2}}, {{3}})";
		}
		return $string;
	}

	/**
	 * Get translation of the given category.
	 *
	 * @param string $category Menu category to get localized name for
	 * @return string Category name, or some generic fallback to the given category id
	 */
	public static function getCategoryName(string $category): string
	{
		if (!empty($category)) {
			if (!preg_match('/^(\w+)\.(.*)$/', $category, $out)) {
				return 'Invalid Category ID format: ' . $category;
			}
			$string = self::translateFileModule($out[1], 'categories', $out[2]);
		}
		if (empty($category) || $string === false) {
			return "!!{$category}!!";
		}
		return $string;
	}

	/**
	 * Get all supported languages as array.
	 *
	 * @param boolean $withName true = return assoc array containing cc and name of all languages;
	 *		false = regular array containing only the ccs
	 * @return array List of languages
	 */
	public static function getLanguages(bool $withName = false): ?array
	{
		if (!$withName)
			return self::$languages;
		if (self::$languagesLong === null) {
			self::$languagesLong = [];
			foreach (self::$languages as $lang) {
				if (file_exists("lang/$lang/name.txt")) {
					$name = file_get_contents("lang/$lang/name.txt");
				} else {
					$name = false;
				}
				if (!isset($name) || $name === false) {
					$name = $lang;
				}
				self::$languagesLong[] = [
					'cc' => $lang,
					'name' => $name,
				];
			}
		}
		return self::$languagesLong;
	}

	/**
	 * Get name of language matching given language CC.
	 * Default to the CC if the language isn't known.
	 */
	public static function getLanguageName(string $langCC): string
	{
		if (file_exists("lang/$langCC/name.txt")) {
			$name = file_get_contents("lang/$langCC/name.txt");
		}
		if (!isset($name) || $name === false) {
			$name = $langCC;
		}
		return $name;
	}

	/**
	 * Get an <img> tag for the given language. If there is no flag image,
	 * fall back to generating a .badge with the CC.
	 * If long mode is requested, returns the name of the language right next
	 * to the image, otherwise, it is just added as the title attribute.
	 *
	 * @param $caption bool with caption next to <img>
	 * @param $langCC ?string Language cc to get flag code for - defaults to current language
	 * @return string html code of img tag for language
	 */
	public static function getFlagHtml(bool $caption = false, string $langCC = null): string
	{
		if ($langCC === null) {
			$langCC = LANG;
		}
		$flag = "lang/$langCC/flag.png";
		$name = htmlspecialchars(self::getLanguageName($langCC));
		if (file_exists($flag)) {
			$img = '<img alt="' . $name . '" title="' . $name . '" src="' . $flag . '"> ';
			if ($caption) {
				$img .= $name;
			}
		} else {
			$img = '<div class="badge" title="' . $name . '">' . $langCC . '</div>';
		}
		return $img;
	}

}

Dictionary::init();