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 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 * @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 = ' '; if ($caption) { $img .= $name; } } else { $img = '