*/ class L10n { /** * @var string */ private $lang; /** * @var array */ private $strings; /** * @var string */ private $lang_path; public function __construct(string $language = 'en', string $lang_path = '') { $this->lang = $language; $this->lang_path = $lang_path; $this->loadTranslationTable(); } /** * Loads string translation table * * First addon strings are loaded, then globals * * Uses an App object shim since all the strings files refer to $a->strings * * @param string $lang language code to load */ private function loadTranslationTable(): void { if (file_exists($this->lang_path . '/' . $this->lang . '/strings.php')) { $this->strings = include $this->lang_path . '/' . $this->lang . '/strings.php'; } } /** * @brief Return the localized version of a singular/plural string with optional string interpolation * * This function takes two english strings as parameters, singular and plural, as * well as a count. If a localized version exists for the current language, they * are used instead. Discrimination between singular and plural is done using the * localized function if any or the default one. Finally, a string interpolation * is performed using the count as parameter. * * Usages: * - L10n::tt('Like', 'Likes', $count) * - L10n::tt("%s user deleted", "%s users deleted", count($users)) * * @param string $singular * @param string $plural * @param int $count * @return string */ public function tt(string $singular, string $plural, int $count): string { if (!empty($this->strings[$singular])) { $t = $this->strings[$singular]; if (is_array($t)) { $plural_function = 'string_plural_select_' . str_replace('-', '_', $this->lang); if (function_exists($plural_function)) { $i = $plural_function($count); } else { $i = $this->stringPluralSelectDefault($count); } // for some languages there is only a single array item if (!isset($t[$i])) { $s = $t[0]; } else { $s = $t[$i]; } } else { $s = $t; } } elseif ($this->stringPluralSelectDefault($count)) { $s = $plural; } else { $s = $singular; } $s = @sprintf($s, $count); return $s; } /** * @brief Return the localized version of the provided string with optional string interpolation * * This function takes a english string as parameter, and if a localized version * exists for the current language, substitutes it before performing an eventual * string interpolation (sprintf) with additional optional arguments. * * Usages: * - L10n::t('This is an example') * - L10n::t('URL %s returned no result', $url) * - L10n::t('Current version: %s, new version: %s', $current_version, $new_version) * * @param string $s * @param array $vars Variables to interpolate in the translation string * @return string */ public function t($s, ...$vars): string { if (empty($s)) { return ''; } if (!empty($this->strings[$s])) { $t = $this->strings[$s]; $s = is_array($t) ? $t[0] : $t; } if (count($vars) > 0) { $s = sprintf($s, ...$vars); } return $s; } /** * Provide a fallback which will not collide with a function defined in any language file */ private function stringPluralSelectDefault(int $n): bool { return $n != 1; } }