summaryrefslogtreecommitdiffstats
path: root/l10n/da/files_external.po
blob: 4a0d6ece905e63fa4f0ed6195845f35bf431af29 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# 
# Translators:
# Amplificator, 2014
msgid ""
msgstr ""
"Project-Id-Version: ownCloud\n"
"Report-Msgid-Bugs-To: translations@owncloud.org\n"
"POT-Creation-Date: 2014-04-09 01:55-0400\n"
"PO-Revision-Date: 2014-04-09 05:55+0000\n"
"Last-Translator: I Robot\n"
"Language-Team: Danish (http://www.transifex.com/projects/p/owncloud/language/da/)\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: da\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"

#: js/dropbox.js:7 js/dropbox.js:29 js/google.js:8 js/google.js:40
msgid "Access granted"
msgstr "Adgang godkendt"

#: js/dropbox.js:33 js/dropbox.js:97 js/dropbox.js:103
msgid "Error configuring Dropbox storage"
msgstr "Fejl ved konfiguration af Dropbox plads"

#: js/dropbox.js:68 js/google.js:89
msgid "Grant access"
msgstr "Godkend adgang"

#: js/dropbox.js:102
msgid "Please provide a valid Dropbox app key and secret."
msgstr "Angiv venligst en valid Dropbox app nøgle og hemmelighed"

#: js/google.js:45 js/google.js:122
msgid "Error configuring Google Drive storage"
msgstr "Fejl ved konfiguration af Google Drive plads"

#: js/settings.js:318 js/settings.js:325
msgid "Saved"
msgstr "Gemt"

#: lib/config.php:592
msgid "<b>Note:</b> "
msgstr ""

#: lib/config.php:602
msgid " and "
msgstr ""

#: lib/config.php:624
#, php-format
msgid ""
"<b>Note:</b> The cURL support in PHP is not enabled or installed. Mounting "
"of %s is not possible. Please ask your system administrator to install it."
msgstr ""

#: lib/config.php:626
#, php-format
msgid ""
"<b>Note:</b> The FTP support in PHP is not enabled or installed. Mounting of"
" %s is not possible. Please ask your system administrator to install it."
msgstr ""

#: lib/config.php:628
#, php-format
msgid ""
"<b>Note:</b> \"%s\" is not installed. Mounting of %s is not possible. Please"
" ask your system administrator to install it."
msgstr ""

#: templates/settings.php:2
msgid "External Storage"
msgstr "Ekstern opbevaring"

#: templates/settings.php:8 templates/settings.php:27
msgid "Folder name"
msgstr "Mappenavn"

#: templates/settings.php:9
msgid "External storage"
msgstr "Eksternt lager"

#: templates/settings.php:10
msgid "Configuration"
msgstr "Opsætning"

#: templates/settings.php:11
msgid "Options"
msgstr "Valgmuligheder"

#: templates/settings.php:12
msgid "Available for"
msgstr ""

#: templates/settings.php:32
msgid "Add storage"
msgstr "Tilføj lager"

#: templates/settings.php:92
msgid "No user or group"
msgstr ""

#: templates/settings.php:95
msgid "All Users"
msgstr "Alle brugere"

#: templates/settings.php:97
msgid "Groups"
msgstr "Grupper"

#: templates/settings.php:105
msgid "Users"
msgstr "Brugere"

#: templates/settings.php:118 templates/settings.php:119
#: templates/settings.php:158 templates/settings.php:159
msgid "Delete"
msgstr "Slet"

#: templates/settings.php:132
msgid "Enable User External Storage"
msgstr "Aktiver ekstern opbevaring for brugere"

#: templates/settings.php:135
msgid "Allow users to mount the following external storage"
msgstr "Tillad brugere at montere følgende som eksternt lager"

#: templates/settings.php:150
msgid "SSL root certificates"
msgstr "SSL-rodcertifikater"

