diff options
author | Christoph Wurst <christoph@winzerhof-wurst.at> | 2021-10-01 09:56:01 +0200 |
---|---|---|
committer | Christoph Wurst <christoph@winzerhof-wurst.at> | 2021-10-13 09:57:21 +0200 |
commit | 5b727fc7da346ce0b33905ac54114102ffa16f13 (patch) | |
tree | 17b4f223f67f734e66902344a391e1c9f74eb613 /lib | |
parent | 5b7764354c71f79b83394796cb947fef92dfd830 (diff) | |
download | nextcloud-server-5b727fc7da346ce0b33905ac54114102ffa16f13.tar.gz nextcloud-server-5b727fc7da346ce0b33905ac54114102ffa16f13.zip |
Add L10n factory method for generic language heuristics
The existing `findLanguage` method tries its best to find the best
language for the current users. For some tasks we don't want this but
rather determine the most generic language for *another* user, e.g. when
the current user trigger an email notifiaction to someone else. In this
case the current user's language is a bad guess in many multi-language
environments.
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/private/L10N/Factory.php | 80 | ||||
-rw-r--r-- | lib/public/L10N/IFactory.php | 35 |
2 files changed, 89 insertions, 26 deletions
diff --git a/lib/private/L10N/Factory.php b/lib/private/L10N/Factory.php index caa26d81cc4..8aa09ab87bc 100644 --- a/lib/private/L10N/Factory.php +++ b/lib/private/L10N/Factory.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl> @@ -42,6 +45,7 @@ use OCP\IUser; use OCP\IUserSession; use OCP\L10N\IFactory; use OCP\L10N\ILanguageIterator; +use function is_null; /** * A factory that generates language instances @@ -157,21 +161,24 @@ class Factory implements IFactory { /** * Find the best language * - * @param string|null $app App id or null for core + * @param string|null $appId App id or null for core + * * @return string language If nothing works it returns 'en' */ - public function findLanguage($app = null) { + public function findLanguage(?string $appId = null): string { + // Step 1: Forced language always has precedence over anything else $forceLang = $this->config->getSystemValue('force_language', false); if (is_string($forceLang)) { $this->requestLanguage = $forceLang; } - if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) { + // Step 2: Return cached language + if ($this->requestLanguage !== '' && $this->languageExists($appId, $this->requestLanguage)) { return $this->requestLanguage; } /** - * At this point Nextcloud might not yet be installed and thus the lookup + * Step 3: At this point Nextcloud might not yet be installed and thus the lookup * in the preferences table might fail. For this reason we need to check * whether the instance has already been installed * @@ -188,30 +195,67 @@ class Factory implements IFactory { $userId = null; $userLang = null; } - if ($userLang) { $this->requestLanguage = $userLang; - if ($this->languageExists($app, $userLang)) { + if ($this->languageExists($appId, $userLang)) { return $userLang; } } + // Step 4: Check the request headers try { // Try to get the language from the Request - $lang = $this->getLanguageFromRequest($app); - if ($userId !== null && $app === null && !$userLang) { + $lang = $this->getLanguageFromRequest($appId); + if ($userId !== null && $appId === null && !$userLang) { $this->config->setUserValue($userId, 'core', 'lang', $lang); } return $lang; } catch (LanguageNotFoundException $e) { // Finding language from request failed fall back to default language $defaultLanguage = $this->config->getSystemValue('default_language', false); - if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) { + if ($defaultLanguage !== false && $this->languageExists($appId, $defaultLanguage)) { return $defaultLanguage; } } - // We could not find any language so fall back to english + // Step 5: fall back to English + return 'en'; + } + + public function findGenericLanguage(string $appId = null): string { + // Step 1: Forced language always has precedence over anything else + $forcedLanguage = $this->config->getSystemValue('force_language', false); + if ($forcedLanguage !== false) { + return $forcedLanguage; + } + + // Step 2: Check if we have a default language + $defaultLanguage = $this->config->getSystemValue('default_language', false); + if ($defaultLanguage !== false && $this->languageExists($appId, $defaultLanguage)) { + return $defaultLanguage; + } + + // Step 3.1: Check if Nextcloud is already installed before we try to access user info + if (!$this->config->getSystemValue('installed', false)) { + return 'en'; + } + // Step 3.2: Check the current user (if any) for their preferred language + $user = $this->userSession->getUser(); + if ($user !== null) { + $userLang = $this->config->getUserValue($user->getUID(), 'core', 'lang', null); + if ($userLang !== null) { + return $userLang; + } + } + + // Step 4: Check the request headers + try { + return $this->getLanguageFromRequest($appId); + } catch (LanguageNotFoundException $e) { + // Ignore and continue + } + + // Step 5: fall back to English return 'en'; } @@ -280,9 +324,9 @@ class Factory implements IFactory { * Find all available languages for an app * * @param string|null $app App id or null for core - * @return array an array of available languages + * @return string[] an array of available languages */ - public function findAvailableLanguages($app = null) { + public function findAvailableLanguages($app = null): array { $key = $app; if ($key === null) { $key = 'null'; @@ -352,7 +396,7 @@ class Factory implements IFactory { } $languages = $this->findAvailableLanguages($app); - return array_search($lang, $languages) !== false; + return in_array($lang, $languages); } public function getLanguageIterator(IUser $user = null): ILanguageIterator { @@ -406,11 +450,9 @@ class Factory implements IFactory { } /** - * @param string|null $app - * @return string * @throws LanguageNotFoundException */ - private function getLanguageFromRequest($app) { + private function getLanguageFromRequest(?string $app = null): string { $header = $this->request->getHeader('ACCEPT_LANGUAGE'); if ($header !== '') { $available = $this->findAvailableLanguages($app); @@ -444,12 +486,8 @@ class Factory implements IFactory { /** * if default language is set to de_DE (formal German) this should be * preferred to 'de' (non-formal German) if possible - * - * @param string|null $app - * @param string $lang - * @return string */ - protected function respectDefaultLanguage($app, $lang) { + protected function respectDefaultLanguage(?string $app, string $lang): string { $result = $lang; $defaultLanguage = $this->config->getSystemValue('default_language', false); diff --git a/lib/public/L10N/IFactory.php b/lib/public/L10N/IFactory.php index 3fe212edb9c..69b7d2281ce 100644 --- a/lib/public/L10N/IFactory.php +++ b/lib/public/L10N/IFactory.php @@ -1,4 +1,7 @@ <?php + +declare(strict_types=1); + /** * @copyright Copyright (c) 2016, ownCloud, Inc. * @@ -46,13 +49,35 @@ interface IFactory { public function get($app, $lang = null, $locale = null); /** - * Find the best language + * Find the best language for the context of the current user * - * @param string|null $app App id or null for core - * @return string language If nothing works it returns 'en' + * This method will try to find the most specific language based on info + * from the user who is logged into the current process and will fall + * back to system settings and heuristics otherwise. + * + * @param string|null $appId specify if you only want a language a specific app supports + * + * @return string language code, defaults to 'en' if no other matches are found * @since 9.0.0 */ - public function findLanguage($app = null); + public function findLanguage(?string $appId = null): string; + + /** + * Try to find the best language for generic tasks + * + * This method will try to find the most generic language based on system + * settings, independent of the user logged into the current process. This + * is useful for tasks that are run for another user. E.g. the current user + * sends an email to someone else, then we don't want the current user's + * language to be picked but rather a instance-wide default that likely fits + * the target user + * + * @param string|null $appId specify if you only want a language a specific app supports + * + * @return string language code, defaults to 'en' if no other matches are found + * @since 23.0.0 + */ + public function findGenericLanguage(string $appId = null): string; /** * @param string|null $lang user language as default locale @@ -78,7 +103,7 @@ interface IFactory { * @return string[] an array of available languages * @since 9.0.0 */ - public function findAvailableLanguages($app = null); + public function findAvailableLanguages($app = null): array; /** * @return array an array of available |