Completed
Push — master ( 12977a...b026b5 )
by Joas
24:55 queued 10:34
created
lib/public/L10N/IFactory.php 1 patch
Indentation   +81 added lines, -81 removed lines patch added patch discarded remove patch
@@ -27,94 +27,94 @@
 block discarded – undo
27 27
  * @since 8.2.0
28 28
  */
29 29
 interface IFactory {
30
-	/**
31
-	 * Get a language instance
32
-	 *
33
-	 * @param string $app
34
-	 * @param string|null $lang
35
-	 * @return \OCP\IL10N
36
-	 * @since 8.2.0
37
-	 */
38
-	public function get($app, $lang = null);
30
+    /**
31
+     * Get a language instance
32
+     *
33
+     * @param string $app
34
+     * @param string|null $lang
35
+     * @return \OCP\IL10N
36
+     * @since 8.2.0
37
+     */
38
+    public function get($app, $lang = null);
39 39
 
40
-	/**
41
-	 * Find the best language
42
-	 *
43
-	 * @param string|null $app App id or null for core
44
-	 * @return string language If nothing works it returns 'en'
45
-	 * @since 9.0.0
46
-	 */
47
-	public function findLanguage($app = null);
40
+    /**
41
+     * Find the best language
42
+     *
43
+     * @param string|null $app App id or null for core
44
+     * @return string language If nothing works it returns 'en'
45
+     * @since 9.0.0
46
+     */
47
+    public function findLanguage($app = null);
48 48
 
49
-	/**
50
-	 * @param string|null $lang user language as default locale
51
-	 * @return string locale If nothing works it returns 'en_US'
52
-	 * @since 14.0.0
53
-	 */
54
-	public function findLocale($lang = null);
49
+    /**
50
+     * @param string|null $lang user language as default locale
51
+     * @return string locale If nothing works it returns 'en_US'
52
+     * @since 14.0.0
53
+     */
54
+    public function findLocale($lang = null);
55 55
 
56
-	/**
57
-	 * find the matching lang from the locale
58
-	 *
59
-	 * @param string $app
60
-	 * @param string $locale
61
-	 * @return null|string
62
-	 * @since 14.0.1
63
-	 */
64
-	public function findLanguageFromLocale(string $app = 'core', string $locale = null);
56
+    /**
57
+     * find the matching lang from the locale
58
+     *
59
+     * @param string $app
60
+     * @param string $locale
61
+     * @return null|string
62
+     * @since 14.0.1
63
+     */
64
+    public function findLanguageFromLocale(string $app = 'core', string $locale = null);
65 65
 
66
-	/**
67
-	 * Find all available languages for an app
68
-	 *
69
-	 * @param string|null $app App id or null for core
70
-	 * @return string[] an array of available languages
71
-	 * @since 9.0.0
72
-	 */
73
-	public function findAvailableLanguages($app = null);
66
+    /**
67
+     * Find all available languages for an app
68
+     *
69
+     * @param string|null $app App id or null for core
70
+     * @return string[] an array of available languages
71
+     * @since 9.0.0
72
+     */
73
+    public function findAvailableLanguages($app = null);
74 74
 
75
-	/**
76
-	 * @return array an array of available
77
-	 * @since 14.0.0
78
-	 */
79
-	public function findAvailableLocales();
75
+    /**
76
+     * @return array an array of available
77
+     * @since 14.0.0
78
+     */
79
+    public function findAvailableLocales();
80 80
 
81
-	/**
82
-	 * @param string|null $app App id or null for core
83
-	 * @param string $lang
84
-	 * @return bool
85
-	 * @since 9.0.0
86
-	 */
87
-	public function languageExists($app, $lang);
81
+    /**
82
+     * @param string|null $app App id or null for core
83
+     * @param string $lang
84
+     * @return bool
85
+     * @since 9.0.0
86
+     */
87
+    public function languageExists($app, $lang);
88 88
 
89
-	/**
90
-	 * @param string $locale
91
-	 * @return bool
92
-	 * @since 14.0.0
93
-	 */
94
-	public function localeExists($locale);
89
+    /**
90
+     * @param string $locale
91
+     * @return bool
92
+     * @since 14.0.0
93
+     */
94
+    public function localeExists($locale);
95 95
 
96
-	/**
97
-	 * Creates a function from the plural string
98
-	 *
99
-	 * @param string $string
100
-	 * @return string Unique function name
101
-	 * @since 14.0.0
102
-	 */
103
-	public function createPluralFunction($string);
96
+    /**
97
+     * Creates a function from the plural string
98
+     *
99
+     * @param string $string
100
+     * @return string Unique function name
101
+     * @since 14.0.0
102
+     */
103
+    public function createPluralFunction($string);
104 104
 
105
-	/**
106
-	 * iterate through language settings (if provided) in this order:
107
-	 * 1. returns the forced language or:
108
-	 * 2. if applicable, the trunk of 1 (e.g. "fu" instead of "fu_BAR"
109
-	 * 3. returns the user language or:
110
-	 * 4. if applicable, the trunk of 3
111
-	 * 5. returns the system default language or:
112
-	 * 6. if applicable, the trunk of 5
113
-	 * 7+∞. returns 'en'
114
-	 *
115
-	 * Hint: in most cases findLanguage() suits you fine
116
-	 *
117
-	 * @since 14.0.0
118
-	 */
119
-	public function getLanguageIterator(IUser $user = null): ILanguageIterator;
105
+    /**
106
+     * iterate through language settings (if provided) in this order:
107
+     * 1. returns the forced language or:
108
+     * 2. if applicable, the trunk of 1 (e.g. "fu" instead of "fu_BAR"
109
+     * 3. returns the user language or:
110
+     * 4. if applicable, the trunk of 3
111
+     * 5. returns the system default language or:
112
+     * 6. if applicable, the trunk of 5
113
+     * 7+∞. returns 'en'
114
+     *
115
+     * Hint: in most cases findLanguage() suits you fine
116
+     *
117
+     * @since 14.0.0
118
+     */
119
+    public function getLanguageIterator(IUser $user = null): ILanguageIterator;
120 120
 }
Please login to merge, or discard this patch.
lib/private/TemplateLayout.php 1 patch
Indentation   +290 added lines, -290 removed lines patch added patch discarded remove patch
@@ -46,294 +46,294 @@
 block discarded – undo
46 46
 