#: templates/settings.php:168
msgid "Import Root Certificate"
msgstr "Importer rodcertifikat"
53' href='#n553'>553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
<?php
/**
 * @copyright Copyright (c) 2016, ownCloud, Inc.
 * @copyright 2016 Roeland Jago Douma <roeland@famdouma.nl>
 * @copyright 2016 Lukas Reschke <lukas@statuscode.ch>
 *
 * @author Bart Visscher <bartv@thisnet.nl>
 * @author Joas Schilling <coding@schilljs.com>
 * @author Lukas Reschke <lukas@statuscode.ch>
 * @author Morris Jobke <hey@morrisjobke.de>
 * @author Robin Appelman <robin@icewind.nl>
 * @author Robin McCorkell <robin@mccorkell.me.uk>
 * @author Roeland Jago Douma <roeland@famdouma.nl>
 *
 * @license AGPL-3.0
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

namespace OC\L10N;

use OCP\IConfig;
use OCP\IRequest;
use OCP\IUser;
use OCP\IUserSession;
use OCP\L10N\IFactory;
use OCP\L10N\ILanguageIterator;

/**
 * A factory that generates language instances
 */
class Factory implements IFactory {

	/** @var string */
	protected $requestLanguage = '';

	/**
	 * cached instances
	 * @var array Structure: Lang => App => \OCP\IL10N
	 */
	protected $instances = [];

	/**
	 * @var array Structure: App => string[]
	 */
	protected $availableLanguages = [];

	/**
	 * @var array
	 */
	protected $availableLocales = [];

	/**
	 * @var array Structure: string => callable
	 */
	protected $pluralFunctions = [];

	const COMMON_LANGUAGE_CODES = [
		'en', 'es', 'fr', 'de', 'de_DE', 'ja', 'ar', 'ru', 'nl', 'it',
		'pt_BR', 'pt_PT', 'da', 'fi_FI', 'nb_NO', 'sv', 'tr', 'zh_CN', 'ko'
	];

	/** @var IConfig */
	protected $config;

	/** @var IRequest */
	protected $request;

	/** @var IUserSession */
	protected $userSession;

	/** @var string */
	protected $serverRoot;

	/**
	 * @param IConfig $config
	 * @param IRequest $request
	 * @param IUserSession $userSession
	 * @param string $serverRoot
	 */
	public function __construct(IConfig $config,
								IRequest $request,
								IUserSession $userSession,
								$serverRoot) {
		$this->config = $config;
		$this->request = $request;
		$this->userSession = $userSession;
		$this->serverRoot = $serverRoot;
	}

	/**
	 * Get a language instance
	 *
	 * @param string $app
	 * @param string|null $lang
	 * @param string|null $locale
	 * @return \OCP\IL10N
	 */
	public function get($app, $lang = null, $locale = null) {
		return new LazyL10N(function() use ($app, $lang, $locale) {

			$app = \OC_App::cleanAppId($app);
			if ($lang !== null) {
				$lang = str_replace(array('\0', '/', '\\', '..'), '', (string)$lang);
			}

			$forceLang = $this->config->getSystemValue('force_language', false);
			if (is_string($forceLang)) {
				$lang = $forceLang;
			}

			$forceLocale = $this->config->getSystemValue('force_locale', false);
			if (is_string($forceLocale)) {
				$locale = $forceLocale;
			}

			if ($lang === null || !$this->languageExists($app, $lang)) {
				$lang = $this->findLanguage($app);
			}

			if ($locale === null || !$this->localeExists($locale)) {
				$locale = $this->findLocale($lang);
			}

			if (!isset($this->instances[$lang][$app])) {
				$this->instances[$lang][$app] = new L10N(
					$this, $app, $lang, $locale,
					$this->getL10nFilesForApp($app, $lang)
				);
			}

			return $this->instances[$lang][$app];
		});
	}

	/**
	 * Find the best language
	 *
	 * @param string|null $app App id or null for core
	 * @return string language If nothing works it returns 'en'
	 */
	public function findLanguage($app = null) {
		$forceLang = $this->config->getSystemValue('force_language', false);
		if (is_string($forceLang)) {
			$this->requestLanguage = $forceLang;
		}

		if ($this->requestLanguage !== '' && $this->languageExists($app, $this->requestLanguage)) {
			return $this->requestLanguage;
		}

		/**
		 * 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
		 *
		 * @link https://github.com/owncloud/core/issues/21955
		 */
		if ($this->config->getSystemValue('installed', false)) {
			$userId = !is_null($this->userSession->getUser()) ? $this->userSession->getUser()->getUID() :  null;
			if (!is_null($userId)) {
				$userLang = $this->config->getUserValue($userId, 'core', 'lang', null);
			} else {
				$userLang = null;
			}
		} else {
			$userId = null;
			$userLang = null;
		}

		if ($userLang) {
			$this->requestLanguage = $userLang;
			if ($this->languageExists($app, $userLang)) {
				return $userLang;
			}
		}

		try {
			// Try to get the language from the Request
			$lang = $this->getLanguageFromRequest($app);
			if ($userId !== null && $app === 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)) {
				return $defaultLanguage;
			}
		}

		// We could not find any language so fall back to english
		return 'en';
	}

	/**
	 * find the best locale
	 *
	 * @param string $lang
	 * @return null|string
	 */
	public function findLocale($lang = null) {
		$forceLocale = $this->config->getSystemValue('force_locale', false);
		if (is_string($forceLocale) && $this->localeExists($forceLocale)) {
			return $forceLocale;
		}

		if ($this->config->getSystemValue('installed', false)) {
			$userId = null !== $this->userSession->getUser() ? $this->userSession->getUser()->getUID() :  null;
			$userLocale = null;
			if (null !== $userId) {
				$userLocale = $this->config->getUserValue($userId, 'core', 'locale', null);
			}
		} else {
			$userId = null;
			$userLocale = null;
		}

		if ($userLocale && $this->localeExists($userLocale)) {
			return $userLocale;
		}

		// Default : use system default locale
		$defaultLocale = $this->config->getSystemValue('default_locale', false);
		if ($defaultLocale !== false && $this->localeExists($defaultLocale)) {
			return $defaultLocale;
		}

		// If no user locale set, use lang as locale
		if (null !== $lang && $this->localeExists($lang)) {
			return $lang;
		}

		// At last, return USA
		return 'en_US';
	}

	/**
	 * find the matching lang from the locale
	 *
	 * @param string $app
	 * @param string $locale
	 * @return null|string
	 */
	public function findLanguageFromLocale(string $app = 'core', string $locale = null) {
		if ($this->languageExists($app, $locale)) {
			return $locale;
		}
		
		// Try to split e.g: fr_FR => fr
		$locale = explode('_', $locale)[0];
		if ($this->languageExists($app, $locale)) {
			return $locale;
		}
	}

	/**
	 * Find all available languages for an app
	 *
	 * @param string|null $app App id or null for core
	 * @return array an array of available languages
	 */
	public function findAvailableLanguages($app = null) {
		$key = $app;
		if ($key === null) {
			$key = 'null';
		}

		// also works with null as key
		if (!empty($this->availableLanguages[$key])) {
			return $this->availableLanguages[$key];
		}

		$available = ['en']; //english is always available
		$dir = $this->findL10nDir($app);
		if (is_dir($dir)) {
			$files = scandir($dir);
			if ($files !== false) {
				foreach ($files as $file) {
					if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
						$available[] = substr($file, 0, -5);
					}
				}
			}
		}

		// merge with translations from theme
		$theme = $this->config->getSystemValue('theme');
		if (!empty($theme)) {
			$themeDir = $this->serverRoot . '/themes/' . $theme . substr($dir, strlen($this->serverRoot));

			if (is_dir($themeDir)) {
				$files = scandir($themeDir);
				if ($files !== false) {
					foreach ($files as $file) {
						if (substr($file, -5) === '.json' && substr($file, 0, 4) !== 'l10n') {
							$available[] = substr($file, 0, -5);
						}
					}
				}
			}
		}

		$this->availableLanguages[$key] = $available;
		return $available;
	}

	/**
	 * @return array|mixed
	 */
	public function findAvailableLocales() {
		if (!empty($this->availableLocales)) {
			return $this->availableLocales;
		}

		$localeData = file_get_contents(\OC::$SERVERROOT . '/resources/locales.json');
		$this->availableLocales = \json_decode($localeData, true);

		return $this->availableLocales;
	}

	/**
	 * @param string|null $app App id or null for core
	 * @param string $lang
	 * @return bool
	 */
	public function languageExists($app, $lang) {
		if ($lang === 'en') {//english is always available
			return true;
		}

		$languages = $this->findAvailableLanguages($app);
		return array_search($lang, $languages) !== false;
	}

	public function getLanguageIterator(IUser $user = null): ILanguageIterator {
		$user = $user ?? $this->userSession->getUser();
		if($user === null) {
			throw new \RuntimeException('Failed to get an IUser instance');
		}
		return new LanguageIterator($user, $this->config);
	}

	/**
	 * @param string $locale
	 * @return bool
	 */
	public function localeExists($locale) {
		if ($locale === 'en') { //english is always available
			return true;
		}

		$locales = $this->findAvailableLocales();
		$userLocale = array_filter($locales, function($value) use ($locale) {
			return $locale === $value['code'];
		});

		return !empty($userLocale);
	}

	/**
	 * @param string|null $app
	 * @return string
	 * @throws LanguageNotFoundException
	 */
	private function getLanguageFromRequest($app) {
		$header = $this->request->getHeader('ACCEPT_LANGUAGE');
		if ($header !== '') {
			$available = $this->findAvailableLanguages($app);

			// E.g. make sure that 'de' is before 'de_DE'.
			sort($available);

			$preferences = preg_split('/,\s*/', strtolower($header));
			foreach ($preferences as $preference) {
				list($preferred_language) = explode(';', $preference);
				$preferred_language = str_replace('-', '_', $preferred_language);

				foreach ($available as $available_language) {
					if ($preferred_language === strtolower($available_language)) {
						return $this->respectDefaultLanguage($app, $available_language);
					}
				}

				// Fallback from de_De to de
				foreach ($available as $available_language) {
					if (substr($preferred_language, 0, 2) === $available_language) {
						return $available_language;
					}
				}
			}
		}

		throw new LanguageNotFoundException();
	}

	/**
	 * 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) {
		$result = $lang;
		$defaultLanguage = $this->config->getSystemValue('default_language', false);

		// use formal version of german ("Sie" instead of "Du") if the default
		// language is set to 'de_DE' if possible
		if (is_string($defaultLanguage) &&
			strtolower($lang) === 'de' &&
			strtolower($defaultLanguage) === 'de_de' &&
			$this->languageExists($app, 'de_DE')
		) {
			$result = 'de_DE';
		}

		return $result;
	}

	/**
	 * Checks if $sub is a subdirectory of $parent
	 *
	 * @param string $sub
	 * @param string $parent
	 * @return bool
	 */
	private function isSubDirectory($sub, $parent) {
		// Check whether $sub contains no ".."
		if (strpos($sub, '..') !== false) {
			return false;
		}

		// Check whether $sub is a subdirectory of $parent
		if (strpos($sub, $parent) === 0) {
			return true;
		}

		return false;
	}

	/**
	 * Get a list of language files that should be loaded
	 *
	 * @param string $app
	 * @param string $lang
	 * @return string[]
	 */
	// FIXME This method is only public, until OC_L10N does not need it anymore,
	// FIXME This is also the reason, why it is not in the public interface
	public function getL10nFilesForApp($app, $lang) {
		$languageFiles = [];

		$i18nDir = $this->findL10nDir($app);
		$transFile = strip_tags($i18nDir) . strip_tags($lang) . '.json';

		if (($this->isSubDirectory($transFile, $this->serverRoot . '/core/l10n/')
				|| $this->isSubDirectory($transFile, $this->serverRoot . '/lib/l10n/')
				|| $this->isSubDirectory($transFile, $this->serverRoot . '/settings/l10n/')
				|| $this->isSubDirectory($transFile, \OC_App::getAppPath($app) . '/l10n/')
			)
			&& file_exists($transFile)) {
			// load the translations file
			$languageFiles[] = $transFile;
		}

		// merge with translations from theme
		$theme = $this->config->getSystemValue('theme');
		if (!empty($theme)) {
			$transFile = $this->serverRoot . '/themes/' . $theme . substr($transFile, strlen($this->serverRoot));
			if (file_exists($transFile)) {
				$languageFiles[] = $transFile;
			}
		}

		return $languageFiles;
	}

	/**
	 * find the l10n directory
	 *
	 * @param string $app App id or empty string for core
	 * @return string directory
	 */
	protected function findL10nDir($app = null) {
		if (in_array($app, ['core', 'lib', 'settings'])) {
			if (file_exists($this->serverRoot . '/' . $app . '/l10n/')) {
				return $this->serverRoot . '/' . $app . '/l10n/';
			}
		} else if ($app && \OC_App::getAppPath($app) !== false) {
			// Check if the app is in the app folder
			return \OC_App::getAppPath($app) . '/l10n/';
		}
		return $this->serverRoot . '/core/l10n/';
	}


	/**
	 * Creates a function from the plural string
	 *
	 * Parts of the code is copied from Habari:
	 * https://github.com/habari/system/blob/master/classes/locale.php
	 * @param string $string
	 * @return string
	 */
	public function createPluralFunction($string) {
		if (isset($this->pluralFunctions[$string])) {
			return $this->pluralFunctions[$string];
		}

		if (preg_match( '/^\s*nplurals\s*=\s*(\d+)\s*;\s*plural=(.*)$/u', $string, $matches)) {
			// sanitize
			$nplurals = preg_replace( '/[^0-9]/', '', $matches[1] );
			$plural = preg_replace( '#[^n0-9:\(\)\?\|\&=!<>+*/\%-]#', '', $matches[2] );

			$body = str_replace(
				array( 'plural', 'n', '$n$plurals', ),
				array( '$plural', '$n', '$nplurals', ),
				'nplurals='. $nplurals . '; plural=' . $plural
			);

			// add parents
			// important since PHP's ternary evaluates from left to right
			$body .= ';';
			$res = '';
			$p = 0;
			$length = strlen($body);
			for($i = 0; $i < $length; $i++) {
				$ch = $body[$i];
				switch ( $ch ) {
					case '?':
						$res .= ' ? (';
						$p++;
						break;
					case ':':
						$res .= ') : (';
						break;
					case ';':
						$res .= str_repeat( ')', $p ) . ';';
						$p = 0;
						break;
					default:
						$res .= $ch;
				}
			}

			$body = $res . 'return ($plural>=$nplurals?$nplurals-1:$plural);';
			$function = create_function('$n', $body);
			$this->pluralFunctions[$string] = $function;
			return $function;
		} else {
			// default: one plural form for all cases but n==1 (english)
			$function = create_function(
				'$n',
				'$nplurals=2;$plural=($n==1?0:1);return ($plural>=$nplurals?$nplurals-1:$plural);'
			);
			$this->pluralFunctions[$string] = $function;
			return $function;
		}
	}

	/**
	 * returns the common language and other languages in an
	 * associative array
	 *
	 * @return array
	 */
	public function getLanguages() {
		$forceLanguage = $this->config->getSystemValue('force_language', false);
		if ($forceLanguage !== false) {
			return [];
		}

		$languageCodes = $this->findAvailableLanguages();

		$commonLanguages = [];
		$languages = [];

		foreach($languageCodes as $lang) {
			$l = $this->get('lib', $lang);
			// TRANSLATORS this is the language name for the language switcher in the personal settings and should be the localized version
			$potentialName = (string) $l->t('__language_name__');
			if ($l->getLanguageCode() === $lang && $potentialName[0] !== '_') {//first check if the language name is in the translation file
				$ln = array(
					'code' => $lang,
					'name' => $potentialName
				);
			} else if ($lang === 'en') {
				$ln = array(
					'code' => $lang,
					'name' => 'English (US)'
				);
			} else {//fallback to language code
				$ln = array(
					'code' => $lang,
					'name' => $lang
				);
			}

			// put appropriate languages into appropriate arrays, to print them sorted
			// common languages -> divider -> other languages
			if (in_array($lang, self::COMMON_LANGUAGE_CODES)) {
				$commonLanguages[array_search($lang, self::COMMON_LANGUAGE_CODES)] = $ln;
			} else {
				$languages[] = $ln;
			}
		}

		ksort($commonLanguages);

		// sort now by displayed language not the iso-code
		usort( $languages, function ($a, $b) {
			if ($a['code'] === $a['name'] && $b['code'] !== $b['name']) {
				// If a doesn't have a name, but b does, list b before a
				return 1;
			}
			if ($a['code'] !== $a['name'] && $b['code'] === $b['name']) {
				// If a does have a name, but b doesn't, list a before b
				return -1;
			}
			// Otherwise compare the names
			return strcmp($a['name'], $b['name']);
		});

		return [
			// reset indexes
			'commonlanguages' => array_values($commonLanguages),
			'languages' => $languages
		];
	}
}