47 47
 class TemplateLayout extends \OC_Template {
48 48
 
49
-	private static $versionHash = '';
50
-
51
-	/**
52
-	 * @var \OCP\IConfig
53
-	 */
54
-	private $config;
55
-
56
-	/**
57
-	 * @param string $renderAs
58
-	 * @param string $appId application id
59
-	 */
60
-	public function __construct( $renderAs, $appId = '' ) {
61
-
62
-		// yes - should be injected ....
63
-		$this->config = \OC::$server->getConfig();
64
-
65
-		if(\OCP\Util::isIE()) {
66
-			\OC_Util::addStyle('ie');
67
-		}
68
-
69
-		// Decide which page we show
70
-		if($renderAs == 'user') {
71
-			parent::__construct( 'core', 'layout.user' );
72
-			if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
73
-				$this->assign('bodyid', 'body-settings');
74
-			}else{
75
-				$this->assign('bodyid', 'body-user');
76
-			}
77
-
78
-			// Code integrity notification
79
-			$integrityChecker = \OC::$server->getIntegrityCodeChecker();
80
-			if(\OC_User::isAdminUser(\OC_User::getUser()) && $integrityChecker->isCodeCheckEnforced() && !$integrityChecker->hasPassedCheck()) {
81
-				\OCP\Util::addScript('core', 'integritycheck-failed-notification');
82
-			}
83
-
84
-			// Add navigation entry
85
-			$this->assign( 'application', '');
86
-			$this->assign( 'appid', $appId );
87
-			$navigation = \OC::$server->getNavigationManager()->getAll();
88
-			$this->assign( 'navigation', $navigation);
89
-			$settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
90
-			$this->assign( 'settingsnavigation', $settingsNavigation);
91
-			foreach($navigation as $entry) {
92
-				if ($entry['active']) {
93
-					$this->assign( 'application', $entry['name'] );
94
-					break;
95
-				}
96
-			}
97
-
98
-			foreach($settingsNavigation as $entry) {
99
-				if ($entry['active']) {
100
-					$this->assign( 'application', $entry['name'] );
101
-					break;
102
-				}
103
-			}
104
-			$userDisplayName = \OC_User::getDisplayName();
105
-			$this->assign('user_displayname', $userDisplayName);
106
-			$this->assign('user_uid', \OC_User::getUser());
107
-
108
-			if (\OC_User::getUser() === false) {
109
-				$this->assign('userAvatarSet', false);
110
-			} else {
111
-				$this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
112
-				$this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
113
-			}
114
-
115
-			// check if app menu icons should be inverted
116
-			try {
117
-				/** @var \OCA\Theming\Util $util */
118
-				$util = \OC::$server->query(\OCA\Theming\Util::class);
119
-				$this->assign('themingInvertMenu', $util->invertTextColor(\OC::$server->getThemingDefaults()->getColorPrimary()));
120
-			} catch (\OCP\AppFramework\QueryException $e) {
121
-				$this->assign('themingInvertMenu', false);
122
-			}
123
-
124
-		} else if ($renderAs == 'error') {
125
-			parent::__construct('core', 'layout.guest', '', false);
126
-			$this->assign('bodyid', 'body-login');
127
-		} else if ($renderAs == 'guest') {
128
-			parent::__construct('core', 'layout.guest');
129
-			\OC_Util::addStyle('guest');
130
-			$this->assign('bodyid', 'body-login');
131
-		} else if ($renderAs == 'public') {
132
-			parent::__construct('core', 'layout.public');
133
-			$this->assign( 'appid', $appId );
134
-			$this->assign('bodyid', 'body-public');
135
-			$this->assign('showSimpleSignUpLink', $this->config->getSystemValue('simpleSignUpLink.shown', true) !== false);
136
-		} else {
137
-			parent::__construct('core', 'layout.base');
138
-
139
-		}
140
-		// Send the language and the locale to our layouts
141
-		$lang = \OC::$server->getL10NFactory()->findLanguage();
142
-		$locale = \OC::$server->getL10NFactory()->findLocale($lang);
143
-		$localeLang = \OC::$server->getL10NFactory()->findLanguageFromLocale('lib', $locale);
144
-
145
-		$lang = str_replace('_', '-', $lang);
146
-		$this->assign('language', $lang);
147
-		$this->assign('locale', $locale);
148
-
149
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
150
-			if (empty(self::$versionHash)) {
151
-				$v = \OC_App::getAppVersions();
152
-				$v['core'] = implode('.', \OCP\Util::getVersion());
153
-				self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
154
-			}
155
-		} else {
156
-			self::$versionHash = md5('not installed');
157
-		}
158
-
159
-		// Add the js files
160
-		$jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
161
-		$this->assign('jsfiles', array());
162
-		if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
163
-			if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
164
-				$jsConfigHelper = new JSConfigHelper(
165
-					\OC::$server->getL10N('lib', $localeLang ?: $lang),
166
-					\OC::$server->query(Defaults::class),
167
-					\OC::$server->getAppManager(),
168
-					\OC::$server->getSession(),
169
-					\OC::$server->getUserSession()->getUser(),
170
-					$this->config,
171
-					\OC::$server->getGroupManager(),
172
-					\OC::$server->getIniWrapper(),
173
-					\OC::$server->getURLGenerator(),
174
-					\OC::$server->getCapabilitiesManager()
175
-				);
176
-				$this->assign('inline_ocjs', $jsConfigHelper->getConfig());
177
-			} else {
178
-				$this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
179
-			}
180
-		}
181
-		foreach($jsFiles as $info) {
182
-			$web = $info[1];
183
-			$file = $info[2];
184
-			$this->append( 'jsfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
185
-		}
186
-
187
-		try {
188
-			$pathInfo = \OC::$server->getRequest()->getPathInfo();
189
-		} catch (\Exception $e) {
190
-			$pathInfo = '';
191
-		}
192
-
193
-		// Do not initialise scss appdata until we have a fully installed instance
194
-		// Do not load scss for update, errors, installation or login page
195
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)
196
-			&& !\OCP\Util::needUpgrade()
197
-			&& $pathInfo !== ''
198
-			&& !preg_match('/^\/login/', $pathInfo)
199
-			&& $renderAs !== 'error'
200
-		) {
201
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
202
-		} else {
203
-			// If we ignore the scss compiler,
204
-			// we need to load the guest css fallback
205
-			\OC_Util::addStyle('guest');
206
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles, false);
207
-		}
208
-
209
-		$this->assign('cssfiles', array());
210
-		$this->assign('printcssfiles', []);
211
-		$this->assign('versionHash', self::$versionHash);
212
-		foreach($cssFiles as $info) {
213
-			$web = $info[1];
214
-			$file = $info[2];
215
-
216
-			if (substr($file, -strlen('print.css')) === 'print.css') {
217
-				$this->append( 'printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
218
-			} else {
219
-				$this->append( 'cssfiles', $web.'/'.$file . $this->getVersionHashSuffix($web, $file)  );
220
-			}
221
-		}
222
-	}
223
-
224
-	/**
225
-	 * @param string $path
226
- 	 * @param string $file
227
-	 * @return string
228
-	 */
229
-	protected function getVersionHashSuffix($path = false, $file = false) {
230
-		if ($this->config->getSystemValue('debug', false)) {
231
-			// allows chrome workspace mapping in debug mode
232
-			return "";
233
-		}
234
-		$themingSuffix = '';
235
-		$v = [];
236
-
237
-		if ($this->config->getSystemValue('installed', false)) {
238
-			if (\OC::$server->getAppManager()->isInstalled('theming')) {
239
-				$themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
240
-			}
241
-			$v = \OC_App::getAppVersions();
242
-		}
243
-
244
-		// Try the webroot path for a match
245
-		if ($path !== false && $path !== '') {
246
-			$appName = $this->getAppNamefromPath($path);
247
-			if(array_key_exists($appName, $v)) {
248
-				$appVersion = $v[$appName];
249
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
250
-			}
251
-		}
252
-		// fallback to the file path instead
253
-		if ($file !== false && $file !== '') {
254
-			$appName = $this->getAppNamefromPath($file);
255
-			if(array_key_exists($appName, $v)) {
256
-				$appVersion = $v[$appName];
257
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
258
-			}
259
-		}
260
-
261
-		return '?v=' . self::$versionHash . $themingSuffix;
262
-	}
263
-
264
-	/**
265
-	 * @param array $styles
266
-	 * @return array
267
-	 */
268
-	static public function findStylesheetFiles($styles, $compileScss = true) {
269
-		// Read the selected theme from the config file
270
-		$theme = \OC_Util::getTheme();
271
-
272
-		if($compileScss) {
273
-			$SCSSCacher = \OC::$server->query(SCSSCacher::class);
274
-		} else {
275
-			$SCSSCacher = null;
276
-		}
277
-
278
-		$locator = new \OC\Template\CSSResourceLocator(
279
-			\OC::$server->getLogger(),
280
-			$theme,
281
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
282
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
283
-			$SCSSCacher
284
-		);
285
-		$locator->find($styles);
286
-		return $locator->getResources();
287
-	}
288
-
289
-	/**
290
-	 * @param string $path
291
-	 * @return string|boolean
292
-	 */
293
-	public function getAppNamefromPath($path) {
294
-		if ($path !== '' && is_string($path)) {
295
-			$pathParts = explode('/', $path);
296
-			if ($pathParts[0] === 'css') {
297
-				// This is a scss request
298
-				return $pathParts[1];
299
-			}
300
-			return end($pathParts);
301
-		}
302
-		return false;
303
-
304
-	}
305
-
306
-	/**
307
-	 * @param array $scripts
308
-	 * @return array
309
-	 */
310
-	static public function findJavascriptFiles($scripts) {
311
-		// Read the selected theme from the config file
312
-		$theme = \OC_Util::getTheme();
313
-
314
-		$locator = new \OC\Template\JSResourceLocator(
315
-			\OC::$server->getLogger(),
316
-			$theme,
317
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
318
-			array( \OC::$SERVERROOT => \OC::$WEBROOT ),
319
-			\OC::$server->query(JSCombiner::class)
320
-			);
321
-		$locator->find($scripts);
322
-		return $locator->getResources();
323
-	}
324
-
325
-	/**
326
-	 * Converts the absolute file path to a relative path from \OC::$SERVERROOT
327
-	 * @param string $filePath Absolute path
328
-	 * @return string Relative path
329
-	 * @throws \Exception If $filePath is not under \OC::$SERVERROOT
330
-	 */
331
-	public static function convertToRelativePath($filePath) {
332
-		$relativePath = explode(\OC::$SERVERROOT, $filePath);
333
-		if(count($relativePath) !== 2) {
334
-			throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
335
-		}
336
-
337
-		return $relativePath[1];
338
-	}
49
+    private static $versionHash = '';
50
+
51
+    /**
52
+     * @var \OCP\IConfig
53
+     */
54
+    private $config;
55
+
56
+    /**
57
+     * @param string $renderAs
58
+     * @param string $appId application id
59
+     */
60
+    public function __construct( $renderAs, $appId = '' ) {
61
+
62
+        // yes - should be injected ....
63
+        $this->config = \OC::$server->getConfig();
64
+
65
+        if(\OCP\Util::isIE()) {
66
+            \OC_Util::addStyle('ie');
67
+        }
68
+
69
+        // Decide which page we show
70
+        if($renderAs == 'user') {
71
+            parent::__construct( 'core', 'layout.user' );
72
+            if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
73
+                $this->assign('bodyid', 'body-settings');
74
+            }else{
75
+                $this->assign('bodyid', 'body-user');
76
+            }
77
+
78
+            // Code integrity notification
79
+            $integrityChecker = \OC::$server->getIntegrityCodeChecker();
80
+            if(\OC_User::isAdminUser(\OC_User::getUser()) && $integrityChecker->isCodeCheckEnforced() && !$integrityChecker->hasPassedCheck()) {
81
+                \OCP\Util::addScript('core', 'integritycheck-failed-notification');
82
+            }
83
+
84
+            // Add navigation entry
85
+            $this->assign( 'application', '');
86
+            $this->assign( 'appid', $appId );
87
+            $navigation = \OC::$server->getNavigationManager()->getAll();
88
+            $this->assign( 'navigation', $navigation);
89
+            $settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
90
+            $this->assign( 'settingsnavigation', $settingsNavigation);
91
+            foreach($navigation as $entry) {
92
+                if ($entry['active']) {
93
+                    $this->assign( 'application', $entry['name'] );
94
+                    break;
95
+                }
96
+            }
97
+
98
+            foreach($settingsNavigation as $entry) {
99
+                if ($entry['active']) {
100
+                    $this->assign( 'application', $entry['name'] );
101
+                    break;
102
+                }
103
+            }
104
+            $userDisplayName = \OC_User::getDisplayName();
105
+            $this->assign('user_displayname', $userDisplayName);
106
+            $this->assign('user_uid', \OC_User::getUser());
107
+
108
+            if (\OC_User::getUser() === false) {
109
+                $this->assign('userAvatarSet', false);
110
+            } else {
111
+                $this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
112
+                $this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
113
+            }
114
+
115
+            // check if app menu icons should be inverted
116
+            try {
117
+                /** @var \OCA\Theming\Util $util */
118
+                $util = \OC::$server->query(\OCA\Theming\Util::class);
119
+                $this->assign('themingInvertMenu', $util->invertTextColor(\OC::$server->getThemingDefaults()->getColorPrimary()));
120
+            } catch (\OCP\AppFramework\QueryException $e) {
121
+                $this->assign('themingInvertMenu', false);
122
+            }
123
+
124
+        } else if ($renderAs == 'error') {
125
+            parent::__construct('core', 'layout.guest', '', false);
126
+            $this->assign('bodyid', 'body-login');
127
+        } else if ($renderAs == 'guest') {
128
+            parent::__construct('core', 'layout.guest');
129
+            \OC_Util::addStyle('guest');
130
+            $this->assign('bodyid', 'body-login');
131
+        } else if ($renderAs == 'public') {
132
+            parent::__construct('core', 'layout.public');
133
+            $this->assign( 'appid', $appId );
134
+            $this->assign('bodyid', 'body-public');
135
+            $this->assign('showSimpleSignUpLink', $this->config->getSystemValue('simpleSignUpLink.shown', true) !== false);
136
+        } else {
137
+            parent::__construct('core', 'layout.base');
138
+
139
+        }
140
+        // Send the language and the locale to our layouts
141
+        $lang = \OC::$server->getL10NFactory()->findLanguage();
142
+        $locale = \OC::$server->getL10NFactory()->findLocale($lang);
143
+        $localeLang = \OC::$server->getL10NFactory()->findLanguageFromLocale('lib', $locale);
144
+
145
+        $lang = str_replace('_', '-', $lang);
146
+        $this->assign('language', $lang);
147
+        $this->assign('locale', $locale);
148
+
149
+        if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
150
+            if (empty(self::$versionHash)) {
151
+                $v = \OC_App::getAppVersions();
152
+                $v['core'] = implode('.', \OCP\Util::getVersion());
153
+                self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
154
+            }
155
+        } else {
156
+            self::$versionHash = md5('not installed');
157
+        }
158
+
159
+        // Add the js files
160
+        $jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
161
+        $this->assign('jsfiles', array());
162
+        if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
163
+            if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
164
+                $jsConfigHelper = new JSConfigHelper(
165
+                    \OC::$server->getL10N('lib', $localeLang ?: $lang),
166
+                    \OC::$server->query(Defaults::class),
167
+                    \OC::$server->getAppManager(),
168
+                    \OC::$server->getSession(),
169
+                    \OC::$server->getUserSession()->getUser(),
170
+                    $this->config,
171
+                    \OC::$server->getGroupManager(),
172
+                    \OC::$server->getIniWrapper(),
173
+                    \OC::$server->getURLGenerator(),
174
+                    \OC::$server->getCapabilitiesManager()
175
+                );
176
+                $this->assign('inline_ocjs', $jsConfigHelper->getConfig());
177
+            } else {
178
+                $this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
179
+            }
180
+        }
181
+        foreach($jsFiles as $info) {
182
+            $web = $info[1];
183
+            $file = $info[2];
184
+            $this->append( 'jsfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
185
+        }
186
+
187
+        try {
188
+            $pathInfo = \OC::$server->getRequest()->getPathInfo();
189
+        } catch (\Exception $e) {
190
+            $pathInfo = '';
191
+        }
192
+
193
+        // Do not initialise scss appdata until we have a fully installed instance
194
+        // Do not load scss for update, errors, installation or login page
195
+        if(\OC::$server->getSystemConfig()->getValue('installed', false)
196
+            && !\OCP\Util::needUpgrade()
197
+            && $pathInfo !== ''
198
+            && !preg_match('/^\/login/', $pathInfo)
199
+            && $renderAs !== 'error'
200
+        ) {
201
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
202
+        } else {
203
+            // If we ignore the scss compiler,
204
+            // we need to load the guest css fallback
205
+            \OC_Util::addStyle('guest');
206
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles, false);
207
+        }
208
+
209
+        $this->assign('cssfiles', array());
210
+        $this->assign('printcssfiles', []);
211
+        $this->assign('versionHash', self::$versionHash);
212
+        foreach($cssFiles as $info) {
213
+            $web = $info[1];
214
+            $file = $info[2];
215
+
216
+            if (substr($file, -strlen('print.css')) === 'print.css') {
217
+                $this->append( 'printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix() );
218
+            } else {
219
+                $this->append( 'cssfiles', $web.'/'.$file . $this->getVersionHashSuffix($web, $file)  );
220
+            }
221
+        }
222
+    }
223
+
224
+    /**
225
+     * @param string $path
226
+     * @param string $file
227
+     * @return string
228
+     */
229
+    protected function getVersionHashSuffix($path = false, $file = false) {
230
+        if ($this->config->getSystemValue('debug', false)) {
231
+            // allows chrome workspace mapping in debug mode
232
+            return "";
233
+        }
234
+        $themingSuffix = '';
235
+        $v = [];
236
+
237
+        if ($this->config->getSystemValue('installed', false)) {
238
+            if (\OC::$server->getAppManager()->isInstalled('theming')) {
239
+                $themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
240
+            }
241
+            $v = \OC_App::getAppVersions();
242
+        }
243
+
244
+        // Try the webroot path for a match
245
+        if ($path !== false && $path !== '') {
246
+            $appName = $this->getAppNamefromPath($path);
247
+            if(array_key_exists($appName, $v)) {
248
+                $appVersion = $v[$appName];
249
+                return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
250
+            }
251
+        }
252
+        // fallback to the file path instead
253
+        if ($file !== false && $file !== '') {
254
+            $appName = $this->getAppNamefromPath($file);
255
+            if(array_key_exists($appName, $v)) {
256
+                $appVersion = $v[$appName];
257
+                return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
258
+            }
259
+        }
260
+
261
+        return '?v=' . self::$versionHash . $themingSuffix;
262
+    }
263
+
264
+    /**
265
+     * @param array $styles
266
+     * @return array
267
+     */
268
+    static public function findStylesheetFiles($styles, $compileScss = true) {
269
+        // Read the selected theme from the config file
270
+        $theme = \OC_Util::getTheme();
271
+
272
+        if($compileScss) {
273
+            $SCSSCacher = \OC::$server->query(SCSSCacher::class);
274
+        } else {
275
+            $SCSSCacher = null;
276
+        }
277
+
278
+        $locator = new \OC\Template\CSSResourceLocator(
279
+            \OC::$server->getLogger(),
280
+            $theme,
281
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
282
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
283
+            $SCSSCacher
284
+        );
285
+        $locator->find($styles);
286
+        return $locator->getResources();
287
+    }
288
+
289
+    /**
290
+     * @param string $path
291
+     * @return string|boolean
292
+     */
293
+    public function getAppNamefromPath($path) {
294
+        if ($path !== '' && is_string($path)) {
295
+            $pathParts = explode('/', $path);
296
+            if ($pathParts[0] === 'css') {
297
+                // This is a scss request
298
+                return $pathParts[1];
299
+            }
300
+            return end($pathParts);
301
+        }
302
+        return false;
303
+
304
+    }
305
+
306
+    /**
307
+     * @param array $scripts
308
+     * @return array
309
+     */
310
+    static public function findJavascriptFiles($scripts) {
311
+        // Read the selected theme from the config file
312
+        $theme = \OC_Util::getTheme();
313
+
314
+        $locator = new \OC\Template\JSResourceLocator(
315
+            \OC::$server->getLogger(),
316
+            $theme,
317
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
318
+            array( \OC::$SERVERROOT => \OC::$WEBROOT ),
319
+            \OC::$server->query(JSCombiner::class)
320
+            );
321
+        $locator->find($scripts);
322
+        return $locator->getResources();
323
+    }
324
+
325
+    /**
326
+     * Converts the absolute file path to a relative path from \OC::$SERVERROOT
327
+     * @param string $filePath Absolute path
328
+     * @return string Relative path
329
+     * @throws \Exception If $filePath is not under \OC::$SERVERROOT
330
+     */
331
+    public static function convertToRelativePath($filePath) {
332
+        $relativePath = explode(\OC::$SERVERROOT, $filePath);
333
+        if(count($relativePath) !== 2) {
334
+            throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
335
+        }
336
+
337
+        return $relativePath[1];
338
+    }
339 339
 }
Please login to merge, or discard this patch.
lib/private/L10N/Factory.php 1 patch
Indentation   +595 added lines, -595 removed lines patch added patch discarded remove patch
@@ -42,600 +42,600 @@
 block discarded – undo
42 42
  */
43 43
 class Factory implements IFactory {
44 44
 
45
-	/** @var string */
46
-	protected $requestLanguage = '';
47
-
48
-	/**
49
-	 * cached instances
50
-	 * @var array Structure: Lang => App => \OCP\IL10N
51
-	 */
52
-	protected $instances = [];
53
-
54
-	/**
55
-	 * @var array Structure: App => string[]
56
-	 */
57
-	protected $availableLanguages = [];
58
-
59
-	/**
60
-	 * @var array
61
-	 */
62
-	protected $availableLocales = [];
63
-
64
-	/**
65
-	 * @var array Structure: string => callable
66
-	 */
67
-	protected $pluralFunctions = [];
68
-
69
-	const COMMON_LANGUAGE_CODES = [
70
-		'en', 'es', 'fr', 'de', 'de_DE', 'ja', 'ar', 'ru', 'nl', 'it',
71
-		'pt_BR', 'pt_PT', 'da', 'fi_FI', 'nb_NO', 'sv', 'tr', 'zh_CN', 'ko'
72
-	];
73
-
74
-	/** @var IConfig */
75
-	protected $config;
76
-
77
-	/** @var IRequest */
78
-	protected $request;
79
-
80
-	/** @var IUserSession */
81
-	protected $userSession;
82
-
83
-	/** @var string */
84
-	protected $serverRoot;
85
-
86
-	/**
87
-	 * @param IConfig $config
88
-	 * @param IRequest $request
89
-	 * @param IUserSession $userSession
90
-	 * @param string $serverRoot
91
-	 */
92
-	public function __construct(IConfig $config,
93
-								IRequest $request,
94
-								IUserSession $userSession,
95
-								$serverRoot) {
96
-		$this->config = $config;
97
-		$this->request = $request;
98
-		$this->userSession = $userSession;
99
-		$this->serverRoot = $serverRoot;
100
-	}
101
-
102
-	/**
103
-	 * Get a language instance
104
-	 *
105
-	 * @param string $app
106
-	 * @param string|null $lang
107
-	 * @param string|null $locale
108
-	 * @return \OCP\IL10N
109
-	 */
110
-	public function get($app, $lang = null, $locale = null) {
111
-		$app = \OC_App::cleanAppId($app);
112
-		if ($lang !== null) {
113
-			$lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
114
-		}
115
-
116
-		$forceLang = $this->config->getSystemValue('force_language', false);
117
-		if (is_string($forceLang)) {
118
-			$lang = $forceLang;
119
-		}
120
-
121
-		$forceLocale = $this->config->getSystemValue('force_locale', false);
122
-		if (is_string($forceLocale)) {
123
-			$locale = $forceLocale;
124
-		}
125
-
126
-		if ($lang === null || !$this->languageExists($app, $lang)) {
127
-			$lang = $this->findLanguage($app);
128
-		}
129
-
130
-		if ($locale === null || !$this->localeExists($locale)) {
131
-			$locale = $this->findLocale($lang);
132
-		}
133
-
134
-		if (!isset($this->instances[$lang][$app])) {
135
-			$this->instances[$lang][$app] = new L10N(
136
-				$this, $app, $lang, $locale,
137
-				$this->getL10nFilesForApp($app, $lang)
138
-			);
139
-		}
140
-
141
-		return $this->instances[$lang][$app];
142
-	}
143
-
144
-	/**
145
-	 * Find the best language
146
-	 *
147
-	 * @param string|null $app App id or null for core
148
-	 * @return string language If nothing works it returns 'en'
149
-	 */
150
-	public function findLanguage($app = null) {
151
-		$forceLang = $this->config->getSystemValue('force_language', false);
152
-		if (is_string($forceLang)) {
153
-			$this->requestLanguage = $forceLang;
154
-		}
155
-
156
-		if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
157
-			return $this->requestLanguage;
158
-		}
159
-
160
-		/**
161
-		 * At this point Nextcloud might not yet be installed and thus the lookup
162
-		 * in the preferences table might fail. For this reason we need to check
163
-		 * whether the instance has already been installed
164
-		 *
165
-		 * @link https://github.com/owncloud/core/issues/21955
166
-		 */
167
-		if ($this->config->getSystemValue('installed', false)) {
168
-			$userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
169
-			if (!is_null($userId)) {
170
-				$userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
171
-			} else {
172
-				$userLang = null;
173
-			}
174
-		} else {
175
-			$userId = null;
176
-			$userLang = null;
177
-		}
178
-
179
-		if ($userLang) {
180
-			$this->requestLanguage = $userLang;
181
-			if ($this->languageExists($app, $userLang)) {
182
-				return $userLang;
183
-			}
184
-		}
185
-
186
-		try {
187
-			// Try to get the language from the Request
188
-			$lang = $this->getLanguageFromRequest($app);
189
-			if ($userId !== null && $app === null && !$userLang) {
190
-				$this->config->setUserValue($userId, 'core', 'lang', $lang);
191
-			}
192
-			return $lang;
193
-		} catch (LanguageNotFoundException $e) {
194
-			// Finding language from request failed fall back to default language
195
-			$defaultLanguage = $this->config->getSystemValue('default_language', false);
196
-			if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
197
-				return $defaultLanguage;
198
-			}
199
-		}
200
-
201
-		// We could not find any language so fall back to english
202
-		return 'en';
203
-	}
204
-
205
-	/**
206
-	 * find the best locale
207
-	 *
208
-	 * @param string $lang
209
-	 * @return null|string
210
-	 */
211
-	public function findLocale($lang = null) {
212
-		$forceLocale = $this->config->getSystemValue('force_locale', false);
213
-		if (is_string($forceLocale) && $this->localeExists($forceLocale)) {
214
-			return $forceLocale;
215
-		}
216
-
217
-		if ($this->config->getSystemValue('installed', false)) {
218
-			$userId = null !== $this->userSession->getUser() ? $this->userSession->getUser()->getUID() :  null;
219
-			$userLocale = null;
220
-			if (null !== $userId) {
221
-				$userLocale = $this->config->getUserValue($userId, 'core', 'locale', null);
222
-			}
223
-		} else {
224
-			$userId = null;
225
-			$userLocale = null;
226
-		}
227
-
228
-		if ($userLocale && $this->localeExists($userLocale)) {
229
-			return $userLocale;
230
-		}
231
-
232
-		// Default : use system default locale
233
-		$defaultLocale = $this->config->getSystemValue('default_locale', false);
234
-		if ($defaultLocale !== false && $this->localeExists($defaultLocale)) {
235
-			return $defaultLocale;
236
-		}
237
-
238
-		// If no user locale set, use lang as locale
239
-		if (null !== $lang && $this->localeExists($lang)) {
240
-			return $lang;
241
-		}
242
-
243
-		// At last, return USA
244
-		return 'en_US';
245
-	}
246
-
247
-	/**
248
-	 * find the matching lang from the locale
249
-	 *
250
-	 * @param string $app
251
-	 * @param string $locale
252
-	 * @return null|string
253
-	 */
254
-	public function findLanguageFromLocale(string $app = 'core', string $locale = null) {
255
-		if ($this->languageExists($app, $locale)) {
256
-			return $locale;
257
-		}
45
+    /** @var string */
46
+    protected $requestLanguage = '';
47
+
48
+    /**
49
+     * cached instances
50
+     * @var array Structure: Lang => App => \OCP\IL10N
51
+     */
52
+    protected $instances = [];
53
+
54
+    /**
55
+     * @var array Structure: App => string[]
56
+     */
57
+    protected $availableLanguages = [];
58
+
59
+    /**
60
+     * @var array
61
+     */
62
+    protected $availableLocales = [];
63
+
64
+    /**
65
+     * @var array Structure: string => callable
66
+     */
67
+    protected $pluralFunctions = [];
68
+
69
+    const COMMON_LANGUAGE_CODES = [
70
+        'en', 'es', 'fr', 'de', 'de_DE', 'ja', 'ar', 'ru', 'nl', 'it',
71
+        'pt_BR', 'pt_PT', 'da', 'fi_FI', 'nb_NO', 'sv', 'tr', 'zh_CN', 'ko'
72
+    ];
73
+
74
+    /** @var IConfig */
75
+    protected $config;
76
+
77
+    /** @var IRequest */
78
+    protected $request;
79
+
80
+    /** @var IUserSession */
81
+    protected $userSession;
82
+
83
+    /** @var string */
84
+    protected $serverRoot;
85
+
86
+    /**
87
+     * @param IConfig $config
88
+     * @param IRequest $request
89
+     * @param IUserSession $userSession
90
+     * @param string $serverRoot
91
+     */
92
+    public function __construct(IConfig $config,
93
+                                IRequest $request,
94
+                                IUserSession $userSession,
95
+                                $serverRoot) {
96
+        $this->config = $config;
97
+        $this->request = $request;
98
+        $this->userSession = $userSession;
99
+        $this->serverRoot = $serverRoot;
100
+    }
101
+
102
+    /**
103
+     * Get a language instance
104
+     *
105
+     * @param string $app
106
+     * @param string|null $lang
107
+     * @param string|null $locale
108
+     * @return \OCP\IL10N
109
+     */
110
+    public function get($app, $lang = null, $locale = null) {
111
+        $app = \OC_App::cleanAppId($app);
112
+        if ($lang !== null) {
113
+            $lang = str_replace(array('\0', '/', '\\', '..'), '', (string) $lang);
114
+        }
115
+
116
+        $forceLang = $this->config->getSystemValue('force_language', false);
117
+        if (is_string($forceLang)) {
118
+            $lang = $forceLang;
119
+        }
120
+
121
+        $forceLocale = $this->config->getSystemValue('force_locale', false);
122
+        if (is_string($forceLocale)) {
123
+            $locale = $forceLocale;
124
+        }
125
+
126
+        if ($lang === null || !$this->languageExists($app, $lang)) {
127
+            $lang = $this->findLanguage($app);
128
+        }
129
+
130
+        if ($locale === null || !$this->localeExists($locale)) {
131
+            $locale = $this->findLocale($lang);
132
+        }
133
+
134
+        if (!isset($this->instances[$lang][$app])) {
135
+            $this->instances[$lang][$app] = new L10N(
136
+                $this, $app, $lang, $locale,
137
+                $this->getL10nFilesForApp($app, $lang)
138
+            );
139
+        }
140
+
141
+        return $this->instances[$lang][$app];
142
+    }
143
+
144
+    /**
145
+     * Find the best language
146
+     *
147
+     * @param string|null $app App id or null for core
148
+     * @return string language If nothing works it returns 'en'
149
+     */
150
+    public function findLanguage($app = null) {
151
+        $forceLang = $this->config->getSystemValue('force_language', false);
152
+        if (is_string($forceLang)) {
153
+            $this->requestLanguage = $forceLang;
154
+        }
155
+
156
+        if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
157
+            return $this->requestLanguage;
158
+        }
159
+
160
+        /**
161
+         * At this point Nextcloud might not yet be installed and thus the lookup
162
+         * in the preferences table might fail. For this reason we need to check
163
+         * whether the instance has already been installed
164
+         *
165
+         * @link https://github.com/owncloud/core/issues/21955
166
+         */
167
+        if ($this->config->getSystemValue('installed', false)) {
168
+            $userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
169
+            if (!is_null($userId)) {
170
+                $userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
171
+            } else {
172
+                $userLang = null;
173
+            }
174
+        } else {
175
+            $userId = null;
176
+            $userLang = null;
177
+        }
178
+
179
+        if ($userLang) {
180
+            $this->requestLanguage = $userLang;
181
+            if ($this->languageExists($app, $userLang)) {
182
+                return $userLang;
183
+            }
184
+        }
185
+
186
+        try {
187
+            // Try to get the language from the Request
188
+            $lang = $this->getLanguageFromRequest($app);
189
+            if ($userId !== null && $app === null && !$userLang) {
190
+                $this->config->setUserValue($userId, 'core', 'lang', $lang);
191
+            }
192
+            return $lang;
193
+        } catch (LanguageNotFoundException $e) {
194
+            // Finding language from request failed fall back to default language
195
+            $defaultLanguage = $this->config->getSystemValue('default_language', false);
196
+            if ($defaultLanguage !== false && $this->languageExists($app, $defaultLanguage)) {
197
+                return $defaultLanguage;
198
+            }
199
+        }
200
+
201
+        // We could not find any language so fall back to english
202
+        return 'en';
203
+    }
204
+
205
+    /**
206
+     * find the best locale
207
+     *
208
+     * @param string $lang
209
+     * @return null|string
210
+     */
211
+    public function findLocale($lang = null) {
212
+        $forceLocale = $this->config->getSystemValue('force_locale', false);
213
+        if (is_string($forceLocale) && $this->localeExists($forceLocale)) {
214
+            return $forceLocale;
215
+        }
216
+
217
+        if ($this->config->getSystemValue('installed', false)) {
218
+            $userId = null !== $this->userSession->getUser() ? $this->userSession->getUser()->getUID() :  null;
219
+            $userLocale = null;
220
+            if (null !== $userId) {
221
+                $userLocale = $this->config->getUserValue($userId, 'core', 'locale', null);
222
+            }
223
+        } else {
224
+            $userId = null;
225
+            $userLocale = null;
226
+        }
227
+
228
+        if ($userLocale && $this->localeExists($userLocale)) {
229
+            return $userLocale;
230
+        }
231
+
232
+        // Default : use system default locale
233
+        $defaultLocale = $this->config->getSystemValue('default_locale', false);
234
+        if ($defaultLocale !== false && $this->localeExists($defaultLocale)) {
235
+            return $defaultLocale;
236
+        }
237
+
238
+        // If no user locale set, use lang as locale
239
+        if (null !== $lang && $this->localeExists($lang)) {
240
+            return $lang;
241
+        }
242
+
243
+        // At last, return USA
244
+        return 'en_US';
245
+    }
246
+
247
+    /**
248
+     * find the matching lang from the locale
249
+     *
250
+     * @param string $app
251
+     * @param string $locale
252
+     * @return null|string
253
+     */
254
+    public function findLanguageFromLocale(string $app = 'core', string $locale = null) {
255
+        if ($this->languageExists($app, $locale)) {
256
+            return $locale;
257
+        }
258 258
 		
259
-		// Try to split e.g: fr_FR => fr
260
-		$locale = explode('_', $locale)[0];
261
-		if ($this->languageExists($app, $locale)) {
262
-			return $locale;
263
-		}
264
-	}
265
-
266
-	/**
267
-	 * Find all available languages for an app
268
-	 *
269
-	 * @param string|null $app App id or null for core
270
-	 * @return array an array of available languages
271
-	 */
272
-	public function findAvailableLanguages($app = null) {
273
-		$key = $app;
274
-		if ($key === null) {
275
-			$key = 'null';
276
-		}
277
-
278
-		// also works with null as key
279
-		if (!empty($this->availableLanguages[$key])) {
280
-			return $this->availableLanguages[$key];
281
-		}
282
-
283
-		$available = ['en']; //english is always available
284
-		$dir = $this->findL10nDir($app);
285
-		if (is_dir($dir)) {
286
-			$files = scandir($dir);
287
-			if ($files !== false) {
288
-				foreach ($files as $file) {
289
-					if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
290
-						$available[] = substr($file, 0, -5);
291
-					}
292
-				}
293
-			}
294
-		}
295
-
296
-		// merge with translations from theme
297
-		$theme = $this->config->getSystemValue('theme');
298
-		if (!empty($theme)) {
299
-			$themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
300
-
301
-			if (is_dir($themeDir)) {
302
-				$files = scandir($themeDir);
303
-				if ($files !== false) {
304
-					foreach ($files as $file) {
305
-						if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
306
-							$available[] = substr($file, 0, -5);
307
-						}
308
-					}
309
-				}
310
-			}
311
-		}
312
-
313
-		$this->availableLanguages[$key] = $available;
314
-		return $available;
315
-	}
316
-
317
-	/**
318
-	 * @return array|mixed
319
-	 */
320
-	public function findAvailableLocales() {
321
-		if (!empty($this->availableLocales)) {
322
-			return $this->availableLocales;
323
-		}
324
-
325
-		$localeData = file_get_contents(\OC::$SERVERROOT . '/resources/locales.json');
326
-		$this->availableLocales = \json_decode($localeData, true);
327
-
328
-		return $this->availableLocales;
329
-	}
330
-
331
-	/**
332
-	 * @param string|null $app App id or null for core
333
-	 * @param string $lang
334
-	 * @return bool
335
-	 */
336
-	public function languageExists($app, $lang) {
337
-		if ($lang === 'en') {//english is always available
338
-			return true;
339
-		}
340
-
341
-		$languages = $this->findAvailableLanguages($app);
342
-		return array_search($lang, $languages) !== false;
343
-	}
344
-
345
-	public function getLanguageIterator(IUser $user = null): ILanguageIterator {
346
-		$user = $user ?? $this->userSession->getUser();
347
-		if($user === null) {
348
-			throw new \RuntimeException('Failed to get an IUser instance');
349
-		}
350
-		return new LanguageIterator($user, $this->config);
351
-	}
352
-
353
-	/**
354
-	 * @param string $locale
355
-	 * @return bool
356
-	 */
357
-	public function localeExists($locale) {
358
-		if ($locale === 'en') { //english is always available
359
-			return true;
360
-		}
361
-
362
-		$locales = $this->findAvailableLocales();
363
-		$userLocale = array_filter($locales, function($value) use ($locale) {
364
-			return $locale === $value['code'];
365
-		});
366
-
367
-		return !empty($userLocale);
368
-	}
369
-
370
-	/**
371
-	 * @param string|null $app
372
-	 * @return string
373
-	 * @throws LanguageNotFoundException
374
-	 */
375
-	private function getLanguageFromRequest($app) {
376
-		$header = $this->request->getHeader('ACCEPT_LANGUAGE');
377
-		if ($header !== '') {
378
-			$available = $this->findAvailableLanguages($app);
379
-
380
-			// E.g. make sure that 'de' is before 'de_DE'.
381
-			sort($available);
382
-
383
-			$preferences = preg_split('/,\s*/', strtolower($header));
384
-			foreach ($preferences as $preference) {
385
-				list($preferred_language) = explode(';', $preference);
386
-				$preferred_language = str_replace('-', '_', $preferred_language);
387
-
388
-				foreach ($available as $available_language) {
389
-					if ($preferred_language === strtolower($available_language)) {
390
-						return $this->respectDefaultLanguage($app, $available_language);
391
-					}
392
-				}
393
-
394
-				// Fallback from de_De to de
395
-				foreach ($available as $available_language) {
396
-					if (substr($preferred_language, 0, 2) === $available_language) {
397
-						return $available_language;
398
-					}
399
-				}
400
-			}
401
-		}
402
-
403
-		throw new LanguageNotFoundException();
404
-	}
405
-
406
-	/**
407
-	 * if default language is set to de_DE (formal German) this should be
408
-	 * preferred to 'de' (non-formal German) if possible
409
-	 *
410
-	 * @param string|null $app
411
-	 * @param string $lang
412
-	 * @return string
413
-	 */
414
-	protected function respectDefaultLanguage($app, $lang) {
415
-		$result = $lang;
416
-		$defaultLanguage = $this->config->getSystemValue('default_language', false);
417
-
418
-		// use formal version of german ("Sie" instead of "Du") if the default
419
-		// language is set to 'de_DE' if possible
420
-		if (is_string($defaultLanguage) &&
421
-			strtolower($lang) === 'de' &&
422
-			strtolower($defaultLanguage) === 'de_de' &&
423
-			$this->languageExists($app, 'de_DE')
424
-		) {
425
-			$result = 'de_DE';
426
-		}
427
-
428
-		return $result;
429
-	}
430
-
431
-	/**
432
-	 * Checks if $sub is a subdirectory of $parent
433
-	 *
434
-	 * @param string $sub
435
-	 * @param string $parent
436
-	 * @return bool
437
-	 */
438
-	private function isSubDirectory($sub, $parent) {
439
-		// Check whether $sub contains no ".."
440
-		if (strpos($sub, '..') !== false) {
441
-			return false;
442
-		}
443
-
444
-		// Check whether $sub is a subdirectory of $parent
445
-		if (strpos($sub, $parent) === 0) {
446
-			return true;
447
-		}
448
-
449
-		return false;
450
-	}
451
-
452
-	/**
453
-	 * Get a list of language files that should be loaded
454
-	 *
455
-	 * @param string $app
456
-	 * @param string $lang
457
-	 * @return string[]
458
-	 */
459
-	// FIXME This method is only public, until OC_L10N does not need it anymore,
460
-	// FIXME This is also the reason, why it is not in the public interface
461
-	public function getL10nFilesForApp($app, $lang) {
462
-		$languageFiles = [];
463
-
464
-		$i18nDir = $this->findL10nDir($app);
465
-		$transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
466
-
467
-		if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
468
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
469
-				|| $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
470
-				|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
471
-			)
472
-			&& file_exists($transFile)) {
473
-			// load the translations file
474
-			$languageFiles[] = $transFile;
475
-		}
476
-
477
-		// merge with translations from theme
478
-		$theme = $this->config->getSystemValue('theme');
479
-		if (!empty($theme)) {
480
-			$transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
481
-			if (file_exists($transFile)) {
482
-				$languageFiles[] = $transFile;
483
-			}
484
-		}
485
-
486
-		return $languageFiles;
487
-	}
488
-
489
-	/**
490
-	 * find the l10n directory
491
-	 *
492
-	 * @param string $app App id or empty string for core
493
-	 * @return string directory
494
-	 */
495
-	protected function findL10nDir($app = null) {
496
-		if (in_array($app, ['core', 'lib', 'settings'])) {
497
-			if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
498
-				return $this->serverRoot . '/' . $app . '/l10n/';
499
-			}
500
-		} else if ($app && \OC_App::getAppPath($app) !== false) {
501
-			// Check if the app is in the app folder
502
-			return \OC_App::getAppPath($app) . '/l10n/';
503
-		}
504
-		return $this->serverRoot . '/core/l10n/';
505
-	}
506
-
507
-
508
-	/**
509
-	 * Creates a function from the plural string
510
-	 *
511
-	 * Parts of the code is copied from Habari:
512
-	 * https://github.com/habari/system/blob/master/classes/locale.php
513
-	 * @param string $string
514
-	 * @return string
515
-	 */
516
-	public function createPluralFunction($string) {
517
-		if (isset($this->pluralFunctions[$string])) {
518
-			return $this->pluralFunctions[$string];
519
-		}
520
-
521
-		if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
522
-			// sanitize
523
-			$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
524
-			$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
525
-
526
-			$body = str_replace(
527
-				array( 'plural', 'n', '$n$plurals', ),
528
-				array( '$plural', '$n', '$nplurals', ),
529
-				'nplurals='. $nplurals . '; plural=' . $plural
530
-			);
531
-
532
-			// add parents
533
-			// important since PHP's ternary evaluates from left to right
534
-			$body .= ';';
535
-			$res = '';
536
-			$p = 0;
537
-			$length = strlen($body);
538
-			for($i = 0; $i < $length; $i++) {
539
-				$ch = $body[$i];
540
-				switch ( $ch ) {
541
-					case '?':
542
-						$res .= ' ? (';
543
-						$p++;
544
-						break;
545
-					case ':':
546
-						$res .= ') : (';
547
-						break;
548
-					case ';':
549
-						$res .= str_repeat( ')', $p ) . ';';
550
-						$p = 0;
551
-						break;
552
-					default:
553
-						$res .= $ch;
554
-				}
555
-			}
556
-
557
-			$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
558
-			$function = create_function('$n', $body);
559
-			$this->pluralFunctions[$string] = $function;
560
-			return $function;
561
-		} else {
562
-			// default: one plural form for all cases but n==1 (english)
563
-			$function = create_function(
564
-				'$n',
565
-				'$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
566
-			);
567
-			$this->pluralFunctions[$string] = $function;
568
-			return $function;
569
-		}
570
-	}
571
-
572
-	/**
573
-	 * returns the common language and other languages in an
574
-	 * associative array
575
-	 *
576
-	 * @return array
577
-	 */
578
-	public function getLanguages() {
579
-		$forceLanguage = $this->config->getSystemValue('force_language', false);
580
-		if ($forceLanguage !== false) {
581
-			return [];
582
-		}
583
-
584
-		$languageCodes = $this->findAvailableLanguages();
585
-
586
-		$commonLanguages = [];
587
-		$languages = [];
588
-
589
-		foreach($languageCodes as $lang) {
590
-			$l = $this->get('lib', $lang);
591
-			// TRANSLATORS this is the language name for the language switcher in the personal settings and should be the localized version
592
-			$potentialName = (string) $l->t('__language_name__');
593
-			if ($l->getLanguageCode() === $lang && $potentialName[0] !== '_') {//first check if the language name is in the translation file
594
-				$ln = array(
595
-					'code' => $lang,
596
-					'name' => $potentialName
597
-				);
598
-			} else if ($lang === 'en') {
599
-				$ln = array(
600
-					'code' => $lang,
601
-					'name' => 'English (US)'
602
-				);
603
-			} else {//fallback to language code
604
-				$ln = array(
605
-					'code' => $lang,
606
-					'name' => $lang
607
-				);
608
-			}
609
-
610
-			// put appropriate languages into appropriate arrays, to print them sorted
611
-			// common languages -> divider -> other languages
612
-			if (in_array($lang, self::COMMON_LANGUAGE_CODES)) {
613
-				$commonLanguages[array_search($lang, self::COMMON_LANGUAGE_CODES)] = $ln;
614
-			} else {
615
-				$languages[] = $ln;
616
-			}
617
-		}
618
-
619
-		ksort($commonLanguages);
620
-
621
-		// sort now by displayed language not the iso-code
622
-		usort( $languages, function ($a, $b) {
623
-			if ($a['code'] === $a['name'] && $b['code'] !== $b['name']) {
624
-				// If a doesn't have a name, but b does, list b before a
625
-				return 1;
626
-			}
627
-			if ($a['code'] !== $a['name'] && $b['code'] === $b['name']) {
628
-				// If a does have a name, but b doesn't, list a before b
629
-				return -1;
630
-			}
631
-			// Otherwise compare the names
632
-			return strcmp($a['name'], $b['name']);
633
-		});
634
-
635
-		return [
636
-			// reset indexes
637
-			'commonlanguages' => array_values($commonLanguages),
638
-			'languages' => $languages
639
-		];
640
-	}
259
+        // Try to split e.g: fr_FR => fr
260
+        $locale = explode('_', $locale)[0];
261
+        if ($this->languageExists($app, $locale)) {
262
+            return $locale;
263
+        }
264
+    }
265
+
266
+    /**
267
+     * Find all available languages for an app
268
+     *
269
+     * @param string|null $app App id or null for core
270
+     * @return array an array of available languages
271
+     */
272
+    public function findAvailableLanguages($app = null) {
273
+        $key = $app;
274
+        if ($key === null) {
275
+            $key = 'null';
276
+        }
277
+
278
+        // also works with null as key
279
+        if (!empty($this->availableLanguages[$key])) {
280
+            return $this->availableLanguages[$key];
281
+        }
282
+
283
+        $available = ['en']; //english is always available
284
+        $dir = $this->findL10nDir($app);
285
+        if (is_dir($dir)) {
286
+            $files = scandir($dir);
287
+            if ($files !== false) {
288
+                foreach ($files as $file) {
289
+                    if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
290
+                        $available[] = substr($file, 0, -5);
291
+                    }
292
+                }
293
+            }
294
+        }
295
+
296
+        // merge with translations from theme
297
+        $theme = $this->config->getSystemValue('theme');
298
+        if (!empty($theme)) {
299
+            $themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));
300
+
301
+            if (is_dir($themeDir)) {
302
+                $files = scandir($themeDir);
303
+                if ($files !== false) {
304
+                    foreach ($files as $file) {
305
+                        if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
306
+                            $available[] = substr($file, 0, -5);
307
+                        }
308
+                    }
309
+                }
310
+            }
311
+        }
312
+
313
+        $this->availableLanguages[$key] = $available;
314
+        return $available;
315
+    }
316
+
317
+    /**
318
+     * @return array|mixed
319
+     */
320
+    public function findAvailableLocales() {
321
+        if (!empty($this->availableLocales)) {
322
+            return $this->availableLocales;
323
+        }
324
+
325
+        $localeData = file_get_contents(\OC::$SERVERROOT . '/resources/locales.json');
326
+        $this->availableLocales = \json_decode($localeData, true);
327
+
328
+        return $this->availableLocales;
329
+    }
330
+
331
+    /**
332
+     * @param string|null $app App id or null for core
333
+     * @param string $lang
334
+     * @return bool
335
+     */
336
+    public function languageExists($app, $lang) {
337
+        if ($lang === 'en') {//english is always available
338
+            return true;
339
+        }
340
+
341
+        $languages = $this->findAvailableLanguages($app);
342
+        return array_search($lang, $languages) !== false;
343
+    }
344
+
345
+    public function getLanguageIterator(IUser $user = null): ILanguageIterator {
346
+        $user = $user ?? $this->userSession->getUser();
347
+        if($user === null) {
348
+            throw new \RuntimeException('Failed to get an IUser instance');
349
+        }
350
+        return new LanguageIterator($user, $this->config);
351
+    }
352
+
353
+    /**
354
+     * @param string $locale
355
+     * @return bool
356
+     */
357
+    public function localeExists($locale) {
358
+        if ($locale === 'en') { //english is always available
359
+            return true;
360
+        }
361
+
362
+        $locales = $this->findAvailableLocales();
363
+        $userLocale = array_filter($locales, function($value) use ($locale) {
364
+            return $locale === $value['code'];
365
+        });
366
+
367
+        return !empty($userLocale);
368
+    }
369
+
370
+    /**
371
+     * @param string|null $app
372
+     * @return string
373
+     * @throws LanguageNotFoundException
374
+     */
375
+    private function getLanguageFromRequest($app) {
376
+        $header = $this->request->getHeader('ACCEPT_LANGUAGE');
377
+        if ($header !== '') {
378
+            $available = $this->findAvailableLanguages($app);
379
+
380
+            // E.g. make sure that 'de' is before 'de_DE'.
381
+            sort($available);
382
+
383
+            $preferences = preg_split('/,\s*/', strtolower($header));
384
+            foreach ($preferences as $preference) {
385
+                list($preferred_language) = explode(';', $preference);
386
+                $preferred_language = str_replace('-', '_', $preferred_language);
387
+
388
+                foreach ($available as $available_language) {
389
+                    if ($preferred_language === strtolower($available_language)) {
390
+                        return $this->respectDefaultLanguage($app, $available_language);
391
+                    }
392
+                }
393
+
394
+                // Fallback from de_De to de
395
+                foreach ($available as $available_language) {
396
+                    if (substr($preferred_language, 0, 2) === $available_language) {
397
+                        return $available_language;
398
+                    }
399
+                }
400
+            }
401
+        }
402
+
403
+        throw new LanguageNotFoundException();
404
+    }
405
+
406
+    /**
407
+     * if default language is set to de_DE (formal German) this should be
408
+     * preferred to 'de' (non-formal German) if possible
409
+     *
410
+     * @param string|null $app
411
+     * @param string $lang
412
+     * @return string
413
+     */
414
+    protected function respectDefaultLanguage($app, $lang) {
415
+        $result = $lang;
416
+        $defaultLanguage = $this->config->getSystemValue('default_language', false);
417
+
418
+        // use formal version of german ("Sie" instead of "Du") if the default
419
+        // language is set to 'de_DE' if possible
420
+        if (is_string($defaultLanguage) &&
421
+            strtolower($lang) === 'de' &&
422
+            strtolower($defaultLanguage) === 'de_de' &&
423
+            $this->languageExists($app, 'de_DE')
424
+        ) {
425
+            $result = 'de_DE';
426
+        }
427
+
428
+        return $result;
429
+    }
430
+
431
+    /**
432
+     * Checks if $sub is a subdirectory of $parent
433
+     *
434
+     * @param string $sub
435
+     * @param string $parent
436
+     * @return bool
437
+     */
438
+    private function isSubDirectory($sub, $parent) {
439
+        // Check whether $sub contains no ".."
440
+        if (strpos($sub, '..') !== false) {
441
+            return false;
442
+        }
443
+
444
+        // Check whether $sub is a subdirectory of $parent
445
+        if (strpos($sub, $parent) === 0) {
446
+            return true;
447
+        }
448
+
449
+        return false;
450
+    }
451
+
452
+    /**
453
+     * Get a list of language files that should be loaded
454
+     *
455
+     * @param string $app
456
+     * @param string $lang
457
+     * @return string[]
458
+     */
459
+    // FIXME This method is only public, until OC_L10N does not need it anymore,
460
+    // FIXME This is also the reason, why it is not in the public interface
461
+    public function getL10nFilesForApp($app, $lang) {
462
+        $languageFiles = [];
463
+
464
+        $i18nDir = $this->findL10nDir($app);
465
+        $transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';
466
+
467
+        if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
468
+                || $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
469
+                || $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
470
+                || $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
471
+            )
472
+            && file_exists($transFile)) {
473
+            // load the translations file
474
+            $languageFiles[] = $transFile;
475
+        }
476
+
477
+        // merge with translations from theme
478
+        $theme = $this->config->getSystemValue('theme');
479
+        if (!empty($theme)) {
480
+            $transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
481
+            if (file_exists($transFile)) {
482
+                $languageFiles[] = $transFile;
483
+            }
484
+        }
485
+
486
+        return $languageFiles;
487
+    }
488
+
489
+    /**
490
+     * find the l10n directory
491
+     *
492
+     * @param string $app App id or empty string for core
493
+     * @return string directory
494
+     */
495
+    protected function findL10nDir($app = null) {
496
+        if (in_array($app, ['core', 'lib', 'settings'])) {
497
+            if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
498
+                return $this->serverRoot . '/' . $app . '/l10n/';
499
+            }
500
+        } else if ($app && \OC_App::getAppPath($app) !== false) {
501
+            // Check if the app is in the app folder
502
+            return \OC_App::getAppPath($app) . '/l10n/';
503
+        }
504
+        return $this->serverRoot . '/core/l10n/';
505
+    }
506
+
507
+
508
+    /**
509
+     * Creates a function from the plural string
510
+     *
511
+     * Parts of the code is copied from Habari:
512
+     * https://github.com/habari/system/blob/master/classes/locale.php
513
+     * @param string $string
514
+     * @return string
515
+     */
516
+    public function createPluralFunction($string) {
517
+        if (isset($this->pluralFunctions[$string])) {
518
+            return $this->pluralFunctions[$string];
519
+        }
520
+
521
+        if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
522
+            // sanitize
523
+            $nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
524
+            $plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );
525
+
526
+            $body = str_replace(
527
+                array( 'plural', 'n', '$n$plurals', ),
528
+                array( '$plural', '$n', '$nplurals', ),
529
+                'nplurals='. $nplurals . '; plural=' . $plural
530
+            );
531
+
532
+            // add parents
533
+            // important since PHP's ternary evaluates from left to right
534
+            $body .= ';';
535
+            $res = '';
536
+            $p = 0;
537
+            $length = strlen($body);
538
+            for($i = 0; $i < $length; $i++) {
539
+                $ch = $body[$i];
540
+                switch ( $ch ) {
541
+                    case '?':
542
+                        $res .= ' ? (';
543
+                        $p++;
544
+                        break;
545
+                    case ':':
546
+                        $res .= ') : (';
547
+                        break;
548
+                    case ';':
549
+                        $res .= str_repeat( ')', $p ) . ';';
550
+                        $p = 0;
551
+                        break;
552
+                    default:
553
+                        $res .= $ch;
554
+                }
555
+            }
556
+
557
+            $body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
558
+            $function = create_function('$n', $body);
559
+            $this->pluralFunctions[$string] = $function;
560
+            return $function;
561
+        } else {
562
+            // default: one plural form for all cases but n==1 (english)
563
+            $function = create_function(
564
+                '$n',
565
+                '$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
566
+            );
567
+            $this->pluralFunctions[$string] = $function;
568
+            return $function;
569
+        }
570
+    }
571
+
572
+    /**
573
+     * returns the common language and other languages in an
574
+     * associative array
575
+     *
576
+     * @return array
577
+     */
578
+    public function getLanguages() {
579
+        $forceLanguage = $this->config->getSystemValue('force_language', false);
580
+        if ($forceLanguage !== false) {
581
+            return [];
582
+        }
583
+
584
+        $languageCodes = $this->findAvailableLanguages();
585
+
586
+        $commonLanguages = [];
587
+        $languages = [];
588
+
589
+        foreach($languageCodes as $lang) {
590
+            $l = $this->get('lib', $lang);
591
+            // TRANSLATORS this is the language name for the language switcher in the personal settings and should be the localized version
592
+            $potentialName = (string) $l->t('__language_name__');
593
+            if ($l->getLanguageCode() === $lang && $potentialName[0] !== '_') {//first check if the language name is in the translation file
594
+                $ln = array(
595
+                    'code' => $lang,
596
+                    'name' => $potentialName
597
+                );
598
+            } else if ($lang === 'en') {
599
+                $ln = array(
600
+                    'code' => $lang,
601
+                    'name' => 'English (US)'
602
+                );
603
+            } else {//fallback to language code
604
+                $ln = array(
605
+                    'code' => $lang,
606
+                    'name' => $lang
607
+                );
608
+            }
609
+
610
+            // put appropriate languages into appropriate arrays, to print them sorted
611
+            // common languages -> divider -> other languages
612
+            if (in_array($lang, self::COMMON_LANGUAGE_CODES)) {
613
+                $commonLanguages[array_search($lang, self::COMMON_LANGUAGE_CODES)] = $ln;
614
+            } else {
615
+                $languages[] = $ln;
616
+            }
617
+        }
618
+
619
+        ksort($commonLanguages);
620
+
621
+        // sort now by displayed language not the iso-code
622
+        usort( $languages, function ($a, $b) {
623
+            if ($a['code'] === $a['name'] && $b['code'] !== $b['name']) {
624
+                // If a doesn't have a name, but b does, list b before a
625
+                return 1;
626
+            }
627
+            if ($a['code'] !== $a['name'] && $b['code'] === $b['name']) {
628
+                // If a does have a name, but b doesn't, list a before b
629
+                return -1;
630
+            }
631
+            // Otherwise compare the names
632
+            return strcmp($a['name'], $b['name']);
633
+        });
634
+
635
+        return [
636
+            // reset indexes
637
+            'commonlanguages' => array_values($commonLanguages),
638
+            'languages' => $languages
639
+        ];
640
+    }
641 641
 }
Please login to merge, or discard this patch.