diff options
Diffstat (limited to 'apps/user_status')
206 files changed, 6493 insertions, 4346 deletions
diff --git a/apps/user_status/.l10nignore b/apps/user_status/.l10nignore index ea53c49c185..91aefac85dc 100644 --- a/apps/user_status/.l10nignore +++ b/apps/user_status/.l10nignore @@ -1,2 +1,4 @@ +# SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors +# SPDX-License-Identifier: AGPL-3.0-or-later #webpack bundled files js/ diff --git a/apps/user_status/appinfo/info.xml b/apps/user_status/appinfo/info.xml index c385886e946..0f9b5235f7c 100644 --- a/apps/user_status/appinfo/info.xml +++ b/apps/user_status/appinfo/info.xml @@ -1,30 +1,35 @@ <?xml version="1.0"?> +<!-- + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later + --> <info xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="https://apps.nextcloud.com/schema/apps/info.xsd"> <id>user_status</id> <name>User status</name> <summary>User status</summary> <description><![CDATA[User status]]></description> - <version>1.5.0</version> + <version>1.12.0</version> <licence>agpl</licence> <author mail="oc.list@georgehrke.com" >Georg Ehrke</author> <namespace>UserStatus</namespace> - <default_enable/> <category>social</category> <bugs>https://github.com/nextcloud/server</bugs> <navigations> <navigation> - <id>user_status-menuitem</id> + <id>user_status-menu-entry</id> <name>User status</name> - <route /> <order>1</order> <type>settings</type> </navigation> </navigations> <dependencies> - <nextcloud min-version="25" max-version="25"/> + <nextcloud min-version="32" max-version="32"/> </dependencies> <background-jobs> <job>OCA\UserStatus\BackgroundJob\ClearOldStatusesBackgroundJob</job> </background-jobs> + <contactsmenu> + <provider>OCA\UserStatus\ContactsMenu\StatusProvider</provider> + </contactsmenu> </info> diff --git a/apps/user_status/appinfo/routes.php b/apps/user_status/appinfo/routes.php deleted file mode 100644 index d360dc1ebd5..00000000000 --- a/apps/user_status/appinfo/routes.php +++ /dev/null @@ -1,43 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -return [ - 'ocs' => [ - // Routes for querying statuses - ['name' => 'Statuses#findAll', 'url' => '/api/v1/statuses', 'verb' => 'GET'], - ['name' => 'Statuses#find', 'url' => '/api/v1/statuses/{userId}', 'verb' => 'GET'], - // Routes for manipulating your own status - ['name' => 'UserStatus#getStatus', 'url' => '/api/v1/user_status', 'verb' => 'GET'], - ['name' => 'UserStatus#setStatus', 'url' => '/api/v1/user_status/status', 'verb' => 'PUT'], - ['name' => 'UserStatus#setPredefinedMessage', 'url' => '/api/v1/user_status/message/predefined', 'verb' => 'PUT'], - ['name' => 'UserStatus#setCustomMessage', 'url' => '/api/v1/user_status/message/custom', 'verb' => 'PUT'], - ['name' => 'UserStatus#clearMessage', 'url' => '/api/v1/user_status/message', 'verb' => 'DELETE'], - // Routes for listing default routes - ['name' => 'PredefinedStatus#findAll', 'url' => '/api/v1/predefined_statuses/', 'verb' => 'GET'] - ], - 'routes' => [ - ['name' => 'Heartbeat#heartbeat', 'url' => '/heartbeat', 'verb' => 'PUT'], - ], -]; diff --git a/apps/user_status/composer/autoload.php b/apps/user_status/composer/autoload.php index a82d4105451..afd560d3ae9 100644 --- a/apps/user_status/composer/autoload.php +++ b/apps/user_status/composer/autoload.php @@ -3,8 +3,21 @@ // autoload.php @generated by Composer if (PHP_VERSION_ID < 50600) { - echo 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; - exit(1); + if (!headers_sent()) { + header('HTTP/1.1 500 Internal Server Error'); + } + $err = 'Composer 2.3.0 dropped support for autoloading on PHP <5.6 and you are running '.PHP_VERSION.', please upgrade PHP or use Composer 2.2 LTS via "composer self-update --2.2". Aborting.'.PHP_EOL; + if (!ini_get('display_errors')) { + if (PHP_SAPI === 'cli' || PHP_SAPI === 'phpdbg') { + fwrite(STDERR, $err); + } elseif (!headers_sent()) { + echo $err; + } + } + trigger_error( + $err, + E_USER_ERROR + ); } require_once __DIR__ . '/composer/autoload_real.php'; diff --git a/apps/user_status/composer/composer/ClassLoader.php b/apps/user_status/composer/composer/ClassLoader.php index afef3fa2ad8..7824d8f7eaf 100644 --- a/apps/user_status/composer/composer/ClassLoader.php +++ b/apps/user_status/composer/composer/ClassLoader.php @@ -42,35 +42,37 @@ namespace Composer\Autoload; */ class ClassLoader { - /** @var ?string */ + /** @var \Closure(string):void */ + private static $includeFile; + + /** @var string|null */ private $vendorDir; // PSR-4 /** - * @var array[] - * @psalm-var array<string, array<string, int>> + * @var array<string, array<string, int>> */ private $prefixLengthsPsr4 = array(); /** - * @var array[] - * @psalm-var array<string, array<int, string>> + * @var array<string, list<string>> */ private $prefixDirsPsr4 = array(); /** - * @var array[] - * @psalm-var array<string, string> + * @var list<string> */ private $fallbackDirsPsr4 = array(); // PSR-0 /** - * @var array[] - * @psalm-var array<string, array<string, string[]>> + * List of PSR-0 prefixes + * + * Structured as array('F (first letter)' => array('Foo\Bar (full prefix)' => array('path', 'path2'))) + * + * @var array<string, array<string, list<string>>> */ private $prefixesPsr0 = array(); /** - * @var array[] - * @psalm-var array<string, string> + * @var list<string> */ private $fallbackDirsPsr0 = array(); @@ -78,8 +80,7 @@ class ClassLoader private $useIncludePath = false; /** - * @var string[] - * @psalm-var array<string, string> + * @var array<string, string> */ private $classMap = array(); @@ -87,29 +88,29 @@ class ClassLoader private $classMapAuthoritative = false; /** - * @var bool[] - * @psalm-var array<string, bool> + * @var array<string, bool> */ private $missingClasses = array(); - /** @var ?string */ + /** @var string|null */ private $apcuPrefix; /** - * @var self[] + * @var array<string, self> */ private static $registeredLoaders = array(); /** - * @param ?string $vendorDir + * @param string|null $vendorDir */ public function __construct($vendorDir = null) { $this->vendorDir = $vendorDir; + self::initializeIncludeClosure(); } /** - * @return string[] + * @return array<string, list<string>> */ public function getPrefixes() { @@ -121,8 +122,7 @@ class ClassLoader } /** - * @return array[] - * @psalm-return array<string, array<int, string>> + * @return array<string, list<string>> */ public function getPrefixesPsr4() { @@ -130,8 +130,7 @@ class ClassLoader } /** - * @return array[] - * @psalm-return array<string, string> + * @return list<string> */ public function getFallbackDirs() { @@ -139,8 +138,7 @@ class ClassLoader } /** - * @return array[] - * @psalm-return array<string, string> + * @return list<string> */ public function getFallbackDirsPsr4() { @@ -148,8 +146,7 @@ class ClassLoader } /** - * @return string[] Array of classname => path - * @psalm-return array<string, string> + * @return array<string, string> Array of classname => path */ public function getClassMap() { @@ -157,8 +154,7 @@ class ClassLoader } /** - * @param string[] $classMap Class to filename map - * @psalm-param array<string, string> $classMap + * @param array<string, string> $classMap Class to filename map * * @return void */ @@ -175,24 +171,25 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, either * appending or prepending to the ones previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 root directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix + * @param list<string>|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories * * @return void */ public function add($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { if ($prepend) { $this->fallbackDirsPsr0 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr0 ); } else { $this->fallbackDirsPsr0 = array_merge( $this->fallbackDirsPsr0, - (array) $paths + $paths ); } @@ -201,19 +198,19 @@ class ClassLoader $first = $prefix[0]; if (!isset($this->prefixesPsr0[$first][$prefix])) { - $this->prefixesPsr0[$first][$prefix] = (array) $paths; + $this->prefixesPsr0[$first][$prefix] = $paths; return; } if ($prepend) { $this->prefixesPsr0[$first][$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixesPsr0[$first][$prefix] ); } else { $this->prefixesPsr0[$first][$prefix] = array_merge( $this->prefixesPsr0[$first][$prefix], - (array) $paths + $paths ); } } @@ -222,9 +219,9 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, either * appending or prepending to the ones previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories - * @param bool $prepend Whether to prepend the directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list<string>|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories * * @throws \InvalidArgumentException * @@ -232,17 +229,18 @@ class ClassLoader */ public function addPsr4($prefix, $paths, $prepend = false) { + $paths = (array) $paths; if (!$prefix) { // Register directories for the root namespace. if ($prepend) { $this->fallbackDirsPsr4 = array_merge( - (array) $paths, + $paths, $this->fallbackDirsPsr4 ); } else { $this->fallbackDirsPsr4 = array_merge( $this->fallbackDirsPsr4, - (array) $paths + $paths ); } } elseif (!isset($this->prefixDirsPsr4[$prefix])) { @@ -252,18 +250,18 @@ class ClassLoader throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); } $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; - $this->prefixDirsPsr4[$prefix] = (array) $paths; + $this->prefixDirsPsr4[$prefix] = $paths; } elseif ($prepend) { // Prepend directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( - (array) $paths, + $paths, $this->prefixDirsPsr4[$prefix] ); } else { // Append directories for an already registered namespace. $this->prefixDirsPsr4[$prefix] = array_merge( $this->prefixDirsPsr4[$prefix], - (array) $paths + $paths ); } } @@ -272,8 +270,8 @@ class ClassLoader * Registers a set of PSR-0 directories for a given prefix, * replacing any others previously set for this prefix. * - * @param string $prefix The prefix - * @param string[]|string $paths The PSR-0 base directories + * @param string $prefix The prefix + * @param list<string>|string $paths The PSR-0 base directories * * @return void */ @@ -290,8 +288,8 @@ class ClassLoader * Registers a set of PSR-4 directories for a given namespace, * replacing any others previously set for this namespace. * - * @param string $prefix The prefix/namespace, with trailing '\\' - * @param string[]|string $paths The PSR-4 base directories + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param list<string>|string $paths The PSR-4 base directories * * @throws \InvalidArgumentException * @@ -425,7 +423,8 @@ class ClassLoader public function loadClass($class) { if ($file = $this->findFile($class)) { - includeFile($file); + $includeFile = self::$includeFile; + $includeFile($file); return true; } @@ -476,9 +475,9 @@ class ClassLoader } /** - * Returns the currently registered loaders indexed by their corresponding vendor directories. + * Returns the currently registered loaders keyed by their corresponding vendor directories. * - * @return self[] + * @return array<string, self> */ public static function getRegisteredLoaders() { @@ -555,18 +554,26 @@ class ClassLoader return false; } -} -/** - * Scope isolated include. - * - * Prevents access to $this/self from included files. - * - * @param string $file - * @return void - * @private - */ -function includeFile($file) -{ - include $file; + /** + * @return void + */ + private static function initializeIncludeClosure() + { + if (self::$includeFile !== null) { + return; + } + + /** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + * + * @param string $file + * @return void + */ + self::$includeFile = \Closure::bind(static function($file) { + include $file; + }, null, null); + } } diff --git a/apps/user_status/composer/composer/InstalledVersions.php b/apps/user_status/composer/composer/InstalledVersions.php index 41bc143c114..51e734a774b 100644 --- a/apps/user_status/composer/composer/InstalledVersions.php +++ b/apps/user_status/composer/composer/InstalledVersions.php @@ -28,7 +28,7 @@ class InstalledVersions { /** * @var mixed[]|null - * @psalm-var array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}|array{}|null + * @psalm-var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}|array{}|null */ private static $installed; @@ -39,7 +39,7 @@ class InstalledVersions /** * @var array[] - * @psalm-var array<string, array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-var array<string, array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */ private static $installedByVendor = array(); @@ -98,7 +98,7 @@ class InstalledVersions { foreach (self::getInstalled() as $installed) { if (isset($installed['versions'][$packageName])) { - return $includeDevRequirements || empty($installed['versions'][$packageName]['dev_requirement']); + return $includeDevRequirements || !isset($installed['versions'][$packageName]['dev_requirement']) || $installed['versions'][$packageName]['dev_requirement'] === false; } } @@ -119,7 +119,7 @@ class InstalledVersions */ public static function satisfies(VersionParser $parser, $packageName, $constraint) { - $constraint = $parser->parseConstraints($constraint); + $constraint = $parser->parseConstraints((string) $constraint); $provided = $parser->parseConstraints(self::getVersionRanges($packageName)); return $provided->matches($constraint); @@ -243,7 +243,7 @@ class InstalledVersions /** * @return array - * @psalm-return array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string} + * @psalm-return array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool} */ public static function getRootPackage() { @@ -257,7 +257,7 @@ class InstalledVersions * * @deprecated Use getAllRawData() instead which returns all datasets for all autoloaders present in the process. getRawData only returns the first dataset loaded, which may not be what you expect. * @return array[] - * @psalm-return array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} + * @psalm-return array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} */ public static function getRawData() { @@ -280,7 +280,7 @@ class InstalledVersions * Returns the raw data of all installed.php which are currently loaded for custom implementations * * @return array[] - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */ public static function getAllRawData() { @@ -303,7 +303,7 @@ class InstalledVersions * @param array[] $data A vendor/composer/installed.php data set * @return void * - * @psalm-param array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>} $data + * @psalm-param array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $data */ public static function reload($data) { @@ -313,7 +313,7 @@ class InstalledVersions /** * @return array[] - * @psalm-return list<array{root: array{name: string, version: string, reference: string, pretty_version: string, aliases: string[], dev: bool, install_path: string, type: string}, versions: array<string, array{dev_requirement: bool, pretty_version?: string, version?: string, aliases?: string[], reference?: string, replaced?: string[], provided?: string[], install_path?: string, type?: string}>}> + * @psalm-return list<array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>}> */ private static function getInstalled() { @@ -328,7 +328,9 @@ class InstalledVersions if (isset(self::$installedByVendor[$vendorDir])) { $installed[] = self::$installedByVendor[$vendorDir]; } elseif (is_file($vendorDir.'/composer/installed.php')) { - $installed[] = self::$installedByVendor[$vendorDir] = require $vendorDir.'/composer/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ + $required = require $vendorDir.'/composer/installed.php'; + $installed[] = self::$installedByVendor[$vendorDir] = $required; if (null === self::$installed && strtr($vendorDir.'/composer', '\\', '/') === strtr(__DIR__, '\\', '/')) { self::$installed = $installed[count($installed) - 1]; } @@ -340,12 +342,17 @@ class InstalledVersions // only require the installed.php file if this file is loaded from its dumped location, // and not from its source location in the composer/composer package, see https://github.com/composer/composer/issues/9937 if (substr(__DIR__, -8, 1) !== 'C') { - self::$installed = require __DIR__ . '/installed.php'; + /** @var array{root: array{name: string, pretty_version: string, version: string, reference: string|null, type: string, install_path: string, aliases: string[], dev: bool}, versions: array<string, array{pretty_version?: string, version?: string, reference?: string|null, type?: string, install_path?: string, aliases?: string[], dev_requirement: bool, replaced?: string[], provided?: string[]}>} $required */ + $required = require __DIR__ . '/installed.php'; + self::$installed = $required; } else { self::$installed = array(); } } - $installed[] = self::$installed; + + if (self::$installed !== array()) { + $installed[] = self::$installed; + } return $installed; } diff --git a/apps/user_status/composer/composer/autoload_classmap.php b/apps/user_status/composer/composer/autoload_classmap.php index 64da04fb8ba..b57df813bc9 100644 --- a/apps/user_status/composer/composer/autoload_classmap.php +++ b/apps/user_status/composer/composer/autoload_classmap.php @@ -12,6 +12,7 @@ return array( 'OCA\\UserStatus\\Capabilities' => $baseDir . '/../lib/Capabilities.php', 'OCA\\UserStatus\\Connector\\UserStatus' => $baseDir . '/../lib/Connector/UserStatus.php', 'OCA\\UserStatus\\Connector\\UserStatusProvider' => $baseDir . '/../lib/Connector/UserStatusProvider.php', + 'OCA\\UserStatus\\ContactsMenu\\StatusProvider' => $baseDir . '/../lib/ContactsMenu/StatusProvider.php', 'OCA\\UserStatus\\Controller\\HeartbeatController' => $baseDir . '/../lib/Controller/HeartbeatController.php', 'OCA\\UserStatus\\Controller\\PredefinedStatusController' => $baseDir . '/../lib/Controller/PredefinedStatusController.php', 'OCA\\UserStatus\\Controller\\StatusesController' => $baseDir . '/../lib/Controller/StatusesController.php', @@ -25,13 +26,15 @@ return array( 'OCA\\UserStatus\\Exception\\InvalidStatusTypeException' => $baseDir . '/../lib/Exception/InvalidStatusTypeException.php', 'OCA\\UserStatus\\Exception\\StatusMessageTooLongException' => $baseDir . '/../lib/Exception/StatusMessageTooLongException.php', 'OCA\\UserStatus\\Listener\\BeforeTemplateRenderedListener' => $baseDir . '/../lib/Listener/BeforeTemplateRenderedListener.php', + 'OCA\\UserStatus\\Listener\\OutOfOfficeStatusListener' => $baseDir . '/../lib/Listener/OutOfOfficeStatusListener.php', 'OCA\\UserStatus\\Listener\\UserDeletedListener' => $baseDir . '/../lib/Listener/UserDeletedListener.php', 'OCA\\UserStatus\\Listener\\UserLiveStatusListener' => $baseDir . '/../lib/Listener/UserLiveStatusListener.php', 'OCA\\UserStatus\\Migration\\Version0001Date20200602134824' => $baseDir . '/../lib/Migration/Version0001Date20200602134824.php', 'OCA\\UserStatus\\Migration\\Version0002Date20200902144824' => $baseDir . '/../lib/Migration/Version0002Date20200902144824.php', 'OCA\\UserStatus\\Migration\\Version1000Date20201111130204' => $baseDir . '/../lib/Migration/Version1000Date20201111130204.php', - 'OCA\\UserStatus\\Migration\\Version2301Date20210809144824' => $baseDir . '/../lib/Migration/Version2301Date20210809144824.php', - 'OCA\\UserStatus\\Service\\EmojiService' => $baseDir . '/../lib/Service/EmojiService.php', + 'OCA\\UserStatus\\Migration\\Version1003Date20210809144824' => $baseDir . '/../lib/Migration/Version1003Date20210809144824.php', + 'OCA\\UserStatus\\Migration\\Version1008Date20230921144701' => $baseDir . '/../lib/Migration/Version1008Date20230921144701.php', + 'OCA\\UserStatus\\ResponseDefinitions' => $baseDir . '/../lib/ResponseDefinitions.php', 'OCA\\UserStatus\\Service\\JSDataService' => $baseDir . '/../lib/Service/JSDataService.php', 'OCA\\UserStatus\\Service\\PredefinedStatusService' => $baseDir . '/../lib/Service/PredefinedStatusService.php', 'OCA\\UserStatus\\Service\\StatusService' => $baseDir . '/../lib/Service/StatusService.php', diff --git a/apps/user_status/composer/composer/autoload_static.php b/apps/user_status/composer/composer/autoload_static.php index c4ee7d031b5..7e494344490 100644 --- a/apps/user_status/composer/composer/autoload_static.php +++ b/apps/user_status/composer/composer/autoload_static.php @@ -27,6 +27,7 @@ class ComposerStaticInitUserStatus 'OCA\\UserStatus\\Capabilities' => __DIR__ . '/..' . '/../lib/Capabilities.php', 'OCA\\UserStatus\\Connector\\UserStatus' => __DIR__ . '/..' . '/../lib/Connector/UserStatus.php', 'OCA\\UserStatus\\Connector\\UserStatusProvider' => __DIR__ . '/..' . '/../lib/Connector/UserStatusProvider.php', + 'OCA\\UserStatus\\ContactsMenu\\StatusProvider' => __DIR__ . '/..' . '/../lib/ContactsMenu/StatusProvider.php', 'OCA\\UserStatus\\Controller\\HeartbeatController' => __DIR__ . '/..' . '/../lib/Controller/HeartbeatController.php', 'OCA\\UserStatus\\Controller\\PredefinedStatusController' => __DIR__ . '/..' . '/../lib/Controller/PredefinedStatusController.php', 'OCA\\UserStatus\\Controller\\StatusesController' => __DIR__ . '/..' . '/../lib/Controller/StatusesController.php', @@ -40,13 +41,15 @@ class ComposerStaticInitUserStatus 'OCA\\UserStatus\\Exception\\InvalidStatusTypeException' => __DIR__ . '/..' . '/../lib/Exception/InvalidStatusTypeException.php', 'OCA\\UserStatus\\Exception\\StatusMessageTooLongException' => __DIR__ . '/..' . '/../lib/Exception/StatusMessageTooLongException.php', 'OCA\\UserStatus\\Listener\\BeforeTemplateRenderedListener' => __DIR__ . '/..' . '/../lib/Listener/BeforeTemplateRenderedListener.php', + 'OCA\\UserStatus\\Listener\\OutOfOfficeStatusListener' => __DIR__ . '/..' . '/../lib/Listener/OutOfOfficeStatusListener.php', 'OCA\\UserStatus\\Listener\\UserDeletedListener' => __DIR__ . '/..' . '/../lib/Listener/UserDeletedListener.php', 'OCA\\UserStatus\\Listener\\UserLiveStatusListener' => __DIR__ . '/..' . '/../lib/Listener/UserLiveStatusListener.php', 'OCA\\UserStatus\\Migration\\Version0001Date20200602134824' => __DIR__ . '/..' . '/../lib/Migration/Version0001Date20200602134824.php', 'OCA\\UserStatus\\Migration\\Version0002Date20200902144824' => __DIR__ . '/..' . '/../lib/Migration/Version0002Date20200902144824.php', 'OCA\\UserStatus\\Migration\\Version1000Date20201111130204' => __DIR__ . '/..' . '/../lib/Migration/Version1000Date20201111130204.php', - 'OCA\\UserStatus\\Migration\\Version2301Date20210809144824' => __DIR__ . '/..' . '/../lib/Migration/Version2301Date20210809144824.php', - 'OCA\\UserStatus\\Service\\EmojiService' => __DIR__ . '/..' . '/../lib/Service/EmojiService.php', + 'OCA\\UserStatus\\Migration\\Version1003Date20210809144824' => __DIR__ . '/..' . '/../lib/Migration/Version1003Date20210809144824.php', + 'OCA\\UserStatus\\Migration\\Version1008Date20230921144701' => __DIR__ . '/..' . '/../lib/Migration/Version1008Date20230921144701.php', + 'OCA\\UserStatus\\ResponseDefinitions' => __DIR__ . '/..' . '/../lib/ResponseDefinitions.php', 'OCA\\UserStatus\\Service\\JSDataService' => __DIR__ . '/..' . '/../lib/Service/JSDataService.php', 'OCA\\UserStatus\\Service\\PredefinedStatusService' => __DIR__ . '/..' . '/../lib/Service/PredefinedStatusService.php', 'OCA\\UserStatus\\Service\\StatusService' => __DIR__ . '/..' . '/../lib/Service/StatusService.php', diff --git a/apps/user_status/composer/composer/installed.php b/apps/user_status/composer/composer/installed.php index 5440719fa40..1a66c7f2416 100644 --- a/apps/user_status/composer/composer/installed.php +++ b/apps/user_status/composer/composer/installed.php @@ -1,22 +1,22 @@ <?php return array( 'root' => array( + 'name' => '__root__', 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => 'b1797842784b250fb01ed5e3bf130705eb94751b', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => 'c6429e6cd19c57582364338362e543580821cf99', - 'name' => '__root__', 'dev' => false, ), 'versions' => array( '__root__' => array( 'pretty_version' => 'dev-master', 'version' => 'dev-master', + 'reference' => 'b1797842784b250fb01ed5e3bf130705eb94751b', 'type' => 'library', 'install_path' => __DIR__ . '/../', 'aliases' => array(), - 'reference' => 'c6429e6cd19c57582364338362e543580821cf99', 'dev_requirement' => false, ), ), diff --git a/apps/user_status/css/user-status-menu.css b/apps/user_status/css/user-status-menu.css new file mode 100644 index 00000000000..5bdbdf01cb4 --- /dev/null +++ b/apps/user_status/css/user-status-menu.css @@ -0,0 +1,4 @@ +/*! + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */.icon-user-status{background-image:url("../img/app.svg")}.icon-user-status-dark{background-image:url("../img/app-dark.svg");filter:var(--background-invert-if-dark)}/*# sourceMappingURL=user-status-menu.css.map */ diff --git a/apps/user_status/css/user-status-menu.css.map b/apps/user_status/css/user-status-menu.css.map new file mode 100644 index 00000000000..d8e862f7108 --- /dev/null +++ b/apps/user_status/css/user-status-menu.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["user-status-menu.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA,GAIA,kBACC,uCAGD,uBACC,4CACA","file":"user-status-menu.css"}
\ No newline at end of file diff --git a/apps/user_status/css/user-status-menu.css.map.license b/apps/user_status/css/user-status-menu.css.map.license new file mode 100644 index 00000000000..7e235b60091 --- /dev/null +++ b/apps/user_status/css/user-status-menu.css.map.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors +SPDX-License-Identifier: AGPL-3.0-or-later diff --git a/apps/user_status/css/user-status-menu.scss b/apps/user_status/css/user-status-menu.scss index 09dfd3124f8..10d761e5dff 100644 --- a/apps/user_status/css/user-status-menu.scss +++ b/apps/user_status/css/user-status-menu.scss @@ -1,50 +1,12 @@ -/** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * +/*! + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ - .icon-user-status { - @include icon-color('app', 'user_status', $color-black, 1); -} - -body.theme--dark .icon-user-status { - @include icon-color('app', 'user_status', $color-white, 1); -} - -.icon-user-status-online { - background-image: url('../img/user-status-online.svg'); -} - -.icon-user-status-away { - background-image: url('../img/user-status-away.svg'); -} - -.icon-user-status-dnd { - background-image: url('../img/user-status-dnd.svg'); -} - -// TODO: debug why icon-black-white does not work here -.icon-user-status-invisible { - @include icon-color('user-status-invisible', 'user_status', $color-black, 1); + background-image: url("../img/app.svg"); } -body.theme--dark .icon-user-status-invisible { - @include icon-color('user-status-invisible', 'user_status', $color-white, 1); +.icon-user-status-dark { + background-image: url("../img/app-dark.svg"); + filter: var(--background-invert-if-dark); } diff --git a/apps/user_status/img/app-dark.svg b/apps/user_status/img/app-dark.svg new file mode 100644 index 00000000000..292424a68ec --- /dev/null +++ b/apps/user_status/img/app-dark.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px"><path d="M479.96-144Q340-144 242-242t-98-238q0-140 97.93-238t237.83-98q13.06 0 25.65 1 12.59 1 25.59 3-39 29-62 72t-23 92q0 85 58.5 143.5T648-446q49 0 92-23t72-62q2 13 3 25.59t1 25.65q0 139.9-98.04 237.83t-238 97.93Z"/></svg>
\ No newline at end of file diff --git a/apps/user_status/img/app.svg b/apps/user_status/img/app.svg index eaf87d52ecf..d7fdef622fd 100644 --- a/apps/user_status/img/app.svg +++ b/apps/user_status/img/app.svg @@ -1 +1 @@ -<svg width="24" height="24" enable-background="new 0 0 24 24" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect width="24" height="24" fill="none"/><path d="m10.615 2.1094c-4.8491 0.68106-8.6152 4.8615-8.6152 9.8906 0 5.5 4.5 10 10 10 5.0292 0 9.2096-3.7661 9.8906-8.6152-1.4654 1.601-3.5625 2.6152-5.8906 2.6152-4.4 0-8-3.6-8-8 0-2.3281 1.0143-4.4252 2.6152-5.8906z" fill="#ffffff"/></svg> +<svg xmlns="http://www.w3.org/2000/svg" height="20px" viewBox="0 -960 960 960" width="20px" fill="#fff"><path d="M479.96-144Q340-144 242-242t-98-238q0-140 97.93-238t237.83-98q13.06 0 25.65 1 12.59 1 25.59 3-39 29-62 72t-23 92q0 85 58.5 143.5T648-446q49 0 92-23t72-62q2 13 3 25.59t1 25.65q0 139.9-98.04 237.83t-238 97.93Z"/></svg>
\ No newline at end of file diff --git a/apps/user_status/img/user-status-away.svg b/apps/user_status/img/user-status-away.svg deleted file mode 100644 index ab308c29efa..00000000000 --- a/apps/user_status/img/user-status-away.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="24" height="24" enable-background="new 0 0 24 24" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><rect width="24" height="24" fill="none"/><path d="m10.615 2.1094c-4.8491 0.68106-8.6152 4.8615-8.6152 9.8906 0 5.5 4.5 10 10 10 5.0292 0 9.2096-3.7661 9.8906-8.6152-1.4654 1.601-3.5625 2.6152-5.8906 2.6152-4.4 0-8-3.6-8-8 0-2.3281 1.0143-4.4252 2.6152-5.8906z" fill="#f4a331"/></svg> diff --git a/apps/user_status/img/user-status-dnd.svg b/apps/user_status/img/user-status-dnd.svg deleted file mode 100644 index d28e52c1293..00000000000 --- a/apps/user_status/img/user-status-dnd.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="24" height="24" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="m12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10z" fill="#ed484c"/><path d="m8 10h8c1.108 0 2 0.892 2 2s-0.892 2-2 2h-8c-1.108 0-2-0.892-2-2s0.892-2 2-2z" fill="#fdffff" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" style="paint-order:stroke markers fill"/></svg> diff --git a/apps/user_status/img/user-status-invisible.svg b/apps/user_status/img/user-status-invisible.svg deleted file mode 100644 index a5dc34cc976..00000000000 --- a/apps/user_status/img/user-status-invisible.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="24" height="24" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h24v24H0z" fill="none"/><path d="m12 2c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 4a6 6 0 0 1 6 6 6 6 0 0 1-6 6 6 6 0 0 1-6-6 6 6 0 0 1 6-6z"/></svg> diff --git a/apps/user_status/img/user-status-online.svg b/apps/user_status/img/user-status-online.svg deleted file mode 100644 index baf93c22b6a..00000000000 --- a/apps/user_status/img/user-status-online.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="24" height="24" enable-background="new 0 0 24 24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m8 16h8v-8h-8v8zm4-14c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10z" fill="#49B382"/></svg> diff --git a/apps/user_status/l10n/af.js b/apps/user_status/l10n/af.js index 0159c29095d..8a4bdf0be20 100644 --- a/apps/user_status/l10n/af.js +++ b/apps/user_status/l10n/af.js @@ -2,36 +2,34 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Onlangse statusse", + "No recent status changes" : "Geen onlangse statusverandering nie", "In a meeting" : "In ’n vergadering", "Commuting" : "In die verkeer", "Out sick" : "Siek tuis", "Vacationing" : "Met vakansie", "Working remotely" : "Werk in die veld", "User status" : "Gebruikerstatus", - "Clear status message after" : "Wis statusboodskap na", - "Set status" : "Stel status", + "Clear status after" : "Wis status na", + "There was an error saving the status" : "Daar was ’n fout toe status bewaar is", + "There was an error clearing the status" : "Daar was ’n fout toe die status gewis is", "Online status" : "Aanlyn status", "Status message" : "Statusboodskap", "Clear status message" : "Wis statusboodskap", "Set status message" : "Stel statusboodskap", - "There was an error saving the status" : "Daar was ’n fout toe status bewaar is", - "There was an error clearing the status" : "Daar was ’n fout toe die status gewis is", - "No recent status changes" : "Geen onlangse statusverandering nie", - "Away" : "Weg", - "Do not disturb" : "Moenie pla nie", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Moenie wis nie", "Today" : "Vandag", "This week" : "Vandeesweek", "Online" : "Aanlyn", + "Away" : "Weg", + "Do not disturb" : "Moenie pla nie", "Invisible" : "Onsigbaar", "Offline" : "Vanlyn", + "Set status" : "Stel status", "There was an error saving the new status" : "Daar was ’n fout toe nuwe status bewaar is", "30 minutes" : "30 minute", "1 hour" : "1 uur", "4 hours" : "4 uur", "Mute all notifications" : "Demp alle kennisgewings", - "Appear offline" : "Toon as vanlyn", - "What's your status?" : "Wat is u status" + "Appear offline" : "Toon as vanlyn" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/af.json b/apps/user_status/l10n/af.json index 48b425b4586..0a92dd9ab7d 100644 --- a/apps/user_status/l10n/af.json +++ b/apps/user_status/l10n/af.json @@ -1,35 +1,33 @@ { "translations": { "Recent statuses" : "Onlangse statusse", + "No recent status changes" : "Geen onlangse statusverandering nie", "In a meeting" : "In ’n vergadering", "Commuting" : "In die verkeer", "Out sick" : "Siek tuis", "Vacationing" : "Met vakansie", "Working remotely" : "Werk in die veld", "User status" : "Gebruikerstatus", - "Clear status message after" : "Wis statusboodskap na", - "Set status" : "Stel status", + "Clear status after" : "Wis status na", + "There was an error saving the status" : "Daar was ’n fout toe status bewaar is", + "There was an error clearing the status" : "Daar was ’n fout toe die status gewis is", "Online status" : "Aanlyn status", "Status message" : "Statusboodskap", "Clear status message" : "Wis statusboodskap", "Set status message" : "Stel statusboodskap", - "There was an error saving the status" : "Daar was ’n fout toe status bewaar is", - "There was an error clearing the status" : "Daar was ’n fout toe die status gewis is", - "No recent status changes" : "Geen onlangse statusverandering nie", - "Away" : "Weg", - "Do not disturb" : "Moenie pla nie", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Moenie wis nie", "Today" : "Vandag", "This week" : "Vandeesweek", "Online" : "Aanlyn", + "Away" : "Weg", + "Do not disturb" : "Moenie pla nie", "Invisible" : "Onsigbaar", "Offline" : "Vanlyn", + "Set status" : "Stel status", "There was an error saving the new status" : "Daar was ’n fout toe nuwe status bewaar is", "30 minutes" : "30 minute", "1 hour" : "1 uur", "4 hours" : "4 uur", "Mute all notifications" : "Demp alle kennisgewings", - "Appear offline" : "Toon as vanlyn", - "What's your status?" : "Wat is u status" + "Appear offline" : "Toon as vanlyn" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ar.js b/apps/user_status/l10n/ar.js index f161cbd3eb4..9557ff74546 100644 --- a/apps/user_status/l10n/ar.js +++ b/apps/user_status/l10n/ar.js @@ -2,37 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "آخر الحالات", + "No recent status changes" : "لم يتم تغيير الحالة مؤخراً", "In a meeting" : "في اجتماع", "Commuting" : "تجوال", - "Out sick" : "مريض", + "Out sick" : "إجازة مرضية", "Vacationing" : "في اجازة", - "Working remotely" : "العمل عن بعد", + "Out of office" : "خارج المكتب", + "Working remotely" : "عمل عن بعد", + "In a call" : "على الهاتف", "User status" : "حالة العضو", - "Clear status message after" : "احذف الحالة بعد", + "Clear status after" : "مسح رسالة الحالة بعد", + "Emoji for your status message" : "رسم تعبيري \"إيموجي\" لرسالة الحالة الخاصة بك", "What is your status?" : "ماهي حالتك؟", - "Set status" : "تعيين الحالة", + "Predefined statuses" : "حالات مُعرّفة مُسبقاً", + "Previously set" : "سبق تعيينها", + "Reset status" : "إعادة تعيين الحالة", + "Reset status to \"{icon} {message}\"" : "إعادة تعيين الحالة إلى \"{icon} {message}\"", + "Reset status to \"{message}\"" : "إعادة تعيين الحالة إلى \"{message}\"", + "Reset status to \"{icon}\"" : "إعادة تعيين الحالة إلى \"{icon}\"", + "There was an error saving the status" : "حدث خطأ اثناء حفظ الحالة", + "There was an error clearing the status" : "حدث خطأ اثناء حذف الحالة", + "There was an error reverting the status" : "حدث خطأ أثناء استرجاع الحالة", "Online status" : "حالة الاتصال", "Status message" : "رسالة الحالة", + "Set absence period" : "تعيين فترة التغيّب", + "Set absence period and replacement" : "تعيين فترة التّغيُّب و البديل", + "Your status was set automatically" : "تمّ تعيين حالتك تلقائيّاً", "Clear status message" : "حذف رسالة الحالة", "Set status message" : "تعيين رسالة الحالة", - "There was an error saving the status" : "حدث خطأ اثناء حفظ الحالة", - "There was an error clearing the status" : "حدث خطأ اثناء حذف الحالة", - "No recent status changes" : "لم يتم تغيير الحالة", - "Away" : "بالخارج", - "Do not disturb" : "عدم الازعاج", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "غير محدد", "Today" : "اليوم", "This week" : "هذا الأسبوع", "Online" : "متصل", + "Away" : "بالخارج", + "Do not disturb" : "عدم الازعاج", "Invisible" : "عدم الظهور", "Offline" : "غير متصل", + "Set status" : "تعيين الحالة", "There was an error saving the new status" : "حدث خطأ اثناء حفظ الحالة الجديدة", "30 minutes" : "30 دقيقة", "1 hour" : "1 ساعة", "4 hours" : "4 ساعات", - "Mute all notifications" : "عدم اظهار جميع التنبيهات", - "Appear offline" : "الحالة غير متصل", - "What's your status?" : "ماهي حالتك؟" + "Busy" : "مشغول", + "Mute all notifications" : "عدم إظهار جميع التنبيهات", + "Appear offline" : "الحالة غير متصل" }, "nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;"); diff --git a/apps/user_status/l10n/ar.json b/apps/user_status/l10n/ar.json index 31a953a830e..79c8c2d184c 100644 --- a/apps/user_status/l10n/ar.json +++ b/apps/user_status/l10n/ar.json @@ -1,36 +1,48 @@ { "translations": { "Recent statuses" : "آخر الحالات", + "No recent status changes" : "لم يتم تغيير الحالة مؤخراً", "In a meeting" : "في اجتماع", "Commuting" : "تجوال", - "Out sick" : "مريض", + "Out sick" : "إجازة مرضية", "Vacationing" : "في اجازة", - "Working remotely" : "العمل عن بعد", + "Out of office" : "خارج المكتب", + "Working remotely" : "عمل عن بعد", + "In a call" : "على الهاتف", "User status" : "حالة العضو", - "Clear status message after" : "احذف الحالة بعد", + "Clear status after" : "مسح رسالة الحالة بعد", + "Emoji for your status message" : "رسم تعبيري \"إيموجي\" لرسالة الحالة الخاصة بك", "What is your status?" : "ماهي حالتك؟", - "Set status" : "تعيين الحالة", + "Predefined statuses" : "حالات مُعرّفة مُسبقاً", + "Previously set" : "سبق تعيينها", + "Reset status" : "إعادة تعيين الحالة", + "Reset status to \"{icon} {message}\"" : "إعادة تعيين الحالة إلى \"{icon} {message}\"", + "Reset status to \"{message}\"" : "إعادة تعيين الحالة إلى \"{message}\"", + "Reset status to \"{icon}\"" : "إعادة تعيين الحالة إلى \"{icon}\"", + "There was an error saving the status" : "حدث خطأ اثناء حفظ الحالة", + "There was an error clearing the status" : "حدث خطأ اثناء حذف الحالة", + "There was an error reverting the status" : "حدث خطأ أثناء استرجاع الحالة", "Online status" : "حالة الاتصال", "Status message" : "رسالة الحالة", + "Set absence period" : "تعيين فترة التغيّب", + "Set absence period and replacement" : "تعيين فترة التّغيُّب و البديل", + "Your status was set automatically" : "تمّ تعيين حالتك تلقائيّاً", "Clear status message" : "حذف رسالة الحالة", "Set status message" : "تعيين رسالة الحالة", - "There was an error saving the status" : "حدث خطأ اثناء حفظ الحالة", - "There was an error clearing the status" : "حدث خطأ اثناء حذف الحالة", - "No recent status changes" : "لم يتم تغيير الحالة", - "Away" : "بالخارج", - "Do not disturb" : "عدم الازعاج", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "غير محدد", "Today" : "اليوم", "This week" : "هذا الأسبوع", "Online" : "متصل", + "Away" : "بالخارج", + "Do not disturb" : "عدم الازعاج", "Invisible" : "عدم الظهور", "Offline" : "غير متصل", + "Set status" : "تعيين الحالة", "There was an error saving the new status" : "حدث خطأ اثناء حفظ الحالة الجديدة", "30 minutes" : "30 دقيقة", "1 hour" : "1 ساعة", "4 hours" : "4 ساعات", - "Mute all notifications" : "عدم اظهار جميع التنبيهات", - "Appear offline" : "الحالة غير متصل", - "What's your status?" : "ماهي حالتك؟" + "Busy" : "مشغول", + "Mute all notifications" : "عدم إظهار جميع التنبيهات", + "Appear offline" : "الحالة غير متصل" },"pluralForm" :"nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ast.js b/apps/user_status/l10n/ast.js new file mode 100644 index 00000000000..ac09b5ac733 --- /dev/null +++ b/apps/user_status/l10n/ast.js @@ -0,0 +1,48 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Estaos de recién", + "No recent status changes" : "Nun hai nengún cambéu d'estáu recién", + "In a meeting" : "Nuna reunión", + "Commuting" : "En desplazamientu", + "Out sick" : "Non disponible por enfermedá", + "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", + "Working remotely" : "Trabayando en remoto", + "In a call" : "Nuna llamada", + "User status" : "Estáu del usuariu", + "Clear status after" : "Borrar l'estúa dempués de", + "Emoji for your status message" : "Fustaxes pa los mensaxes d'estáu", + "What is your status?" : "¿Cuál ye'l to estáu?", + "Predefined statuses" : "Estaos predefiníos", + "Previously set" : "Afitóse con anterioridá", + "Reset status" : "Reafitar l'estáu", + "Reset status to \"{icon} {message}\"" : "Reafitar l'estáu a «{icon} {message}»", + "Reset status to \"{message}\"" : "Reafitar l'estáu a «{message}»", + "Reset status to \"{icon}\"" : "Reafitar l'estáu a «{icon}»", + "There was an error saving the status" : "Hebo un error al guardar l'estáu", + "There was an error clearing the status" : "Hebo un error al borrar l'estáu", + "There was an error reverting the status" : "Hebo un error al recuperar l'estáu anterior", + "Online status" : "Estáu en llinia", + "Status message" : "Mensaxe del estáu", + "Your status was set automatically" : "L'estáu afitóse automáticamente", + "Clear status message" : "Borrar el mensaxe del estáu", + "Set status message" : "Afitar el mensaxe del estáu", + "Don't clear" : "Nun borrar", + "Today" : "Güei", + "This week" : "Esta selmana", + "Online" : "En llinia", + "Away" : "Ausente", + "Do not disturb" : "Nun molestar", + "Invisible" : "Invisible", + "Offline" : "Desconectáu", + "Set status" : "Afitar l'estáu", + "There was an error saving the new status" : "Hebo un error al guardar l'estáu nuevu", + "30 minutes" : "30 minutos", + "1 hour" : "1 hora", + "4 hours" : "4 hores", + "Busy" : "Ocupáu", + "Mute all notifications" : "Desactivar tolos avisos", + "Appear offline" : "Apaecer desconectáu" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/ast.json b/apps/user_status/l10n/ast.json new file mode 100644 index 00000000000..0a6e2ee9681 --- /dev/null +++ b/apps/user_status/l10n/ast.json @@ -0,0 +1,46 @@ +{ "translations": { + "Recent statuses" : "Estaos de recién", + "No recent status changes" : "Nun hai nengún cambéu d'estáu recién", + "In a meeting" : "Nuna reunión", + "Commuting" : "En desplazamientu", + "Out sick" : "Non disponible por enfermedá", + "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", + "Working remotely" : "Trabayando en remoto", + "In a call" : "Nuna llamada", + "User status" : "Estáu del usuariu", + "Clear status after" : "Borrar l'estúa dempués de", + "Emoji for your status message" : "Fustaxes pa los mensaxes d'estáu", + "What is your status?" : "¿Cuál ye'l to estáu?", + "Predefined statuses" : "Estaos predefiníos", + "Previously set" : "Afitóse con anterioridá", + "Reset status" : "Reafitar l'estáu", + "Reset status to \"{icon} {message}\"" : "Reafitar l'estáu a «{icon} {message}»", + "Reset status to \"{message}\"" : "Reafitar l'estáu a «{message}»", + "Reset status to \"{icon}\"" : "Reafitar l'estáu a «{icon}»", + "There was an error saving the status" : "Hebo un error al guardar l'estáu", + "There was an error clearing the status" : "Hebo un error al borrar l'estáu", + "There was an error reverting the status" : "Hebo un error al recuperar l'estáu anterior", + "Online status" : "Estáu en llinia", + "Status message" : "Mensaxe del estáu", + "Your status was set automatically" : "L'estáu afitóse automáticamente", + "Clear status message" : "Borrar el mensaxe del estáu", + "Set status message" : "Afitar el mensaxe del estáu", + "Don't clear" : "Nun borrar", + "Today" : "Güei", + "This week" : "Esta selmana", + "Online" : "En llinia", + "Away" : "Ausente", + "Do not disturb" : "Nun molestar", + "Invisible" : "Invisible", + "Offline" : "Desconectáu", + "Set status" : "Afitar l'estáu", + "There was an error saving the new status" : "Hebo un error al guardar l'estáu nuevu", + "30 minutes" : "30 minutos", + "1 hour" : "1 hora", + "4 hours" : "4 hores", + "Busy" : "Ocupáu", + "Mute all notifications" : "Desactivar tolos avisos", + "Appear offline" : "Apaecer desconectáu" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/bg.js b/apps/user_status/l10n/bg.js index 6f0ea7d1c58..e799fa1f212 100644 --- a/apps/user_status/l10n/bg.js +++ b/apps/user_status/l10n/bg.js @@ -2,39 +2,47 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Последни състояния", + "No recent status changes" : "Няма скорошни промени в състоянието", "In a meeting" : "В среща", - "Commuting" : "Работно пътуване", + "Commuting" : "Пътувам до работа", "Out sick" : "Болничен", "Vacationing" : "Отпуск", + "Out of office" : "Извън офиса", "Working remotely" : "Работа от разстояние", "In a call" : "В обаждане", "User status" : "Потребителско състояние", - "View profile" : "Преглед на профил", - "Clear status message after" : "Изчистване на съобщение за състоянието след", - "What is your status?" : "Какъв е вашият статус?", - "Set status" : "Задаване на състояние", - "Online status" : "Състояние на линия", - "Status message" : "Съобщение за състояние", - "Clear status message" : "Изчистване на съобщението за състояние", - "Set status message" : "Задаване на съобщение за състояние", + "Clear status after" : "Изчистване на състоянието след", + "What is your status?" : "Какво е вашето състояние?", + "Previously set" : "Предишно зададени", + "Reset status" : "Възстановяване на състоянието", + "Reset status to \"{icon} {message}\"" : "Възстановяване на състоянието на „{icon} {message}“", + "Reset status to \"{message}\"" : "Възстановяване на състоянието на „{message}“", + "Reset status to \"{icon}\"" : "Възстановяване на състоянието на „{icon}“", "There was an error saving the status" : "Възникна грешка при запазване на състоянието", "There was an error clearing the status" : "Възникна грешка при изчистване на състоянието", - "No recent status changes" : "Няма скорошни промени в състоянието", - "Away" : "Отсъстващ", - "Do not disturb" : "Не безпокойте", - "{status}, {timestamp}" : "{status}, {timestamp}", + "There was an error reverting the status" : "Имаше грешка при връщане на състоянието", + "Online status" : "Състояние", + "Status message" : "Съобщение за състояние", + "Set absence period" : "Задай период на отсъствие", + "Set absence period and replacement" : "Задай период на отсъствие и заместник.", + "Your status was set automatically" : "Състоянието ви беше зададено автоматично", + "Clear status message" : "Изчисти състоянието", + "Set status message" : "Задай състояние", "Don't clear" : "Да не се изчиства", "Today" : "Днес", "This week" : "Тази седмица", "Online" : "На линия", + "Away" : "Отсъстващ", + "Do not disturb" : "Не безпокойте", "Invisible" : "Невидим", "Offline" : "Офлайн", + "Set status" : "Задаване на състояние", "There was an error saving the new status" : "Възникна грешка при запазване на новото състояние", "30 minutes" : "30 минути", "1 hour" : "1 час", - "4 hours" : "4 часа", + "4 hours" : "4 чàса", + "Busy" : "Зает", "Mute all notifications" : "Заглушаване на всички известия", - "Appear offline" : "Показване като офлайн", - "What's your status?" : "Какъв е вашият статус?" + "Appear offline" : "Показване като офлайн" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/bg.json b/apps/user_status/l10n/bg.json index f2eb04be680..639aab4a411 100644 --- a/apps/user_status/l10n/bg.json +++ b/apps/user_status/l10n/bg.json @@ -1,38 +1,46 @@ { "translations": { "Recent statuses" : "Последни състояния", + "No recent status changes" : "Няма скорошни промени в състоянието", "In a meeting" : "В среща", - "Commuting" : "Работно пътуване", + "Commuting" : "Пътувам до работа", "Out sick" : "Болничен", "Vacationing" : "Отпуск", + "Out of office" : "Извън офиса", "Working remotely" : "Работа от разстояние", "In a call" : "В обаждане", "User status" : "Потребителско състояние", - "View profile" : "Преглед на профил", - "Clear status message after" : "Изчистване на съобщение за състоянието след", - "What is your status?" : "Какъв е вашият статус?", - "Set status" : "Задаване на състояние", - "Online status" : "Състояние на линия", - "Status message" : "Съобщение за състояние", - "Clear status message" : "Изчистване на съобщението за състояние", - "Set status message" : "Задаване на съобщение за състояние", + "Clear status after" : "Изчистване на състоянието след", + "What is your status?" : "Какво е вашето състояние?", + "Previously set" : "Предишно зададени", + "Reset status" : "Възстановяване на състоянието", + "Reset status to \"{icon} {message}\"" : "Възстановяване на състоянието на „{icon} {message}“", + "Reset status to \"{message}\"" : "Възстановяване на състоянието на „{message}“", + "Reset status to \"{icon}\"" : "Възстановяване на състоянието на „{icon}“", "There was an error saving the status" : "Възникна грешка при запазване на състоянието", "There was an error clearing the status" : "Възникна грешка при изчистване на състоянието", - "No recent status changes" : "Няма скорошни промени в състоянието", - "Away" : "Отсъстващ", - "Do not disturb" : "Не безпокойте", - "{status}, {timestamp}" : "{status}, {timestamp}", + "There was an error reverting the status" : "Имаше грешка при връщане на състоянието", + "Online status" : "Състояние", + "Status message" : "Съобщение за състояние", + "Set absence period" : "Задай период на отсъствие", + "Set absence period and replacement" : "Задай период на отсъствие и заместник.", + "Your status was set automatically" : "Състоянието ви беше зададено автоматично", + "Clear status message" : "Изчисти състоянието", + "Set status message" : "Задай състояние", "Don't clear" : "Да не се изчиства", "Today" : "Днес", "This week" : "Тази седмица", "Online" : "На линия", + "Away" : "Отсъстващ", + "Do not disturb" : "Не безпокойте", "Invisible" : "Невидим", "Offline" : "Офлайн", + "Set status" : "Задаване на състояние", "There was an error saving the new status" : "Възникна грешка при запазване на новото състояние", "30 minutes" : "30 минути", "1 hour" : "1 час", - "4 hours" : "4 часа", + "4 hours" : "4 чàса", + "Busy" : "Зает", "Mute all notifications" : "Заглушаване на всички известия", - "Appear offline" : "Показване като офлайн", - "What's your status?" : "Какъв е вашият статус?" + "Appear offline" : "Показване като офлайн" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ca.js b/apps/user_status/l10n/ca.js index d40a3b143a4..8fa53f7f41b 100644 --- a/apps/user_status/l10n/ca.js +++ b/apps/user_status/l10n/ca.js @@ -2,37 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Estats recents", + "No recent status changes" : "No hi ha cap canvi d'estat recent", "In a meeting" : "En una reunió", - "Commuting" : "Trajecte", - "Out sick" : "Fora malalt", - "Vacationing" : "Vacances", - "Working remotely" : "Treballant a distància", + "Commuting" : "En desplaçament", + "Out sick" : "No disponible per malaltia", + "Vacationing" : "De vacances", + "Out of office" : "Fora de l'oficina", + "Working remotely" : "Treballant en remot", + "In a call" : "En una trucada", "User status" : "Estat de l'usuari", - "Clear status message after" : "Esborra el missatge d'estat després", + "Clear status after" : "Esborra l'estat després de", + "Emoji for your status message" : "Emoji per al missatge d'estat", "What is your status?" : "Quin és el vostre estat?", - "Set status" : "Estableix l'estat", - "Online status" : "Estat en línia", - "Status message" : "Missatge d'estat", - "Clear status message" : "Esborrar el missatge d'estat", - "Set status message" : "Estableix un missatge d'estat", + "Predefined statuses" : "Estats predefinits", + "Previously set" : "Definits anteriorment", + "Reset status" : "Reinicialitza l'estat", + "Reset status to \"{icon} {message}\"" : "Reinicialitza l'estat a «{icon} {message}»", + "Reset status to \"{message}\"" : "Reinicialitza l'estat a «{message}»", + "Reset status to \"{icon}\"" : "Reinicialitza l'estat a «{icon}»", "There was an error saving the status" : "S'ha produït un error en desar l'estat", "There was an error clearing the status" : "S'ha produït un error en esborrar l'estat", - "No recent status changes" : "No hi ha canvis d'estat recents", - "Away" : "Absent", - "Do not disturb" : "No molesteu", - "{status}, {timestamp}" : "{status}, {timestamp}", - "Don't clear" : "No esborrar", + "There was an error reverting the status" : "S'ha produït un error en recuperar l'estat anterior", + "Online status" : "Estat en línia", + "Status message" : "Missatge d'estat", + "Set absence period" : "Establir període d'absència", + "Set absence period and replacement" : "Establir període d'absència i substitució", + "Your status was set automatically" : "S'ha indicat l'estat automàticament", + "Clear status message" : "Esborra el missatge d'estat", + "Set status message" : "Indica el missatge d'estat", + "Don't clear" : "No l'esborris", "Today" : "Avui", "This week" : "Aquesta setmana", "Online" : "En línia", + "Away" : "Absent", + "Do not disturb" : "No molesteu", "Invisible" : "Invisible", "Offline" : "Fora de línia", + "Set status" : "Indica l'estat", "There was an error saving the new status" : "S'ha produït un error en desar l'estat nou", "30 minutes" : "30 minuts", "1 hour" : "1 hora", "4 hours" : "4 hores", - "Mute all notifications" : "Silenciar totes les notificacions", - "Appear offline" : "Apareix com \"desconnectat\"", - "What's your status?" : "Quin és el teu estat?" + "Busy" : "Ocupat", + "Mute all notifications" : "Silencieu totes les notificacions", + "Appear offline" : "Apareixeu fora de línia" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/ca.json b/apps/user_status/l10n/ca.json index c88c2284aee..c40c658b992 100644 --- a/apps/user_status/l10n/ca.json +++ b/apps/user_status/l10n/ca.json @@ -1,36 +1,48 @@ { "translations": { "Recent statuses" : "Estats recents", + "No recent status changes" : "No hi ha cap canvi d'estat recent", "In a meeting" : "En una reunió", - "Commuting" : "Trajecte", - "Out sick" : "Fora malalt", - "Vacationing" : "Vacances", - "Working remotely" : "Treballant a distància", + "Commuting" : "En desplaçament", + "Out sick" : "No disponible per malaltia", + "Vacationing" : "De vacances", + "Out of office" : "Fora de l'oficina", + "Working remotely" : "Treballant en remot", + "In a call" : "En una trucada", "User status" : "Estat de l'usuari", - "Clear status message after" : "Esborra el missatge d'estat després", + "Clear status after" : "Esborra l'estat després de", + "Emoji for your status message" : "Emoji per al missatge d'estat", "What is your status?" : "Quin és el vostre estat?", - "Set status" : "Estableix l'estat", - "Online status" : "Estat en línia", - "Status message" : "Missatge d'estat", - "Clear status message" : "Esborrar el missatge d'estat", - "Set status message" : "Estableix un missatge d'estat", + "Predefined statuses" : "Estats predefinits", + "Previously set" : "Definits anteriorment", + "Reset status" : "Reinicialitza l'estat", + "Reset status to \"{icon} {message}\"" : "Reinicialitza l'estat a «{icon} {message}»", + "Reset status to \"{message}\"" : "Reinicialitza l'estat a «{message}»", + "Reset status to \"{icon}\"" : "Reinicialitza l'estat a «{icon}»", "There was an error saving the status" : "S'ha produït un error en desar l'estat", "There was an error clearing the status" : "S'ha produït un error en esborrar l'estat", - "No recent status changes" : "No hi ha canvis d'estat recents", - "Away" : "Absent", - "Do not disturb" : "No molesteu", - "{status}, {timestamp}" : "{status}, {timestamp}", - "Don't clear" : "No esborrar", + "There was an error reverting the status" : "S'ha produït un error en recuperar l'estat anterior", + "Online status" : "Estat en línia", + "Status message" : "Missatge d'estat", + "Set absence period" : "Establir període d'absència", + "Set absence period and replacement" : "Establir període d'absència i substitució", + "Your status was set automatically" : "S'ha indicat l'estat automàticament", + "Clear status message" : "Esborra el missatge d'estat", + "Set status message" : "Indica el missatge d'estat", + "Don't clear" : "No l'esborris", "Today" : "Avui", "This week" : "Aquesta setmana", "Online" : "En línia", + "Away" : "Absent", + "Do not disturb" : "No molesteu", "Invisible" : "Invisible", "Offline" : "Fora de línia", + "Set status" : "Indica l'estat", "There was an error saving the new status" : "S'ha produït un error en desar l'estat nou", "30 minutes" : "30 minuts", "1 hour" : "1 hora", "4 hours" : "4 hores", - "Mute all notifications" : "Silenciar totes les notificacions", - "Appear offline" : "Apareix com \"desconnectat\"", - "What's your status?" : "Quin és el teu estat?" + "Busy" : "Ocupat", + "Mute all notifications" : "Silencieu totes les notificacions", + "Appear offline" : "Apareixeu fora de línia" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/cs.js b/apps/user_status/l10n/cs.js index 6a4997b6fd7..9d21e89f539 100644 --- a/apps/user_status/l10n/cs.js +++ b/apps/user_status/l10n/cs.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Nedávné stavy", + "No recent status changes" : "Žádné nedávné změny stavu", "In a meeting" : "Na poradě", "Commuting" : "Dojíždění", "Out sick" : "Nemoc", "Vacationing" : "Dovolená", + "Out of office" : "Mimo kancelář", "Working remotely" : "Pracuje na dálku", "In a call" : "Má hovor", "User status" : "Stav uživatele", - "View profile" : "Zobrazit profil ", - "Clear status message after" : "Vyčistit stavovou zprávu po uplynutí", + "Clear status after" : "Vyčistit stav po uplynutí", + "Emoji for your status message" : "Emotikona pro vaší stavovou zprávu", "What is your status?" : "Jaký je váš stav?", - "Set status" : "Nastavit stav", + "Predefined statuses" : "Předdefinované stavy", + "Previously set" : "Dříve nastavené", + "Reset status" : "Resetovat stav", + "Reset status to \"{icon} {message}\"" : "Resetovat stav na „{icon} {message}“", + "Reset status to \"{message}\"" : "Resetovat stav na „{message}“", + "Reset status to \"{icon}\"" : "Resetovat stav na „{icon}“", + "There was an error saving the status" : "Došlo k chybě při ukládání stavu", + "There was an error clearing the status" : "Při čištění stavu došlo k chybě", + "There was an error reverting the status" : "Při vracení stavu nazpět došlo k chybě", "Online status" : "Stav online", "Status message" : "Stavová zpráva", + "Set absence period" : "Nastavit období nepřítomnosti", + "Set absence period and replacement" : "Nastavit období nepřítomnosti a zástup", + "Your status was set automatically" : "Váš stav byl nastaven automaticky", "Clear status message" : "Vyčistit stavovou zprávu", "Set status message" : "Nastavit stavovou zprávu", - "There was an error saving the status" : "Došlo k chybě při ukládání stavu", - "There was an error clearing the status" : "Při čištění stavu došlo k chybě", - "No recent status changes" : "Žádné nedávné změny stavu", - "Away" : "Pryč", - "Do not disturb" : "Nerušit", - "{status}, {timestamp}" : "{status}, {timestamp}", - "Don't clear" : "Nikdy", + "Don't clear" : "Do odvolání", "Today" : "Dnes", "This week" : "Tento týden", "Online" : "Online", - "Invisible" : "Neviditelný", + "Away" : "Pryč", + "Do not disturb" : "Nerušit", + "Invisible" : "Není vidět", "Offline" : "Offline", + "Set status" : "Nastavit stav", "There was an error saving the new status" : "Při ukládání nového stavu došlo k chybě", "30 minutes" : "30 minut", "1 hour" : "1 hodina", "4 hours" : "4 hodiny", + "Busy" : "Zaneprázdněn(a)", "Mute all notifications" : "Ztlumit veškerá upozornění", - "Appear offline" : "Jevit se offline", - "What's your status?" : "Jaký je váš stav?" + "Appear offline" : "Jevit se offline" }, "nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;"); diff --git a/apps/user_status/l10n/cs.json b/apps/user_status/l10n/cs.json index 7febf6f0aa5..c6c875d3454 100644 --- a/apps/user_status/l10n/cs.json +++ b/apps/user_status/l10n/cs.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Nedávné stavy", + "No recent status changes" : "Žádné nedávné změny stavu", "In a meeting" : "Na poradě", "Commuting" : "Dojíždění", "Out sick" : "Nemoc", "Vacationing" : "Dovolená", + "Out of office" : "Mimo kancelář", "Working remotely" : "Pracuje na dálku", "In a call" : "Má hovor", "User status" : "Stav uživatele", - "View profile" : "Zobrazit profil ", - "Clear status message after" : "Vyčistit stavovou zprávu po uplynutí", + "Clear status after" : "Vyčistit stav po uplynutí", + "Emoji for your status message" : "Emotikona pro vaší stavovou zprávu", "What is your status?" : "Jaký je váš stav?", - "Set status" : "Nastavit stav", + "Predefined statuses" : "Předdefinované stavy", + "Previously set" : "Dříve nastavené", + "Reset status" : "Resetovat stav", + "Reset status to \"{icon} {message}\"" : "Resetovat stav na „{icon} {message}“", + "Reset status to \"{message}\"" : "Resetovat stav na „{message}“", + "Reset status to \"{icon}\"" : "Resetovat stav na „{icon}“", + "There was an error saving the status" : "Došlo k chybě při ukládání stavu", + "There was an error clearing the status" : "Při čištění stavu došlo k chybě", + "There was an error reverting the status" : "Při vracení stavu nazpět došlo k chybě", "Online status" : "Stav online", "Status message" : "Stavová zpráva", + "Set absence period" : "Nastavit období nepřítomnosti", + "Set absence period and replacement" : "Nastavit období nepřítomnosti a zástup", + "Your status was set automatically" : "Váš stav byl nastaven automaticky", "Clear status message" : "Vyčistit stavovou zprávu", "Set status message" : "Nastavit stavovou zprávu", - "There was an error saving the status" : "Došlo k chybě při ukládání stavu", - "There was an error clearing the status" : "Při čištění stavu došlo k chybě", - "No recent status changes" : "Žádné nedávné změny stavu", - "Away" : "Pryč", - "Do not disturb" : "Nerušit", - "{status}, {timestamp}" : "{status}, {timestamp}", - "Don't clear" : "Nikdy", + "Don't clear" : "Do odvolání", "Today" : "Dnes", "This week" : "Tento týden", "Online" : "Online", - "Invisible" : "Neviditelný", + "Away" : "Pryč", + "Do not disturb" : "Nerušit", + "Invisible" : "Není vidět", "Offline" : "Offline", + "Set status" : "Nastavit stav", "There was an error saving the new status" : "Při ukládání nového stavu došlo k chybě", "30 minutes" : "30 minut", "1 hour" : "1 hodina", "4 hours" : "4 hodiny", + "Busy" : "Zaneprázdněn(a)", "Mute all notifications" : "Ztlumit veškerá upozornění", - "Appear offline" : "Jevit se offline", - "What's your status?" : "Jaký je váš stav?" + "Appear offline" : "Jevit se offline" },"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n >= 2 && n <= 4 && n % 1 == 0) ? 1: (n % 1 != 0 ) ? 2 : 3;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/da.js b/apps/user_status/l10n/da.js index 786c91b3992..43b4560d086 100644 --- a/apps/user_status/l10n/da.js +++ b/apps/user_status/l10n/da.js @@ -1,24 +1,50 @@ OC.L10N.register( "user_status", { - "Clear status message after" : "Ryd status notifikationer efter", + "Recent statuses" : "Senestestatus", + "No recent status changes" : "Ingen ændringer i status", + "In a meeting" : "I et møde", + "Commuting" : "Undervejs", + "Out sick" : "Sygemeldt", + "Vacationing" : "Holder ferie", + "Out of office" : "Ikke på kontoret", + "Working remotely" : "Arbejder hjemmefra", + "In a call" : "Taler i telefon", + "User status" : "Brugerstatus", + "Clear status after" : "Ryd status efter", + "Emoji for your status message" : "Emoji til din statusbesked", "What is your status?" : "Hvad er din status", - "Set status" : "Sæt status", + "Predefined statuses" : "Foruddefinerede status", + "Previously set" : "Tidligere sat", + "Reset status" : "Nulstil status", + "Reset status to \"{icon} {message}\"" : "Nulstil status til \"{icon}{message}\"", + "Reset status to \"{message}\"" : "Nulstil status til \"{message}\"", + "Reset status to \"{icon}\"" : "Nulstil status til \"{icon}\"", + "There was an error saving the status" : "Der opstod en fejl ved lagring af status", + "There was an error clearing the status" : "Der opstod en fejl ved rydning af status", + "There was an error reverting the status" : "Der opstod en fejl ved indstillingen af status", "Online status" : "Online status", "Status message" : "Statusbesked", - "Clear status message" : "Ryd status notifikation", + "Set absence period" : "Indstil fraværs periode", + "Set absence period and replacement" : "Indstil fraværs periode og angiv afløser", + "Your status was set automatically" : "Status sat automatisk", + "Clear status message" : "Ryd statusnotifikation", "Set status message" : "Sæt statusbesked", - "Away" : "Ikke tilstede", - "Do not disturb" : "Forstyr ikke", "Don't clear" : "Ryd ikke", "Today" : "I dag", "This week" : "Denne uge", "Online" : "Online", + "Away" : "Ikke tilstede", + "Do not disturb" : "Forstyr ikke", "Invisible" : "Usynlig", "Offline" : "Offline", + "Set status" : "Sæt status", + "There was an error saving the new status" : "Der opstod en fejl ved lagring af den nye status", "30 minutes" : "30 minutter", "1 hour" : "1 time", "4 hours" : "4 timer", - "What's your status?" : "Hvad er din status" + "Busy" : "Optaget", + "Mute all notifications" : "Vis ikke notifikationer", + "Appear offline" : "Er offline" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/da.json b/apps/user_status/l10n/da.json index a3bdd3c01a7..67708311d7b 100644 --- a/apps/user_status/l10n/da.json +++ b/apps/user_status/l10n/da.json @@ -1,22 +1,48 @@ { "translations": { - "Clear status message after" : "Ryd status notifikationer efter", + "Recent statuses" : "Senestestatus", + "No recent status changes" : "Ingen ændringer i status", + "In a meeting" : "I et møde", + "Commuting" : "Undervejs", + "Out sick" : "Sygemeldt", + "Vacationing" : "Holder ferie", + "Out of office" : "Ikke på kontoret", + "Working remotely" : "Arbejder hjemmefra", + "In a call" : "Taler i telefon", + "User status" : "Brugerstatus", + "Clear status after" : "Ryd status efter", + "Emoji for your status message" : "Emoji til din statusbesked", "What is your status?" : "Hvad er din status", - "Set status" : "Sæt status", + "Predefined statuses" : "Foruddefinerede status", + "Previously set" : "Tidligere sat", + "Reset status" : "Nulstil status", + "Reset status to \"{icon} {message}\"" : "Nulstil status til \"{icon}{message}\"", + "Reset status to \"{message}\"" : "Nulstil status til \"{message}\"", + "Reset status to \"{icon}\"" : "Nulstil status til \"{icon}\"", + "There was an error saving the status" : "Der opstod en fejl ved lagring af status", + "There was an error clearing the status" : "Der opstod en fejl ved rydning af status", + "There was an error reverting the status" : "Der opstod en fejl ved indstillingen af status", "Online status" : "Online status", "Status message" : "Statusbesked", - "Clear status message" : "Ryd status notifikation", + "Set absence period" : "Indstil fraværs periode", + "Set absence period and replacement" : "Indstil fraværs periode og angiv afløser", + "Your status was set automatically" : "Status sat automatisk", + "Clear status message" : "Ryd statusnotifikation", "Set status message" : "Sæt statusbesked", - "Away" : "Ikke tilstede", - "Do not disturb" : "Forstyr ikke", "Don't clear" : "Ryd ikke", "Today" : "I dag", "This week" : "Denne uge", "Online" : "Online", + "Away" : "Ikke tilstede", + "Do not disturb" : "Forstyr ikke", "Invisible" : "Usynlig", "Offline" : "Offline", + "Set status" : "Sæt status", + "There was an error saving the new status" : "Der opstod en fejl ved lagring af den nye status", "30 minutes" : "30 minutter", "1 hour" : "1 time", "4 hours" : "4 timer", - "What's your status?" : "Hvad er din status" + "Busy" : "Optaget", + "Mute all notifications" : "Vis ikke notifikationer", + "Appear offline" : "Er offline" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/de.js b/apps/user_status/l10n/de.js index 791da791c28..b59906d6135 100644 --- a/apps/user_status/l10n/de.js +++ b/apps/user_status/l10n/de.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Letzter Status", + "No recent status changes" : "Keine kürzlichen Statusänderungen", "In a meeting" : "In einer Besprechung", "Commuting" : "Pendelt", "Out sick" : "Krankgeschrieben", "Vacationing" : "Im Urlaub", + "Out of office" : "Nicht im Büro", "Working remotely" : "Arbeitet aus der Ferne", "In a call" : "In einem Anruf", + "Be right back" : "Bin gleich zurück", "User status" : "Benutzerstatus", - "View profile" : "Profil ansehen", - "Clear status message after" : "Statusnachricht löschen nach", - "What is your status?" : "Wie ist Dein Status?", - "Set status" : "Status setzen", + "Clear status after" : "Status löschen nach", + "Emoji for your status message" : "Emoji für deine Statusnachricht", + "What is your status?" : "Wie ist dein Status?", + "Predefined statuses" : "Vordefinierte Status", + "Previously set" : "Zuvor eingestellt", + "Reset status" : "Status zurücksetzen", + "Reset status to \"{icon} {message}\"" : "Status auf \"{icon} {message}\" zurücksetzen", + "Reset status to \"{message}\"" : "Status auf \"{message}\" zurücksetzen", + "Reset status to \"{icon}\"" : "Status auf \"{icon}\" zurücksetzen", + "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", + "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", + "There was an error reverting the status" : "Es ist ein Fehler beim Zurücksetzen des Status aufgetreten", "Online status" : "Online-Status", "Status message" : "Statusnachricht", + "Set absence period" : "Abwesenheitszeitraum festlegen", + "Set absence period and replacement" : "Abwesenheitszeitraum und Vertretung festlegen", + "Your status was set automatically" : "Dein Status wurde automatisch gesetzt", "Clear status message" : "Statusnachricht löschen", "Set status message" : "Statusnachricht setzen", - "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", - "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", - "No recent status changes" : "Keine kürzlichen Statusänderungen", - "Away" : "Abwesend", - "Do not disturb" : "Bitte nicht stören", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nicht löschen", "Today" : "Heute", "This week" : "Diese Woche", "Online" : "Online", + "Away" : "Abwesend", + "Do not disturb" : "Bitte nicht stören", "Invisible" : "Unsichtbar", "Offline" : "Offline", + "Set status" : "Status setzen", "There was an error saving the new status" : "Es gab einen Fehler beim Speichern des neuen Status", "30 minutes" : "30 Minuten", "1 hour" : "1 Stunde", "4 hours" : "4 Stunden", + "Busy" : "Beschäftigt", "Mute all notifications" : "Alle Benachrichtigungen stummschalten", - "Appear offline" : "Offline erscheinen", - "What's your status?" : "Wie ist Dein Status?" + "Appear offline" : "Offline erscheinen" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/de.json b/apps/user_status/l10n/de.json index 7cf652ab8f0..2badd82476c 100644 --- a/apps/user_status/l10n/de.json +++ b/apps/user_status/l10n/de.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "Letzter Status", + "No recent status changes" : "Keine kürzlichen Statusänderungen", "In a meeting" : "In einer Besprechung", "Commuting" : "Pendelt", "Out sick" : "Krankgeschrieben", "Vacationing" : "Im Urlaub", + "Out of office" : "Nicht im Büro", "Working remotely" : "Arbeitet aus der Ferne", "In a call" : "In einem Anruf", + "Be right back" : "Bin gleich zurück", "User status" : "Benutzerstatus", - "View profile" : "Profil ansehen", - "Clear status message after" : "Statusnachricht löschen nach", - "What is your status?" : "Wie ist Dein Status?", - "Set status" : "Status setzen", + "Clear status after" : "Status löschen nach", + "Emoji for your status message" : "Emoji für deine Statusnachricht", + "What is your status?" : "Wie ist dein Status?", + "Predefined statuses" : "Vordefinierte Status", + "Previously set" : "Zuvor eingestellt", + "Reset status" : "Status zurücksetzen", + "Reset status to \"{icon} {message}\"" : "Status auf \"{icon} {message}\" zurücksetzen", + "Reset status to \"{message}\"" : "Status auf \"{message}\" zurücksetzen", + "Reset status to \"{icon}\"" : "Status auf \"{icon}\" zurücksetzen", + "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", + "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", + "There was an error reverting the status" : "Es ist ein Fehler beim Zurücksetzen des Status aufgetreten", "Online status" : "Online-Status", "Status message" : "Statusnachricht", + "Set absence period" : "Abwesenheitszeitraum festlegen", + "Set absence period and replacement" : "Abwesenheitszeitraum und Vertretung festlegen", + "Your status was set automatically" : "Dein Status wurde automatisch gesetzt", "Clear status message" : "Statusnachricht löschen", "Set status message" : "Statusnachricht setzen", - "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", - "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", - "No recent status changes" : "Keine kürzlichen Statusänderungen", - "Away" : "Abwesend", - "Do not disturb" : "Bitte nicht stören", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nicht löschen", "Today" : "Heute", "This week" : "Diese Woche", "Online" : "Online", + "Away" : "Abwesend", + "Do not disturb" : "Bitte nicht stören", "Invisible" : "Unsichtbar", "Offline" : "Offline", + "Set status" : "Status setzen", "There was an error saving the new status" : "Es gab einen Fehler beim Speichern des neuen Status", "30 minutes" : "30 Minuten", "1 hour" : "1 Stunde", "4 hours" : "4 Stunden", + "Busy" : "Beschäftigt", "Mute all notifications" : "Alle Benachrichtigungen stummschalten", - "Appear offline" : "Offline erscheinen", - "What's your status?" : "Wie ist Dein Status?" + "Appear offline" : "Offline erscheinen" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/de_DE.js b/apps/user_status/l10n/de_DE.js index a2226851f9e..23d86b06643 100644 --- a/apps/user_status/l10n/de_DE.js +++ b/apps/user_status/l10n/de_DE.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Letzter Status", + "No recent status changes" : "Keine kürzlichen Statusänderungen", "In a meeting" : "In einer Besprechung", "Commuting" : "Pendelt", "Out sick" : "Krank geschrieben", "Vacationing" : "Im Urlaub", + "Out of office" : "Nicht im Büro", "Working remotely" : "Arbeitet aus der Ferne", "In a call" : "In einem Anruf", + "Be right back" : "Bin gleich zurück", "User status" : "Benutzerstatus", - "View profile" : "Profil ansehen", - "Clear status message after" : "Statusnachricht löschen nach", + "Clear status after" : "Status löschen nach", + "Emoji for your status message" : "Emoji für Ihre Statusnachricht", "What is your status?" : "Wie ist Ihr Status?", - "Set status" : "Status setzen", + "Predefined statuses" : "Vordefinierte Status", + "Previously set" : "Zuvor eingestellt", + "Reset status" : "Status zurücksetzen", + "Reset status to \"{icon} {message}\"" : "Status auf \"{icon} {message}\" zurücksetzen", + "Reset status to \"{message}\"" : "Status auf \"{message}\" zurücksetzen", + "Reset status to \"{icon}\"" : "Status auf \"{icon}\" zurücksetzen", + "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", + "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", + "There was an error reverting the status" : "Es ist ein Fehler beim Zurücksetzen des Status aufgetreten", "Online status" : "Online-Status", "Status message" : "Statusnachricht", + "Set absence period" : "Abwesenheitszeitraum festlegen", + "Set absence period and replacement" : "Abwesenheitszeitraum und Vertretung festlegen", + "Your status was set automatically" : "Ihr Status wurde automatisch gesetzt", "Clear status message" : "Statusnachricht löschen", "Set status message" : "Statusnachricht setzen", - "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", - "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", - "No recent status changes" : "Keine kürzlichen Statusänderungen", - "Away" : "Abwesend", - "Do not disturb" : "Bitte nicht stören", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nicht löschen", "Today" : "Heute", "This week" : "Diese Woche", "Online" : "Online", + "Away" : "Abwesend", + "Do not disturb" : "Nicht stören", "Invisible" : "Unsichtbar", "Offline" : "Offline", + "Set status" : "Status setzen", "There was an error saving the new status" : "Es gab einen Fehler beim Speichern des neuen Status", "30 minutes" : "30 Minuten", "1 hour" : "1 Stunde", "4 hours" : "4 Stunden", + "Busy" : "Beschäftigt", "Mute all notifications" : "Alle Benachrichtigungen stummschalten", - "Appear offline" : "Offline erscheinen", - "What's your status?" : "Wie ist Ihr Status?" + "Appear offline" : "Offline erscheinen" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/de_DE.json b/apps/user_status/l10n/de_DE.json index b6951e4789a..9be300f0e29 100644 --- a/apps/user_status/l10n/de_DE.json +++ b/apps/user_status/l10n/de_DE.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "Letzter Status", + "No recent status changes" : "Keine kürzlichen Statusänderungen", "In a meeting" : "In einer Besprechung", "Commuting" : "Pendelt", "Out sick" : "Krank geschrieben", "Vacationing" : "Im Urlaub", + "Out of office" : "Nicht im Büro", "Working remotely" : "Arbeitet aus der Ferne", "In a call" : "In einem Anruf", + "Be right back" : "Bin gleich zurück", "User status" : "Benutzerstatus", - "View profile" : "Profil ansehen", - "Clear status message after" : "Statusnachricht löschen nach", + "Clear status after" : "Status löschen nach", + "Emoji for your status message" : "Emoji für Ihre Statusnachricht", "What is your status?" : "Wie ist Ihr Status?", - "Set status" : "Status setzen", + "Predefined statuses" : "Vordefinierte Status", + "Previously set" : "Zuvor eingestellt", + "Reset status" : "Status zurücksetzen", + "Reset status to \"{icon} {message}\"" : "Status auf \"{icon} {message}\" zurücksetzen", + "Reset status to \"{message}\"" : "Status auf \"{message}\" zurücksetzen", + "Reset status to \"{icon}\"" : "Status auf \"{icon}\" zurücksetzen", + "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", + "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", + "There was an error reverting the status" : "Es ist ein Fehler beim Zurücksetzen des Status aufgetreten", "Online status" : "Online-Status", "Status message" : "Statusnachricht", + "Set absence period" : "Abwesenheitszeitraum festlegen", + "Set absence period and replacement" : "Abwesenheitszeitraum und Vertretung festlegen", + "Your status was set automatically" : "Ihr Status wurde automatisch gesetzt", "Clear status message" : "Statusnachricht löschen", "Set status message" : "Statusnachricht setzen", - "There was an error saving the status" : "Es gab einen Fehler beim Speichern des Status", - "There was an error clearing the status" : "Es gab einen Fehler beim Löschen des Status", - "No recent status changes" : "Keine kürzlichen Statusänderungen", - "Away" : "Abwesend", - "Do not disturb" : "Bitte nicht stören", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nicht löschen", "Today" : "Heute", "This week" : "Diese Woche", "Online" : "Online", + "Away" : "Abwesend", + "Do not disturb" : "Nicht stören", "Invisible" : "Unsichtbar", "Offline" : "Offline", + "Set status" : "Status setzen", "There was an error saving the new status" : "Es gab einen Fehler beim Speichern des neuen Status", "30 minutes" : "30 Minuten", "1 hour" : "1 Stunde", "4 hours" : "4 Stunden", + "Busy" : "Beschäftigt", "Mute all notifications" : "Alle Benachrichtigungen stummschalten", - "Appear offline" : "Offline erscheinen", - "What's your status?" : "Wie ist Ihr Status?" + "Appear offline" : "Offline erscheinen" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/el.js b/apps/user_status/l10n/el.js index 8462de725ba..0818d00d791 100644 --- a/apps/user_status/l10n/el.js +++ b/apps/user_status/l10n/el.js @@ -2,39 +2,38 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Πρόσφατες καταστάσεις", + "No recent status changes" : "Δεν υπάρχουν πρόσφατες αλλαγές κατάστασης", "In a meeting" : "Σε συνάντηση", "Commuting" : "Μετακίνηση προς την εργασία", "Out sick" : "Αναρρωτική άδεια", "Vacationing" : "Διακοπάρω", + "Out of office" : "Εκτός γραφείου", "Working remotely" : "Εργασία εξ αποστάσεως", "In a call" : "Σε μια κλήση", "User status" : "Κατάσταση χρήστη", - "View profile" : "Προβολή προφίλ", - "Clear status message after" : "Εκκαθάριση μηνύματος κατάστασης μετά από", + "Clear status after" : "Εκκαθάριση κατάστασης μετά από", "What is your status?" : "Ποια είναι η κατάστασή σας;", - "Set status" : "Ορισμός κατάστασης", + "There was an error saving the status" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση της κατάστασης", + "There was an error clearing the status" : "Παρουσιάστηκε σφάλμα κατά την εκκαθάριση της κατάστασης", "Online status" : "Κατάσταση σε σύνδεση", "Status message" : "Μήνυμα κατάστασης", "Clear status message" : "Εκκαθάριση μηνύματος κατάστασης", "Set status message" : "Ορισμός μηνύματος κατάστασης", - "There was an error saving the status" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση της κατάστασης", - "There was an error clearing the status" : "Παρουσιάστηκε σφάλμα κατά την εκκαθάριση της κατάστασης", - "No recent status changes" : "Δεν υπάρχουν πρόσφατες αλλαγές κατάστασης", - "Away" : "Λείπω", - "Do not disturb" : "Μην ενοχλείτε", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Να μη γίνεται εκκαθάριση", "Today" : "Σήμερα", "This week" : "Αυτή την εβδομάδα", "Online" : "Σε σύνδεση", + "Away" : "Λείπω", + "Do not disturb" : "Μην ενοχλείτε", "Invisible" : "Αόρατος", "Offline" : "Εκτός σύνδεσης", + "Set status" : "Ορισμός κατάστασης", "There was an error saving the new status" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση της νέας κατάστασης", "30 minutes" : "30 λεπτά", "1 hour" : "1 ώρα", "4 hours" : "4 ώρες", + "Busy" : "Απασχολημένος", "Mute all notifications" : "Σίγαση όλων των ειδοποιήσεων", - "Appear offline" : "Εμφάνιση εκτός σύνδεσης", - "What's your status?" : "Ποια είναι η κατάστασή σας;" + "Appear offline" : "Εμφάνιση εκτός σύνδεσης" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/el.json b/apps/user_status/l10n/el.json index beb3728768d..bef6486de08 100644 --- a/apps/user_status/l10n/el.json +++ b/apps/user_status/l10n/el.json @@ -1,38 +1,37 @@ { "translations": { "Recent statuses" : "Πρόσφατες καταστάσεις", + "No recent status changes" : "Δεν υπάρχουν πρόσφατες αλλαγές κατάστασης", "In a meeting" : "Σε συνάντηση", "Commuting" : "Μετακίνηση προς την εργασία", "Out sick" : "Αναρρωτική άδεια", "Vacationing" : "Διακοπάρω", + "Out of office" : "Εκτός γραφείου", "Working remotely" : "Εργασία εξ αποστάσεως", "In a call" : "Σε μια κλήση", "User status" : "Κατάσταση χρήστη", - "View profile" : "Προβολή προφίλ", - "Clear status message after" : "Εκκαθάριση μηνύματος κατάστασης μετά από", + "Clear status after" : "Εκκαθάριση κατάστασης μετά από", "What is your status?" : "Ποια είναι η κατάστασή σας;", - "Set status" : "Ορισμός κατάστασης", + "There was an error saving the status" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση της κατάστασης", + "There was an error clearing the status" : "Παρουσιάστηκε σφάλμα κατά την εκκαθάριση της κατάστασης", "Online status" : "Κατάσταση σε σύνδεση", "Status message" : "Μήνυμα κατάστασης", "Clear status message" : "Εκκαθάριση μηνύματος κατάστασης", "Set status message" : "Ορισμός μηνύματος κατάστασης", - "There was an error saving the status" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση της κατάστασης", - "There was an error clearing the status" : "Παρουσιάστηκε σφάλμα κατά την εκκαθάριση της κατάστασης", - "No recent status changes" : "Δεν υπάρχουν πρόσφατες αλλαγές κατάστασης", - "Away" : "Λείπω", - "Do not disturb" : "Μην ενοχλείτε", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Να μη γίνεται εκκαθάριση", "Today" : "Σήμερα", "This week" : "Αυτή την εβδομάδα", "Online" : "Σε σύνδεση", + "Away" : "Λείπω", + "Do not disturb" : "Μην ενοχλείτε", "Invisible" : "Αόρατος", "Offline" : "Εκτός σύνδεσης", + "Set status" : "Ορισμός κατάστασης", "There was an error saving the new status" : "Παρουσιάστηκε σφάλμα κατά την αποθήκευση της νέας κατάστασης", "30 minutes" : "30 λεπτά", "1 hour" : "1 ώρα", "4 hours" : "4 ώρες", + "Busy" : "Απασχολημένος", "Mute all notifications" : "Σίγαση όλων των ειδοποιήσεων", - "Appear offline" : "Εμφάνιση εκτός σύνδεσης", - "What's your status?" : "Ποια είναι η κατάστασή σας;" + "Appear offline" : "Εμφάνιση εκτός σύνδεσης" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/en_GB.js b/apps/user_status/l10n/en_GB.js index 2eb26c16667..2ef82ebed8a 100644 --- a/apps/user_status/l10n/en_GB.js +++ b/apps/user_status/l10n/en_GB.js @@ -1,24 +1,51 @@ OC.L10N.register( "user_status", { - "Clear status message after" : "Clear status message after", + "Recent statuses" : "Recent statuses", + "No recent status changes" : "No recent status changes", + "In a meeting" : "In a meeting", + "Commuting" : "Commuting", + "Out sick" : "Out sick", + "Vacationing" : "Vacationing", + "Out of office" : "Out of office", + "Working remotely" : "Working remotely", + "In a call" : "In a call", + "Be right back" : "Be right back", + "User status" : "User status", + "Clear status after" : "Clear status after", + "Emoji for your status message" : "Emoji for your status message", "What is your status?" : "What is your status?", - "Set status" : "Set status", + "Predefined statuses" : "Predefined statuses", + "Previously set" : "Previously set", + "Reset status" : "Reset status", + "Reset status to \"{icon} {message}\"" : "Reset status to \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Reset status to \"{message}\"", + "Reset status to \"{icon}\"" : "Reset status to \"{icon}\"", + "There was an error saving the status" : "There was an error saving the status", + "There was an error clearing the status" : "There was an error clearing the status", + "There was an error reverting the status" : "There was an error reverting the status", "Online status" : "Online status", "Status message" : "Status message", + "Set absence period" : "Set absence period", + "Set absence period and replacement" : "Set absence period and replacement", + "Your status was set automatically" : "Your status was set automatically", "Clear status message" : "Clear status message", "Set status message" : "Set status message", - "Away" : "Away", - "Do not disturb" : "Do not disturb", "Don't clear" : "Don't clear", "Today" : "Today", "This week" : "This week", "Online" : "Online", + "Away" : "Away", + "Do not disturb" : "Do not disturb", "Invisible" : "Invisible", "Offline" : "Offline", + "Set status" : "Set status", + "There was an error saving the new status" : "There was an error saving the new status", "30 minutes" : "30 minutes", "1 hour" : "1 hour", "4 hours" : "4 hours", - "What's your status?" : "What's your status?" + "Busy" : "Busy", + "Mute all notifications" : "Mute all notifications", + "Appear offline" : "Appear offline" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/en_GB.json b/apps/user_status/l10n/en_GB.json index d2709baf623..0e646a02599 100644 --- a/apps/user_status/l10n/en_GB.json +++ b/apps/user_status/l10n/en_GB.json @@ -1,22 +1,49 @@ { "translations": { - "Clear status message after" : "Clear status message after", + "Recent statuses" : "Recent statuses", + "No recent status changes" : "No recent status changes", + "In a meeting" : "In a meeting", + "Commuting" : "Commuting", + "Out sick" : "Out sick", + "Vacationing" : "Vacationing", + "Out of office" : "Out of office", + "Working remotely" : "Working remotely", + "In a call" : "In a call", + "Be right back" : "Be right back", + "User status" : "User status", + "Clear status after" : "Clear status after", + "Emoji for your status message" : "Emoji for your status message", "What is your status?" : "What is your status?", - "Set status" : "Set status", + "Predefined statuses" : "Predefined statuses", + "Previously set" : "Previously set", + "Reset status" : "Reset status", + "Reset status to \"{icon} {message}\"" : "Reset status to \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Reset status to \"{message}\"", + "Reset status to \"{icon}\"" : "Reset status to \"{icon}\"", + "There was an error saving the status" : "There was an error saving the status", + "There was an error clearing the status" : "There was an error clearing the status", + "There was an error reverting the status" : "There was an error reverting the status", "Online status" : "Online status", "Status message" : "Status message", + "Set absence period" : "Set absence period", + "Set absence period and replacement" : "Set absence period and replacement", + "Your status was set automatically" : "Your status was set automatically", "Clear status message" : "Clear status message", "Set status message" : "Set status message", - "Away" : "Away", - "Do not disturb" : "Do not disturb", "Don't clear" : "Don't clear", "Today" : "Today", "This week" : "This week", "Online" : "Online", + "Away" : "Away", + "Do not disturb" : "Do not disturb", "Invisible" : "Invisible", "Offline" : "Offline", + "Set status" : "Set status", + "There was an error saving the new status" : "There was an error saving the new status", "30 minutes" : "30 minutes", "1 hour" : "1 hour", "4 hours" : "4 hours", - "What's your status?" : "What's your status?" + "Busy" : "Busy", + "Mute all notifications" : "Mute all notifications", + "Appear offline" : "Appear offline" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/es.js b/apps/user_status/l10n/es.js index 2772f05eb84..d76dd2511f5 100644 --- a/apps/user_status/l10n/es.js +++ b/apps/user_status/l10n/es.js @@ -2,39 +2,47 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Estados recientes", + "No recent status changes" : "No hay cambios de estado recientes", "In a meeting" : "En una reunión", "Commuting" : "De viaje", "Out sick" : "Ausente por enfermedad", "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", "Working remotely" : "Teletrabajando", "In a call" : "En una llamada", "User status" : "Estado del usuario", - "View profile" : "Ver perfil", - "Clear status message after" : "Borrar mensaje de estado después de", + "Clear status after" : "Eliminar el estado después de", + "Emoji for your status message" : "Emoji para sus mensaje de estado", "What is your status?" : "¿Cuál es su estado?", - "Set status" : "Configurar estado", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Previamente definido", + "Reset status" : "Re-inicializar estado", + "Reset status to \"{icon} {message}\"" : "Re-inicializar estado a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Re-inicializar estado a \"{message}\"", + "Reset status to \"{icon}\"" : "Re-inicializar estado a \"{icon}\"", + "There was an error saving the status" : "Ha habido un error al guardar el estado", + "There was an error clearing the status" : "Ha habido un error al eliminar el estado", + "There was an error reverting the status" : "Ocurrió un error al revertir el estado", "Online status" : "Estado en línea", "Status message" : "Mensaje de estado", + "Your status was set automatically" : "Su estado fue definido automáticamente", "Clear status message" : "Borrar mensaje de estado", "Set status message" : "Ajustar el mensaje de estado", - "There was an error saving the status" : "Ha habido un error al guardar el estado", - "There was an error clearing the status" : "Ha habido un error al eliminar el estado", - "No recent status changes" : "No hay cambios de estado recientes", - "Away" : "Ausente", - "Do not disturb" : "No molestar", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "No eliminar", "Today" : "Hoy", "This week" : "Esta semana", "Online" : "En línea", + "Away" : "Ausente", + "Do not disturb" : "No molestar", "Invisible" : "Invisible", "Offline" : "Sin conexión", + "Set status" : "Configurar estado", "There was an error saving the new status" : "Ha habido un error al guardar el nuevo estado", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", + "Busy" : "Ocupado", "Mute all notifications" : "Silenciar todas las notificaciones", - "Appear offline" : "Aparecer sin conexión", - "What's your status?" : "¿Cuál es tu estado?" + "Appear offline" : "Aparecer sin conexión" }, -"nplurals=2; plural=(n != 1);"); +"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/es.json b/apps/user_status/l10n/es.json index 689eca66c74..d743ee8a033 100644 --- a/apps/user_status/l10n/es.json +++ b/apps/user_status/l10n/es.json @@ -1,38 +1,46 @@ { "translations": { "Recent statuses" : "Estados recientes", + "No recent status changes" : "No hay cambios de estado recientes", "In a meeting" : "En una reunión", "Commuting" : "De viaje", "Out sick" : "Ausente por enfermedad", "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", "Working remotely" : "Teletrabajando", "In a call" : "En una llamada", "User status" : "Estado del usuario", - "View profile" : "Ver perfil", - "Clear status message after" : "Borrar mensaje de estado después de", + "Clear status after" : "Eliminar el estado después de", + "Emoji for your status message" : "Emoji para sus mensaje de estado", "What is your status?" : "¿Cuál es su estado?", - "Set status" : "Configurar estado", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Previamente definido", + "Reset status" : "Re-inicializar estado", + "Reset status to \"{icon} {message}\"" : "Re-inicializar estado a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Re-inicializar estado a \"{message}\"", + "Reset status to \"{icon}\"" : "Re-inicializar estado a \"{icon}\"", + "There was an error saving the status" : "Ha habido un error al guardar el estado", + "There was an error clearing the status" : "Ha habido un error al eliminar el estado", + "There was an error reverting the status" : "Ocurrió un error al revertir el estado", "Online status" : "Estado en línea", "Status message" : "Mensaje de estado", + "Your status was set automatically" : "Su estado fue definido automáticamente", "Clear status message" : "Borrar mensaje de estado", "Set status message" : "Ajustar el mensaje de estado", - "There was an error saving the status" : "Ha habido un error al guardar el estado", - "There was an error clearing the status" : "Ha habido un error al eliminar el estado", - "No recent status changes" : "No hay cambios de estado recientes", - "Away" : "Ausente", - "Do not disturb" : "No molestar", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "No eliminar", "Today" : "Hoy", "This week" : "Esta semana", "Online" : "En línea", + "Away" : "Ausente", + "Do not disturb" : "No molestar", "Invisible" : "Invisible", "Offline" : "Sin conexión", + "Set status" : "Configurar estado", "There was an error saving the new status" : "Ha habido un error al guardar el nuevo estado", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", + "Busy" : "Ocupado", "Mute all notifications" : "Silenciar todas las notificaciones", - "Appear offline" : "Aparecer sin conexión", - "What's your status?" : "¿Cuál es tu estado?" -},"pluralForm" :"nplurals=2; plural=(n != 1);" + "Appear offline" : "Aparecer sin conexión" +},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/es_AR.js b/apps/user_status/l10n/es_AR.js deleted file mode 100644 index b5430541548..00000000000 --- a/apps/user_status/l10n/es_AR.js +++ /dev/null @@ -1,23 +0,0 @@ -OC.L10N.register( - "user_status", - { - "Clear status message after" : "Limpiar mensaje de estado después", - "Set status" : "Establecer estado", - "Online status" : "Estado en línea", - "Status message" : "Mensaje de estado", - "Clear status message" : "Limpiar mensaje de estado", - "Set status message" : "Establecer mensaje de estado", - "Away" : "Lejos", - "Do not disturb" : "No molestar", - "Don't clear" : "No vaciar", - "Today" : "Hoy", - "This week" : "Esta semana", - "Online" : "En línea", - "Invisible" : "Invisible", - "Offline" : "Sin conexión", - "30 minutes" : "30 minutos", - "1 hour" : "1 hora", - "4 hours" : "4 horas", - "What's your status?" : "¿Cual es tu estado?" -}, -"nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/es_AR.json b/apps/user_status/l10n/es_AR.json deleted file mode 100644 index fb7502e9499..00000000000 --- a/apps/user_status/l10n/es_AR.json +++ /dev/null @@ -1,21 +0,0 @@ -{ "translations": { - "Clear status message after" : "Limpiar mensaje de estado después", - "Set status" : "Establecer estado", - "Online status" : "Estado en línea", - "Status message" : "Mensaje de estado", - "Clear status message" : "Limpiar mensaje de estado", - "Set status message" : "Establecer mensaje de estado", - "Away" : "Lejos", - "Do not disturb" : "No molestar", - "Don't clear" : "No vaciar", - "Today" : "Hoy", - "This week" : "Esta semana", - "Online" : "En línea", - "Invisible" : "Invisible", - "Offline" : "Sin conexión", - "30 minutes" : "30 minutos", - "1 hour" : "1 hora", - "4 hours" : "4 horas", - "What's your status?" : "¿Cual es tu estado?" -},"pluralForm" :"nplurals=2; plural=(n != 1);" -}
\ No newline at end of file diff --git a/apps/user_status/l10n/es_EC.js b/apps/user_status/l10n/es_EC.js new file mode 100644 index 00000000000..6500afa7c5a --- /dev/null +++ b/apps/user_status/l10n/es_EC.js @@ -0,0 +1,48 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Estados recientes", + "No recent status changes" : "No hay cambios recientes de estado", + "In a meeting" : "En una reunión", + "Commuting" : "Desplazamiento", + "Out sick" : "Ausente por enfermedad", + "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", + "Working remotely" : "Trabajando de forma remota", + "In a call" : "En una llamada", + "User status" : "Estado de usuario", + "Clear status after" : "Borrar estado después de", + "Emoji for your status message" : "Emoji para tu mensaje de estado", + "What is your status?" : "¿Cuál es tu estado?", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Previamente establecido", + "Reset status" : "Restablecer estado", + "Reset status to \"{icon} {message}\"" : "Restablecer estado a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Restablecer estado a \"{message}\"", + "Reset status to \"{icon}\"" : "Restablecer estado a \"{icon}\"", + "There was an error saving the status" : "Hubo un error al guardar el estado", + "There was an error clearing the status" : "Hubo un error al borrar el estado", + "There was an error reverting the status" : "Hubo un error al revertir el estado", + "Online status" : "Estado en línea", + "Status message" : "Mensaje de estado", + "Your status was set automatically" : "Tu estado se estableció automáticamente", + "Clear status message" : "Borrar mensaje de estado", + "Set status message" : "Establecer mensaje de estado", + "Don't clear" : "No borrar", + "Today" : "Hoy", + "This week" : "Esta semana", + "Online" : "En línea", + "Away" : "Ausente", + "Do not disturb" : "No molestar", + "Invisible" : "Invisible", + "Offline" : "Sin conexión", + "Set status" : "Establecer estado", + "There was an error saving the new status" : "Hubo un error al guardar el nuevo estado", + "30 minutes" : "30 minutos", + "1 hour" : "1 hora", + "4 hours" : "4 horas", + "Busy" : "Ocupado", + "Mute all notifications" : "Silenciar todas las notificaciones", + "Appear offline" : "Aparecer como desconectado" +}, +"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/es_EC.json b/apps/user_status/l10n/es_EC.json new file mode 100644 index 00000000000..4d6f3df54ec --- /dev/null +++ b/apps/user_status/l10n/es_EC.json @@ -0,0 +1,46 @@ +{ "translations": { + "Recent statuses" : "Estados recientes", + "No recent status changes" : "No hay cambios recientes de estado", + "In a meeting" : "En una reunión", + "Commuting" : "Desplazamiento", + "Out sick" : "Ausente por enfermedad", + "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", + "Working remotely" : "Trabajando de forma remota", + "In a call" : "En una llamada", + "User status" : "Estado de usuario", + "Clear status after" : "Borrar estado después de", + "Emoji for your status message" : "Emoji para tu mensaje de estado", + "What is your status?" : "¿Cuál es tu estado?", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Previamente establecido", + "Reset status" : "Restablecer estado", + "Reset status to \"{icon} {message}\"" : "Restablecer estado a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Restablecer estado a \"{message}\"", + "Reset status to \"{icon}\"" : "Restablecer estado a \"{icon}\"", + "There was an error saving the status" : "Hubo un error al guardar el estado", + "There was an error clearing the status" : "Hubo un error al borrar el estado", + "There was an error reverting the status" : "Hubo un error al revertir el estado", + "Online status" : "Estado en línea", + "Status message" : "Mensaje de estado", + "Your status was set automatically" : "Tu estado se estableció automáticamente", + "Clear status message" : "Borrar mensaje de estado", + "Set status message" : "Establecer mensaje de estado", + "Don't clear" : "No borrar", + "Today" : "Hoy", + "This week" : "Esta semana", + "Online" : "En línea", + "Away" : "Ausente", + "Do not disturb" : "No molestar", + "Invisible" : "Invisible", + "Offline" : "Sin conexión", + "Set status" : "Establecer estado", + "There was an error saving the new status" : "Hubo un error al guardar el nuevo estado", + "30 minutes" : "30 minutos", + "1 hour" : "1 hora", + "4 hours" : "4 horas", + "Busy" : "Ocupado", + "Mute all notifications" : "Silenciar todas las notificaciones", + "Appear offline" : "Aparecer como desconectado" +},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/es_MX.js b/apps/user_status/l10n/es_MX.js new file mode 100644 index 00000000000..1b5aae7f116 --- /dev/null +++ b/apps/user_status/l10n/es_MX.js @@ -0,0 +1,48 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Estados recientes", + "No recent status changes" : "No hay cambios recientes de estado", + "In a meeting" : "En una reunión", + "Commuting" : "Trasladándose", + "Out sick" : "Enfermo", + "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", + "Working remotely" : "Trabajando remotamente", + "In a call" : "En una llamada", + "User status" : "Estado de usuario", + "Clear status after" : "Limpiar el estado después de", + "Emoji for your status message" : "Emoji para su mensaje de estado", + "What is your status?" : "¿Cuál es su estado?", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Previamente establecido", + "Reset status" : "Restablecer estado", + "Reset status to \"{icon} {message}\"" : "Restablecer estado a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Restablecer estado a \"{message}\"", + "Reset status to \"{icon}\"" : "Restablecer estado a \"{icon}\"", + "There was an error saving the status" : "Hubo un error al guardar el estado", + "There was an error clearing the status" : "Hubo un error al limpiar el estado", + "There was an error reverting the status" : "Hubo un error al revertir el estado", + "Online status" : "Estado en línea", + "Status message" : "Mensaje de estado", + "Your status was set automatically" : "Su estado se estableció automáticamente", + "Clear status message" : "Borrar mensaje de estado", + "Set status message" : "Establecer mensaje de estado", + "Don't clear" : "No borrar", + "Today" : "Hoy", + "This week" : "Esta semana", + "Online" : "En línea", + "Away" : "Ausente", + "Do not disturb" : "No molestar", + "Invisible" : "Invisible", + "Offline" : "Sin conexión", + "Set status" : "Establecer estado", + "There was an error saving the new status" : "Hubo un error al guardar el nuevo estado", + "30 minutes" : "30 minutos", + "1 hour" : "1 hora", + "4 hours" : "4 horas", + "Busy" : "Ocupado", + "Mute all notifications" : "Silenciar todas las notificaciones", + "Appear offline" : "Aparecer como desconectado" +}, +"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/es_MX.json b/apps/user_status/l10n/es_MX.json new file mode 100644 index 00000000000..26f418adc7f --- /dev/null +++ b/apps/user_status/l10n/es_MX.json @@ -0,0 +1,46 @@ +{ "translations": { + "Recent statuses" : "Estados recientes", + "No recent status changes" : "No hay cambios recientes de estado", + "In a meeting" : "En una reunión", + "Commuting" : "Trasladándose", + "Out sick" : "Enfermo", + "Vacationing" : "De vacaciones", + "Out of office" : "Fuera de la oficina", + "Working remotely" : "Trabajando remotamente", + "In a call" : "En una llamada", + "User status" : "Estado de usuario", + "Clear status after" : "Limpiar el estado después de", + "Emoji for your status message" : "Emoji para su mensaje de estado", + "What is your status?" : "¿Cuál es su estado?", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Previamente establecido", + "Reset status" : "Restablecer estado", + "Reset status to \"{icon} {message}\"" : "Restablecer estado a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Restablecer estado a \"{message}\"", + "Reset status to \"{icon}\"" : "Restablecer estado a \"{icon}\"", + "There was an error saving the status" : "Hubo un error al guardar el estado", + "There was an error clearing the status" : "Hubo un error al limpiar el estado", + "There was an error reverting the status" : "Hubo un error al revertir el estado", + "Online status" : "Estado en línea", + "Status message" : "Mensaje de estado", + "Your status was set automatically" : "Su estado se estableció automáticamente", + "Clear status message" : "Borrar mensaje de estado", + "Set status message" : "Establecer mensaje de estado", + "Don't clear" : "No borrar", + "Today" : "Hoy", + "This week" : "Esta semana", + "Online" : "En línea", + "Away" : "Ausente", + "Do not disturb" : "No molestar", + "Invisible" : "Invisible", + "Offline" : "Sin conexión", + "Set status" : "Establecer estado", + "There was an error saving the new status" : "Hubo un error al guardar el nuevo estado", + "30 minutes" : "30 minutos", + "1 hour" : "1 hora", + "4 hours" : "4 horas", + "Busy" : "Ocupado", + "Mute all notifications" : "Silenciar todas las notificaciones", + "Appear offline" : "Aparecer como desconectado" +},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/et_EE.js b/apps/user_status/l10n/et_EE.js new file mode 100644 index 00000000000..18c3c88e824 --- /dev/null +++ b/apps/user_status/l10n/et_EE.js @@ -0,0 +1,51 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Hiljutised olekud", + "No recent status changes" : "Pole hiljutisi olekumuudatusi", + "In a meeting" : "Koosolekul", + "Commuting" : "Sõidus", + "Out sick" : "Haige", + "Vacationing" : "Puhkusel", + "Out of office" : "Kontorist väljas", + "Working remotely" : "Kaugtööl", + "In a call" : "Kõnes", + "Be right back" : "Kohe jõuan tagasi", + "User status" : "Kasutaja olek", + "Clear status after" : "Eemalda olekuteade peale", + "Emoji for your status message" : "Sinu olekuteate emoji", + "What is your status?" : "Mis on su olek?", + "Predefined statuses" : "Eeldefineeritud olekud", + "Previously set" : "Varasemalt seatud", + "Reset status" : "Lähesta olek", + "Reset status to \"{icon} {message}\"" : "Lähesta olek „{icon} {message}“-ks", + "Reset status to \"{message}\"" : "Lähesta olek „{message}“-ks", + "Reset status to \"{icon}\"" : "Lähesta olek „{icon}“-ks", + "There was an error saving the status" : "Oleku salvestamisel tekkis viga", + "There was an error clearing the status" : "Oleku eemaldamisel tekkis viga", + "There was an error reverting the status" : "Oleku taastamisel tekkis viga", + "Online status" : "Olek võrgus", + "Status message" : "Olekuteade", + "Set absence period" : "Määra eemaloleku periood", + "Set absence period and replacement" : "Määra eemaloleku periood ja asendaja", + "Your status was set automatically" : "Su olek määrati automaatselt", + "Clear status message" : "Eemalda olekuteade", + "Set status message" : "Lisa olekusõnum", + "Don't clear" : "Ära kustuta", + "Today" : "Tänast", + "This week" : "Käesoleval nädalal", + "Online" : "Võrgus", + "Away" : "Eemal", + "Do not disturb" : "Ära sega", + "Invisible" : "Nähtamatu", + "Offline" : "Pole võrgus", + "Set status" : "Määra olek", + "There was an error saving the new status" : "Uue oleku salvestamisel esines viga", + "30 minutes" : "30 minutit", + "1 hour" : "1 tundi", + "4 hours" : "4 tundi", + "Busy" : "Hõivatud", + "Mute all notifications" : "Sellega summutad teavitused", + "Appear offline" : "Sellega paistad olema võrgust väljas" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/et_EE.json b/apps/user_status/l10n/et_EE.json new file mode 100644 index 00000000000..903466eef24 --- /dev/null +++ b/apps/user_status/l10n/et_EE.json @@ -0,0 +1,49 @@ +{ "translations": { + "Recent statuses" : "Hiljutised olekud", + "No recent status changes" : "Pole hiljutisi olekumuudatusi", + "In a meeting" : "Koosolekul", + "Commuting" : "Sõidus", + "Out sick" : "Haige", + "Vacationing" : "Puhkusel", + "Out of office" : "Kontorist väljas", + "Working remotely" : "Kaugtööl", + "In a call" : "Kõnes", + "Be right back" : "Kohe jõuan tagasi", + "User status" : "Kasutaja olek", + "Clear status after" : "Eemalda olekuteade peale", + "Emoji for your status message" : "Sinu olekuteate emoji", + "What is your status?" : "Mis on su olek?", + "Predefined statuses" : "Eeldefineeritud olekud", + "Previously set" : "Varasemalt seatud", + "Reset status" : "Lähesta olek", + "Reset status to \"{icon} {message}\"" : "Lähesta olek „{icon} {message}“-ks", + "Reset status to \"{message}\"" : "Lähesta olek „{message}“-ks", + "Reset status to \"{icon}\"" : "Lähesta olek „{icon}“-ks", + "There was an error saving the status" : "Oleku salvestamisel tekkis viga", + "There was an error clearing the status" : "Oleku eemaldamisel tekkis viga", + "There was an error reverting the status" : "Oleku taastamisel tekkis viga", + "Online status" : "Olek võrgus", + "Status message" : "Olekuteade", + "Set absence period" : "Määra eemaloleku periood", + "Set absence period and replacement" : "Määra eemaloleku periood ja asendaja", + "Your status was set automatically" : "Su olek määrati automaatselt", + "Clear status message" : "Eemalda olekuteade", + "Set status message" : "Lisa olekusõnum", + "Don't clear" : "Ära kustuta", + "Today" : "Tänast", + "This week" : "Käesoleval nädalal", + "Online" : "Võrgus", + "Away" : "Eemal", + "Do not disturb" : "Ära sega", + "Invisible" : "Nähtamatu", + "Offline" : "Pole võrgus", + "Set status" : "Määra olek", + "There was an error saving the new status" : "Uue oleku salvestamisel esines viga", + "30 minutes" : "30 minutit", + "1 hour" : "1 tundi", + "4 hours" : "4 tundi", + "Busy" : "Hõivatud", + "Mute all notifications" : "Sellega summutad teavitused", + "Appear offline" : "Sellega paistad olema võrgust väljas" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/eu.js b/apps/user_status/l10n/eu.js index 3570ea6f8f1..b10e38ec09e 100644 --- a/apps/user_status/l10n/eu.js +++ b/apps/user_status/l10n/eu.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Azken egoerak", + "No recent status changes" : "Azken egoera-aldaketarik ez", "In a meeting" : "Bilera batean", "Commuting" : "Lanerako bidean", "Out sick" : "Gaixorik", "Vacationing" : "Oporretan", + "Out of office" : "Bulegotik kanpo", "Working remotely" : "Urrutitik lanean", "In a call" : "Dei batean", "User status" : "Erabiltzaile-egoera", - "View profile" : "Ikusi profila", - "Clear status message after" : "Garbitu egoera mezua ondoren", + "Clear status after" : "Garbitu egoera honen ondoren", + "Emoji for your status message" : "Zure egoera-mezurako emojia", "What is your status?" : "Zein da zure egoera?", - "Set status" : "Ezarri egoera", + "Predefined statuses" : "Aurrez definitutako egoerak", + "Previously set" : "Lehendik ezarrita", + "Reset status" : "Berrezarri egoera", + "Reset status to \"{icon} {message}\"" : "Berrezarri egoera \"{icon} {message}\"(e)ra", + "Reset status to \"{message}\"" : "Berrezarri egoera \"{message}\"(e)ra", + "Reset status to \"{icon}\"" : "Berrezarri egoera \"{icon}\"(e)ra", + "There was an error saving the status" : "Errore bat gertatu da egoera gordetzean", + "There was an error clearing the status" : "Errore bat gertatu da egoera garbitzean", + "There was an error reverting the status" : "Errore bat gertatu da egoera berrezartzean", "Online status" : "Lineako egoera", "Status message" : "Egoera-mezua", + "Set absence period" : "Ezarri absentzia aldia", + "Set absence period and replacement" : "Ezarri absentzia aldia eta ordezkoa", + "Your status was set automatically" : "Zure egoera automatikoki ezarriko dira", "Clear status message" : "Garbitu egoera-mezua", "Set status message" : "Ezarri egoera-mezua", - "There was an error saving the status" : "Errore bat gertatu da egoera gordetzean", - "There was an error clearing the status" : "Errore bat gertatu da egoera garbitzean", - "No recent status changes" : "Azken egoera-aldaketarik ez", - "Away" : "Kanpoan", - "Do not disturb" : "Ez molestatu", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ez garbitu", "Today" : "Gaur", "This week" : "Aste honetan", "Online" : "Linean", + "Away" : "Kanpoan", + "Do not disturb" : "Ez molestatu", "Invisible" : "Ikusezina", "Offline" : "Lineaz kanpo", + "Set status" : "Ezarri egoera", "There was an error saving the new status" : "Errore bat gertatu da egoera berria gordetzean", "30 minutes" : "30 minutu", "1 hour" : "Ordu 1", "4 hours" : "4 ordu", + "Busy" : "Lanpetua", "Mute all notifications" : "Mututu jakinarazpen guztiak", - "Appear offline" : "Lineaz kanpo agertu", - "What's your status?" : "Zein da zure egoera?" + "Appear offline" : "Lineaz kanpo agertu" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/eu.json b/apps/user_status/l10n/eu.json index 61b8ec3bee0..3362581d9f5 100644 --- a/apps/user_status/l10n/eu.json +++ b/apps/user_status/l10n/eu.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Azken egoerak", + "No recent status changes" : "Azken egoera-aldaketarik ez", "In a meeting" : "Bilera batean", "Commuting" : "Lanerako bidean", "Out sick" : "Gaixorik", "Vacationing" : "Oporretan", + "Out of office" : "Bulegotik kanpo", "Working remotely" : "Urrutitik lanean", "In a call" : "Dei batean", "User status" : "Erabiltzaile-egoera", - "View profile" : "Ikusi profila", - "Clear status message after" : "Garbitu egoera mezua ondoren", + "Clear status after" : "Garbitu egoera honen ondoren", + "Emoji for your status message" : "Zure egoera-mezurako emojia", "What is your status?" : "Zein da zure egoera?", - "Set status" : "Ezarri egoera", + "Predefined statuses" : "Aurrez definitutako egoerak", + "Previously set" : "Lehendik ezarrita", + "Reset status" : "Berrezarri egoera", + "Reset status to \"{icon} {message}\"" : "Berrezarri egoera \"{icon} {message}\"(e)ra", + "Reset status to \"{message}\"" : "Berrezarri egoera \"{message}\"(e)ra", + "Reset status to \"{icon}\"" : "Berrezarri egoera \"{icon}\"(e)ra", + "There was an error saving the status" : "Errore bat gertatu da egoera gordetzean", + "There was an error clearing the status" : "Errore bat gertatu da egoera garbitzean", + "There was an error reverting the status" : "Errore bat gertatu da egoera berrezartzean", "Online status" : "Lineako egoera", "Status message" : "Egoera-mezua", + "Set absence period" : "Ezarri absentzia aldia", + "Set absence period and replacement" : "Ezarri absentzia aldia eta ordezkoa", + "Your status was set automatically" : "Zure egoera automatikoki ezarriko dira", "Clear status message" : "Garbitu egoera-mezua", "Set status message" : "Ezarri egoera-mezua", - "There was an error saving the status" : "Errore bat gertatu da egoera gordetzean", - "There was an error clearing the status" : "Errore bat gertatu da egoera garbitzean", - "No recent status changes" : "Azken egoera-aldaketarik ez", - "Away" : "Kanpoan", - "Do not disturb" : "Ez molestatu", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ez garbitu", "Today" : "Gaur", "This week" : "Aste honetan", "Online" : "Linean", + "Away" : "Kanpoan", + "Do not disturb" : "Ez molestatu", "Invisible" : "Ikusezina", "Offline" : "Lineaz kanpo", + "Set status" : "Ezarri egoera", "There was an error saving the new status" : "Errore bat gertatu da egoera berria gordetzean", "30 minutes" : "30 minutu", "1 hour" : "Ordu 1", "4 hours" : "4 ordu", + "Busy" : "Lanpetua", "Mute all notifications" : "Mututu jakinarazpen guztiak", - "Appear offline" : "Lineaz kanpo agertu", - "What's your status?" : "Zein da zure egoera?" + "Appear offline" : "Lineaz kanpo agertu" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/fa.js b/apps/user_status/l10n/fa.js index 1c366ee07ce..e3e600eb696 100644 --- a/apps/user_status/l10n/fa.js +++ b/apps/user_status/l10n/fa.js @@ -1,24 +1,48 @@ OC.L10N.register( "user_status", { - "Clear status message after" : "بعد از آن پیام وضعیت را پاک کن ", + "Recent statuses" : "وضعیت های اخیر", + "No recent status changes" : "هیچ تغییر وضعیت جدیدی وجود ندارد", + "In a meeting" : "در جلسه", + "Commuting" : "در رفت و آمد", + "Out sick" : "مرخصی استعلاجی", + "Vacationing" : "تعطیلات", + "Out of office" : "بیرون از دفتر", + "Working remotely" : "دورکاری", + "In a call" : "در حال تماس تلفنی", + "User status" : "وضعبت کاربر", + "Clear status after" : "پاک کردن وضعیت بعدی", + "Emoji for your status message" : "Emoji for your status message", "What is your status?" : "وضعیت شما چیست؟", - "Set status" : "تنظیم وضعیت", + "Predefined statuses" : "Predefined statuses", + "Previously set" : "Previously set", + "Reset status" : "Reset status", + "Reset status to \"{icon} {message}\"" : "Reset status to \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Reset status to \"{message}\"", + "Reset status to \"{icon}\"" : "Reset status to \"{icon}\"", + "There was an error saving the status" : "مشکلی در ذخیره سازی وضعیت پیش آمده", + "There was an error clearing the status" : "مشکلی در پاک کردن وضعیت پیش آمده", + "There was an error reverting the status" : "There was an error reverting the status", "Online status" : "وضعیت آنلاین", "Status message" : "پیغام وضعیت", + "Your status was set automatically" : "Your status was set automatically", "Clear status message" : "پیام وضعیت را پاک کن", "Set status message" : "تنظیم پیام وضعیت", - "Away" : "دور", - "Do not disturb" : "مزاحم نشوید", "Don't clear" : "پاک نکن", - "Today" : "Today", + "Today" : "امروز", "This week" : "این هفته", "Online" : "آنلاین", - "Invisible" : "نامرئی", + "Away" : "بیرون", + "Do not disturb" : "مزاحم نشوید", + "Invisible" : "غیر قابل مشاهده", "Offline" : "آفلاین", + "Set status" : "تنظیم وضعیت", + "There was an error saving the new status" : "مشکلی در ذخیره سازی وضعیت جدید پیش آمده", "30 minutes" : "۳۰ دقیقه", - "1 hour" : "1 ساعت", + "1 hour" : "۱ ساعت", "4 hours" : "۴ ساعت", - "What's your status?" : "وضعیت شما چیست؟" + "Busy" : "مشغول", + "Mute all notifications" : "خاموش کردن همه اعلانات", + "Appear offline" : "نمایش آفلاین" }, "nplurals=2; plural=(n > 1);"); diff --git a/apps/user_status/l10n/fa.json b/apps/user_status/l10n/fa.json index 798741ed37d..ab997e0a8a7 100644 --- a/apps/user_status/l10n/fa.json +++ b/apps/user_status/l10n/fa.json @@ -1,22 +1,46 @@ { "translations": { - "Clear status message after" : "بعد از آن پیام وضعیت را پاک کن ", + "Recent statuses" : "وضعیت های اخیر", + "No recent status changes" : "هیچ تغییر وضعیت جدیدی وجود ندارد", + "In a meeting" : "در جلسه", + "Commuting" : "در رفت و آمد", + "Out sick" : "مرخصی استعلاجی", + "Vacationing" : "تعطیلات", + "Out of office" : "بیرون از دفتر", + "Working remotely" : "دورکاری", + "In a call" : "در حال تماس تلفنی", + "User status" : "وضعبت کاربر", + "Clear status after" : "پاک کردن وضعیت بعدی", + "Emoji for your status message" : "Emoji for your status message", "What is your status?" : "وضعیت شما چیست؟", - "Set status" : "تنظیم وضعیت", + "Predefined statuses" : "Predefined statuses", + "Previously set" : "Previously set", + "Reset status" : "Reset status", + "Reset status to \"{icon} {message}\"" : "Reset status to \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Reset status to \"{message}\"", + "Reset status to \"{icon}\"" : "Reset status to \"{icon}\"", + "There was an error saving the status" : "مشکلی در ذخیره سازی وضعیت پیش آمده", + "There was an error clearing the status" : "مشکلی در پاک کردن وضعیت پیش آمده", + "There was an error reverting the status" : "There was an error reverting the status", "Online status" : "وضعیت آنلاین", "Status message" : "پیغام وضعیت", + "Your status was set automatically" : "Your status was set automatically", "Clear status message" : "پیام وضعیت را پاک کن", "Set status message" : "تنظیم پیام وضعیت", - "Away" : "دور", - "Do not disturb" : "مزاحم نشوید", "Don't clear" : "پاک نکن", - "Today" : "Today", + "Today" : "امروز", "This week" : "این هفته", "Online" : "آنلاین", - "Invisible" : "نامرئی", + "Away" : "بیرون", + "Do not disturb" : "مزاحم نشوید", + "Invisible" : "غیر قابل مشاهده", "Offline" : "آفلاین", + "Set status" : "تنظیم وضعیت", + "There was an error saving the new status" : "مشکلی در ذخیره سازی وضعیت جدید پیش آمده", "30 minutes" : "۳۰ دقیقه", - "1 hour" : "1 ساعت", + "1 hour" : "۱ ساعت", "4 hours" : "۴ ساعت", - "What's your status?" : "وضعیت شما چیست؟" + "Busy" : "مشغول", + "Mute all notifications" : "خاموش کردن همه اعلانات", + "Appear offline" : "نمایش آفلاین" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/fi.js b/apps/user_status/l10n/fi.js index 248b2793723..db936384ff9 100644 --- a/apps/user_status/l10n/fi.js +++ b/apps/user_status/l10n/fi.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Viimeisimmät tilatiedot", + "No recent status changes" : "Ei viimeisimpiä tilatietomuutoksia", "In a meeting" : "Tapaamisessa", "Commuting" : "Työmatkalla", "Out sick" : "Sairaana", "Vacationing" : "Lomailemassa", + "Out of office" : "Poissa työpaikalta", "Working remotely" : "Etätyössä", "In a call" : "Puhelussa", "User status" : "Käyttäjän tilatieto", - "View profile" : "Näytä profiili", - "Clear status message after" : "Tyhjennä tilaviesti, kun on kulunut", + "Clear status after" : "Tyhjennä tilatieto", + "Emoji for your status message" : "Emoji tilaviestiisi", "What is your status?" : "Mikä on tilatietosi?", - "Set status" : "Aseta tilatieto", + "Predefined statuses" : "Ennalta määritellyt tilatiedot", + "Previously set" : "Aiemmin asetettu", + "Reset status" : "Palauta tilatieto", + "Reset status to \"{icon} {message}\"" : "Palauta tilatiedoksi \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Palauta tilatiedoksi \"{message}\"", + "Reset status to \"{icon}\"" : "Palauta tilatiedoksi \"{icon}\"", + "There was an error saving the status" : "Tilatiedon tallentamisessa tapahtui virhe", + "There was an error clearing the status" : "Tilatietoa tyhjentäessä tapahtui virhe", + "There was an error reverting the status" : "Tilatietoa palauttaessa tapahtui virhe", "Online status" : "Online-tila", "Status message" : "Tilaviesti", + "Set absence period" : "Aseta poissaoloaika", + "Set absence period and replacement" : "Aseta poissaoloaika ja sijainen", + "Your status was set automatically" : "Tilatietosi asetettiin automaattisesti", "Clear status message" : "Tyhjennä tilaviesti", "Set status message" : "Aseta tilaviesti", - "There was an error saving the status" : "Tilatiedon tallentamisessa tapahtui virhe", - "There was an error clearing the status" : "Tilatietoa tyhjentäessä tapahtui virhe", - "No recent status changes" : "Ei viimeisimpiä tilatietomuutoksia", - "Away" : "Poissa", - "Do not disturb" : "Älä häiritse", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Älä tyhjennä", "Today" : "Tänään", "This week" : "Tällä viikolla", "Online" : "Paikalla", + "Away" : "Poissa", + "Do not disturb" : "Älä häiritse", "Invisible" : "Näkymätön", "Offline" : "Poissa", + "Set status" : "Aseta tilatieto", "There was an error saving the new status" : "Uuden tilatiedon tallentamisessa tapahtui virhe", "30 minutes" : "30 minuuttia", "1 hour" : "1 tunti", "4 hours" : "4 tuntia", + "Busy" : "Varattu", "Mute all notifications" : "Mykistä kaikki ilmoitukset", - "Appear offline" : "Näytä olevan poissa", - "What's your status?" : "Mikä on tilatietosi?" + "Appear offline" : "Näytä olevan poissa" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/fi.json b/apps/user_status/l10n/fi.json index 60ff001643c..5a7ad4fa685 100644 --- a/apps/user_status/l10n/fi.json +++ b/apps/user_status/l10n/fi.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Viimeisimmät tilatiedot", + "No recent status changes" : "Ei viimeisimpiä tilatietomuutoksia", "In a meeting" : "Tapaamisessa", "Commuting" : "Työmatkalla", "Out sick" : "Sairaana", "Vacationing" : "Lomailemassa", + "Out of office" : "Poissa työpaikalta", "Working remotely" : "Etätyössä", "In a call" : "Puhelussa", "User status" : "Käyttäjän tilatieto", - "View profile" : "Näytä profiili", - "Clear status message after" : "Tyhjennä tilaviesti, kun on kulunut", + "Clear status after" : "Tyhjennä tilatieto", + "Emoji for your status message" : "Emoji tilaviestiisi", "What is your status?" : "Mikä on tilatietosi?", - "Set status" : "Aseta tilatieto", + "Predefined statuses" : "Ennalta määritellyt tilatiedot", + "Previously set" : "Aiemmin asetettu", + "Reset status" : "Palauta tilatieto", + "Reset status to \"{icon} {message}\"" : "Palauta tilatiedoksi \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Palauta tilatiedoksi \"{message}\"", + "Reset status to \"{icon}\"" : "Palauta tilatiedoksi \"{icon}\"", + "There was an error saving the status" : "Tilatiedon tallentamisessa tapahtui virhe", + "There was an error clearing the status" : "Tilatietoa tyhjentäessä tapahtui virhe", + "There was an error reverting the status" : "Tilatietoa palauttaessa tapahtui virhe", "Online status" : "Online-tila", "Status message" : "Tilaviesti", + "Set absence period" : "Aseta poissaoloaika", + "Set absence period and replacement" : "Aseta poissaoloaika ja sijainen", + "Your status was set automatically" : "Tilatietosi asetettiin automaattisesti", "Clear status message" : "Tyhjennä tilaviesti", "Set status message" : "Aseta tilaviesti", - "There was an error saving the status" : "Tilatiedon tallentamisessa tapahtui virhe", - "There was an error clearing the status" : "Tilatietoa tyhjentäessä tapahtui virhe", - "No recent status changes" : "Ei viimeisimpiä tilatietomuutoksia", - "Away" : "Poissa", - "Do not disturb" : "Älä häiritse", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Älä tyhjennä", "Today" : "Tänään", "This week" : "Tällä viikolla", "Online" : "Paikalla", + "Away" : "Poissa", + "Do not disturb" : "Älä häiritse", "Invisible" : "Näkymätön", "Offline" : "Poissa", + "Set status" : "Aseta tilatieto", "There was an error saving the new status" : "Uuden tilatiedon tallentamisessa tapahtui virhe", "30 minutes" : "30 minuuttia", "1 hour" : "1 tunti", "4 hours" : "4 tuntia", + "Busy" : "Varattu", "Mute all notifications" : "Mykistä kaikki ilmoitukset", - "Appear offline" : "Näytä olevan poissa", - "What's your status?" : "Mikä on tilatietosi?" + "Appear offline" : "Näytä olevan poissa" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/fr.js b/apps/user_status/l10n/fr.js index 01abc796d3c..a00b780a33d 100644 --- a/apps/user_status/l10n/fr.js +++ b/apps/user_status/l10n/fr.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Statuts récents", + "No recent status changes" : "Aucun changement de statut récent", "In a meeting" : "En réunion", - "Commuting" : "En transit", + "Commuting" : "Trajet", "Out sick" : "En congé de maladie", "Vacationing" : "En vacances", + "Out of office" : "Absent du bureau", "Working remotely" : "Travail à distance", "In a call" : "En communication", "User status" : "Statut utilisateur", - "View profile" : "Voir le profil", - "Clear status message after" : "Effacer le message d'état après", + "Clear status after" : "Effacer l'état après", + "Emoji for your status message" : "Emoji pour votre message de statut", "What is your status?" : "Quel est votre statut ?", - "Set status" : "Définir le statut", + "Predefined statuses" : "Statuts prédéfinis", + "Previously set" : "Précédemment défini", + "Reset status" : "Réinitialiser l'état", + "Reset status to \"{icon} {message}\"" : "Réinitialiser l'état en \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Réinitialiser l'état en \"{message}\"", + "Reset status to \"{icon}\"" : "Réinitialiser l'état en \"{icon}\"", + "There was an error saving the status" : "Une erreur s'est produite lors de l'enregistrement de l'état", + "There was an error clearing the status" : "Une erreur s'est produite lors de l'effacement de l'état", + "There was an error reverting the status" : "Une erreur est survenue dans le rétablissement d'état", "Online status" : "Statut en ligne", "Status message" : "Message d'état", + "Set absence period" : "Définir une période d'absence", + "Set absence period and replacement" : "Définir une période d'absence et un remplaçant", + "Your status was set automatically" : "Votre état a été automatiquement défini", "Clear status message" : "Effacer le message d'état", - "Set status message" : "Message d'état", - "There was an error saving the status" : "Une erreur s'est produite lors de l'enregistrement de l'état", - "There was an error clearing the status" : "Une erreur s'est produite lors de l'effacement de l'état", - "No recent status changes" : "Aucun changement de statut récent", - "Away" : "Absent(e)", - "Do not disturb" : "Ne pas déranger", - "{status}, {timestamp}" : "{status}, {timestamp}", + "Set status message" : "Enregistrer le message d'état", "Don't clear" : "Ne pas effacer", "Today" : "Aujourd'hui", "This week" : "Cette semaine", "Online" : "En ligne", + "Away" : "Absent(e)", + "Do not disturb" : "Ne pas déranger", "Invisible" : "Invisible", "Offline" : "Hors-ligne", + "Set status" : "Définir le statut", "There was an error saving the new status" : "Une erreur s'est produite lors de l'enregistrement du nouveau statut", "30 minutes" : "30 minutes", "1 hour" : "1 heure", "4 hours" : "4 heures", - "Mute all notifications" : "Désactiver toutes les notifications", - "Appear offline" : "Apparaitre hors-ligne", - "What's your status?" : "Quel est votre statut ?" + "Busy" : "Occupé", + "Mute all notifications" : "Désactiver les notifications", + "Appear offline" : "Apparaitre hors-ligne" }, -"nplurals=2; plural=(n > 1);"); +"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/fr.json b/apps/user_status/l10n/fr.json index a62900e8f1f..98c873a2060 100644 --- a/apps/user_status/l10n/fr.json +++ b/apps/user_status/l10n/fr.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Statuts récents", + "No recent status changes" : "Aucun changement de statut récent", "In a meeting" : "En réunion", - "Commuting" : "En transit", + "Commuting" : "Trajet", "Out sick" : "En congé de maladie", "Vacationing" : "En vacances", + "Out of office" : "Absent du bureau", "Working remotely" : "Travail à distance", "In a call" : "En communication", "User status" : "Statut utilisateur", - "View profile" : "Voir le profil", - "Clear status message after" : "Effacer le message d'état après", + "Clear status after" : "Effacer l'état après", + "Emoji for your status message" : "Emoji pour votre message de statut", "What is your status?" : "Quel est votre statut ?", - "Set status" : "Définir le statut", + "Predefined statuses" : "Statuts prédéfinis", + "Previously set" : "Précédemment défini", + "Reset status" : "Réinitialiser l'état", + "Reset status to \"{icon} {message}\"" : "Réinitialiser l'état en \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Réinitialiser l'état en \"{message}\"", + "Reset status to \"{icon}\"" : "Réinitialiser l'état en \"{icon}\"", + "There was an error saving the status" : "Une erreur s'est produite lors de l'enregistrement de l'état", + "There was an error clearing the status" : "Une erreur s'est produite lors de l'effacement de l'état", + "There was an error reverting the status" : "Une erreur est survenue dans le rétablissement d'état", "Online status" : "Statut en ligne", "Status message" : "Message d'état", + "Set absence period" : "Définir une période d'absence", + "Set absence period and replacement" : "Définir une période d'absence et un remplaçant", + "Your status was set automatically" : "Votre état a été automatiquement défini", "Clear status message" : "Effacer le message d'état", - "Set status message" : "Message d'état", - "There was an error saving the status" : "Une erreur s'est produite lors de l'enregistrement de l'état", - "There was an error clearing the status" : "Une erreur s'est produite lors de l'effacement de l'état", - "No recent status changes" : "Aucun changement de statut récent", - "Away" : "Absent(e)", - "Do not disturb" : "Ne pas déranger", - "{status}, {timestamp}" : "{status}, {timestamp}", + "Set status message" : "Enregistrer le message d'état", "Don't clear" : "Ne pas effacer", "Today" : "Aujourd'hui", "This week" : "Cette semaine", "Online" : "En ligne", + "Away" : "Absent(e)", + "Do not disturb" : "Ne pas déranger", "Invisible" : "Invisible", "Offline" : "Hors-ligne", + "Set status" : "Définir le statut", "There was an error saving the new status" : "Une erreur s'est produite lors de l'enregistrement du nouveau statut", "30 minutes" : "30 minutes", "1 hour" : "1 heure", "4 hours" : "4 heures", - "Mute all notifications" : "Désactiver toutes les notifications", - "Appear offline" : "Apparaitre hors-ligne", - "What's your status?" : "Quel est votre statut ?" -},"pluralForm" :"nplurals=2; plural=(n > 1);" + "Busy" : "Occupé", + "Mute all notifications" : "Désactiver les notifications", + "Appear offline" : "Apparaitre hors-ligne" +},"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ga.js b/apps/user_status/l10n/ga.js new file mode 100644 index 00000000000..d976c272537 --- /dev/null +++ b/apps/user_status/l10n/ga.js @@ -0,0 +1,51 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Stádais le déanaí", + "No recent status changes" : "Níl aon athrú stádais le déanaí", + "In a meeting" : "I gcruinniú", + "Commuting" : "Comaitéireacht", + "Out sick" : "Amach tinn", + "Vacationing" : "Laethanta saoire", + "Out of office" : "As oifig", + "Working remotely" : "Ag obair go cianda", + "In a call" : "I nglao", + "Be right back" : "Ar ais láithreach", + "User status" : "Stádas úsáideora", + "Clear status after" : "Stádas soiléir tar éis", + "Emoji for your status message" : "Emoji do do theachtaireacht stádais", + "What is your status?" : "Cad é do stádas?", + "Predefined statuses" : "Stádais réamhshainithe", + "Previously set" : "Socraíodh roimhe seo", + "Reset status" : "Stádas a athshocrú", + "Reset status to \"{icon} {message}\"" : "Athshocraigh stádas go \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Athshocraigh stádas go \"{message}\"", + "Reset status to \"{icon}\"" : "Athshocraigh stádas go \"{icon}\"", + "There was an error saving the status" : "Tharla earráid agus an stádas á shábháil", + "There was an error clearing the status" : "Tharla earráid agus an stádas á ghlanadh", + "There was an error reverting the status" : "Tharla earráid agus an stádas á chur ar ais", + "Online status" : "Stádas ar líne", + "Status message" : "Teachtaireacht stádais", + "Set absence period" : "Socraigh tréimhse neamhláithreachta", + "Set absence period and replacement" : "Socraigh tréimhse neamhláithreachta agus athsholáthar", + "Your status was set automatically" : "Socraíodh do stádas go huathoibríoch", + "Clear status message" : "Glan teachtaireacht stádais", + "Set status message" : "Socraigh teachtaireacht stádais", + "Don't clear" : "Ná soiléir", + "Today" : "Inniu", + "This week" : "An tseachtain seo", + "Online" : "Ar líne", + "Away" : "Amach", + "Do not disturb" : "Ná cur as", + "Invisible" : "Dofheicthe", + "Offline" : "As líne", + "Set status" : "Socraigh stádas", + "There was an error saving the new status" : "Tharla earráid agus an stádas nua á shábháil", + "30 minutes" : "30 nóiméad", + "1 hour" : "1 uair", + "4 hours" : "4 uair an chloig", + "Busy" : "Gnóthach", + "Mute all notifications" : "Balbhaigh gach fógra", + "Appear offline" : "Le feiceáil as líne" +}, +"nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);"); diff --git a/apps/user_status/l10n/ga.json b/apps/user_status/l10n/ga.json new file mode 100644 index 00000000000..c672231aab3 --- /dev/null +++ b/apps/user_status/l10n/ga.json @@ -0,0 +1,49 @@ +{ "translations": { + "Recent statuses" : "Stádais le déanaí", + "No recent status changes" : "Níl aon athrú stádais le déanaí", + "In a meeting" : "I gcruinniú", + "Commuting" : "Comaitéireacht", + "Out sick" : "Amach tinn", + "Vacationing" : "Laethanta saoire", + "Out of office" : "As oifig", + "Working remotely" : "Ag obair go cianda", + "In a call" : "I nglao", + "Be right back" : "Ar ais láithreach", + "User status" : "Stádas úsáideora", + "Clear status after" : "Stádas soiléir tar éis", + "Emoji for your status message" : "Emoji do do theachtaireacht stádais", + "What is your status?" : "Cad é do stádas?", + "Predefined statuses" : "Stádais réamhshainithe", + "Previously set" : "Socraíodh roimhe seo", + "Reset status" : "Stádas a athshocrú", + "Reset status to \"{icon} {message}\"" : "Athshocraigh stádas go \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Athshocraigh stádas go \"{message}\"", + "Reset status to \"{icon}\"" : "Athshocraigh stádas go \"{icon}\"", + "There was an error saving the status" : "Tharla earráid agus an stádas á shábháil", + "There was an error clearing the status" : "Tharla earráid agus an stádas á ghlanadh", + "There was an error reverting the status" : "Tharla earráid agus an stádas á chur ar ais", + "Online status" : "Stádas ar líne", + "Status message" : "Teachtaireacht stádais", + "Set absence period" : "Socraigh tréimhse neamhláithreachta", + "Set absence period and replacement" : "Socraigh tréimhse neamhláithreachta agus athsholáthar", + "Your status was set automatically" : "Socraíodh do stádas go huathoibríoch", + "Clear status message" : "Glan teachtaireacht stádais", + "Set status message" : "Socraigh teachtaireacht stádais", + "Don't clear" : "Ná soiléir", + "Today" : "Inniu", + "This week" : "An tseachtain seo", + "Online" : "Ar líne", + "Away" : "Amach", + "Do not disturb" : "Ná cur as", + "Invisible" : "Dofheicthe", + "Offline" : "As líne", + "Set status" : "Socraigh stádas", + "There was an error saving the new status" : "Tharla earráid agus an stádas nua á shábháil", + "30 minutes" : "30 nóiméad", + "1 hour" : "1 uair", + "4 hours" : "4 uair an chloig", + "Busy" : "Gnóthach", + "Mute all notifications" : "Balbhaigh gach fógra", + "Appear offline" : "Le feiceáil as líne" +},"pluralForm" :"nplurals=5; plural=(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/gl.js b/apps/user_status/l10n/gl.js index 043184c79a0..3045c22fb4a 100644 --- a/apps/user_status/l10n/gl.js +++ b/apps/user_status/l10n/gl.js @@ -2,38 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Estados recentes", + "No recent status changes" : "Non hai cambios de estado recentes", "In a meeting" : "Nunha xuntanza", "Commuting" : "De casa ao traballo ou ao revés", "Out sick" : "Enfermo", "Vacationing" : "De vacacións", + "Out of office" : "Fóra da oficina", "Working remotely" : "Traballando en remoto", + "In a call" : "Nunha chamada", "User status" : "Estado do usuario", - "View profile" : "Ver o perfil", - "Clear status message after" : "Limpar a mensaxe de estado após", + "Clear status after" : "Limpar o estado após", + "Emoji for your status message" : "«Emoji» para a súa mensaxe de estado", "What is your status?" : "Cal é o seu estado?", - "Set status" : "Estabelecer o estado", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Estabelecido previamente", + "Reset status" : "Restabelecer o estado", + "Reset status to \"{icon} {message}\"" : "Restabelecer o estado a «{icon} {message}»", + "Reset status to \"{message}\"" : "Restabelecer o estado a «{message}»", + "Reset status to \"{icon}\"" : "Restabelecer o estado a «{icon}»", + "There was an error saving the status" : "Produciuse un erro ao gardar o estado", + "There was an error clearing the status" : "Produciuse un erro ao limpar o estado", + "There was an error reverting the status" : "Produciuse un erro ao reverter o estado", "Online status" : "Estado en liña", "Status message" : "Mensaxe de estado", + "Set absence period" : "Definir o período de ausencia", + "Set absence period and replacement" : "Definir o período de ausencia e substitución", + "Your status was set automatically" : "O seu estado foi estabelecido automaticamente", "Clear status message" : "Limpar a mensaxe de estado", - "Set status message" : "Establecer a mensaxe de estado", - "There was an error saving the status" : "Produciuse un erro ao gardar o estado", - "There was an error clearing the status" : "Produciuse un erro ao limpar o estado", - "No recent status changes" : "Non hai cambios de estado recentes", - "Away" : "Ausente", - "Do not disturb" : "Non molestar", - "{status}, {timestamp}" : "{status} ás {timestamp}", + "Set status message" : "Definir a mensaxe de estado", "Don't clear" : "Non limpar", "Today" : "Hoxe", "This week" : "Esta semana", "Online" : "En liña", + "Away" : "Ausente", + "Do not disturb" : "Non molestar", "Invisible" : "Invisíbel", "Offline" : "Sen conexión", + "Set status" : "Definir o estado", "There was an error saving the new status" : "Produciuse un erro ao gardar o novo estado", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", - "Mute all notifications" : "Silenciar todas as notificacións", - "Appear offline" : "Aparece coma sen conexión", - "What's your status?" : "Cal é o seu estado?" + "Busy" : "Ocupado", + "Mute all notifications" : "Enmudecer todas as notificacións", + "Appear offline" : "Aparece coma sen conexión" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/gl.json b/apps/user_status/l10n/gl.json index f96950bfd74..c90de4d4f13 100644 --- a/apps/user_status/l10n/gl.json +++ b/apps/user_status/l10n/gl.json @@ -1,37 +1,48 @@ { "translations": { "Recent statuses" : "Estados recentes", + "No recent status changes" : "Non hai cambios de estado recentes", "In a meeting" : "Nunha xuntanza", "Commuting" : "De casa ao traballo ou ao revés", "Out sick" : "Enfermo", "Vacationing" : "De vacacións", + "Out of office" : "Fóra da oficina", "Working remotely" : "Traballando en remoto", + "In a call" : "Nunha chamada", "User status" : "Estado do usuario", - "View profile" : "Ver o perfil", - "Clear status message after" : "Limpar a mensaxe de estado após", + "Clear status after" : "Limpar o estado após", + "Emoji for your status message" : "«Emoji» para a súa mensaxe de estado", "What is your status?" : "Cal é o seu estado?", - "Set status" : "Estabelecer o estado", + "Predefined statuses" : "Estados predefinidos", + "Previously set" : "Estabelecido previamente", + "Reset status" : "Restabelecer o estado", + "Reset status to \"{icon} {message}\"" : "Restabelecer o estado a «{icon} {message}»", + "Reset status to \"{message}\"" : "Restabelecer o estado a «{message}»", + "Reset status to \"{icon}\"" : "Restabelecer o estado a «{icon}»", + "There was an error saving the status" : "Produciuse un erro ao gardar o estado", + "There was an error clearing the status" : "Produciuse un erro ao limpar o estado", + "There was an error reverting the status" : "Produciuse un erro ao reverter o estado", "Online status" : "Estado en liña", "Status message" : "Mensaxe de estado", + "Set absence period" : "Definir o período de ausencia", + "Set absence period and replacement" : "Definir o período de ausencia e substitución", + "Your status was set automatically" : "O seu estado foi estabelecido automaticamente", "Clear status message" : "Limpar a mensaxe de estado", - "Set status message" : "Establecer a mensaxe de estado", - "There was an error saving the status" : "Produciuse un erro ao gardar o estado", - "There was an error clearing the status" : "Produciuse un erro ao limpar o estado", - "No recent status changes" : "Non hai cambios de estado recentes", - "Away" : "Ausente", - "Do not disturb" : "Non molestar", - "{status}, {timestamp}" : "{status} ás {timestamp}", + "Set status message" : "Definir a mensaxe de estado", "Don't clear" : "Non limpar", "Today" : "Hoxe", "This week" : "Esta semana", "Online" : "En liña", + "Away" : "Ausente", + "Do not disturb" : "Non molestar", "Invisible" : "Invisíbel", "Offline" : "Sen conexión", + "Set status" : "Definir o estado", "There was an error saving the new status" : "Produciuse un erro ao gardar o novo estado", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", - "Mute all notifications" : "Silenciar todas as notificacións", - "Appear offline" : "Aparece coma sen conexión", - "What's your status?" : "Cal é o seu estado?" + "Busy" : "Ocupado", + "Mute all notifications" : "Enmudecer todas as notificacións", + "Appear offline" : "Aparece coma sen conexión" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/he.js b/apps/user_status/l10n/he.js index 05514060b59..c14e661e90c 100644 --- a/apps/user_status/l10n/he.js +++ b/apps/user_status/l10n/he.js @@ -2,37 +2,37 @@ OC.L10N.register( "user_status", { "Recent statuses" : "מצבים אחרונים", + "No recent status changes" : "אין שינויים אחרונים למצב", "In a meeting" : "בפגישה", "Commuting" : "בדרכים", "Out sick" : "בחופשת מחלה", "Vacationing" : "בחופש", + "Out of office" : "מחוץ למשרד", "Working remotely" : "בעבודה מרחוק", "User status" : "מצב משתמש", - "Clear status message after" : "מחיקת הודעת מצב לאחר", + "Clear status after" : "לפנות את המצב לאחר", "What is your status?" : "מה המצב שלך?", - "Set status" : "הגדרת מצב", + "There was an error saving the status" : "אירעה שגיאה בשמירת המצב", + "There was an error clearing the status" : "אירעה שגיאה בפינוי המצב", "Online status" : "מצב מקוון", "Status message" : "הודעת מצב", "Clear status message" : "פינוי הודעת המצב", "Set status message" : "הגדרת הודעת מצב", - "There was an error saving the status" : "אירעה שגיאה בשמירת המצב", - "There was an error clearing the status" : "אירעה שגיאה בפינוי המצב", - "No recent status changes" : "אין שינויים אחרונים למצב", - "Away" : "לא פה", - "Do not disturb" : "לא להפריע", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "לא לפנות", "Today" : "היום", "This week" : "השבוע", "Online" : "מקוון", + "Away" : "לא פה", + "Do not disturb" : "לא להפריע", "Invisible" : "נסתרת", "Offline" : "בלתי מקוון", + "Set status" : "הגדרת מצב", "There was an error saving the new status" : "אירעה שגיאה בשמירת המצב החדש", "30 minutes" : "30 דקות", "1 hour" : "שעה", "4 hours" : "4 שעות", + "Busy" : "עסוק", "Mute all notifications" : "השתקת כל ההתראות", - "Appear offline" : "להופיע במצב בלתי מקוון", - "What's your status?" : "מה המצב שלך?" + "Appear offline" : "להופיע במצב בלתי מקוון" }, -"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;"); +"nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;"); diff --git a/apps/user_status/l10n/he.json b/apps/user_status/l10n/he.json index 80c8109ac84..1475c5c48e9 100644 --- a/apps/user_status/l10n/he.json +++ b/apps/user_status/l10n/he.json @@ -1,36 +1,36 @@ { "translations": { "Recent statuses" : "מצבים אחרונים", + "No recent status changes" : "אין שינויים אחרונים למצב", "In a meeting" : "בפגישה", "Commuting" : "בדרכים", "Out sick" : "בחופשת מחלה", "Vacationing" : "בחופש", + "Out of office" : "מחוץ למשרד", "Working remotely" : "בעבודה מרחוק", "User status" : "מצב משתמש", - "Clear status message after" : "מחיקת הודעת מצב לאחר", + "Clear status after" : "לפנות את המצב לאחר", "What is your status?" : "מה המצב שלך?", - "Set status" : "הגדרת מצב", + "There was an error saving the status" : "אירעה שגיאה בשמירת המצב", + "There was an error clearing the status" : "אירעה שגיאה בפינוי המצב", "Online status" : "מצב מקוון", "Status message" : "הודעת מצב", "Clear status message" : "פינוי הודעת המצב", "Set status message" : "הגדרת הודעת מצב", - "There was an error saving the status" : "אירעה שגיאה בשמירת המצב", - "There was an error clearing the status" : "אירעה שגיאה בפינוי המצב", - "No recent status changes" : "אין שינויים אחרונים למצב", - "Away" : "לא פה", - "Do not disturb" : "לא להפריע", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "לא לפנות", "Today" : "היום", "This week" : "השבוע", "Online" : "מקוון", + "Away" : "לא פה", + "Do not disturb" : "לא להפריע", "Invisible" : "נסתרת", "Offline" : "בלתי מקוון", + "Set status" : "הגדרת מצב", "There was an error saving the new status" : "אירעה שגיאה בשמירת המצב החדש", "30 minutes" : "30 דקות", "1 hour" : "שעה", "4 hours" : "4 שעות", + "Busy" : "עסוק", "Mute all notifications" : "השתקת כל ההתראות", - "Appear offline" : "להופיע במצב בלתי מקוון", - "What's your status?" : "מה המצב שלך?" -},"pluralForm" :"nplurals=4; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: (n % 10 == 0 && n % 1 == 0 && n > 10) ? 2 : 3;" + "Appear offline" : "להופיע במצב בלתי מקוון" +},"pluralForm" :"nplurals=3; plural=(n == 1 && n % 1 == 0) ? 0 : (n == 2 && n % 1 == 0) ? 1: 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/hr.js b/apps/user_status/l10n/hr.js index cd986995419..32026e39816 100644 --- a/apps/user_status/l10n/hr.js +++ b/apps/user_status/l10n/hr.js @@ -2,39 +2,38 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Nedavni statusi", + "No recent status changes" : "Nema nedavnih promjena statusa", "In a meeting" : "Na sastanku", "Commuting" : "Na putu", "Out sick" : "Na bolovanju", "Vacationing" : "Na odmoru", + "Out of office" : "Izvan ureda", "Working remotely" : "Rad na daljinu", "In a call" : "U pozivu", "User status" : "Status korisnika", - "View profile" : "Prikaži profil", - "Clear status message after" : "Izbriši poruku statusa nakon", + "Clear status after" : "Izbriši status nakon", "What is your status?" : "Koji je vaš status?", - "Set status" : "Postavi status", + "There was an error saving the status" : "Došlo je do pogreške pri spremanju statusa", + "There was an error clearing the status" : "Došlo je do pogreške pri brisanju statusa", "Online status" : "Status na mreži", "Status message" : "Poruka statusa", "Clear status message" : "Izbriši poruku statusa", "Set status message" : "Postavi poruku statusa", - "There was an error saving the status" : "Došlo je do pogreške pri spremanju statusa", - "There was an error clearing the status" : "Došlo je do pogreške pri brisanju statusa", - "No recent status changes" : "Nema nedavnih promjena statusa", - "Away" : "Odsutan", - "Do not disturb" : "Ne ometaj", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ne briši", "Today" : "Danas", "This week" : "Ovaj tjedan", "Online" : "Na mreži", + "Away" : "Odsutan", + "Do not disturb" : "Ne ometaj", "Invisible" : "Nevidljiva", "Offline" : "Izvanmrežno", + "Set status" : "Postavi status", "There was an error saving the new status" : "Došlo je do pogreške pri spremanju novog statusa", "30 minutes" : "30 minuta", "1 hour" : "1 sat", "4 hours" : "4 sata", + "Busy" : "Zauzeto", "Mute all notifications" : "Utišaj sve obavijesti", - "Appear offline" : "Prikaži izvanmrežno", - "What's your status?" : "Koji je vaš status?" + "Appear offline" : "Prikaži izvanmrežno" }, "nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;"); diff --git a/apps/user_status/l10n/hr.json b/apps/user_status/l10n/hr.json index b0270a29781..ba0a7d987f4 100644 --- a/apps/user_status/l10n/hr.json +++ b/apps/user_status/l10n/hr.json @@ -1,38 +1,37 @@ { "translations": { "Recent statuses" : "Nedavni statusi", + "No recent status changes" : "Nema nedavnih promjena statusa", "In a meeting" : "Na sastanku", "Commuting" : "Na putu", "Out sick" : "Na bolovanju", "Vacationing" : "Na odmoru", + "Out of office" : "Izvan ureda", "Working remotely" : "Rad na daljinu", "In a call" : "U pozivu", "User status" : "Status korisnika", - "View profile" : "Prikaži profil", - "Clear status message after" : "Izbriši poruku statusa nakon", + "Clear status after" : "Izbriši status nakon", "What is your status?" : "Koji je vaš status?", - "Set status" : "Postavi status", + "There was an error saving the status" : "Došlo je do pogreške pri spremanju statusa", + "There was an error clearing the status" : "Došlo je do pogreške pri brisanju statusa", "Online status" : "Status na mreži", "Status message" : "Poruka statusa", "Clear status message" : "Izbriši poruku statusa", "Set status message" : "Postavi poruku statusa", - "There was an error saving the status" : "Došlo je do pogreške pri spremanju statusa", - "There was an error clearing the status" : "Došlo je do pogreške pri brisanju statusa", - "No recent status changes" : "Nema nedavnih promjena statusa", - "Away" : "Odsutan", - "Do not disturb" : "Ne ometaj", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ne briši", "Today" : "Danas", "This week" : "Ovaj tjedan", "Online" : "Na mreži", + "Away" : "Odsutan", + "Do not disturb" : "Ne ometaj", "Invisible" : "Nevidljiva", "Offline" : "Izvanmrežno", + "Set status" : "Postavi status", "There was an error saving the new status" : "Došlo je do pogreške pri spremanju novog statusa", "30 minutes" : "30 minuta", "1 hour" : "1 sat", "4 hours" : "4 sata", + "Busy" : "Zauzeto", "Mute all notifications" : "Utišaj sve obavijesti", - "Appear offline" : "Prikaži izvanmrežno", - "What's your status?" : "Koji je vaš status?" + "Appear offline" : "Prikaži izvanmrežno" },"pluralForm" :"nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/hu.js b/apps/user_status/l10n/hu.js index 85021fe7809..9610f72b24e 100644 --- a/apps/user_status/l10n/hu.js +++ b/apps/user_status/l10n/hu.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Legutóbbi állapotok", + "No recent status changes" : "Nincsenek legutóbbi állapotváltozások", "In a meeting" : "Találkozón", "Commuting" : "Ingázás", "Out sick" : "Betegszabadságon", "Vacationing" : "Szabadságon", + "Out of office" : "Irodán kívül", "Working remotely" : "Távoli munkavégzés", "In a call" : "Hívásban", "User status" : "Felhasználói állapot", - "View profile" : "Profil megtekintése", - "Clear status message after" : "Állapotüzenet törlése ennyi idő után:", + "Clear status after" : "Állapot törlése ennyi idő után", + "Emoji for your status message" : "Emodzsi az állapotüzenetéhez", "What is your status?" : "Mi az állapota?", - "Set status" : "Állapot beállítása", + "Predefined statuses" : "Előre meghatározott állapotok", + "Previously set" : "Előzőleg beállított", + "Reset status" : "Állapot visszaállítása", + "Reset status to \"{icon} {message}\"" : "Állapot visszaállítása erre: „{icon} {message}”", + "Reset status to \"{message}\"" : "Állapot visszaállítása erre: „{message}”", + "Reset status to \"{icon}\"" : "Állapot visszaállítása erre: „{icon}”", + "There was an error saving the status" : "Hiba történt az állapot mentése során", + "There was an error clearing the status" : "Hiba történt az állapot törlése sorá", + "There was an error reverting the status" : "Hiba történt az állapot visszaállítása során", "Online status" : "Elérhető állapot", "Status message" : "Állapotüzenet", + "Set absence period" : "Távolléti időszak beállítása", + "Set absence period and replacement" : "Távolléti időszak és helyettes beállítása", + "Your status was set automatically" : "Az állapota automatikusan lett beállítva", "Clear status message" : "Állapotüzenet törlése", "Set status message" : "Állapotüzenet beállítása", - "There was an error saving the status" : "Hiba történt az állapot mentése során", - "There was an error clearing the status" : "Hiba történt az állapot törlése sorá", - "No recent status changes" : "Nincsenek legutóbbi állapotváltozások", - "Away" : "Távol", - "Do not disturb" : "Ne zavarjanak", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ne törölje", "Today" : "Ma", "This week" : "Ezen a héten", "Online" : "Elérhető", + "Away" : "Távol", + "Do not disturb" : "Ne zavarjanak", "Invisible" : "Láthatatlan", "Offline" : "Nem kapcsolódott", + "Set status" : "Állapot beállítása", "There was an error saving the new status" : "Hiba történt az új állapot mentése sorá", "30 minutes" : "30 perc", "1 hour" : "1 óra", "4 hours" : "4 óra", + "Busy" : "Foglalt", "Mute all notifications" : "Összes értesítés némítása", - "Appear offline" : "Megjelenés nem kapcsolódottként", - "What's your status?" : "Mi az állapota?" + "Appear offline" : "Megjelenés nem kapcsolódottként" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/hu.json b/apps/user_status/l10n/hu.json index a98cdefba11..9dbf642fc0d 100644 --- a/apps/user_status/l10n/hu.json +++ b/apps/user_status/l10n/hu.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Legutóbbi állapotok", + "No recent status changes" : "Nincsenek legutóbbi állapotváltozások", "In a meeting" : "Találkozón", "Commuting" : "Ingázás", "Out sick" : "Betegszabadságon", "Vacationing" : "Szabadságon", + "Out of office" : "Irodán kívül", "Working remotely" : "Távoli munkavégzés", "In a call" : "Hívásban", "User status" : "Felhasználói állapot", - "View profile" : "Profil megtekintése", - "Clear status message after" : "Állapotüzenet törlése ennyi idő után:", + "Clear status after" : "Állapot törlése ennyi idő után", + "Emoji for your status message" : "Emodzsi az állapotüzenetéhez", "What is your status?" : "Mi az állapota?", - "Set status" : "Állapot beállítása", + "Predefined statuses" : "Előre meghatározott állapotok", + "Previously set" : "Előzőleg beállított", + "Reset status" : "Állapot visszaállítása", + "Reset status to \"{icon} {message}\"" : "Állapot visszaállítása erre: „{icon} {message}”", + "Reset status to \"{message}\"" : "Állapot visszaállítása erre: „{message}”", + "Reset status to \"{icon}\"" : "Állapot visszaállítása erre: „{icon}”", + "There was an error saving the status" : "Hiba történt az állapot mentése során", + "There was an error clearing the status" : "Hiba történt az állapot törlése sorá", + "There was an error reverting the status" : "Hiba történt az állapot visszaállítása során", "Online status" : "Elérhető állapot", "Status message" : "Állapotüzenet", + "Set absence period" : "Távolléti időszak beállítása", + "Set absence period and replacement" : "Távolléti időszak és helyettes beállítása", + "Your status was set automatically" : "Az állapota automatikusan lett beállítva", "Clear status message" : "Állapotüzenet törlése", "Set status message" : "Állapotüzenet beállítása", - "There was an error saving the status" : "Hiba történt az állapot mentése során", - "There was an error clearing the status" : "Hiba történt az állapot törlése sorá", - "No recent status changes" : "Nincsenek legutóbbi állapotváltozások", - "Away" : "Távol", - "Do not disturb" : "Ne zavarjanak", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ne törölje", "Today" : "Ma", "This week" : "Ezen a héten", "Online" : "Elérhető", + "Away" : "Távol", + "Do not disturb" : "Ne zavarjanak", "Invisible" : "Láthatatlan", "Offline" : "Nem kapcsolódott", + "Set status" : "Állapot beállítása", "There was an error saving the new status" : "Hiba történt az új állapot mentése sorá", "30 minutes" : "30 perc", "1 hour" : "1 óra", "4 hours" : "4 óra", + "Busy" : "Foglalt", "Mute all notifications" : "Összes értesítés némítása", - "Appear offline" : "Megjelenés nem kapcsolódottként", - "What's your status?" : "Mi az állapota?" + "Appear offline" : "Megjelenés nem kapcsolódottként" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/is.js b/apps/user_status/l10n/is.js index 953e729b5bf..1f17415040b 100644 --- a/apps/user_status/l10n/is.js +++ b/apps/user_status/l10n/is.js @@ -2,37 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Nýlegar stöður", + "No recent status changes" : "Engar nýlegar breytingar á stöðu", "In a meeting" : "Á fundi", "Commuting" : "Á ferðinni", "Out sick" : "Veikindi", "Vacationing" : "Í fríi", + "Out of office" : "Ekki á staðnum", "Working remotely" : "Fjarvinna", + "In a call" : "Er í símtali", "User status" : "Staða notanda", - "Clear status message after" : "Hreinsa stöðuskilaboð eftir", + "Clear status after" : "Hreinsa stöðu eftir", + "Emoji for your status message" : "Tákn fyrir stöðufærsluna þína", "What is your status?" : "Hver er staðan á þér?", - "Set status" : "Setja stöðu", + "Predefined statuses" : "Forákvarðaðar stöður", + "Previously set" : "Áður stillt", + "Reset status" : "Endurstilla stöðu", + "Reset status to \"{icon} {message}\"" : "Endurstilla stöðu sem \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Endurstilla stöðu sem \"{message}\"", + "Reset status to \"{icon}\"" : "Endurstilla stöðu sem \"{icon}\"", + "There was an error saving the status" : "Það kom upp villa við að vista stöðuna", + "There was an error clearing the status" : "Það kom upp villa við að hreinsa stöðuna", + "There was an error reverting the status" : "Það kom upp villa við að afturkalla stöðuna", "Online status" : "Staða á netinu", "Status message" : "Stöðuskilaboð", + "Set absence period" : "Setja tímabil fjarveru", + "Set absence period and replacement" : "Setja tímabil fjarveru og afleysingu", + "Your status was set automatically" : "Staðan þín var stillt sjálfvirkt", "Clear status message" : "Hreinsa stöðuskilaboð", "Set status message" : "Setja stöðuskilaboð", - "There was an error saving the status" : "Það kom upp villa við að vista stöðuna", - "There was an error clearing the status" : "Það kom upp villa við að hreinsa stöðuna", - "No recent status changes" : "Engar nýlegar breytingar á stöðu", - "Away" : "Fjarverandi", - "Do not disturb" : "Ónáðið ekki", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ekki hreinsa", "Today" : "Í dag", "This week" : "Í þessari viku", "Online" : "Á netinu", + "Away" : "Fjarverandi", + "Do not disturb" : "Ónáðið ekki", "Invisible" : "Ósýnilegt", - "Offline" : "Ótengt neti", + "Offline" : "Ótengdur neti", + "Set status" : "Setja stöðu", "There was an error saving the new status" : "Það kom upp villa við að vista nýju stöðuna", "30 minutes" : "30 mínútur", "1 hour" : "1 klukkustund", "4 hours" : "4 klukkustundir", + "Busy" : "Upptekinn", "Mute all notifications" : "Þagga allar tilkynningar", - "Appear offline" : "Birtast ótengt", - "What's your status?" : "Hver er staðan á þér?" + "Appear offline" : "Birtast ótengt" }, "nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);"); diff --git a/apps/user_status/l10n/is.json b/apps/user_status/l10n/is.json index 4f4784fa4f0..f081ed2745f 100644 --- a/apps/user_status/l10n/is.json +++ b/apps/user_status/l10n/is.json @@ -1,36 +1,48 @@ { "translations": { "Recent statuses" : "Nýlegar stöður", + "No recent status changes" : "Engar nýlegar breytingar á stöðu", "In a meeting" : "Á fundi", "Commuting" : "Á ferðinni", "Out sick" : "Veikindi", "Vacationing" : "Í fríi", + "Out of office" : "Ekki á staðnum", "Working remotely" : "Fjarvinna", + "In a call" : "Er í símtali", "User status" : "Staða notanda", - "Clear status message after" : "Hreinsa stöðuskilaboð eftir", + "Clear status after" : "Hreinsa stöðu eftir", + "Emoji for your status message" : "Tákn fyrir stöðufærsluna þína", "What is your status?" : "Hver er staðan á þér?", - "Set status" : "Setja stöðu", + "Predefined statuses" : "Forákvarðaðar stöður", + "Previously set" : "Áður stillt", + "Reset status" : "Endurstilla stöðu", + "Reset status to \"{icon} {message}\"" : "Endurstilla stöðu sem \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Endurstilla stöðu sem \"{message}\"", + "Reset status to \"{icon}\"" : "Endurstilla stöðu sem \"{icon}\"", + "There was an error saving the status" : "Það kom upp villa við að vista stöðuna", + "There was an error clearing the status" : "Það kom upp villa við að hreinsa stöðuna", + "There was an error reverting the status" : "Það kom upp villa við að afturkalla stöðuna", "Online status" : "Staða á netinu", "Status message" : "Stöðuskilaboð", + "Set absence period" : "Setja tímabil fjarveru", + "Set absence period and replacement" : "Setja tímabil fjarveru og afleysingu", + "Your status was set automatically" : "Staðan þín var stillt sjálfvirkt", "Clear status message" : "Hreinsa stöðuskilaboð", "Set status message" : "Setja stöðuskilaboð", - "There was an error saving the status" : "Það kom upp villa við að vista stöðuna", - "There was an error clearing the status" : "Það kom upp villa við að hreinsa stöðuna", - "No recent status changes" : "Engar nýlegar breytingar á stöðu", - "Away" : "Fjarverandi", - "Do not disturb" : "Ónáðið ekki", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ekki hreinsa", "Today" : "Í dag", "This week" : "Í þessari viku", "Online" : "Á netinu", + "Away" : "Fjarverandi", + "Do not disturb" : "Ónáðið ekki", "Invisible" : "Ósýnilegt", - "Offline" : "Ótengt neti", + "Offline" : "Ótengdur neti", + "Set status" : "Setja stöðu", "There was an error saving the new status" : "Það kom upp villa við að vista nýju stöðuna", "30 minutes" : "30 mínútur", "1 hour" : "1 klukkustund", "4 hours" : "4 klukkustundir", + "Busy" : "Upptekinn", "Mute all notifications" : "Þagga allar tilkynningar", - "Appear offline" : "Birtast ótengt", - "What's your status?" : "Hver er staðan á þér?" + "Appear offline" : "Birtast ótengt" },"pluralForm" :"nplurals=2; plural=(n % 10 != 1 || n % 100 == 11);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/it.js b/apps/user_status/l10n/it.js index 491519dc102..9917b09972e 100644 --- a/apps/user_status/l10n/it.js +++ b/apps/user_status/l10n/it.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Stati recenti", + "No recent status changes" : "Nessun cambio di stato recente", "In a meeting" : "In una riunione", "Commuting" : "Pendolare", "Out sick" : "In malattia", "Vacationing" : "In vacanza", + "Out of office" : "Fuori sede", "Working remotely" : "Lavoro da remoto", "In a call" : "In una chiamata", "User status" : "Stato utente", - "View profile" : "Vedi profilo", - "Clear status message after" : "Cancella il messaggio di stato dopo", + "Clear status after" : "Togli lo stato dopo", + "Emoji for your status message" : "Emoji per il tuo messaggio di stato", "What is your status?" : "Qual è il tuo stato?", - "Set status" : "Imposta stato", + "Predefined statuses" : "Stati predefiniti", + "Previously set" : "Impostato in precedenza", + "Reset status" : "Ripristina stato", + "Reset status to \"{icon} {message}\"" : "Ripristina stato a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Ripristina stato a \"{message}\"", + "Reset status to \"{icon}\"" : "Ripristina stato a \"{icon}\"", + "There was an error saving the status" : "Si è verificato un errore durante il salvataggio dello stato", + "There was an error clearing the status" : "Si è verificato un errore durante la rimozione dello stato", + "There was an error reverting the status" : "Si è verificato un errore ripristinando lo stato", "Online status" : "Stato in linea", "Status message" : "Messaggio di stato", + "Set absence period" : "Imposta periodo di assenza", + "Set absence period and replacement" : "Imposta periodo di assenza e sostituzione", + "Your status was set automatically" : "Stato impostato automaticamente", "Clear status message" : "Cancella il messaggio di stato", "Set status message" : "Imposta messaggio di stato", - "There was an error saving the status" : "Si è verificato un errore durante il salvataggio dello stato", - "There was an error clearing the status" : "Si è verificato un errore durante la rimozione dello stato", - "No recent status changes" : "Nessun cambio di stato recente", - "Away" : "Assente", - "Do not disturb" : "Non disturbare", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Non togliere", "Today" : "Oggi", "This week" : "Questa settimana", "Online" : "In linea", + "Away" : "Assente", + "Do not disturb" : "Non disturbare", "Invisible" : "Invisibile", "Offline" : "Non in linea", + "Set status" : "Imposta stato", "There was an error saving the new status" : "Si è verificato un errore durante il salvataggio del nuovo stato", "30 minutes" : "30 minuti", "1 hour" : "1 ora", "4 hours" : "4 ore", + "Busy" : "Occupato", "Mute all notifications" : "Silenzia tutte le notifiche", - "Appear offline" : "Mostrati non in linea", - "What's your status?" : "Qual è il tuo stato?" + "Appear offline" : "Mostrati non in linea" }, -"nplurals=2; plural=(n != 1);"); +"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/it.json b/apps/user_status/l10n/it.json index d1587ee699d..96a6af919a5 100644 --- a/apps/user_status/l10n/it.json +++ b/apps/user_status/l10n/it.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Stati recenti", + "No recent status changes" : "Nessun cambio di stato recente", "In a meeting" : "In una riunione", "Commuting" : "Pendolare", "Out sick" : "In malattia", "Vacationing" : "In vacanza", + "Out of office" : "Fuori sede", "Working remotely" : "Lavoro da remoto", "In a call" : "In una chiamata", "User status" : "Stato utente", - "View profile" : "Vedi profilo", - "Clear status message after" : "Cancella il messaggio di stato dopo", + "Clear status after" : "Togli lo stato dopo", + "Emoji for your status message" : "Emoji per il tuo messaggio di stato", "What is your status?" : "Qual è il tuo stato?", - "Set status" : "Imposta stato", + "Predefined statuses" : "Stati predefiniti", + "Previously set" : "Impostato in precedenza", + "Reset status" : "Ripristina stato", + "Reset status to \"{icon} {message}\"" : "Ripristina stato a \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Ripristina stato a \"{message}\"", + "Reset status to \"{icon}\"" : "Ripristina stato a \"{icon}\"", + "There was an error saving the status" : "Si è verificato un errore durante il salvataggio dello stato", + "There was an error clearing the status" : "Si è verificato un errore durante la rimozione dello stato", + "There was an error reverting the status" : "Si è verificato un errore ripristinando lo stato", "Online status" : "Stato in linea", "Status message" : "Messaggio di stato", + "Set absence period" : "Imposta periodo di assenza", + "Set absence period and replacement" : "Imposta periodo di assenza e sostituzione", + "Your status was set automatically" : "Stato impostato automaticamente", "Clear status message" : "Cancella il messaggio di stato", "Set status message" : "Imposta messaggio di stato", - "There was an error saving the status" : "Si è verificato un errore durante il salvataggio dello stato", - "There was an error clearing the status" : "Si è verificato un errore durante la rimozione dello stato", - "No recent status changes" : "Nessun cambio di stato recente", - "Away" : "Assente", - "Do not disturb" : "Non disturbare", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Non togliere", "Today" : "Oggi", "This week" : "Questa settimana", "Online" : "In linea", + "Away" : "Assente", + "Do not disturb" : "Non disturbare", "Invisible" : "Invisibile", "Offline" : "Non in linea", + "Set status" : "Imposta stato", "There was an error saving the new status" : "Si è verificato un errore durante il salvataggio del nuovo stato", "30 minutes" : "30 minuti", "1 hour" : "1 ora", "4 hours" : "4 ore", + "Busy" : "Occupato", "Mute all notifications" : "Silenzia tutte le notifiche", - "Appear offline" : "Mostrati non in linea", - "What's your status?" : "Qual è il tuo stato?" -},"pluralForm" :"nplurals=2; plural=(n != 1);" + "Appear offline" : "Mostrati non in linea" +},"pluralForm" :"nplurals=3; plural=n == 1 ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ja.js b/apps/user_status/l10n/ja.js index 35c87d0647f..74f480e0f36 100644 --- a/apps/user_status/l10n/ja.js +++ b/apps/user_status/l10n/ja.js @@ -2,38 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "最近のステータス", + "No recent status changes" : "最近のステータスの変更はありません", "In a meeting" : "会議中", "Commuting" : "通勤中", "Out sick" : "体調不良", "Vacationing" : "休暇", + "Out of office" : "オフィス外", "Working remotely" : "リモートワーク中", + "In a call" : "通話中", + "Be right back" : "すぐ戻ります", "User status" : "ユーザーステータス", - "View profile" : "プロフィールを表示", - "Clear status message after" : "ステータスメッセージの有効期限", + "Clear status after" : "ステータスの有効期限", + "Emoji for your status message" : "あなたのステータスメッセージに絵文字を", "What is your status?" : "現在のオンラインステータスは?", - "Set status" : "ステータスを設定", + "Predefined statuses" : "事前定義されたステータス", + "Previously set" : "以前の設定", + "Reset status" : "ステータスをリセット", + "Reset status to \"{icon} {message}\"" : "ステータスを \"{icon} {message}\" にリセット", + "Reset status to \"{message}\"" : "ステータスを \"{message}\" にリセット", + "Reset status to \"{icon}\"" : "ステータスを \"{icon}\" にリセット", + "There was an error saving the status" : "ステータスの保存中にエラーが発生しました", + "There was an error clearing the status" : "ステータスの消去中にエラーが発生しました", + "There was an error reverting the status" : "ステータスを戻す際にエラーが発生しました", "Online status" : "オンラインステータス", "Status message" : "状態メッセージ", + "Set absence period" : "不在設定をセットする", + "Set absence period and replacement" : "不在期間と交代要員をセットする", + "Your status was set automatically" : "あなたのステータスは自動的に設定されました", "Clear status message" : "ステータスメッセージを消去", "Set status message" : "ステータスメッセージを設定", - "There was an error saving the status" : "ステータスの保存中にエラーが発生しました", - "There was an error clearing the status" : "ステータスの消去中にエラーが発生しました", - "No recent status changes" : "最近のステータスの変更はありません", - "Away" : "離席中", - "Do not disturb" : "取り込み中", - "{status}, {timestamp}" : "{status}、{timestamp}", "Don't clear" : "消去しない", "Today" : "今日", "This week" : "今週", "Online" : "オンライン", + "Away" : "離席中", + "Do not disturb" : "取り込み中", "Invisible" : "ステータスを隠す", "Offline" : "オフライン", + "Set status" : "ステータスを設定", "There was an error saving the new status" : "新しいステータスの保存中にエラーが発生しました", "30 minutes" : "30分", "1 hour" : "1時間", "4 hours" : "4時間", + "Busy" : "ビジー", "Mute all notifications" : "全ての通知をミュート", - "Appear offline" : "オフライン", - "What's your status?" : "現在のオンラインステータスは?" + "Appear offline" : "オフライン" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/ja.json b/apps/user_status/l10n/ja.json index 9aea78f7969..183ed4f1c1e 100644 --- a/apps/user_status/l10n/ja.json +++ b/apps/user_status/l10n/ja.json @@ -1,37 +1,49 @@ { "translations": { "Recent statuses" : "最近のステータス", + "No recent status changes" : "最近のステータスの変更はありません", "In a meeting" : "会議中", "Commuting" : "通勤中", "Out sick" : "体調不良", "Vacationing" : "休暇", + "Out of office" : "オフィス外", "Working remotely" : "リモートワーク中", + "In a call" : "通話中", + "Be right back" : "すぐ戻ります", "User status" : "ユーザーステータス", - "View profile" : "プロフィールを表示", - "Clear status message after" : "ステータスメッセージの有効期限", + "Clear status after" : "ステータスの有効期限", + "Emoji for your status message" : "あなたのステータスメッセージに絵文字を", "What is your status?" : "現在のオンラインステータスは?", - "Set status" : "ステータスを設定", + "Predefined statuses" : "事前定義されたステータス", + "Previously set" : "以前の設定", + "Reset status" : "ステータスをリセット", + "Reset status to \"{icon} {message}\"" : "ステータスを \"{icon} {message}\" にリセット", + "Reset status to \"{message}\"" : "ステータスを \"{message}\" にリセット", + "Reset status to \"{icon}\"" : "ステータスを \"{icon}\" にリセット", + "There was an error saving the status" : "ステータスの保存中にエラーが発生しました", + "There was an error clearing the status" : "ステータスの消去中にエラーが発生しました", + "There was an error reverting the status" : "ステータスを戻す際にエラーが発生しました", "Online status" : "オンラインステータス", "Status message" : "状態メッセージ", + "Set absence period" : "不在設定をセットする", + "Set absence period and replacement" : "不在期間と交代要員をセットする", + "Your status was set automatically" : "あなたのステータスは自動的に設定されました", "Clear status message" : "ステータスメッセージを消去", "Set status message" : "ステータスメッセージを設定", - "There was an error saving the status" : "ステータスの保存中にエラーが発生しました", - "There was an error clearing the status" : "ステータスの消去中にエラーが発生しました", - "No recent status changes" : "最近のステータスの変更はありません", - "Away" : "離席中", - "Do not disturb" : "取り込み中", - "{status}, {timestamp}" : "{status}、{timestamp}", "Don't clear" : "消去しない", "Today" : "今日", "This week" : "今週", "Online" : "オンライン", + "Away" : "離席中", + "Do not disturb" : "取り込み中", "Invisible" : "ステータスを隠す", "Offline" : "オフライン", + "Set status" : "ステータスを設定", "There was an error saving the new status" : "新しいステータスの保存中にエラーが発生しました", "30 minutes" : "30分", "1 hour" : "1時間", "4 hours" : "4時間", + "Busy" : "ビジー", "Mute all notifications" : "全ての通知をミュート", - "Appear offline" : "オフライン", - "What's your status?" : "現在のオンラインステータスは?" + "Appear offline" : "オフライン" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ko.js b/apps/user_status/l10n/ko.js index 2d270ed983a..3afaa412ee2 100644 --- a/apps/user_status/l10n/ko.js +++ b/apps/user_status/l10n/ko.js @@ -2,39 +2,38 @@ OC.L10N.register( "user_status", { "Recent statuses" : "최근 상태", + "No recent status changes" : "최근 상태 변경 없음", "In a meeting" : "회의 중", "Commuting" : "이동 중", "Out sick" : "병가", "Vacationing" : "휴가 중", + "Out of office" : "자리에 없음", "Working remotely" : "원격 근무 중", "In a call" : "통화중", "User status" : "사용자 상태", - "View profile" : "프로파일 보기", - "Clear status message after" : "상태 메시지 지우기 예약", + "Clear status after" : "상태 메시지 지우기 예약", "What is your status?" : "당신의 상태는?", - "Set status" : "상태 설정", + "There was an error saving the status" : "상태 저장에 오류가 발생했습니다.", + "There was an error clearing the status" : "상태 해제에 오류가 발생했습니다.", "Online status" : "접속 상태", "Status message" : "상태 메시지", "Clear status message" : "상태 메시지 지움", "Set status message" : "상태 메시지 설정", - "There was an error saving the status" : "상태 저장에 오류가 발생했습니다", - "There was an error clearing the status" : "상태 해제에 오류가 발생했습니다", - "No recent status changes" : "최근 상태 변경 없음", - "Away" : "자리 비움", - "Do not disturb" : "방해 금지", - "{status}, {timestamp}" : "{status},{timestamp}", "Don't clear" : "지우지 않음", "Today" : "오늘", "This week" : "이번 주", "Online" : "접속 중", + "Away" : "자리 비움", + "Do not disturb" : "방해 금지", "Invisible" : "숨겨짐", "Offline" : "오프라인", - "There was an error saving the new status" : "새로운 상태 저장에 오류가 발생했습니다", + "Set status" : "상태 설정", + "There was an error saving the new status" : "새로운 상태 저장에 오류가 발생했습니다.", "30 minutes" : "30 분", "1 hour" : "한 시간", "4 hours" : "4 시간", - "Mute all notifications" : "모든 알림을 무시합니다", - "Appear offline" : "접속 안함으로 표시", - "What's your status?" : "지금 무엇을 하나요?" + "Busy" : "바쁨", + "Mute all notifications" : "모든 알림을 음소거", + "Appear offline" : "접속 안함으로 표시" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/ko.json b/apps/user_status/l10n/ko.json index a5948eb8b61..4858bccd4e0 100644 --- a/apps/user_status/l10n/ko.json +++ b/apps/user_status/l10n/ko.json @@ -1,38 +1,37 @@ { "translations": { "Recent statuses" : "최근 상태", + "No recent status changes" : "최근 상태 변경 없음", "In a meeting" : "회의 중", "Commuting" : "이동 중", "Out sick" : "병가", "Vacationing" : "휴가 중", + "Out of office" : "자리에 없음", "Working remotely" : "원격 근무 중", "In a call" : "통화중", "User status" : "사용자 상태", - "View profile" : "프로파일 보기", - "Clear status message after" : "상태 메시지 지우기 예약", + "Clear status after" : "상태 메시지 지우기 예약", "What is your status?" : "당신의 상태는?", - "Set status" : "상태 설정", + "There was an error saving the status" : "상태 저장에 오류가 발생했습니다.", + "There was an error clearing the status" : "상태 해제에 오류가 발생했습니다.", "Online status" : "접속 상태", "Status message" : "상태 메시지", "Clear status message" : "상태 메시지 지움", "Set status message" : "상태 메시지 설정", - "There was an error saving the status" : "상태 저장에 오류가 발생했습니다", - "There was an error clearing the status" : "상태 해제에 오류가 발생했습니다", - "No recent status changes" : "최근 상태 변경 없음", - "Away" : "자리 비움", - "Do not disturb" : "방해 금지", - "{status}, {timestamp}" : "{status},{timestamp}", "Don't clear" : "지우지 않음", "Today" : "오늘", "This week" : "이번 주", "Online" : "접속 중", + "Away" : "자리 비움", + "Do not disturb" : "방해 금지", "Invisible" : "숨겨짐", "Offline" : "오프라인", - "There was an error saving the new status" : "새로운 상태 저장에 오류가 발생했습니다", + "Set status" : "상태 설정", + "There was an error saving the new status" : "새로운 상태 저장에 오류가 발생했습니다.", "30 minutes" : "30 분", "1 hour" : "한 시간", "4 hours" : "4 시간", - "Mute all notifications" : "모든 알림을 무시합니다", - "Appear offline" : "접속 안함으로 표시", - "What's your status?" : "지금 무엇을 하나요?" + "Busy" : "바쁨", + "Mute all notifications" : "모든 알림을 음소거", + "Appear offline" : "접속 안함으로 표시" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/lo.js b/apps/user_status/l10n/lo.js deleted file mode 100644 index 969c89b381b..00000000000 --- a/apps/user_status/l10n/lo.js +++ /dev/null @@ -1,25 +0,0 @@ -OC.L10N.register( - "user_status", - { - "Clear status message after" : "ລ້າງສະຖານະພາບຂໍ້ຄວາມພາຍຫຼັງ", - "Set status" : "ຕັ້ງຄ່າສະຖານະພາບ", - "Online status" : "ສະຖານະພາບອອນລາຍ", - "Status message" : "ສະຖານະຂໍ້ຄວາມ", - "Clear status message" : "ລ້າງສະຖານະພາບຂໍ້ຄວາມ", - "Set status message" : "ຕັ້ງຄ່າສະຖານະພາບຂໍ້ຄວາມ", - "Away" : "ອອກໄປ", - "Do not disturb" : "ຫ້າມລົບກວນ", - "Don't clear" : "ບໍ່ຈະແຈ້ງ", - "Today" : "ມື້ນີ້", - "This week" : "ທິດນີ້", - "Online" : "ອອນລາຍ", - "Invisible" : "ເບິ່ງບໍ່ເຫັນ", - "Offline" : "ອັອບລາຍ", - "30 minutes" : "30 ນາທີ", - "1 hour" : "1 ຊົ່ວໂມງ", - "4 hours" : "4 ຊົ່ວໂມງ", - "Mute all notifications" : "ປິດການແຈ້ງເຕືອນທັງໝົດ", - "Appear offline" : "ເປີດອັອບລາຍ", - "What's your status?" : "ສະຖານະຂອງທ່ານແມ່ນຫຍັງ?" -}, -"nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/lo.json b/apps/user_status/l10n/lo.json deleted file mode 100644 index a9b070b83f0..00000000000 --- a/apps/user_status/l10n/lo.json +++ /dev/null @@ -1,23 +0,0 @@ -{ "translations": { - "Clear status message after" : "ລ້າງສະຖານະພາບຂໍ້ຄວາມພາຍຫຼັງ", - "Set status" : "ຕັ້ງຄ່າສະຖານະພາບ", - "Online status" : "ສະຖານະພາບອອນລາຍ", - "Status message" : "ສະຖານະຂໍ້ຄວາມ", - "Clear status message" : "ລ້າງສະຖານະພາບຂໍ້ຄວາມ", - "Set status message" : "ຕັ້ງຄ່າສະຖານະພາບຂໍ້ຄວາມ", - "Away" : "ອອກໄປ", - "Do not disturb" : "ຫ້າມລົບກວນ", - "Don't clear" : "ບໍ່ຈະແຈ້ງ", - "Today" : "ມື້ນີ້", - "This week" : "ທິດນີ້", - "Online" : "ອອນລາຍ", - "Invisible" : "ເບິ່ງບໍ່ເຫັນ", - "Offline" : "ອັອບລາຍ", - "30 minutes" : "30 ນາທີ", - "1 hour" : "1 ຊົ່ວໂມງ", - "4 hours" : "4 ຊົ່ວໂມງ", - "Mute all notifications" : "ປິດການແຈ້ງເຕືອນທັງໝົດ", - "Appear offline" : "ເປີດອັອບລາຍ", - "What's your status?" : "ສະຖານະຂອງທ່ານແມ່ນຫຍັງ?" -},"pluralForm" :"nplurals=1; plural=0;" -}
\ No newline at end of file diff --git a/apps/user_status/l10n/lt_LT.js b/apps/user_status/l10n/lt_LT.js index ae9823e1c0e..b440b3f1c05 100644 --- a/apps/user_status/l10n/lt_LT.js +++ b/apps/user_status/l10n/lt_LT.js @@ -2,38 +2,40 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Paskiausios būsenos", + "No recent status changes" : "Jokių paskiausių būsenos pasikeitimų", "In a meeting" : "Susitikime", "Commuting" : "Važinėju", "Out sick" : "Sergu", "Vacationing" : "Poilsiauju", + "Out of office" : "Ne darbo vietoje", "Working remotely" : "Dirbu nuotoliniu būdu", + "In a call" : "Dalyvauju skambutyje", "User status" : "Naudotojo būsena", - "View profile" : "Rodyti profilį", - "Clear status message after" : "Išvalyti būsenos žinutę po", + "Clear status after" : "Išvalyti būseną po", "What is your status?" : "Kokia jūsų būsena?", - "Set status" : "Nustatyti būseną", + "Predefined statuses" : "Iš anksto apibrėžtos būsenos", + "There was an error saving the status" : "Įrašant būseną, įvyko klaida", + "There was an error clearing the status" : "Išvalant būseną, įvyko klaida", "Online status" : "Prisijungimo būsena", "Status message" : "Būsenos žinutė", + "Your status was set automatically" : "Jūsų būsena buvo nustatyta automatiškai", "Clear status message" : "Išvalyti būsenos žinutę", "Set status message" : "Nustatyti būsenos žinutę", - "There was an error saving the status" : "Įrašant būseną, įvyko klaida", - "There was an error clearing the status" : "Išvalant būseną, įvyko klaida", - "No recent status changes" : "Jokių paskiausių būsenos pasikeitimų", - "Away" : "Atsitraukęs", - "Do not disturb" : "Netrukdyti", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Neišvalyti", "Today" : "Šiandien", "This week" : "Šią savaitę", "Online" : "Prisijungęs", - "Invisible" : "Nematoma", + "Away" : "Atsitraukęs", + "Do not disturb" : "Netrukdyti", + "Invisible" : "Nematomas", "Offline" : "Atsijungęs", + "Set status" : "Nustatyti būseną", "There was an error saving the new status" : "Įrašant naują būseną, įvyko klaida", "30 minutes" : "30 minučių", "1 hour" : "1 valanda", "4 hours" : "4 valandos", + "Busy" : "Užimtas laikas", "Mute all notifications" : "Išjungti visus pranešimus", - "Appear offline" : "Atrodyti atsijungusiu", - "What's your status?" : "Kokia jūsų būsena?" + "Appear offline" : "Atrodyti atsijungusiu" }, "nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);"); diff --git a/apps/user_status/l10n/lt_LT.json b/apps/user_status/l10n/lt_LT.json index 37cc733d0a1..d1df46a90f2 100644 --- a/apps/user_status/l10n/lt_LT.json +++ b/apps/user_status/l10n/lt_LT.json @@ -1,37 +1,39 @@ { "translations": { "Recent statuses" : "Paskiausios būsenos", + "No recent status changes" : "Jokių paskiausių būsenos pasikeitimų", "In a meeting" : "Susitikime", "Commuting" : "Važinėju", "Out sick" : "Sergu", "Vacationing" : "Poilsiauju", + "Out of office" : "Ne darbo vietoje", "Working remotely" : "Dirbu nuotoliniu būdu", + "In a call" : "Dalyvauju skambutyje", "User status" : "Naudotojo būsena", - "View profile" : "Rodyti profilį", - "Clear status message after" : "Išvalyti būsenos žinutę po", + "Clear status after" : "Išvalyti būseną po", "What is your status?" : "Kokia jūsų būsena?", - "Set status" : "Nustatyti būseną", + "Predefined statuses" : "Iš anksto apibrėžtos būsenos", + "There was an error saving the status" : "Įrašant būseną, įvyko klaida", + "There was an error clearing the status" : "Išvalant būseną, įvyko klaida", "Online status" : "Prisijungimo būsena", "Status message" : "Būsenos žinutė", + "Your status was set automatically" : "Jūsų būsena buvo nustatyta automatiškai", "Clear status message" : "Išvalyti būsenos žinutę", "Set status message" : "Nustatyti būsenos žinutę", - "There was an error saving the status" : "Įrašant būseną, įvyko klaida", - "There was an error clearing the status" : "Išvalant būseną, įvyko klaida", - "No recent status changes" : "Jokių paskiausių būsenos pasikeitimų", - "Away" : "Atsitraukęs", - "Do not disturb" : "Netrukdyti", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Neišvalyti", "Today" : "Šiandien", "This week" : "Šią savaitę", "Online" : "Prisijungęs", - "Invisible" : "Nematoma", + "Away" : "Atsitraukęs", + "Do not disturb" : "Netrukdyti", + "Invisible" : "Nematomas", "Offline" : "Atsijungęs", + "Set status" : "Nustatyti būseną", "There was an error saving the new status" : "Įrašant naują būseną, įvyko klaida", "30 minutes" : "30 minučių", "1 hour" : "1 valanda", "4 hours" : "4 valandos", + "Busy" : "Užimtas laikas", "Mute all notifications" : "Išjungti visus pranešimus", - "Appear offline" : "Atrodyti atsijungusiu", - "What's your status?" : "Kokia jūsų būsena?" + "Appear offline" : "Atrodyti atsijungusiu" },"pluralForm" :"nplurals=4; plural=(n % 10 == 1 && (n % 100 > 19 || n % 100 < 11) ? 0 : (n % 10 >= 2 && n % 10 <=9) && (n % 100 > 19 || n % 100 < 11) ? 1 : n % 1 != 0 ? 2: 3);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/mk.js b/apps/user_status/l10n/mk.js index ca6e5ae528d..64501b2f6df 100644 --- a/apps/user_status/l10n/mk.js +++ b/apps/user_status/l10n/mk.js @@ -2,39 +2,38 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Неодамнешни статуси", + "No recent status changes" : "Нема неодамнешна промена на статус", "In a meeting" : "На состанок", "Commuting" : "На пат", "Out sick" : "На боледување", "Vacationing" : "На одмор", + "Out of office" : "Надвор од канцеларија", "Working remotely" : "Присутен од дома", "In a call" : "Во разговор", "User status" : "Статус на корисникот", - "View profile" : "Прегледај профил", - "Clear status message after" : "Тргни го статусот после", + "Clear status after" : "Тргни го статусот после", "What is your status?" : "Кој е вашиот статус?", - "Set status" : "Постави статус", + "There was an error saving the status" : "Грешка при зачувување на статус", + "There was an error clearing the status" : "Грешка при отстранување на статус", "Online status" : "Присутен", "Status message" : "Статус порака", "Clear status message" : "Тргни ја статус пораката", "Set status message" : "Постави статус порака", - "There was an error saving the status" : "Грешка при зачувување на статус", - "There was an error clearing the status" : "Грешка при отстранување на статус", - "No recent status changes" : "Нема неодамнешна промена на статус", - "Away" : "Неактивен", - "Do not disturb" : "Не вознемирувај", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Не го тргај", "Today" : "Денес", "This week" : "Оваа недела", "Online" : "Приклучен", + "Away" : "Неактивен", + "Do not disturb" : "Не вознемирувај", "Invisible" : "Невидливо", "Offline" : "Исклучен", + "Set status" : "Постави статус", "There was an error saving the new status" : "Настана грешка при зачувување на нов статус", "30 minutes" : "30 минути", "1 hour" : "1 час", "4 hours" : "4 часа", + "Busy" : "Зафатен", "Mute all notifications" : "Занеми (Mute) ги сите известувања", - "Appear offline" : "Прикажи исклучен", - "What's your status?" : "Кој е вашиот статус?" + "Appear offline" : "Прикажи исклучен" }, "nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;"); diff --git a/apps/user_status/l10n/mk.json b/apps/user_status/l10n/mk.json index c1629cb8b51..393500ad5c5 100644 --- a/apps/user_status/l10n/mk.json +++ b/apps/user_status/l10n/mk.json @@ -1,38 +1,37 @@ { "translations": { "Recent statuses" : "Неодамнешни статуси", + "No recent status changes" : "Нема неодамнешна промена на статус", "In a meeting" : "На состанок", "Commuting" : "На пат", "Out sick" : "На боледување", "Vacationing" : "На одмор", + "Out of office" : "Надвор од канцеларија", "Working remotely" : "Присутен од дома", "In a call" : "Во разговор", "User status" : "Статус на корисникот", - "View profile" : "Прегледај профил", - "Clear status message after" : "Тргни го статусот после", + "Clear status after" : "Тргни го статусот после", "What is your status?" : "Кој е вашиот статус?", - "Set status" : "Постави статус", + "There was an error saving the status" : "Грешка при зачувување на статус", + "There was an error clearing the status" : "Грешка при отстранување на статус", "Online status" : "Присутен", "Status message" : "Статус порака", "Clear status message" : "Тргни ја статус пораката", "Set status message" : "Постави статус порака", - "There was an error saving the status" : "Грешка при зачувување на статус", - "There was an error clearing the status" : "Грешка при отстранување на статус", - "No recent status changes" : "Нема неодамнешна промена на статус", - "Away" : "Неактивен", - "Do not disturb" : "Не вознемирувај", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Не го тргај", "Today" : "Денес", "This week" : "Оваа недела", "Online" : "Приклучен", + "Away" : "Неактивен", + "Do not disturb" : "Не вознемирувај", "Invisible" : "Невидливо", "Offline" : "Исклучен", + "Set status" : "Постави статус", "There was an error saving the new status" : "Настана грешка при зачувување на нов статус", "30 minutes" : "30 минути", "1 hour" : "1 час", "4 hours" : "4 часа", + "Busy" : "Зафатен", "Mute all notifications" : "Занеми (Mute) ги сите известувања", - "Appear offline" : "Прикажи исклучен", - "What's your status?" : "Кој е вашиот статус?" + "Appear offline" : "Прикажи исклучен" },"pluralForm" :"nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/nb.js b/apps/user_status/l10n/nb.js index 78ae951ef19..f627aaa1e60 100644 --- a/apps/user_status/l10n/nb.js +++ b/apps/user_status/l10n/nb.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Nylige statuser", + "No recent status changes" : "Ingen nylige statusendringer", "In a meeting" : "I et møte", "Commuting" : "Pendler", "Out sick" : "Syk", "Vacationing" : "På ferie", + "Out of office" : "Fraværende", "Working remotely" : "Jobber utenfra", "In a call" : "I en samtale", "User status" : "Brukerstatus", - "View profile" : "Vis profil", - "Clear status message after" : "Fjern statusmelding etter", + "Clear status after" : "Fjern status etter", + "Emoji for your status message" : "Emoji for statusmeldingene dine", "What is your status?" : "Hva er din status?", - "Set status" : "Velg status", + "Predefined statuses" : "Forhåndsdefinerte statuser", + "Previously set" : "Tidligere angitt", + "Reset status" : "Tilbakestill status", + "Reset status to \"{icon} {message}\"" : "Tilbakestill status til \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Tilbakestill status til \"{message}\"", + "Reset status to \"{icon}\"" : "Tilbakestill status til \"{icon}\"", + "There was an error saving the status" : "Det oppsto en feil ved lagring av status", + "There was an error clearing the status" : "Det oppsto en feil ved fjerning av status", + "There was an error reverting the status" : "Det oppstod en feil under tilbakestilling av statusen", "Online status" : "Online-status", "Status message" : "Statusmelding", + "Set absence period" : "Angi fraværsperiode", + "Set absence period and replacement" : "Angi fraværsperiode og erstatter", + "Your status was set automatically" : "Statusen din ble satt", "Clear status message" : "Fjern statusmelding", "Set status message" : "Velg statusmelding", - "There was an error saving the status" : "Det oppstod en feil ved lagring av status", - "There was an error clearing the status" : "Det oppstod en feil ved fjerning av status", - "No recent status changes" : "Ingen nylige statusendringer", - "Away" : "Borte", - "Do not disturb" : "Ikke forstyrr", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ikke fjern", "Today" : "I dag", "This week" : "Denne uken", "Online" : "Pålogget", + "Away" : "Borte", + "Do not disturb" : "Ikke forstyrr", "Invisible" : "Usynlig", "Offline" : "Frakoblet", - "There was an error saving the new status" : "Det oppstod en feil ved lagring av ny status", + "Set status" : "Velg status", + "There was an error saving the new status" : "Det oppsto en feil ved lagring av ny status", "30 minutes" : "30 minutter", "1 hour" : "1 time", "4 hours" : "4 timer", + "Busy" : "Opptatt", "Mute all notifications" : "Demp alle varslinger", - "Appear offline" : "Vis som frakoblet", - "What's your status?" : "Hva er din status?" + "Appear offline" : "Vis som frakoblet" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/nb.json b/apps/user_status/l10n/nb.json index 0e2d5cb3824..4e47d91a20b 100644 --- a/apps/user_status/l10n/nb.json +++ b/apps/user_status/l10n/nb.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Nylige statuser", + "No recent status changes" : "Ingen nylige statusendringer", "In a meeting" : "I et møte", "Commuting" : "Pendler", "Out sick" : "Syk", "Vacationing" : "På ferie", + "Out of office" : "Fraværende", "Working remotely" : "Jobber utenfra", "In a call" : "I en samtale", "User status" : "Brukerstatus", - "View profile" : "Vis profil", - "Clear status message after" : "Fjern statusmelding etter", + "Clear status after" : "Fjern status etter", + "Emoji for your status message" : "Emoji for statusmeldingene dine", "What is your status?" : "Hva er din status?", - "Set status" : "Velg status", + "Predefined statuses" : "Forhåndsdefinerte statuser", + "Previously set" : "Tidligere angitt", + "Reset status" : "Tilbakestill status", + "Reset status to \"{icon} {message}\"" : "Tilbakestill status til \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Tilbakestill status til \"{message}\"", + "Reset status to \"{icon}\"" : "Tilbakestill status til \"{icon}\"", + "There was an error saving the status" : "Det oppsto en feil ved lagring av status", + "There was an error clearing the status" : "Det oppsto en feil ved fjerning av status", + "There was an error reverting the status" : "Det oppstod en feil under tilbakestilling av statusen", "Online status" : "Online-status", "Status message" : "Statusmelding", + "Set absence period" : "Angi fraværsperiode", + "Set absence period and replacement" : "Angi fraværsperiode og erstatter", + "Your status was set automatically" : "Statusen din ble satt", "Clear status message" : "Fjern statusmelding", "Set status message" : "Velg statusmelding", - "There was an error saving the status" : "Det oppstod en feil ved lagring av status", - "There was an error clearing the status" : "Det oppstod en feil ved fjerning av status", - "No recent status changes" : "Ingen nylige statusendringer", - "Away" : "Borte", - "Do not disturb" : "Ikke forstyrr", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Ikke fjern", "Today" : "I dag", "This week" : "Denne uken", "Online" : "Pålogget", + "Away" : "Borte", + "Do not disturb" : "Ikke forstyrr", "Invisible" : "Usynlig", "Offline" : "Frakoblet", - "There was an error saving the new status" : "Det oppstod en feil ved lagring av ny status", + "Set status" : "Velg status", + "There was an error saving the new status" : "Det oppsto en feil ved lagring av ny status", "30 minutes" : "30 minutter", "1 hour" : "1 time", "4 hours" : "4 timer", + "Busy" : "Opptatt", "Mute all notifications" : "Demp alle varslinger", - "Appear offline" : "Vis som frakoblet", - "What's your status?" : "Hva er din status?" + "Appear offline" : "Vis som frakoblet" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/nl.js b/apps/user_status/l10n/nl.js index 7861577cbbc..745507c57c0 100644 --- a/apps/user_status/l10n/nl.js +++ b/apps/user_status/l10n/nl.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Recente statussen", + "No recent status changes" : "Geen recente statuswijzigingen", "In a meeting" : "In een vergadering", "Commuting" : "Woon-werk", "Out sick" : "Ziek", "Vacationing" : "Op vakantie", + "Out of office" : "Niet op kantoor", "Working remotely" : "Thuiswerken", "In a call" : "In gesprek", + "Be right back" : "Zo weer terug", "User status" : "Gebruikersstatus", - "View profile" : "Bekijk profiel", - "Clear status message after" : "Statusbericht wissen na", + "Clear status after" : "Maak de status leeg na", + "Emoji for your status message" : "Emoji voor je statusbericht", "What is your status?" : "Wat is jouw status?", - "Set status" : "Instellen status", - "Online status" : "Online status", - "Status message" : "Statusbericht", - "Clear status message" : "Opruimen statusbericht", - "Set status message" : "Instellen statusbericht", + "Predefined statuses" : "Voorgedefinieerde statussen", + "Previously set" : "Eerder ingesteld", + "Reset status" : "Reset status", + "Reset status to \"{icon} {message}\"" : "Status terugzetten naar \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Status terugzetten naar \"{message}\"", + "Reset status to \"{icon}\"" : "Status terugzetten naar \"{icon}\"", "There was an error saving the status" : "Er is een fout opgetreden bij het bewaren van de status", "There was an error clearing the status" : "Er is een fout opgetreden bij het leegmaken van de status", - "No recent status changes" : "Geen recente statuswijzigingen", - "Away" : "Afwezig", - "Do not disturb" : "Niet storen", - "{status}, {timestamp}" : "{status}, {timestamp}", + "There was an error reverting the status" : "Er was een fout bij het terugdraaien van de status", + "Online status" : "Online status", + "Status message" : "Statusbericht", + "Set absence period" : "Afwezigheidsperiode instellen", + "Set absence period and replacement" : "Afwezigheidsperiode en vervanging instellen", + "Your status was set automatically" : "Uw status is automatisch ingesteld", + "Clear status message" : "Statusbericht wissen", + "Set status message" : "Statusbericht instellen", "Don't clear" : "Niet schoonmaken", "Today" : "Vandaag", "This week" : "Deze week", "Online" : "Online", + "Away" : "Afwezig", + "Do not disturb" : "Niet storen", "Invisible" : "Verborgen", "Offline" : "Off-line", + "Set status" : "Status instellen", "There was an error saving the new status" : "Er is een fout opgetreden bij het bewaren van de nieuwe status", "30 minutes" : "30 minuten", "1 hour" : "1 uur", "4 hours" : "4 uur", + "Busy" : "Bezet", "Mute all notifications" : "Onderdruk alle meldingen", - "Appear offline" : "Toon afwezig", - "What's your status?" : "Wat is je status?" + "Appear offline" : "Toon afwezig" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/nl.json b/apps/user_status/l10n/nl.json index 3c1adb39f68..643cf4c27fb 100644 --- a/apps/user_status/l10n/nl.json +++ b/apps/user_status/l10n/nl.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "Recente statussen", + "No recent status changes" : "Geen recente statuswijzigingen", "In a meeting" : "In een vergadering", "Commuting" : "Woon-werk", "Out sick" : "Ziek", "Vacationing" : "Op vakantie", + "Out of office" : "Niet op kantoor", "Working remotely" : "Thuiswerken", "In a call" : "In gesprek", + "Be right back" : "Zo weer terug", "User status" : "Gebruikersstatus", - "View profile" : "Bekijk profiel", - "Clear status message after" : "Statusbericht wissen na", + "Clear status after" : "Maak de status leeg na", + "Emoji for your status message" : "Emoji voor je statusbericht", "What is your status?" : "Wat is jouw status?", - "Set status" : "Instellen status", - "Online status" : "Online status", - "Status message" : "Statusbericht", - "Clear status message" : "Opruimen statusbericht", - "Set status message" : "Instellen statusbericht", + "Predefined statuses" : "Voorgedefinieerde statussen", + "Previously set" : "Eerder ingesteld", + "Reset status" : "Reset status", + "Reset status to \"{icon} {message}\"" : "Status terugzetten naar \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Status terugzetten naar \"{message}\"", + "Reset status to \"{icon}\"" : "Status terugzetten naar \"{icon}\"", "There was an error saving the status" : "Er is een fout opgetreden bij het bewaren van de status", "There was an error clearing the status" : "Er is een fout opgetreden bij het leegmaken van de status", - "No recent status changes" : "Geen recente statuswijzigingen", - "Away" : "Afwezig", - "Do not disturb" : "Niet storen", - "{status}, {timestamp}" : "{status}, {timestamp}", + "There was an error reverting the status" : "Er was een fout bij het terugdraaien van de status", + "Online status" : "Online status", + "Status message" : "Statusbericht", + "Set absence period" : "Afwezigheidsperiode instellen", + "Set absence period and replacement" : "Afwezigheidsperiode en vervanging instellen", + "Your status was set automatically" : "Uw status is automatisch ingesteld", + "Clear status message" : "Statusbericht wissen", + "Set status message" : "Statusbericht instellen", "Don't clear" : "Niet schoonmaken", "Today" : "Vandaag", "This week" : "Deze week", "Online" : "Online", + "Away" : "Afwezig", + "Do not disturb" : "Niet storen", "Invisible" : "Verborgen", "Offline" : "Off-line", + "Set status" : "Status instellen", "There was an error saving the new status" : "Er is een fout opgetreden bij het bewaren van de nieuwe status", "30 minutes" : "30 minuten", "1 hour" : "1 uur", "4 hours" : "4 uur", + "Busy" : "Bezet", "Mute all notifications" : "Onderdruk alle meldingen", - "Appear offline" : "Toon afwezig", - "What's your status?" : "Wat is je status?" + "Appear offline" : "Toon afwezig" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/oc.js b/apps/user_status/l10n/oc.js index dead048130f..bbd00e9e551 100644 --- a/apps/user_status/l10n/oc.js +++ b/apps/user_status/l10n/oc.js @@ -2,39 +2,38 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Estats recents", + "No recent status changes" : "Cap de cambiament recent d’estat", "In a meeting" : "En reünion", "Commuting" : "En comunicacion", "Out sick" : "Malaut", "Vacationing" : "En vacanças", + "Out of office" : "Fòra del burèu", "Working remotely" : "En teletrabalh", "In a call" : "Al telefòn", "User status" : "Estat utilizaire", - "View profile" : "Veire perfil", - "Clear status message after" : "Escafar lo messatge d’estat aprèp", + "Clear status after" : "Escafar l’estat aprèp", "What is your status?" : "Quin es vòstre estat ?", - "Set status" : "Definir estat", + "There was an error saving the status" : "Error en enregistrant l’estat", + "There was an error clearing the status" : "Error en escafant l’estat", "Online status" : "Estat en linha", "Status message" : "Messatge d’estat", "Clear status message" : "Escafar messatge d’estat", "Set status message" : "Definir messatge d’estat", - "There was an error saving the status" : "Error en enregistrant l’estat", - "There was an error clearing the status" : "Error en escafant l’estat", - "No recent status changes" : "Cap de cambiament recent d’estat", - "Away" : "Absent", - "Do not disturb" : "Me desrengar pas", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Escafar pas", "Today" : "Uèi", "This week" : "Aquesta setmana", "Online" : "En linha", + "Away" : "Absent", + "Do not disturb" : "Me desrengar pas", "Invisible" : "Invisible", "Offline" : "Fòra linha", + "Set status" : "Definir estat", "There was an error saving the new status" : "Error en enregistrant l’estat novèl", "30 minutes" : "30 minutas", "1 hour" : "1 ora", "4 hours" : "4 oras", + "Busy" : "Ocupat", "Mute all notifications" : "Amudir totas las notificacions", - "Appear offline" : "Aparéisser fòra linha", - "What's your status?" : "Quin es vòstre estat ?" + "Appear offline" : "Aparéisser fòra linha" }, "nplurals=2; plural=(n > 1);"); diff --git a/apps/user_status/l10n/oc.json b/apps/user_status/l10n/oc.json index 7a8ad9554f7..388df700e75 100644 --- a/apps/user_status/l10n/oc.json +++ b/apps/user_status/l10n/oc.json @@ -1,38 +1,37 @@ { "translations": { "Recent statuses" : "Estats recents", + "No recent status changes" : "Cap de cambiament recent d’estat", "In a meeting" : "En reünion", "Commuting" : "En comunicacion", "Out sick" : "Malaut", "Vacationing" : "En vacanças", + "Out of office" : "Fòra del burèu", "Working remotely" : "En teletrabalh", "In a call" : "Al telefòn", "User status" : "Estat utilizaire", - "View profile" : "Veire perfil", - "Clear status message after" : "Escafar lo messatge d’estat aprèp", + "Clear status after" : "Escafar l’estat aprèp", "What is your status?" : "Quin es vòstre estat ?", - "Set status" : "Definir estat", + "There was an error saving the status" : "Error en enregistrant l’estat", + "There was an error clearing the status" : "Error en escafant l’estat", "Online status" : "Estat en linha", "Status message" : "Messatge d’estat", "Clear status message" : "Escafar messatge d’estat", "Set status message" : "Definir messatge d’estat", - "There was an error saving the status" : "Error en enregistrant l’estat", - "There was an error clearing the status" : "Error en escafant l’estat", - "No recent status changes" : "Cap de cambiament recent d’estat", - "Away" : "Absent", - "Do not disturb" : "Me desrengar pas", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Escafar pas", "Today" : "Uèi", "This week" : "Aquesta setmana", "Online" : "En linha", + "Away" : "Absent", + "Do not disturb" : "Me desrengar pas", "Invisible" : "Invisible", "Offline" : "Fòra linha", + "Set status" : "Definir estat", "There was an error saving the new status" : "Error en enregistrant l’estat novèl", "30 minutes" : "30 minutas", "1 hour" : "1 ora", "4 hours" : "4 oras", + "Busy" : "Ocupat", "Mute all notifications" : "Amudir totas las notificacions", - "Appear offline" : "Aparéisser fòra linha", - "What's your status?" : "Quin es vòstre estat ?" + "Appear offline" : "Aparéisser fòra linha" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/pl.js b/apps/user_status/l10n/pl.js index e77f95de04e..c25c92e27e1 100644 --- a/apps/user_status/l10n/pl.js +++ b/apps/user_status/l10n/pl.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Najnowsze statusy", + "No recent status changes" : "Brak ostatnich zmian statusu", "In a meeting" : "Na spotkaniu", "Commuting" : "W drodze", "Out sick" : "Chory", "Vacationing" : "Na wakacjach", + "Out of office" : "Biuro nie funkcjonuje", "Working remotely" : "Praca zdalna", "In a call" : "Rozmawia", + "Be right back" : "Zaraz wracam", "User status" : "Status użytkownika", - "View profile" : "Zobacz profil", - "Clear status message after" : "Wyczyść komunikat statusu po", + "Clear status after" : "Wyczyść status po", + "Emoji for your status message" : "Emoji dla komunikatu o statusie", "What is your status?" : "Jaki jest Twój status?", - "Set status" : "Ustaw status", + "Predefined statuses" : "Predefiniowane statusy", + "Previously set" : "Ustawione wcześniej", + "Reset status" : "Zresetuj status", + "Reset status to \"{icon} {message}\"" : "Zresetuj status do \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Zresetuj status do \"{message}\"", + "Reset status to \"{icon}\"" : "Zresetuj status do \"{icon}\"", + "There was an error saving the status" : "Wystąpił błąd podczas zapisywania statusu", + "There was an error clearing the status" : "Wystąpił błąd podczas usuwania statusu", + "There was an error reverting the status" : "Podczas przywracania statusu wystąpił błąd", "Online status" : "Status online", "Status message" : "Komunikat statusu", + "Set absence period" : "Ustaw okres nieobecności", + "Set absence period and replacement" : "Ustaw okres nieobecności i zastępstwo", + "Your status was set automatically" : "Twój status został ustawiony automatycznie", "Clear status message" : "Wyczyść komunikat statusu", "Set status message" : "Ustaw komunikat statusu", - "There was an error saving the status" : "Wystąpił błąd podczas zapisywania statusu", - "There was an error clearing the status" : "Wystąpił błąd podczas usuwania statusu", - "No recent status changes" : "Brak ostatnich zmian statusu", - "Away" : "Bezczynny", - "Do not disturb" : "Nie przeszkadzać", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nie czyść", "Today" : "Dzisiaj", "This week" : "W tym tygodniu", "Online" : "Online", + "Away" : "Bezczynny", + "Do not disturb" : "Nie przeszkadzać", "Invisible" : "Niewidoczny", "Offline" : "Offline", + "Set status" : "Ustaw status", "There was an error saving the new status" : "Wystąpił błąd podczas zapisywania nowego statusu", "30 minutes" : "30 minut", "1 hour" : "1 godzina", "4 hours" : "4 godziny", + "Busy" : "Brak dostępności", "Mute all notifications" : "Wycisz wszystkie powiadomienia", - "Appear offline" : "Widnieje jako offline", - "What's your status?" : "Jaki jest Twój status?" + "Appear offline" : "Widnieje jako offline" }, "nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);"); diff --git a/apps/user_status/l10n/pl.json b/apps/user_status/l10n/pl.json index 528ff7d9f9c..48079696e54 100644 --- a/apps/user_status/l10n/pl.json +++ b/apps/user_status/l10n/pl.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "Najnowsze statusy", + "No recent status changes" : "Brak ostatnich zmian statusu", "In a meeting" : "Na spotkaniu", "Commuting" : "W drodze", "Out sick" : "Chory", "Vacationing" : "Na wakacjach", + "Out of office" : "Biuro nie funkcjonuje", "Working remotely" : "Praca zdalna", "In a call" : "Rozmawia", + "Be right back" : "Zaraz wracam", "User status" : "Status użytkownika", - "View profile" : "Zobacz profil", - "Clear status message after" : "Wyczyść komunikat statusu po", + "Clear status after" : "Wyczyść status po", + "Emoji for your status message" : "Emoji dla komunikatu o statusie", "What is your status?" : "Jaki jest Twój status?", - "Set status" : "Ustaw status", + "Predefined statuses" : "Predefiniowane statusy", + "Previously set" : "Ustawione wcześniej", + "Reset status" : "Zresetuj status", + "Reset status to \"{icon} {message}\"" : "Zresetuj status do \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Zresetuj status do \"{message}\"", + "Reset status to \"{icon}\"" : "Zresetuj status do \"{icon}\"", + "There was an error saving the status" : "Wystąpił błąd podczas zapisywania statusu", + "There was an error clearing the status" : "Wystąpił błąd podczas usuwania statusu", + "There was an error reverting the status" : "Podczas przywracania statusu wystąpił błąd", "Online status" : "Status online", "Status message" : "Komunikat statusu", + "Set absence period" : "Ustaw okres nieobecności", + "Set absence period and replacement" : "Ustaw okres nieobecności i zastępstwo", + "Your status was set automatically" : "Twój status został ustawiony automatycznie", "Clear status message" : "Wyczyść komunikat statusu", "Set status message" : "Ustaw komunikat statusu", - "There was an error saving the status" : "Wystąpił błąd podczas zapisywania statusu", - "There was an error clearing the status" : "Wystąpił błąd podczas usuwania statusu", - "No recent status changes" : "Brak ostatnich zmian statusu", - "Away" : "Bezczynny", - "Do not disturb" : "Nie przeszkadzać", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nie czyść", "Today" : "Dzisiaj", "This week" : "W tym tygodniu", "Online" : "Online", + "Away" : "Bezczynny", + "Do not disturb" : "Nie przeszkadzać", "Invisible" : "Niewidoczny", "Offline" : "Offline", + "Set status" : "Ustaw status", "There was an error saving the new status" : "Wystąpił błąd podczas zapisywania nowego statusu", "30 minutes" : "30 minut", "1 hour" : "1 godzina", "4 hours" : "4 godziny", + "Busy" : "Brak dostępności", "Mute all notifications" : "Wycisz wszystkie powiadomienia", - "Appear offline" : "Widnieje jako offline", - "What's your status?" : "Jaki jest Twój status?" + "Appear offline" : "Widnieje jako offline" },"pluralForm" :"nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/pt_BR.js b/apps/user_status/l10n/pt_BR.js index a4b95c86569..3844bd746f7 100644 --- a/apps/user_status/l10n/pt_BR.js +++ b/apps/user_status/l10n/pt_BR.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Status recentes", + "No recent status changes" : "Sem alterações de status recentes", "In a meeting" : "Em reunião", "Commuting" : "Em trânsito", "Out sick" : "Doente", "Vacationing" : "Férias", + "Out of office" : "Fora do escritório", "Working remotely" : "Em trabalho remoto", - "In a call" : "Numa chamada", + "In a call" : "Em uma chamada", + "Be right back" : "Volto já", "User status" : "Status do usuário", - "View profile" : "Visualizar perfil", - "Clear status message after" : "Limpar status do usuário após", + "Clear status after" : "Limpar status após", + "Emoji for your status message" : "Emoji para sua mensagem de status", "What is your status?" : "Qual é o seu status?", - "Set status" : "Definir status", - "Online status" : "Status online", + "Predefined statuses" : "Status predefinidos", + "Previously set" : "Definido anteriormente", + "Reset status" : "Redefinir status", + "Reset status to \"{icon} {message}\"" : "Redefinir status para \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Redefinir status para \"{message}\"", + "Reset status to \"{icon}\"" : "Redefinir status para \"{icon}\"", + "There was an error saving the status" : "Ocorreu um erro ao salvar o status", + "There was an error clearing the status" : "Ocorreu um erro ao limpar o status", + "There was an error reverting the status" : "Ocorreu um erro ao reverter o status", + "Online status" : "Status on-line", "Status message" : "Mensagem de status", + "Set absence period" : "Definir período de ausência", + "Set absence period and replacement" : "Definir período de ausência e substituição", + "Your status was set automatically" : "Seu status foi definido automaticamente", "Clear status message" : "Limpar mensagem de status", "Set status message" : "Definir mensagem de status", - "There was an error saving the status" : "Ocorreu um erro ao salvar o status", - "There was an error clearing the status" : "Ocorreu um erro ao limpar o status", - "No recent status changes" : "Sem alterações de status recentes", - "Away" : "Fora", - "Do not disturb" : "Não perturbe", - "{status}, {timestamp}" : "{status}, {timestamp}", - "Don't clear" : "Não limpar", + "Don't clear" : "Não limpe", "Today" : "Hoje", "This week" : "Esta semana", - "Online" : "Online", + "Online" : "On-line", + "Away" : "Fora", + "Do not disturb" : "Não perturbe", "Invisible" : "Invisível", - "Offline" : "Offline", + "Offline" : "Off-line", + "Set status" : "Definir status", "There was an error saving the new status" : "Ocorreu um erro ao salvar o novo status", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", + "Busy" : "Ocupado", "Mute all notifications" : "Silenciar todas as notificações", - "Appear offline" : "Aparecer offline", - "What's your status?" : "Qual é o seu status?" + "Appear offline" : "Aparecer off-line" }, -"nplurals=2; plural=(n > 1);"); +"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/pt_BR.json b/apps/user_status/l10n/pt_BR.json index 4c73045cfce..e596a39e2bf 100644 --- a/apps/user_status/l10n/pt_BR.json +++ b/apps/user_status/l10n/pt_BR.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "Status recentes", + "No recent status changes" : "Sem alterações de status recentes", "In a meeting" : "Em reunião", "Commuting" : "Em trânsito", "Out sick" : "Doente", "Vacationing" : "Férias", + "Out of office" : "Fora do escritório", "Working remotely" : "Em trabalho remoto", - "In a call" : "Numa chamada", + "In a call" : "Em uma chamada", + "Be right back" : "Volto já", "User status" : "Status do usuário", - "View profile" : "Visualizar perfil", - "Clear status message after" : "Limpar status do usuário após", + "Clear status after" : "Limpar status após", + "Emoji for your status message" : "Emoji para sua mensagem de status", "What is your status?" : "Qual é o seu status?", - "Set status" : "Definir status", - "Online status" : "Status online", + "Predefined statuses" : "Status predefinidos", + "Previously set" : "Definido anteriormente", + "Reset status" : "Redefinir status", + "Reset status to \"{icon} {message}\"" : "Redefinir status para \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Redefinir status para \"{message}\"", + "Reset status to \"{icon}\"" : "Redefinir status para \"{icon}\"", + "There was an error saving the status" : "Ocorreu um erro ao salvar o status", + "There was an error clearing the status" : "Ocorreu um erro ao limpar o status", + "There was an error reverting the status" : "Ocorreu um erro ao reverter o status", + "Online status" : "Status on-line", "Status message" : "Mensagem de status", + "Set absence period" : "Definir período de ausência", + "Set absence period and replacement" : "Definir período de ausência e substituição", + "Your status was set automatically" : "Seu status foi definido automaticamente", "Clear status message" : "Limpar mensagem de status", "Set status message" : "Definir mensagem de status", - "There was an error saving the status" : "Ocorreu um erro ao salvar o status", - "There was an error clearing the status" : "Ocorreu um erro ao limpar o status", - "No recent status changes" : "Sem alterações de status recentes", - "Away" : "Fora", - "Do not disturb" : "Não perturbe", - "{status}, {timestamp}" : "{status}, {timestamp}", - "Don't clear" : "Não limpar", + "Don't clear" : "Não limpe", "Today" : "Hoje", "This week" : "Esta semana", - "Online" : "Online", + "Online" : "On-line", + "Away" : "Fora", + "Do not disturb" : "Não perturbe", "Invisible" : "Invisível", - "Offline" : "Offline", + "Offline" : "Off-line", + "Set status" : "Definir status", "There was an error saving the new status" : "Ocorreu um erro ao salvar o novo status", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", + "Busy" : "Ocupado", "Mute all notifications" : "Silenciar todas as notificações", - "Appear offline" : "Aparecer offline", - "What's your status?" : "Qual é o seu status?" -},"pluralForm" :"nplurals=2; plural=(n > 1);" + "Appear offline" : "Aparecer off-line" +},"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/pt_PT.js b/apps/user_status/l10n/pt_PT.js index 63bce5917ae..e6b64625619 100644 --- a/apps/user_status/l10n/pt_PT.js +++ b/apps/user_status/l10n/pt_PT.js @@ -2,39 +2,38 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Estados recentes", + "No recent status changes" : "Sem alterações de estado recentes", "In a meeting" : "Numa reunião", "Commuting" : "Em trânsito", "Out sick" : "Doente", "Vacationing" : "Férias", + "Out of office" : "Fora do escritório", "Working remotely" : "A trabalhar à distância", "In a call" : "Numa chamada", "User status" : "Estado do utilizador", - "View profile" : "Visualizar perfil", - "Clear status message after" : "Limpar mensagem de estado após", + "Clear status after" : "Limpar mensagem de estado após", "What is your status?" : "Qual é o seu estado?", - "Set status" : "Definir estado", + "There was an error saving the status" : "Ocorreu um erro ao guardar o estado", + "There was an error clearing the status" : "Ocorreu um erro ao apagar o estado", "Online status" : "Estado online", "Status message" : "Mensagem de estado", "Clear status message" : "Limpar mensagem de estado", "Set status message" : "Definir mensagem de estado", - "There was an error saving the status" : "Ocorreu um erro ao guardar o estado", - "There was an error clearing the status" : "Ocorreu um erro ao apagar o estado", - "No recent status changes" : "Sem alterações de estado recentes", - "Away" : "Ausente", - "Do not disturb" : "Não incomodar", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Não apagar", "Today" : "Hoje", "This week" : "Esta semana", "Online" : "Online", + "Away" : "Ausente", + "Do not disturb" : "Não incomodar", "Invisible" : "Invisível ", "Offline" : "Offline", + "Set status" : "Definir estado", "There was an error saving the new status" : "Ocorreu um erro ao guardar o novo estado", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", + "Busy" : "Ocupado", "Mute all notifications" : "Desativar todas as notificações", - "Appear offline" : "Aparecer offline", - "What's your status?" : "Qual é o seu estado?" + "Appear offline" : "Aparecer offline" }, -"nplurals=2; plural=(n != 1);"); +"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;"); diff --git a/apps/user_status/l10n/pt_PT.json b/apps/user_status/l10n/pt_PT.json index 243d1a4512b..17762a3db45 100644 --- a/apps/user_status/l10n/pt_PT.json +++ b/apps/user_status/l10n/pt_PT.json @@ -1,38 +1,37 @@ { "translations": { "Recent statuses" : "Estados recentes", + "No recent status changes" : "Sem alterações de estado recentes", "In a meeting" : "Numa reunião", "Commuting" : "Em trânsito", "Out sick" : "Doente", "Vacationing" : "Férias", + "Out of office" : "Fora do escritório", "Working remotely" : "A trabalhar à distância", "In a call" : "Numa chamada", "User status" : "Estado do utilizador", - "View profile" : "Visualizar perfil", - "Clear status message after" : "Limpar mensagem de estado após", + "Clear status after" : "Limpar mensagem de estado após", "What is your status?" : "Qual é o seu estado?", - "Set status" : "Definir estado", + "There was an error saving the status" : "Ocorreu um erro ao guardar o estado", + "There was an error clearing the status" : "Ocorreu um erro ao apagar o estado", "Online status" : "Estado online", "Status message" : "Mensagem de estado", "Clear status message" : "Limpar mensagem de estado", "Set status message" : "Definir mensagem de estado", - "There was an error saving the status" : "Ocorreu um erro ao guardar o estado", - "There was an error clearing the status" : "Ocorreu um erro ao apagar o estado", - "No recent status changes" : "Sem alterações de estado recentes", - "Away" : "Ausente", - "Do not disturb" : "Não incomodar", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Não apagar", "Today" : "Hoje", "This week" : "Esta semana", "Online" : "Online", + "Away" : "Ausente", + "Do not disturb" : "Não incomodar", "Invisible" : "Invisível ", "Offline" : "Offline", + "Set status" : "Definir estado", "There was an error saving the new status" : "Ocorreu um erro ao guardar o novo estado", "30 minutes" : "30 minutos", "1 hour" : "1 hora", "4 hours" : "4 horas", + "Busy" : "Ocupado", "Mute all notifications" : "Desativar todas as notificações", - "Appear offline" : "Aparecer offline", - "What's your status?" : "Qual é o seu estado?" -},"pluralForm" :"nplurals=2; plural=(n != 1);" + "Appear offline" : "Aparecer offline" +},"pluralForm" :"nplurals=3; plural=(n == 0 || n == 1) ? 0 : n != 0 && n % 1000000 == 0 ? 1 : 2;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ro.js b/apps/user_status/l10n/ro.js index 444a7badebc..3214bdf6d73 100644 --- a/apps/user_status/l10n/ro.js +++ b/apps/user_status/l10n/ro.js @@ -1,25 +1,48 @@ OC.L10N.register( "user_status", { - "Clear status message after" : "Șterge mesajul de stare după", + "Recent statuses" : "Statusuri recente", + "No recent status changes" : "Nu există modificări recente ale statutului", + "In a meeting" : "În cadrul unei întâlniri", + "Commuting" : "În deplasare", + "Out sick" : "Bolnav", + "Vacationing" : "În vacanță", + "Out of office" : "În afara serviciului", + "Working remotely" : "Lucru la distanță", + "In a call" : "Într-un apel", + "User status" : "Statusul utilizatorului", + "Clear status after" : "Șterge statusul după", + "Emoji for your status message" : "Emoji pentru mesajul de status", "What is your status?" : "Care este statusul dumneavoastră?", - "Set status" : "Setează status", + "Predefined statuses" : "Stări predefinite", + "Previously set" : "Setat anterior", + "Reset status" : "Resetează starea", + "Reset status to \"{icon} {message}\"" : "Resetează statusul la \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Resetează statusul la \"{message}\"", + "Reset status to \"{icon}\"" : "Resetează statusul la \"{icon}\"", + "There was an error saving the status" : "S-a produs o eroare la salvarea stării", + "There was an error clearing the status" : "S-a produs o eroare de ștergere a statutului", + "There was an error reverting the status" : "Eroare la revenirea la statusul anterior", "Online status" : "Status online", "Status message" : "Mesaj de status", + "Your status was set automatically" : "Statusul a fost setat automat", "Clear status message" : "Șterge mesajul de stare", "Set status message" : "Setează mesajul de status", - "Away" : "Plecat", - "Do not disturb" : "Nu deranja", "Don't clear" : "Nu curăța", "Today" : "Azi", "This week" : "Săptămâna asta", "Online" : "Online", + "Away" : "Plecat", + "Do not disturb" : "Nu deranja", "Invisible" : "Invizibil", + "Offline" : "Offline", + "Set status" : "Setează status", + "There was an error saving the new status" : "S-a produs o eroare de salvare a noului status", "30 minutes" : "30 minute", "1 hour" : "1 oră", "4 hours" : "4 ore", + "Busy" : "Ocupat", "Mute all notifications" : "Dezactivați toate notificările", - "Appear offline" : "Apari deconectat", - "What's your status?" : "Care este statusul tău?" + "Appear offline" : "Apari deconectat" }, "nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));"); diff --git a/apps/user_status/l10n/ro.json b/apps/user_status/l10n/ro.json index 3b4c2630f74..292a2aaac70 100644 --- a/apps/user_status/l10n/ro.json +++ b/apps/user_status/l10n/ro.json @@ -1,23 +1,46 @@ { "translations": { - "Clear status message after" : "Șterge mesajul de stare după", + "Recent statuses" : "Statusuri recente", + "No recent status changes" : "Nu există modificări recente ale statutului", + "In a meeting" : "În cadrul unei întâlniri", + "Commuting" : "În deplasare", + "Out sick" : "Bolnav", + "Vacationing" : "În vacanță", + "Out of office" : "În afara serviciului", + "Working remotely" : "Lucru la distanță", + "In a call" : "Într-un apel", + "User status" : "Statusul utilizatorului", + "Clear status after" : "Șterge statusul după", + "Emoji for your status message" : "Emoji pentru mesajul de status", "What is your status?" : "Care este statusul dumneavoastră?", - "Set status" : "Setează status", + "Predefined statuses" : "Stări predefinite", + "Previously set" : "Setat anterior", + "Reset status" : "Resetează starea", + "Reset status to \"{icon} {message}\"" : "Resetează statusul la \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Resetează statusul la \"{message}\"", + "Reset status to \"{icon}\"" : "Resetează statusul la \"{icon}\"", + "There was an error saving the status" : "S-a produs o eroare la salvarea stării", + "There was an error clearing the status" : "S-a produs o eroare de ștergere a statutului", + "There was an error reverting the status" : "Eroare la revenirea la statusul anterior", "Online status" : "Status online", "Status message" : "Mesaj de status", + "Your status was set automatically" : "Statusul a fost setat automat", "Clear status message" : "Șterge mesajul de stare", "Set status message" : "Setează mesajul de status", - "Away" : "Plecat", - "Do not disturb" : "Nu deranja", "Don't clear" : "Nu curăța", "Today" : "Azi", "This week" : "Săptămâna asta", "Online" : "Online", + "Away" : "Plecat", + "Do not disturb" : "Nu deranja", "Invisible" : "Invizibil", + "Offline" : "Offline", + "Set status" : "Setează status", + "There was an error saving the new status" : "S-a produs o eroare de salvare a noului status", "30 minutes" : "30 minute", "1 hour" : "1 oră", "4 hours" : "4 ore", + "Busy" : "Ocupat", "Mute all notifications" : "Dezactivați toate notificările", - "Appear offline" : "Apari deconectat", - "What's your status?" : "Care este statusul tău?" + "Appear offline" : "Apari deconectat" },"pluralForm" :"nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ru.js b/apps/user_status/l10n/ru.js index afe0ce63846..32b784b5e0c 100644 --- a/apps/user_status/l10n/ru.js +++ b/apps/user_status/l10n/ru.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Недавние статусы", + "No recent status changes" : "Нет недавних изменений статуса", "In a meeting" : "На встрече", "Commuting" : "В пути", - "Out sick" : "Болею", + "Out sick" : "Болен", "Vacationing" : "В отпуске", - "Working remotely" : "Удалённая работа", - "In a call" : "Вызывать", + "Out of office" : "Вне офиса", + "Working remotely" : "Удалённо", + "In a call" : "В вызове", + "Be right back" : "Скоро вернусь", "User status" : "Статус пользователя", - "View profile" : "Открыть профиль", - "Clear status message after" : "Очистить сообщение о состоянии через", - "What is your status?" : "Какой у вас статус?", - "Set status" : "Установить статус", - "Online status" : "Статус работы в сети", + "Clear status after" : "Очистить статус после", + "Emoji for your status message" : "Эмодзи для вашего сообщения к статусу", + "What is your status?" : "Какой у Вас статус?", + "Predefined statuses" : "Предопределенные статусы", + "Previously set" : "Установлено ранее", + "Reset status" : "Сбросить статус", + "Reset status to \"{icon} {message}\"" : "Сбросить статус на \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Сбросить статус на \"{message}\"", + "Reset status to \"{icon}\"" : "Сбросить статус на \"{icon}\"", + "There was an error saving the status" : "Произошла ошибка при сохранении статуса", + "There was an error clearing the status" : "Произошла ошибка при удалении статуса", + "There was an error reverting the status" : "Произошла ошибка при сбросе статуса", + "Online status" : "Онлайн статус", "Status message" : "Описание статуса", - "Clear status message" : "Удалить описание статуса", - "Set status message" : "Установить описание статуса", - "There was an error saving the status" : "Не удалось сохранить статус", - "There was an error clearing the status" : "Не удалось убрать статус", - "No recent status changes" : "Недавние изменения статуса отсуствуют ", - "Away" : "Отошёл", - "Do not disturb" : "Не беспокоить", - "{status}, {timestamp}" : "{status}, {timestamp}", + "Set absence period" : "Задать период отсутствия", + "Set absence period and replacement" : "Задать период отсутствия и замену", + "Your status was set automatically" : "Ваш статус был установлен автоматически", + "Clear status message" : "Удалить сообщение к статусу", + "Set status message" : "Установить сообщение к статусу", "Don't clear" : "Не очищать", "Today" : "Сегодня", "This week" : "Эта неделя", - "Online" : "На связи", - "Invisible" : "Невидимка", - "Offline" : "Автономно", - "There was an error saving the new status" : "Не удалось сохранить новый статус", + "Online" : "В сети", + "Away" : "Неактивен", + "Do not disturb" : "Не беспокоить", + "Invisible" : "Невидимый", + "Offline" : "Не в сети", + "Set status" : "Установить статус", + "There was an error saving the new status" : "Произошла ошибка при сохранении нового статуса", "30 minutes" : "30 минут", "1 hour" : "1 час", "4 hours" : "4 часа", + "Busy" : "Занят", "Mute all notifications" : "Отключить все уведомления", - "Appear offline" : "Возможно, не в сети", - "What's your status?" : "Укажите свой статус" + "Appear offline" : "\"Не в сети\" для остальных" }, "nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);"); diff --git a/apps/user_status/l10n/ru.json b/apps/user_status/l10n/ru.json index 0161434c967..f6b8d241ac4 100644 --- a/apps/user_status/l10n/ru.json +++ b/apps/user_status/l10n/ru.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "Недавние статусы", + "No recent status changes" : "Нет недавних изменений статуса", "In a meeting" : "На встрече", "Commuting" : "В пути", - "Out sick" : "Болею", + "Out sick" : "Болен", "Vacationing" : "В отпуске", - "Working remotely" : "Удалённая работа", - "In a call" : "Вызывать", + "Out of office" : "Вне офиса", + "Working remotely" : "Удалённо", + "In a call" : "В вызове", + "Be right back" : "Скоро вернусь", "User status" : "Статус пользователя", - "View profile" : "Открыть профиль", - "Clear status message after" : "Очистить сообщение о состоянии через", - "What is your status?" : "Какой у вас статус?", - "Set status" : "Установить статус", - "Online status" : "Статус работы в сети", + "Clear status after" : "Очистить статус после", + "Emoji for your status message" : "Эмодзи для вашего сообщения к статусу", + "What is your status?" : "Какой у Вас статус?", + "Predefined statuses" : "Предопределенные статусы", + "Previously set" : "Установлено ранее", + "Reset status" : "Сбросить статус", + "Reset status to \"{icon} {message}\"" : "Сбросить статус на \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Сбросить статус на \"{message}\"", + "Reset status to \"{icon}\"" : "Сбросить статус на \"{icon}\"", + "There was an error saving the status" : "Произошла ошибка при сохранении статуса", + "There was an error clearing the status" : "Произошла ошибка при удалении статуса", + "There was an error reverting the status" : "Произошла ошибка при сбросе статуса", + "Online status" : "Онлайн статус", "Status message" : "Описание статуса", - "Clear status message" : "Удалить описание статуса", - "Set status message" : "Установить описание статуса", - "There was an error saving the status" : "Не удалось сохранить статус", - "There was an error clearing the status" : "Не удалось убрать статус", - "No recent status changes" : "Недавние изменения статуса отсуствуют ", - "Away" : "Отошёл", - "Do not disturb" : "Не беспокоить", - "{status}, {timestamp}" : "{status}, {timestamp}", + "Set absence period" : "Задать период отсутствия", + "Set absence period and replacement" : "Задать период отсутствия и замену", + "Your status was set automatically" : "Ваш статус был установлен автоматически", + "Clear status message" : "Удалить сообщение к статусу", + "Set status message" : "Установить сообщение к статусу", "Don't clear" : "Не очищать", "Today" : "Сегодня", "This week" : "Эта неделя", - "Online" : "На связи", - "Invisible" : "Невидимка", - "Offline" : "Автономно", - "There was an error saving the new status" : "Не удалось сохранить новый статус", + "Online" : "В сети", + "Away" : "Неактивен", + "Do not disturb" : "Не беспокоить", + "Invisible" : "Невидимый", + "Offline" : "Не в сети", + "Set status" : "Установить статус", + "There was an error saving the new status" : "Произошла ошибка при сохранении нового статуса", "30 minutes" : "30 минут", "1 hour" : "1 час", "4 hours" : "4 часа", + "Busy" : "Занят", "Mute all notifications" : "Отключить все уведомления", - "Appear offline" : "Возможно, не в сети", - "What's your status?" : "Укажите свой статус" + "Appear offline" : "\"Не в сети\" для остальных" },"pluralForm" :"nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/sc.js b/apps/user_status/l10n/sc.js index 2586a7ca022..d4836447296 100644 --- a/apps/user_status/l10n/sc.js +++ b/apps/user_status/l10n/sc.js @@ -2,37 +2,37 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Istados reghentes", + "No recent status changes" : "Perunu càmbiu de istadu reghente", "In a meeting" : "In riunione", "Commuting" : "Biagende", "Out sick" : "In maladia", "Vacationing" : "In vacàntzia", + "Out of office" : "Foras de serbìtziu", "Working remotely" : "Traballende in remotu", "User status" : "Istadu de s'utente", - "Clear status message after" : "Lìmpia su messàgiu de istadu a pustis", + "Clear status after" : "Lìmpia s'istadu a pustis", "What is your status?" : "Cale est s'istadu tuo?", - "Set status" : "Imposta istadu", + "There was an error saving the status" : "B'at àpidu un'errore sarvende s'istadu", + "There was an error clearing the status" : "B'at àpidu un'errore limpiende s'istadu", "Online status" : "Istadu in lìnia", "Status message" : "Messàgiu de istadu", "Clear status message" : "Lìmpia su messàgiu de istadu", - "Set status message" : "Imposta messàgiu de istadu", - "There was an error saving the status" : "B'at àpidu un'errore sarvende s'istadu", - "There was an error clearing the status" : "B'at àpidu un'errore limpiende s'istadu", - "No recent status changes" : "Perunu càmbiu de istadu reghente", - "Away" : "Ausente", - "Do not disturb" : "No istorbes", - "{status}, {timestamp}" : "{status}, {timestamp}", + "Set status message" : "Cunfigura su messàgiu de istadu", "Don't clear" : "Non nche ddu lìmpies", "Today" : "Oe", "This week" : "Custa chida", "Online" : "In lìnia", + "Away" : "Ausente", + "Do not disturb" : "No istorbes", "Invisible" : "Invisìbile", "Offline" : "Fora de lìnia", + "Set status" : "Cunfigura un'istadu", "There was an error saving the new status" : "B'at àpidu un'errore sarvende s'istadu nou", "30 minutes" : "30 minutos", "1 hour" : "1 ora", "4 hours" : "4 oras", + "Busy" : "Impinnadu", "Mute all notifications" : "Istuda totu is notìficas", - "Appear offline" : "Mustra•ti foras de lìnia", - "What's your status?" : "Cale est s'istadu tuo?" + "Appear offline" : "Mustra•ti foras de lìnia" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/sc.json b/apps/user_status/l10n/sc.json index 81e5320e537..9bec309186e 100644 --- a/apps/user_status/l10n/sc.json +++ b/apps/user_status/l10n/sc.json @@ -1,36 +1,36 @@ { "translations": { "Recent statuses" : "Istados reghentes", + "No recent status changes" : "Perunu càmbiu de istadu reghente", "In a meeting" : "In riunione", "Commuting" : "Biagende", "Out sick" : "In maladia", "Vacationing" : "In vacàntzia", + "Out of office" : "Foras de serbìtziu", "Working remotely" : "Traballende in remotu", "User status" : "Istadu de s'utente", - "Clear status message after" : "Lìmpia su messàgiu de istadu a pustis", + "Clear status after" : "Lìmpia s'istadu a pustis", "What is your status?" : "Cale est s'istadu tuo?", - "Set status" : "Imposta istadu", + "There was an error saving the status" : "B'at àpidu un'errore sarvende s'istadu", + "There was an error clearing the status" : "B'at àpidu un'errore limpiende s'istadu", "Online status" : "Istadu in lìnia", "Status message" : "Messàgiu de istadu", "Clear status message" : "Lìmpia su messàgiu de istadu", - "Set status message" : "Imposta messàgiu de istadu", - "There was an error saving the status" : "B'at àpidu un'errore sarvende s'istadu", - "There was an error clearing the status" : "B'at àpidu un'errore limpiende s'istadu", - "No recent status changes" : "Perunu càmbiu de istadu reghente", - "Away" : "Ausente", - "Do not disturb" : "No istorbes", - "{status}, {timestamp}" : "{status}, {timestamp}", + "Set status message" : "Cunfigura su messàgiu de istadu", "Don't clear" : "Non nche ddu lìmpies", "Today" : "Oe", "This week" : "Custa chida", "Online" : "In lìnia", + "Away" : "Ausente", + "Do not disturb" : "No istorbes", "Invisible" : "Invisìbile", "Offline" : "Fora de lìnia", + "Set status" : "Cunfigura un'istadu", "There was an error saving the new status" : "B'at àpidu un'errore sarvende s'istadu nou", "30 minutes" : "30 minutos", "1 hour" : "1 ora", "4 hours" : "4 oras", + "Busy" : "Impinnadu", "Mute all notifications" : "Istuda totu is notìficas", - "Appear offline" : "Mustra•ti foras de lìnia", - "What's your status?" : "Cale est s'istadu tuo?" + "Appear offline" : "Mustra•ti foras de lìnia" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/sk.js b/apps/user_status/l10n/sk.js index d97a6ec4df2..9d91578b0f2 100644 --- a/apps/user_status/l10n/sk.js +++ b/apps/user_status/l10n/sk.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Nedávne stavy", + "No recent status changes" : "Žiadne nedávne zmeny stavu", "In a meeting" : "Na schôdzke", "Commuting" : "Na ceste", "Out sick" : "Choroba", "Vacationing" : "Na dovolenke", - "Working remotely" : "Pracuje na diaľku", + "Out of office" : "Mimo kancelárie", + "Working remotely" : "Pracujem na diaľku", "In a call" : "práve telefonuje", "User status" : "Stav užívateľa", - "View profile" : "Zobraziť profil", - "Clear status message after" : "Vyčistiť správu o stave po", + "Clear status after" : "Vyčistiť správu o stave po", + "Emoji for your status message" : "Emoji pre vašu statusovú správu", "What is your status?" : "Aký je váš stav?", - "Set status" : "Nastaviť stav", + "Predefined statuses" : "Preddefinované statusy", + "Previously set" : "Predtým nastavené", + "Reset status" : "Obnoviť status", + "Reset status to \"{icon} {message}\"" : "Obnoviť stav na „{icon} {message}“", + "Reset status to \"{message}\"" : "Obnoviť stav na „{message}“", + "Reset status to \"{icon}\"" : "Obnoviť stav na „{icon}“", + "There was an error saving the status" : "Pri ukladaní stavu sa vyskytla chyba", + "There was an error clearing the status" : "Pri čistení stavu sa vyskytla chyba", + "There was an error reverting the status" : "Pri zmene statusu sa vyskytla chyba", "Online status" : "Stav pripojenia", "Status message" : "Správa o stave", + "Set absence period" : "Nastaviť dobu neprítomnosti", + "Set absence period and replacement" : "Nastaviť dobu neprítomnosti a svoju náhradu", + "Your status was set automatically" : "Váš status bol nastavený automaticky", "Clear status message" : "Vyčistiť správu o stave", "Set status message" : "Nastaviť správu o stave", - "There was an error saving the status" : "Pri ukladaní stavu sa vyskytla chyba", - "There was an error clearing the status" : "Pri čistení stavu sa vyskytla chyba", - "No recent status changes" : "Žiadne nedávne zmeny stavu", - "Away" : "Preč", - "Do not disturb" : "Nerušiť", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nemazať", "Today" : "Dnes", "This week" : "Tento týždeň", "Online" : "Pripojené", - "Invisible" : "Neviditeľné", + "Away" : "Preč", + "Do not disturb" : "Nerušiť", + "Invisible" : "Neviditeľnosť", "Offline" : "Offline", + "Set status" : "Nastaviť stav", "There was an error saving the new status" : "Pri ukladaní nového stavu sa vyskytla chyba", "30 minutes" : "30 minút", "1 hour" : "1 hodina", "4 hours" : "4 hodiny", + "Busy" : "Zaneprázdnený", "Mute all notifications" : "Stíšiť všetky upozornenia", - "Appear offline" : "V odpojenom režime", - "What's your status?" : "Aký je váš stav?" + "Appear offline" : "V odpojenom režime" }, "nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);"); diff --git a/apps/user_status/l10n/sk.json b/apps/user_status/l10n/sk.json index 7bb3f9c56a8..dffd39b9e8c 100644 --- a/apps/user_status/l10n/sk.json +++ b/apps/user_status/l10n/sk.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Nedávne stavy", + "No recent status changes" : "Žiadne nedávne zmeny stavu", "In a meeting" : "Na schôdzke", "Commuting" : "Na ceste", "Out sick" : "Choroba", "Vacationing" : "Na dovolenke", - "Working remotely" : "Pracuje na diaľku", + "Out of office" : "Mimo kancelárie", + "Working remotely" : "Pracujem na diaľku", "In a call" : "práve telefonuje", "User status" : "Stav užívateľa", - "View profile" : "Zobraziť profil", - "Clear status message after" : "Vyčistiť správu o stave po", + "Clear status after" : "Vyčistiť správu o stave po", + "Emoji for your status message" : "Emoji pre vašu statusovú správu", "What is your status?" : "Aký je váš stav?", - "Set status" : "Nastaviť stav", + "Predefined statuses" : "Preddefinované statusy", + "Previously set" : "Predtým nastavené", + "Reset status" : "Obnoviť status", + "Reset status to \"{icon} {message}\"" : "Obnoviť stav na „{icon} {message}“", + "Reset status to \"{message}\"" : "Obnoviť stav na „{message}“", + "Reset status to \"{icon}\"" : "Obnoviť stav na „{icon}“", + "There was an error saving the status" : "Pri ukladaní stavu sa vyskytla chyba", + "There was an error clearing the status" : "Pri čistení stavu sa vyskytla chyba", + "There was an error reverting the status" : "Pri zmene statusu sa vyskytla chyba", "Online status" : "Stav pripojenia", "Status message" : "Správa o stave", + "Set absence period" : "Nastaviť dobu neprítomnosti", + "Set absence period and replacement" : "Nastaviť dobu neprítomnosti a svoju náhradu", + "Your status was set automatically" : "Váš status bol nastavený automaticky", "Clear status message" : "Vyčistiť správu o stave", "Set status message" : "Nastaviť správu o stave", - "There was an error saving the status" : "Pri ukladaní stavu sa vyskytla chyba", - "There was an error clearing the status" : "Pri čistení stavu sa vyskytla chyba", - "No recent status changes" : "Žiadne nedávne zmeny stavu", - "Away" : "Preč", - "Do not disturb" : "Nerušiť", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Nemazať", "Today" : "Dnes", "This week" : "Tento týždeň", "Online" : "Pripojené", - "Invisible" : "Neviditeľné", + "Away" : "Preč", + "Do not disturb" : "Nerušiť", + "Invisible" : "Neviditeľnosť", "Offline" : "Offline", + "Set status" : "Nastaviť stav", "There was an error saving the new status" : "Pri ukladaní nového stavu sa vyskytla chyba", "30 minutes" : "30 minút", "1 hour" : "1 hodina", "4 hours" : "4 hodiny", + "Busy" : "Zaneprázdnený", "Mute all notifications" : "Stíšiť všetky upozornenia", - "Appear offline" : "V odpojenom režime", - "What's your status?" : "Aký je váš stav?" + "Appear offline" : "V odpojenom režime" },"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/sl.js b/apps/user_status/l10n/sl.js index 0909507c34d..0eb3b4a6d14 100644 --- a/apps/user_status/l10n/sl.js +++ b/apps/user_status/l10n/sl.js @@ -2,39 +2,47 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Nedavna stanja", + "No recent status changes" : "Ni nedavnih sprememb stanja", "In a meeting" : "Na sestanku", "Commuting" : "Med vožnjo", "Out sick" : "Na bolniški", "Vacationing" : "Na dopustu", + "Out of office" : "Službena odsotnost", "Working remotely" : "Delam od doma", "In a call" : "V klicu", "User status" : "Stanje uporabnika", - "View profile" : "Pokaži profil", - "Clear status message after" : "Počisti sporočilo stanja po", + "Clear status after" : "Počisti stanje", + "Emoji for your status message" : "Izrazne ikone za stanje sporočila", "What is your status?" : "Kako želite nastaviti stanje?", - "Set status" : "Nastavi stanje", + "Predefined statuses" : "Pripravljena stanja", + "Previously set" : "Predhodno nastavljeno", + "Reset status" : "Ponastavi stanje", + "Reset status to \"{icon} {message}\"" : "Ponastavi stanje na »{icon} {message}«", + "Reset status to \"{message}\"" : "Ponastavi stanje na »{message}«", + "Reset status to \"{icon}\"" : "Ponastavi stanje na »{icon}«", + "There was an error saving the status" : "Prišlo je do napake med shranjevanjem stanja", + "There was an error clearing the status" : "Prišlo je do napake med odstranjevanjem stanja", + "There was an error reverting the status" : "Prišlo je do napake spreminjanja stanja", "Online status" : "Povezano stanje", "Status message" : "Sporočilo stanja", + "Your status was set automatically" : "Stanje je določeno samodejno", "Clear status message" : "Počisti sporočilo stanja", "Set status message" : "Nastavi sporočilo stanja", - "There was an error saving the status" : "Prišlo je do napake med shranjevanjem stanja", - "There was an error clearing the status" : "Prišlo je do napake med odstranjevanjem stanja", - "No recent status changes" : "Ni nedavnih sprememb stanja", - "Away" : "Trenutno ne spremljam", - "Do not disturb" : "Ne pustim se motiti", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "ne počisti", "Today" : "enkrat danes", "This week" : "še ta teden", "Online" : "Na spletu", + "Away" : "Trenutno ne spremljam", + "Do not disturb" : "Ne pustim se motiti", "Invisible" : "Drugim neviden", - "Offline" : "Začasno brez povezave", + "Offline" : "Brez povezave", + "Set status" : "Nastavi stanje", "There was an error saving the new status" : "Prišlo je do napake med shranjevanjem novega stanja", "30 minutes" : "po 30 minutah", "1 hour" : "po 1 uri", "4 hours" : "po 4 urah", + "Busy" : "Zasedeno", "Mute all notifications" : "Utiša vsa obvestila", - "Appear offline" : "Pokaže kot brez povezave", - "What's your status?" : "Kako želite nastaviti stanje?" + "Appear offline" : "Pokaže kot brez povezave" }, "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"); diff --git a/apps/user_status/l10n/sl.json b/apps/user_status/l10n/sl.json index ab1638778c7..4e0c8582227 100644 --- a/apps/user_status/l10n/sl.json +++ b/apps/user_status/l10n/sl.json @@ -1,38 +1,46 @@ { "translations": { "Recent statuses" : "Nedavna stanja", + "No recent status changes" : "Ni nedavnih sprememb stanja", "In a meeting" : "Na sestanku", "Commuting" : "Med vožnjo", "Out sick" : "Na bolniški", "Vacationing" : "Na dopustu", + "Out of office" : "Službena odsotnost", "Working remotely" : "Delam od doma", "In a call" : "V klicu", "User status" : "Stanje uporabnika", - "View profile" : "Pokaži profil", - "Clear status message after" : "Počisti sporočilo stanja po", + "Clear status after" : "Počisti stanje", + "Emoji for your status message" : "Izrazne ikone za stanje sporočila", "What is your status?" : "Kako želite nastaviti stanje?", - "Set status" : "Nastavi stanje", + "Predefined statuses" : "Pripravljena stanja", + "Previously set" : "Predhodno nastavljeno", + "Reset status" : "Ponastavi stanje", + "Reset status to \"{icon} {message}\"" : "Ponastavi stanje na »{icon} {message}«", + "Reset status to \"{message}\"" : "Ponastavi stanje na »{message}«", + "Reset status to \"{icon}\"" : "Ponastavi stanje na »{icon}«", + "There was an error saving the status" : "Prišlo je do napake med shranjevanjem stanja", + "There was an error clearing the status" : "Prišlo je do napake med odstranjevanjem stanja", + "There was an error reverting the status" : "Prišlo je do napake spreminjanja stanja", "Online status" : "Povezano stanje", "Status message" : "Sporočilo stanja", + "Your status was set automatically" : "Stanje je določeno samodejno", "Clear status message" : "Počisti sporočilo stanja", "Set status message" : "Nastavi sporočilo stanja", - "There was an error saving the status" : "Prišlo je do napake med shranjevanjem stanja", - "There was an error clearing the status" : "Prišlo je do napake med odstranjevanjem stanja", - "No recent status changes" : "Ni nedavnih sprememb stanja", - "Away" : "Trenutno ne spremljam", - "Do not disturb" : "Ne pustim se motiti", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "ne počisti", "Today" : "enkrat danes", "This week" : "še ta teden", "Online" : "Na spletu", + "Away" : "Trenutno ne spremljam", + "Do not disturb" : "Ne pustim se motiti", "Invisible" : "Drugim neviden", - "Offline" : "Začasno brez povezave", + "Offline" : "Brez povezave", + "Set status" : "Nastavi stanje", "There was an error saving the new status" : "Prišlo je do napake med shranjevanjem novega stanja", "30 minutes" : "po 30 minutah", "1 hour" : "po 1 uri", "4 hours" : "po 4 urah", + "Busy" : "Zasedeno", "Mute all notifications" : "Utiša vsa obvestila", - "Appear offline" : "Pokaže kot brez povezave", - "What's your status?" : "Kako želite nastaviti stanje?" + "Appear offline" : "Pokaže kot brez povezave" },"pluralForm" :"nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/sr.js b/apps/user_status/l10n/sr.js new file mode 100644 index 00000000000..8c94ab10e2e --- /dev/null +++ b/apps/user_status/l10n/sr.js @@ -0,0 +1,50 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Скорашњи статуси", + "No recent status changes" : "Нема скорашњих измена статуса", + "In a meeting" : "На састанку", + "Commuting" : "На путу до посла", + "Out sick" : "На боловању", + "Vacationing" : "На одмору", + "Out of office" : "Ван канцеларије", + "Working remotely" : "Радим од куће", + "In a call" : "У позиву", + "User status" : "Корисников статус", + "Clear status after" : "Обриши статус након", + "Emoji for your status message" : "Емођи за вашу статусну поруку", + "What is your status?" : "Који је ваш статус?", + "Predefined statuses" : "Предефинисани статуси", + "Previously set" : "Претходно постављено", + "Reset status" : "Ресетуј статус", + "Reset status to \"{icon} {message}\"" : "Ресетуј статус на „{icon} {message}”", + "Reset status to \"{message}\"" : "Ресетуј статус на „{message}”", + "Reset status to \"{icon}\"" : "Ресетуј статус на „{icon}”", + "There was an error saving the status" : "Дошло је до грешке приликом чувања статуса", + "There was an error clearing the status" : "Дошло је до грешке приликом брисања статуса", + "There was an error reverting the status" : "Дошло је до грешке приликом враћања претходног статуса", + "Online status" : "Мрежни статус", + "Status message" : "Порука стања", + "Set absence period" : "Постави период одсутности", + "Set absence period and replacement" : "Постави период одсутности и замену", + "Your status was set automatically" : "Ваш статус је аутоматски постављен", + "Clear status message" : "Обриши статусну поруку", + "Set status message" : "Постављање статусне поруке", + "Don't clear" : "Не бриши", + "Today" : "Данас", + "This week" : "Ове недеље", + "Online" : "На мрежи", + "Away" : "Одсутан", + "Do not disturb" : "Не узнемиравај", + "Invisible" : "Невидљива", + "Offline" : "Ван мреже", + "Set status" : "Постави статус", + "There was an error saving the new status" : "Дошло је до грешке приликом чувања новог статуса", + "30 minutes" : "30 минута", + "1 hour" : "1 сат", + "4 hours" : "4 сата", + "Busy" : "Заузет", + "Mute all notifications" : "Искључи сва обавештења", + "Appear offline" : "Прикажи као ван мреже" +}, +"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); diff --git a/apps/user_status/l10n/sr.json b/apps/user_status/l10n/sr.json new file mode 100644 index 00000000000..a7953e5e0a3 --- /dev/null +++ b/apps/user_status/l10n/sr.json @@ -0,0 +1,48 @@ +{ "translations": { + "Recent statuses" : "Скорашњи статуси", + "No recent status changes" : "Нема скорашњих измена статуса", + "In a meeting" : "На састанку", + "Commuting" : "На путу до посла", + "Out sick" : "На боловању", + "Vacationing" : "На одмору", + "Out of office" : "Ван канцеларије", + "Working remotely" : "Радим од куће", + "In a call" : "У позиву", + "User status" : "Корисников статус", + "Clear status after" : "Обриши статус након", + "Emoji for your status message" : "Емођи за вашу статусну поруку", + "What is your status?" : "Који је ваш статус?", + "Predefined statuses" : "Предефинисани статуси", + "Previously set" : "Претходно постављено", + "Reset status" : "Ресетуј статус", + "Reset status to \"{icon} {message}\"" : "Ресетуј статус на „{icon} {message}”", + "Reset status to \"{message}\"" : "Ресетуј статус на „{message}”", + "Reset status to \"{icon}\"" : "Ресетуј статус на „{icon}”", + "There was an error saving the status" : "Дошло је до грешке приликом чувања статуса", + "There was an error clearing the status" : "Дошло је до грешке приликом брисања статуса", + "There was an error reverting the status" : "Дошло је до грешке приликом враћања претходног статуса", + "Online status" : "Мрежни статус", + "Status message" : "Порука стања", + "Set absence period" : "Постави период одсутности", + "Set absence period and replacement" : "Постави период одсутности и замену", + "Your status was set automatically" : "Ваш статус је аутоматски постављен", + "Clear status message" : "Обриши статусну поруку", + "Set status message" : "Постављање статусне поруке", + "Don't clear" : "Не бриши", + "Today" : "Данас", + "This week" : "Ове недеље", + "Online" : "На мрежи", + "Away" : "Одсутан", + "Do not disturb" : "Не узнемиравај", + "Invisible" : "Невидљива", + "Offline" : "Ван мреже", + "Set status" : "Постави статус", + "There was an error saving the new status" : "Дошло је до грешке приликом чувања новог статуса", + "30 minutes" : "30 минута", + "1 hour" : "1 сат", + "4 hours" : "4 сата", + "Busy" : "Заузет", + "Mute all notifications" : "Искључи сва обавештења", + "Appear offline" : "Прикажи као ван мреже" +},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/sr@latin.js b/apps/user_status/l10n/sr@latin.js new file mode 100644 index 00000000000..532e6651761 --- /dev/null +++ b/apps/user_status/l10n/sr@latin.js @@ -0,0 +1,47 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Poslednji statusi", + "No recent status changes" : "Nema skorašnjih promena statusa", + "In a meeting" : "Na sastanku", + "Commuting" : "Na putu do posla", + "Out sick" : "Na bolovanju", + "Vacationing" : "Na odmoru", + "Out of office" : "Van kancelarije", + "Working remotely" : "Radim od kuće", + "In a call" : "U pozivu", + "User status" : "Status korisnika", + "Clear status after" : "Obriši status nakon", + "Emoji for your status message" : "Emoji za vašu statusnu poruku", + "What is your status?" : "Koji je vaš status?", + "Predefined statuses" : "Predefinisani statusi", + "Previously set" : "Prethodno postavljeno", + "Reset status" : "Resetuj status", + "Reset status to \"{icon} {message}\"" : "Resetuj status na „{icon} {message}”", + "Reset status to \"{message}\"" : "Resertuj status na „{message}”", + "Reset status to \"{icon}\"" : "Resetuj status na „{icon}”", + "There was an error saving the status" : "Greška u snimanju statusa", + "There was an error clearing the status" : "Greška u brisanju statusa", + "There was an error reverting the status" : "Greška u vraćanju statusa", + "Online status" : "Mrežni status", + "Status message" : "Poruka stanja", + "Your status was set automatically" : "Vaš status je postavljen automatski", + "Clear status message" : "Obriši statusnu poruku", + "Set status message" : "Postavi statusnu poruku", + "Don't clear" : "Ne briši", + "Today" : "Danas", + "This week" : "Ove sedmice", + "Online" : "Na mreži", + "Away" : "Odsutan", + "Do not disturb" : "Ne uznemiravaj", + "Invisible" : "Nevidljiv", + "Offline" : "Van mreže", + "Set status" : "Postavi status", + "There was an error saving the new status" : "Greška u snimanju novog statusa", + "30 minutes" : "30 minuta", + "1 hour" : "1 sat", + "4 hours" : "4 sata", + "Mute all notifications" : "Isključi sva obaveštenja", + "Appear offline" : "Prikaži kao van mreže" +}, +"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"); diff --git a/apps/user_status/l10n/sr@latin.json b/apps/user_status/l10n/sr@latin.json new file mode 100644 index 00000000000..bb642d5708c --- /dev/null +++ b/apps/user_status/l10n/sr@latin.json @@ -0,0 +1,45 @@ +{ "translations": { + "Recent statuses" : "Poslednji statusi", + "No recent status changes" : "Nema skorašnjih promena statusa", + "In a meeting" : "Na sastanku", + "Commuting" : "Na putu do posla", + "Out sick" : "Na bolovanju", + "Vacationing" : "Na odmoru", + "Out of office" : "Van kancelarije", + "Working remotely" : "Radim od kuće", + "In a call" : "U pozivu", + "User status" : "Status korisnika", + "Clear status after" : "Obriši status nakon", + "Emoji for your status message" : "Emoji za vašu statusnu poruku", + "What is your status?" : "Koji je vaš status?", + "Predefined statuses" : "Predefinisani statusi", + "Previously set" : "Prethodno postavljeno", + "Reset status" : "Resetuj status", + "Reset status to \"{icon} {message}\"" : "Resetuj status na „{icon} {message}”", + "Reset status to \"{message}\"" : "Resertuj status na „{message}”", + "Reset status to \"{icon}\"" : "Resetuj status na „{icon}”", + "There was an error saving the status" : "Greška u snimanju statusa", + "There was an error clearing the status" : "Greška u brisanju statusa", + "There was an error reverting the status" : "Greška u vraćanju statusa", + "Online status" : "Mrežni status", + "Status message" : "Poruka stanja", + "Your status was set automatically" : "Vaš status je postavljen automatski", + "Clear status message" : "Obriši statusnu poruku", + "Set status message" : "Postavi statusnu poruku", + "Don't clear" : "Ne briši", + "Today" : "Danas", + "This week" : "Ove sedmice", + "Online" : "Na mreži", + "Away" : "Odsutan", + "Do not disturb" : "Ne uznemiravaj", + "Invisible" : "Nevidljiv", + "Offline" : "Van mreže", + "Set status" : "Postavi status", + "There was an error saving the new status" : "Greška u snimanju novog statusa", + "30 minutes" : "30 minuta", + "1 hour" : "1 sat", + "4 hours" : "4 sata", + "Mute all notifications" : "Isključi sva obaveštenja", + "Appear offline" : "Prikaži kao van mreže" +},"pluralForm" :"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/sv.js b/apps/user_status/l10n/sv.js index 1ce860a949e..acd1b224d4b 100644 --- a/apps/user_status/l10n/sv.js +++ b/apps/user_status/l10n/sv.js @@ -2,39 +2,49 @@ OC.L10N.register( "user_status", { "Recent statuses" : "Senaste statusuppdateringar", + "No recent status changes" : "Inga statusuppdateringar den sista tiden", "In a meeting" : "På ett möte", "Commuting" : "Reser", "Out sick" : "Sjuk", "Vacationing" : "På semester", + "Out of office" : "Ej på plats", "Working remotely" : "Arbetar hemifrån", "In a call" : "I ett samtal", "User status" : "Användarstatus", - "View profile" : "Visa profil", - "Clear status message after" : "Rensa statusmeddelande efter", + "Clear status after" : "Rensa status efter", + "Emoji for your status message" : "Emoji för ditt statusmeddelande", "What is your status?" : "Vad är din status?", - "Set status" : "Sätt status", + "Predefined statuses" : "Fördefinierade statusar", + "Previously set" : "Tidigare inställd", + "Reset status" : "Återställ status", + "Reset status to \"{icon} {message}\"" : "Återställ status till \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Återställ status till \"{message}\"", + "Reset status to \"{icon}\"" : "Återställ status till \"{icon}\"", + "There was an error saving the status" : "Ett fel inträffade när statusen skulle ändras", + "There was an error clearing the status" : "Ett fel inträffade när statusen skulle rensas", + "There was an error reverting the status" : "Det gick inte att återställa statusen", "Online status" : "Online-status", "Status message" : "Statusmeddelande", + "Set absence period" : "Ställ in frånvaroperiod", + "Set absence period and replacement" : "Ställ in frånvaroperiod och ersättare", + "Your status was set automatically" : "Din status ställdes in automatiskt", "Clear status message" : "Rensa statusmeddelande", "Set status message" : "Sätt statusmeddelande", - "There was an error saving the status" : "Ett fel inträffade när statusen skulle ändras", - "There was an error clearing the status" : "Ett fel inträffade när statusen skulle rensas", - "No recent status changes" : "Inga statusuppdateringar den sista tiden", - "Away" : "Iväg", - "Do not disturb" : "Stör ej", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Rensa inte", "Today" : "Idag", "This week" : "Denna vecka", "Online" : "Online", + "Away" : "Iväg", + "Do not disturb" : "Stör ej", "Invisible" : "Osynlig", "Offline" : "Frånkopplad", + "Set status" : "Sätt status", "There was an error saving the new status" : "Ett fel inträffade när den nya statusen skulle sparas", "30 minutes" : "30 minuter", "1 hour" : "1 timme", "4 hours" : "4 timmar", + "Busy" : "Upptagen", "Mute all notifications" : "Dölj alla aviseringar", - "Appear offline" : "Visa som frånkopplad", - "What's your status?" : "Vad är din status?" + "Appear offline" : "Visa som frånkopplad" }, "nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/sv.json b/apps/user_status/l10n/sv.json index 52ecbee3bed..502baef321b 100644 --- a/apps/user_status/l10n/sv.json +++ b/apps/user_status/l10n/sv.json @@ -1,38 +1,48 @@ { "translations": { "Recent statuses" : "Senaste statusuppdateringar", + "No recent status changes" : "Inga statusuppdateringar den sista tiden", "In a meeting" : "På ett möte", "Commuting" : "Reser", "Out sick" : "Sjuk", "Vacationing" : "På semester", + "Out of office" : "Ej på plats", "Working remotely" : "Arbetar hemifrån", "In a call" : "I ett samtal", "User status" : "Användarstatus", - "View profile" : "Visa profil", - "Clear status message after" : "Rensa statusmeddelande efter", + "Clear status after" : "Rensa status efter", + "Emoji for your status message" : "Emoji för ditt statusmeddelande", "What is your status?" : "Vad är din status?", - "Set status" : "Sätt status", + "Predefined statuses" : "Fördefinierade statusar", + "Previously set" : "Tidigare inställd", + "Reset status" : "Återställ status", + "Reset status to \"{icon} {message}\"" : "Återställ status till \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Återställ status till \"{message}\"", + "Reset status to \"{icon}\"" : "Återställ status till \"{icon}\"", + "There was an error saving the status" : "Ett fel inträffade när statusen skulle ändras", + "There was an error clearing the status" : "Ett fel inträffade när statusen skulle rensas", + "There was an error reverting the status" : "Det gick inte att återställa statusen", "Online status" : "Online-status", "Status message" : "Statusmeddelande", + "Set absence period" : "Ställ in frånvaroperiod", + "Set absence period and replacement" : "Ställ in frånvaroperiod och ersättare", + "Your status was set automatically" : "Din status ställdes in automatiskt", "Clear status message" : "Rensa statusmeddelande", "Set status message" : "Sätt statusmeddelande", - "There was an error saving the status" : "Ett fel inträffade när statusen skulle ändras", - "There was an error clearing the status" : "Ett fel inträffade när statusen skulle rensas", - "No recent status changes" : "Inga statusuppdateringar den sista tiden", - "Away" : "Iväg", - "Do not disturb" : "Stör ej", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Rensa inte", "Today" : "Idag", "This week" : "Denna vecka", "Online" : "Online", + "Away" : "Iväg", + "Do not disturb" : "Stör ej", "Invisible" : "Osynlig", "Offline" : "Frånkopplad", + "Set status" : "Sätt status", "There was an error saving the new status" : "Ett fel inträffade när den nya statusen skulle sparas", "30 minutes" : "30 minuter", "1 hour" : "1 timme", "4 hours" : "4 timmar", + "Busy" : "Upptagen", "Mute all notifications" : "Dölj alla aviseringar", - "Appear offline" : "Visa som frånkopplad", - "What's your status?" : "Vad är din status?" + "Appear offline" : "Visa som frånkopplad" },"pluralForm" :"nplurals=2; plural=(n != 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/sw.js b/apps/user_status/l10n/sw.js new file mode 100644 index 00000000000..69e9430b920 --- /dev/null +++ b/apps/user_status/l10n/sw.js @@ -0,0 +1,51 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Hali za hivi karibuni", + "No recent status changes" : "Hakuna mabadiliko ya hali ya hivi karibuni", + "In a meeting" : "Katika mkutano", + "Commuting" : "Kuelekea", + "Out sick" : "Nje mgonjwa", + "Vacationing" : "Likizo", + "Out of office" : "Nje ya ofisi", + "Working remotely" : "Kufanyia kazi mbali", + "In a call" : "Katika simu", + "Be right back" : "Rudi mara moja", + "User status" : "Hadhi ya mtumiaji", + "Clear status after" : "Futa hali baada ya", + "Emoji for your status message" : "Emoji kwa hali yako ya ujumbe", + "What is your status?" : "Hadhi yako ni nini?", + "Predefined statuses" : "Hali zilizoainishwa awali", + "Previously set" : "Imepangiliwa mwanzo", + "Reset status" : "Pangilia hali", + "Reset status to \"{icon} {message}\"" : " Weka upya hali kuwa \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Weka upya hali kuwa \"{message}\"", + "Reset status to \"{icon}\"" : "Weka upya hali kuwa \"{icon}\"", + "There was an error saving the status" : "Kulikuwa na hitilafu katika kuhifadhi hali", + "There was an error clearing the status" : "Kulikuwa na hitilafu katika kufuta hali", + "There was an error reverting the status" : "Kulikuwa na hitilafu katika kurejesha hali", + "Online status" : "Hali ya mtandaoni", + "Status message" : "Hali ya ujumbe", + "Set absence period" : "Weka kipindi cha kutokuwepo", + "Set absence period and replacement" : " Weka kipindi cha kutokuwepo na uingizwaji mbadala", + "Your status was set automatically" : "Hadhi yako ilipangiliwa moja kwa moja", + "Clear status message" : "Futa jumbe za wadhifa", + "Set status message" : "Pangilia hali ya ujumbe", + "Don't clear" : "Usifute", + "Today" : "Leo", + "This week" : "Wiki hii", + "Online" : "Mtandaoni", + "Away" : "Mbali", + "Do not disturb" : "Acha kusumbua", + "Invisible" : "Haionekani", + "Offline" : "Nje ya mtandao", + "Set status" : "Panglia hali", + "There was an error saving the new status" : "Kulikuwa na hitilafu katika kuhifadhi hali mpya", + "30 minutes" : "Dakika 30", + "1 hour" : "Saa 1", + "4 hours" : "Masaa 4", + "Busy" : "Bize", + "Mute all notifications" : "Zima arifu zote", + "Appear offline" : "Tokea nje ya mtandao" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/sw.json b/apps/user_status/l10n/sw.json new file mode 100644 index 00000000000..a106159c6fb --- /dev/null +++ b/apps/user_status/l10n/sw.json @@ -0,0 +1,49 @@ +{ "translations": { + "Recent statuses" : "Hali za hivi karibuni", + "No recent status changes" : "Hakuna mabadiliko ya hali ya hivi karibuni", + "In a meeting" : "Katika mkutano", + "Commuting" : "Kuelekea", + "Out sick" : "Nje mgonjwa", + "Vacationing" : "Likizo", + "Out of office" : "Nje ya ofisi", + "Working remotely" : "Kufanyia kazi mbali", + "In a call" : "Katika simu", + "Be right back" : "Rudi mara moja", + "User status" : "Hadhi ya mtumiaji", + "Clear status after" : "Futa hali baada ya", + "Emoji for your status message" : "Emoji kwa hali yako ya ujumbe", + "What is your status?" : "Hadhi yako ni nini?", + "Predefined statuses" : "Hali zilizoainishwa awali", + "Previously set" : "Imepangiliwa mwanzo", + "Reset status" : "Pangilia hali", + "Reset status to \"{icon} {message}\"" : " Weka upya hali kuwa \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Weka upya hali kuwa \"{message}\"", + "Reset status to \"{icon}\"" : "Weka upya hali kuwa \"{icon}\"", + "There was an error saving the status" : "Kulikuwa na hitilafu katika kuhifadhi hali", + "There was an error clearing the status" : "Kulikuwa na hitilafu katika kufuta hali", + "There was an error reverting the status" : "Kulikuwa na hitilafu katika kurejesha hali", + "Online status" : "Hali ya mtandaoni", + "Status message" : "Hali ya ujumbe", + "Set absence period" : "Weka kipindi cha kutokuwepo", + "Set absence period and replacement" : " Weka kipindi cha kutokuwepo na uingizwaji mbadala", + "Your status was set automatically" : "Hadhi yako ilipangiliwa moja kwa moja", + "Clear status message" : "Futa jumbe za wadhifa", + "Set status message" : "Pangilia hali ya ujumbe", + "Don't clear" : "Usifute", + "Today" : "Leo", + "This week" : "Wiki hii", + "Online" : "Mtandaoni", + "Away" : "Mbali", + "Do not disturb" : "Acha kusumbua", + "Invisible" : "Haionekani", + "Offline" : "Nje ya mtandao", + "Set status" : "Panglia hali", + "There was an error saving the new status" : "Kulikuwa na hitilafu katika kuhifadhi hali mpya", + "30 minutes" : "Dakika 30", + "1 hour" : "Saa 1", + "4 hours" : "Masaa 4", + "Busy" : "Bize", + "Mute all notifications" : "Zima arifu zote", + "Appear offline" : "Tokea nje ya mtandao" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/th.js b/apps/user_status/l10n/th.js index e2d4a9b1e5c..00bdced011d 100644 --- a/apps/user_status/l10n/th.js +++ b/apps/user_status/l10n/th.js @@ -2,36 +2,35 @@ OC.L10N.register( "user_status", { "Recent statuses" : "สถานะล่าสุด", + "No recent status changes" : "ไม่มีการเปลี่ยนสถานะล่าสุด", "In a meeting" : "กำลังประชุม", "Commuting" : "กำลังเดินทาง", "Out sick" : "ป่วย", "Vacationing" : "วันหยุดพักผ่อน", "Working remotely" : "ทำงานจากระยะไกล", "User status" : "สถานะผู้ใช้", - "Clear status message after" : "ลบข้อความสถานะหลังจาก", - "Set status" : "กำหนดสถานะ", + "Clear status after" : "ล้างสถานะหลังจาก", + "What is your status?" : "สถานะของคุณ", + "There was an error saving the status" : "เกิดข้อผิดพลาดในการบันทึกสถานะ", + "There was an error clearing the status" : "เกิดข้อผิดพลาดในการลบสถานะ", "Online status" : "สถานะออนไลน์", "Status message" : "ข้อความสถานะ", "Clear status message" : "ล้างข้อความสถานะ", "Set status message" : "กำหนดข้อความสถานะ", - "There was an error saving the status" : "เกิดข้อผิดพลาดในการบันทึกสถานะ", - "There was an error clearing the status" : "เกิดข้อผิดพลาดในการลบสถานะ", - "No recent status changes" : "ไม่มีการเปลี่ยนสถานะล่าสุด", - "Away" : "ไม่อยู่", - "Do not disturb" : "ห้ามรบกวน", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "ไม่ต้องล้าง", "Today" : "วันนี้", "This week" : "สัปดาห์นี้", "Online" : "ออนไลน์", + "Away" : "ไม่อยู่", + "Do not disturb" : "ห้ามรบกวน", "Invisible" : "ไม่แสดงสถานะ", "Offline" : "ออฟไลน์", + "Set status" : "กำหนดสถานะ", "There was an error saving the new status" : "เกิดข้อผิดพลาดในการบันทึกสถานะใหม่", "30 minutes" : "30 นาที", "1 hour" : "1 ชั่วโมง", "4 hours" : "4 ชั่วโมง", "Mute all notifications" : "ปิดการแจ้งเตือนทั้งหมด", - "Appear offline" : "แสดงเป็นออฟไลน์", - "What's your status?" : "สถานะของคุณคืออะไร" + "Appear offline" : "แสดงเป็นออฟไลน์" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/th.json b/apps/user_status/l10n/th.json index bb6364a7eb5..36ca7503b17 100644 --- a/apps/user_status/l10n/th.json +++ b/apps/user_status/l10n/th.json @@ -1,35 +1,34 @@ { "translations": { "Recent statuses" : "สถานะล่าสุด", + "No recent status changes" : "ไม่มีการเปลี่ยนสถานะล่าสุด", "In a meeting" : "กำลังประชุม", "Commuting" : "กำลังเดินทาง", "Out sick" : "ป่วย", "Vacationing" : "วันหยุดพักผ่อน", "Working remotely" : "ทำงานจากระยะไกล", "User status" : "สถานะผู้ใช้", - "Clear status message after" : "ลบข้อความสถานะหลังจาก", - "Set status" : "กำหนดสถานะ", + "Clear status after" : "ล้างสถานะหลังจาก", + "What is your status?" : "สถานะของคุณ", + "There was an error saving the status" : "เกิดข้อผิดพลาดในการบันทึกสถานะ", + "There was an error clearing the status" : "เกิดข้อผิดพลาดในการลบสถานะ", "Online status" : "สถานะออนไลน์", "Status message" : "ข้อความสถานะ", "Clear status message" : "ล้างข้อความสถานะ", "Set status message" : "กำหนดข้อความสถานะ", - "There was an error saving the status" : "เกิดข้อผิดพลาดในการบันทึกสถานะ", - "There was an error clearing the status" : "เกิดข้อผิดพลาดในการลบสถานะ", - "No recent status changes" : "ไม่มีการเปลี่ยนสถานะล่าสุด", - "Away" : "ไม่อยู่", - "Do not disturb" : "ห้ามรบกวน", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "ไม่ต้องล้าง", "Today" : "วันนี้", "This week" : "สัปดาห์นี้", "Online" : "ออนไลน์", + "Away" : "ไม่อยู่", + "Do not disturb" : "ห้ามรบกวน", "Invisible" : "ไม่แสดงสถานะ", "Offline" : "ออฟไลน์", + "Set status" : "กำหนดสถานะ", "There was an error saving the new status" : "เกิดข้อผิดพลาดในการบันทึกสถานะใหม่", "30 minutes" : "30 นาที", "1 hour" : "1 ชั่วโมง", "4 hours" : "4 ชั่วโมง", "Mute all notifications" : "ปิดการแจ้งเตือนทั้งหมด", - "Appear offline" : "แสดงเป็นออฟไลน์", - "What's your status?" : "สถานะของคุณคืออะไร" + "Appear offline" : "แสดงเป็นออฟไลน์" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/tr.js b/apps/user_status/l10n/tr.js index b9082b44da5..c63ff93c164 100644 --- a/apps/user_status/l10n/tr.js +++ b/apps/user_status/l10n/tr.js @@ -1,40 +1,50 @@ OC.L10N.register( "user_status", { - "Recent statuses" : "Yakın zamandaki durumlar", + "Recent statuses" : "Son durumlar", + "No recent status changes" : "Son zamanlarda durum değiştirilmemiş", "In a meeting" : "Toplantıda", "Commuting" : "İşe gidiyor/geliyor", "Out sick" : "Hasta", "Vacationing" : "Tatilde", + "Out of office" : "İş yeri dışında", "Working remotely" : "Uzaktan çalışıyor", - "In a call" : "Bir görüşmede", + "In a call" : "Bir çağrıda", "User status" : "Kullanıcı durumu", - "View profile" : "Profili görüntüle", - "Clear status message after" : "Durum iletisi şu süre sonunda kaldırılsın", + "Clear status after" : "Durum şu kadar sonra kaldırılsın", + "Emoji for your status message" : "Durum iletiniz için emoji", "What is your status?" : "Durumunuz nedir?", - "Set status" : "Durumu ayarla", - "Online status" : "Çevrimiçi durumu", + "Predefined statuses" : "Hazır durumlar", + "Previously set" : "Önceden ayarlanmış", + "Reset status" : "Durumu sıfırla", + "Reset status to \"{icon} {message}\"" : "Durumu \"{icon} {message}\" olarak sıfırla", + "Reset status to \"{message}\"" : "Durumu \"{message}\" olarak sıfırla", + "Reset status to \"{icon}\"" : "Durumu \"{icon}\" olarak sıfırla", + "There was an error saving the status" : "Durum kaydedilirken bir sorun çıktı", + "There was an error clearing the status" : "Durum kaldırılırken bir sorun çıktı", + "There was an error reverting the status" : "Durum geri alınırken bir sorun çıktı", + "Online status" : "Çevrim içi durumu", "Status message" : "Durum iletisi", + "Set absence period" : "Bulunmama aralığını ayarla", + "Set absence period and replacement" : "Bulunmama aralığını ve yedek kişiyi ayarla", + "Your status was set automatically" : "Durumunuz otomatik olarak ayarlanmış", "Clear status message" : "Durum iletisini temizle", "Set status message" : "Durum iletisini ayarla", - "There was an error saving the status" : "Durum kaydedilirken bir sorun çıktı", - "There was an error clearing the status" : "Durum kaldırılırken bir sorun çıktı", - "No recent status changes" : "Yakın zamanda değiştirilmiş bir durum yok", - "Away" : "Uzakta", - "Do not disturb" : "Rahatsız etmeyin", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Kaldırılmasın", "Today" : "Bugün", "This week" : "Bu hafta", - "Online" : "Çevrimiçi", + "Online" : "Çevrim içi", + "Away" : "Uzakta", + "Do not disturb" : "Rahatsız etmeyin", "Invisible" : "Gizli", - "Offline" : "Çevrimdışı", + "Offline" : "Çevrim dışı", + "Set status" : "Durumu ayarla", "There was an error saving the new status" : "Yeni durum kaydedilirken bir sorun çıktı", "30 minutes" : "30 dakika", "1 hour" : "1 saat", "4 hours" : "4 saat", + "Busy" : "Meşgul", "Mute all notifications" : "Tüm bildirimleri kapat", - "Appear offline" : "Çevrimdışı görün", - "What's your status?" : "Durumunuz nedir?" + "Appear offline" : "Çevrim dışı görün" }, "nplurals=2; plural=(n > 1);"); diff --git a/apps/user_status/l10n/tr.json b/apps/user_status/l10n/tr.json index f0a52887536..c601fbbd635 100644 --- a/apps/user_status/l10n/tr.json +++ b/apps/user_status/l10n/tr.json @@ -1,38 +1,48 @@ { "translations": { - "Recent statuses" : "Yakın zamandaki durumlar", + "Recent statuses" : "Son durumlar", + "No recent status changes" : "Son zamanlarda durum değiştirilmemiş", "In a meeting" : "Toplantıda", "Commuting" : "İşe gidiyor/geliyor", "Out sick" : "Hasta", "Vacationing" : "Tatilde", + "Out of office" : "İş yeri dışında", "Working remotely" : "Uzaktan çalışıyor", - "In a call" : "Bir görüşmede", + "In a call" : "Bir çağrıda", "User status" : "Kullanıcı durumu", - "View profile" : "Profili görüntüle", - "Clear status message after" : "Durum iletisi şu süre sonunda kaldırılsın", + "Clear status after" : "Durum şu kadar sonra kaldırılsın", + "Emoji for your status message" : "Durum iletiniz için emoji", "What is your status?" : "Durumunuz nedir?", - "Set status" : "Durumu ayarla", - "Online status" : "Çevrimiçi durumu", + "Predefined statuses" : "Hazır durumlar", + "Previously set" : "Önceden ayarlanmış", + "Reset status" : "Durumu sıfırla", + "Reset status to \"{icon} {message}\"" : "Durumu \"{icon} {message}\" olarak sıfırla", + "Reset status to \"{message}\"" : "Durumu \"{message}\" olarak sıfırla", + "Reset status to \"{icon}\"" : "Durumu \"{icon}\" olarak sıfırla", + "There was an error saving the status" : "Durum kaydedilirken bir sorun çıktı", + "There was an error clearing the status" : "Durum kaldırılırken bir sorun çıktı", + "There was an error reverting the status" : "Durum geri alınırken bir sorun çıktı", + "Online status" : "Çevrim içi durumu", "Status message" : "Durum iletisi", + "Set absence period" : "Bulunmama aralığını ayarla", + "Set absence period and replacement" : "Bulunmama aralığını ve yedek kişiyi ayarla", + "Your status was set automatically" : "Durumunuz otomatik olarak ayarlanmış", "Clear status message" : "Durum iletisini temizle", "Set status message" : "Durum iletisini ayarla", - "There was an error saving the status" : "Durum kaydedilirken bir sorun çıktı", - "There was an error clearing the status" : "Durum kaldırılırken bir sorun çıktı", - "No recent status changes" : "Yakın zamanda değiştirilmiş bir durum yok", - "Away" : "Uzakta", - "Do not disturb" : "Rahatsız etmeyin", - "{status}, {timestamp}" : "{status}, {timestamp}", "Don't clear" : "Kaldırılmasın", "Today" : "Bugün", "This week" : "Bu hafta", - "Online" : "Çevrimiçi", + "Online" : "Çevrim içi", + "Away" : "Uzakta", + "Do not disturb" : "Rahatsız etmeyin", "Invisible" : "Gizli", - "Offline" : "Çevrimdışı", + "Offline" : "Çevrim dışı", + "Set status" : "Durumu ayarla", "There was an error saving the new status" : "Yeni durum kaydedilirken bir sorun çıktı", "30 minutes" : "30 dakika", "1 hour" : "1 saat", "4 hours" : "4 saat", + "Busy" : "Meşgul", "Mute all notifications" : "Tüm bildirimleri kapat", - "Appear offline" : "Çevrimdışı görün", - "What's your status?" : "Durumunuz nedir?" + "Appear offline" : "Çevrim dışı görün" },"pluralForm" :"nplurals=2; plural=(n > 1);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/ug.js b/apps/user_status/l10n/ug.js new file mode 100644 index 00000000000..43c620037e3 --- /dev/null +++ b/apps/user_status/l10n/ug.js @@ -0,0 +1,50 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "يېقىنقى ھالەت", + "No recent status changes" : "يېقىنقى ھالەت ئۆزگەرمىدى", + "In a meeting" : "بىر يىغىندا", + "Commuting" : "سەپەرگە چىقىش", + "Out sick" : "كېسەل", + "Vacationing" : "دەم ئېلىش", + "Out of office" : "ئىشخانىدىن چىقتى", + "Working remotely" : "يىراقتىن ئىشلەش", + "In a call" : "تېلېفوندا", + "User status" : "ئىشلەتكۈچى ھالىتى", + "Clear status after" : "كېيىنكى ھالەتنى ئېنىقلاش", + "Emoji for your status message" : "ھالەت ئۇچۇرىڭىز ئۈچۈن Emoji", + "What is your status?" : "ئەھۋالىڭىز نېمە؟", + "Predefined statuses" : "ئالدىن بېكىتىلگەن ھالەت", + "Previously set" : "ئىلگىرى تەڭشەلگەن", + "Reset status" : "ھالىتىنى ئەسلىگە كەلتۈرۈش", + "Reset status to \"{icon} {message}\"" : "ھالەتنى \"{icon} {message}\" غا قايتۇرۇڭ", + "Reset status to \"{message}\"" : "ھالەتنى \"{message}\" غا قايتۇرۇڭ", + "Reset status to \"{icon}\"" : "ھالەتنى \"{icon}\" گە قايتۇرۇڭ", + "There was an error saving the status" : "ھالەتنى ساقلاشتا خاتالىق كۆرۈلدى", + "There was an error clearing the status" : "ھالەتنى تازىلاشتا خاتالىق كۆرۈلدى", + "There was an error reverting the status" : "ھالەتنى ئەسلىگە كەلتۈرۈشتە خاتالىق كۆرۈلدى", + "Online status" : "توردىكى ئورنى", + "Status message" : "ھالەت ئۇچۇرى", + "Set absence period" : "يوقلۇق ۋاقتىنى بەلگىلەڭ", + "Set absence period and replacement" : "يوقلۇق ۋاقتى ۋە ئورنىنى بەلگىلەڭ", + "Your status was set automatically" : "ھالىتىڭىز ئاپتوماتىك تەڭشەلدى", + "Clear status message" : "ھالەت ئۇچۇرىنى تازىلاش", + "Set status message" : "ھالەت ئۇچۇرىنى بەلگىلەڭ", + "Don't clear" : "ئېنىق ئەمەس", + "Today" : "بۈگۈن", + "This week" : "بۇ ھەپتە", + "Online" : "توردا", + "Away" : "يىراق", + "Do not disturb" : "ئاۋارە قىلماڭ", + "Invisible" : "كۆرۈنمەيدۇ", + "Offline" : "تورسىز", + "Set status" : "ھالەت بەلگىلەڭ", + "There was an error saving the new status" : "يېڭى ھالەتنى ساقلاشتا خاتالىق كۆرۈلدى", + "30 minutes" : "30 مىنۇت", + "1 hour" : "1 سائەت", + "4 hours" : "4 سائەت", + "Busy" : "ئالدىراش", + "Mute all notifications" : "بارلىق ئۇقتۇرۇشلارنى ئاۋازسىز قىلىڭ", + "Appear offline" : "تورسىز كۆرۈنۈش" +}, +"nplurals=2; plural=(n != 1);"); diff --git a/apps/user_status/l10n/ug.json b/apps/user_status/l10n/ug.json new file mode 100644 index 00000000000..eb439948185 --- /dev/null +++ b/apps/user_status/l10n/ug.json @@ -0,0 +1,48 @@ +{ "translations": { + "Recent statuses" : "يېقىنقى ھالەت", + "No recent status changes" : "يېقىنقى ھالەت ئۆزگەرمىدى", + "In a meeting" : "بىر يىغىندا", + "Commuting" : "سەپەرگە چىقىش", + "Out sick" : "كېسەل", + "Vacationing" : "دەم ئېلىش", + "Out of office" : "ئىشخانىدىن چىقتى", + "Working remotely" : "يىراقتىن ئىشلەش", + "In a call" : "تېلېفوندا", + "User status" : "ئىشلەتكۈچى ھالىتى", + "Clear status after" : "كېيىنكى ھالەتنى ئېنىقلاش", + "Emoji for your status message" : "ھالەت ئۇچۇرىڭىز ئۈچۈن Emoji", + "What is your status?" : "ئەھۋالىڭىز نېمە؟", + "Predefined statuses" : "ئالدىن بېكىتىلگەن ھالەت", + "Previously set" : "ئىلگىرى تەڭشەلگەن", + "Reset status" : "ھالىتىنى ئەسلىگە كەلتۈرۈش", + "Reset status to \"{icon} {message}\"" : "ھالەتنى \"{icon} {message}\" غا قايتۇرۇڭ", + "Reset status to \"{message}\"" : "ھالەتنى \"{message}\" غا قايتۇرۇڭ", + "Reset status to \"{icon}\"" : "ھالەتنى \"{icon}\" گە قايتۇرۇڭ", + "There was an error saving the status" : "ھالەتنى ساقلاشتا خاتالىق كۆرۈلدى", + "There was an error clearing the status" : "ھالەتنى تازىلاشتا خاتالىق كۆرۈلدى", + "There was an error reverting the status" : "ھالەتنى ئەسلىگە كەلتۈرۈشتە خاتالىق كۆرۈلدى", + "Online status" : "توردىكى ئورنى", + "Status message" : "ھالەت ئۇچۇرى", + "Set absence period" : "يوقلۇق ۋاقتىنى بەلگىلەڭ", + "Set absence period and replacement" : "يوقلۇق ۋاقتى ۋە ئورنىنى بەلگىلەڭ", + "Your status was set automatically" : "ھالىتىڭىز ئاپتوماتىك تەڭشەلدى", + "Clear status message" : "ھالەت ئۇچۇرىنى تازىلاش", + "Set status message" : "ھالەت ئۇچۇرىنى بەلگىلەڭ", + "Don't clear" : "ئېنىق ئەمەس", + "Today" : "بۈگۈن", + "This week" : "بۇ ھەپتە", + "Online" : "توردا", + "Away" : "يىراق", + "Do not disturb" : "ئاۋارە قىلماڭ", + "Invisible" : "كۆرۈنمەيدۇ", + "Offline" : "تورسىز", + "Set status" : "ھالەت بەلگىلەڭ", + "There was an error saving the new status" : "يېڭى ھالەتنى ساقلاشتا خاتالىق كۆرۈلدى", + "30 minutes" : "30 مىنۇت", + "1 hour" : "1 سائەت", + "4 hours" : "4 سائەت", + "Busy" : "ئالدىراش", + "Mute all notifications" : "بارلىق ئۇقتۇرۇشلارنى ئاۋازسىز قىلىڭ", + "Appear offline" : "تورسىز كۆرۈنۈش" +},"pluralForm" :"nplurals=2; plural=(n != 1);" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/uk.js b/apps/user_status/l10n/uk.js index 745ce96edb7..b73417b164b 100644 --- a/apps/user_status/l10n/uk.js +++ b/apps/user_status/l10n/uk.js @@ -1,23 +1,51 @@ OC.L10N.register( "user_status", { - "View profile" : "Перегляд профілю", - "Clear status message after" : "Очистити повідомлення про стан після", - "Set status" : "Встановити статус", - "Online status" : "Статус онлайну", + "Recent statuses" : "Останні статуси", + "No recent status changes" : "Статус не змінювався", + "In a meeting" : "На зустрічі", + "Commuting" : "В дорозі на роботу", + "Out sick" : "Хворію", + "Vacationing" : "У відпустці", + "Out of office" : "Недоступний(-а)", + "Working remotely" : "Працюю віддалено", + "In a call" : "На дзвінку", + "Be right back" : "Зараз повернуся", + "User status" : "Статус користувача", + "Clear status after" : "Очистити статус після", + "Emoji for your status message" : "Емоційки для повідомлення вашого статусу", + "What is your status?" : "Який твій статус?", + "Predefined statuses" : "Попередньо визначені статуси", + "Previously set" : "Раніше встановлений", + "Reset status" : "Скинути статус", + "Reset status to \"{icon} {message}\"" : "Скинути статус на \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Скинути статус на \"{message}\"", + "Reset status to \"{icon}\"" : "Скинути статус на \"{icon}\"", + "There was an error saving the status" : "Помилка під час збереження статусу", + "There was an error clearing the status" : "Помилка під час очищення статусу", + "There was an error reverting the status" : "Помилка при скиданні статусу", + "Online status" : "Мій статус доступності", "Status message" : "Повідомлення про статус", - "Clear status message" : "Очистити повідомлення про стан", - "Set status message" : "Встановити повідомлення про стан", - "Away" : "Піти", - "Do not disturb" : "Не турбувати", - "Don't clear" : "Не очистувати", + "Set absence period" : "Встановити період відсутности", + "Set absence period and replacement" : "Встановити період відсутности та тимчасово виконуючого обов'язки", + "Your status was set automatically" : "Ваш статус встановлено автоматично", + "Clear status message" : "Прибрати статус", + "Set status message" : "Оновити статус", + "Don't clear" : "Залишити поточний", "Today" : "Сьогодні", "This week" : "Цього тижня", - "Online" : "Онлайн", - "Invisible" : "Невидима", + "Online" : "Доступний(-а)", + "Away" : "Відсутній(-я)", + "Do not disturb" : "Не турбувати", + "Invisible" : "Невидимка", + "Offline" : "Поза мережею", + "Set status" : "Встановити статус", + "There was an error saving the new status" : "Помилка під час збереження статусу", "30 minutes" : "30 хвилин", "1 hour" : "1 година", "4 hours" : "4 години", - "What's your status?" : "Який ваш статус?" + "Busy" : "Зайнято", + "Mute all notifications" : "Вимкнути всі сповіщення", + "Appear offline" : "Перебуваю поза мережею" }, "nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);"); diff --git a/apps/user_status/l10n/uk.json b/apps/user_status/l10n/uk.json index 04593c06b97..e115bf09f5f 100644 --- a/apps/user_status/l10n/uk.json +++ b/apps/user_status/l10n/uk.json @@ -1,21 +1,49 @@ { "translations": { - "View profile" : "Перегляд профілю", - "Clear status message after" : "Очистити повідомлення про стан після", - "Set status" : "Встановити статус", - "Online status" : "Статус онлайну", + "Recent statuses" : "Останні статуси", + "No recent status changes" : "Статус не змінювався", + "In a meeting" : "На зустрічі", + "Commuting" : "В дорозі на роботу", + "Out sick" : "Хворію", + "Vacationing" : "У відпустці", + "Out of office" : "Недоступний(-а)", + "Working remotely" : "Працюю віддалено", + "In a call" : "На дзвінку", + "Be right back" : "Зараз повернуся", + "User status" : "Статус користувача", + "Clear status after" : "Очистити статус після", + "Emoji for your status message" : "Емоційки для повідомлення вашого статусу", + "What is your status?" : "Який твій статус?", + "Predefined statuses" : "Попередньо визначені статуси", + "Previously set" : "Раніше встановлений", + "Reset status" : "Скинути статус", + "Reset status to \"{icon} {message}\"" : "Скинути статус на \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Скинути статус на \"{message}\"", + "Reset status to \"{icon}\"" : "Скинути статус на \"{icon}\"", + "There was an error saving the status" : "Помилка під час збереження статусу", + "There was an error clearing the status" : "Помилка під час очищення статусу", + "There was an error reverting the status" : "Помилка при скиданні статусу", + "Online status" : "Мій статус доступності", "Status message" : "Повідомлення про статус", - "Clear status message" : "Очистити повідомлення про стан", - "Set status message" : "Встановити повідомлення про стан", - "Away" : "Піти", - "Do not disturb" : "Не турбувати", - "Don't clear" : "Не очистувати", + "Set absence period" : "Встановити період відсутности", + "Set absence period and replacement" : "Встановити період відсутности та тимчасово виконуючого обов'язки", + "Your status was set automatically" : "Ваш статус встановлено автоматично", + "Clear status message" : "Прибрати статус", + "Set status message" : "Оновити статус", + "Don't clear" : "Залишити поточний", "Today" : "Сьогодні", "This week" : "Цього тижня", - "Online" : "Онлайн", - "Invisible" : "Невидима", + "Online" : "Доступний(-а)", + "Away" : "Відсутній(-я)", + "Do not disturb" : "Не турбувати", + "Invisible" : "Невидимка", + "Offline" : "Поза мережею", + "Set status" : "Встановити статус", + "There was an error saving the new status" : "Помилка під час збереження статусу", "30 minutes" : "30 хвилин", "1 hour" : "1 година", "4 hours" : "4 години", - "What's your status?" : "Який ваш статус?" + "Busy" : "Зайнято", + "Mute all notifications" : "Вимкнути всі сповіщення", + "Appear offline" : "Перебуваю поза мережею" },"pluralForm" :"nplurals=4; plural=(n % 1 == 0 && n % 10 == 1 && n % 100 != 11 ? 0 : n % 1 == 0 && n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14) ? 1 : n % 1 == 0 && (n % 10 ==0 || (n % 10 >=5 && n % 10 <=9) || (n % 100 >=11 && n % 100 <=14 )) ? 2: 3);" }
\ No newline at end of file diff --git a/apps/user_status/l10n/uz.js b/apps/user_status/l10n/uz.js new file mode 100644 index 00000000000..c2ada8c65d0 --- /dev/null +++ b/apps/user_status/l10n/uz.js @@ -0,0 +1,50 @@ +OC.L10N.register( + "user_status", + { + "Recent statuses" : "Oxirgi holatlar", + "No recent status changes" : "Oxirgi holatda o'zgarish mavjud emas", + "In a meeting" : "Uchrashuvda", + "Commuting" : "Qatnov", + "Out sick" : "Kasal", + "Vacationing" : "Dam olish", + "Out of office" : "Ofisda emas", + "Working remotely" : "Masofadan ishlash", + "In a call" : "Qo'ng'iroqda", + "User status" : "Foydalanuvchi holati", + "Clear status after" : "Holatni tozalashdan keyin", + "Emoji for your status message" : "Xabar holati uchun emoji", + "What is your status?" : "Sizning holatingiz qanday?", + "Predefined statuses" : "Oldindan belgilangan holatlar", + "Previously set" : "Ilgari o'rnatilgan", + "Reset status" : "Holatni tiklash", + "Reset status to \"{icon} {message}\"" : " \"{icon} {message}\" uchun holatni tiklash", + "Reset status to \"{message}\"" : " \"{message}\" uchun holatni tiklash", + "Reset status to \"{icon}\"" : " \"{icon}\" uchun holatni tiklash", + "There was an error saving the status" : "Holatni saqlashda xatolik yuz berdi", + "There was an error clearing the status" : "Holatni tozalashda xatolik yuz berdi", + "There was an error reverting the status" : "Holatni qaytarishda xatolik yuz berdi", + "Online status" : "Onlayn holat", + "Status message" : "Holat xabari", + "Set absence period" : "Aloqadan o`chirilgan muddatini belgilang", + "Set absence period and replacement" : "Aloqadan o`chirilgan muddatini va almashtirish belgilang", + "Your status was set automatically" : "Sizning holatingiz avtomatik ravishda o'rnatildi", + "Clear status message" : "Holat xabarini tozalash", + "Set status message" : "Holat xabarini o'rnatish", + "Don't clear" : "Aniq emas", + "Today" : "Bugun", + "This week" : "Shu hafta", + "Online" : "Online", + "Away" : "Uzoqda", + "Do not disturb" : "Bezovta qilmang", + "Invisible" : "Ko'rinmas", + "Offline" : "Offline", + "Set status" : "Holatni belgilash", + "There was an error saving the new status" : "Yangi holatni saqlashda xatolik yuz berdi", + "30 minutes" : "30 minut", + "1 hour" : "1 soat", + "4 hours" : "4 soat", + "Busy" : "Band", + "Mute all notifications" : "Barcha bildirishnomalarni o'chirish", + "Appear offline" : "Oflayn ko'rinishda" +}, +"nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/uz.json b/apps/user_status/l10n/uz.json new file mode 100644 index 00000000000..8d4d073a89f --- /dev/null +++ b/apps/user_status/l10n/uz.json @@ -0,0 +1,48 @@ +{ "translations": { + "Recent statuses" : "Oxirgi holatlar", + "No recent status changes" : "Oxirgi holatda o'zgarish mavjud emas", + "In a meeting" : "Uchrashuvda", + "Commuting" : "Qatnov", + "Out sick" : "Kasal", + "Vacationing" : "Dam olish", + "Out of office" : "Ofisda emas", + "Working remotely" : "Masofadan ishlash", + "In a call" : "Qo'ng'iroqda", + "User status" : "Foydalanuvchi holati", + "Clear status after" : "Holatni tozalashdan keyin", + "Emoji for your status message" : "Xabar holati uchun emoji", + "What is your status?" : "Sizning holatingiz qanday?", + "Predefined statuses" : "Oldindan belgilangan holatlar", + "Previously set" : "Ilgari o'rnatilgan", + "Reset status" : "Holatni tiklash", + "Reset status to \"{icon} {message}\"" : " \"{icon} {message}\" uchun holatni tiklash", + "Reset status to \"{message}\"" : " \"{message}\" uchun holatni tiklash", + "Reset status to \"{icon}\"" : " \"{icon}\" uchun holatni tiklash", + "There was an error saving the status" : "Holatni saqlashda xatolik yuz berdi", + "There was an error clearing the status" : "Holatni tozalashda xatolik yuz berdi", + "There was an error reverting the status" : "Holatni qaytarishda xatolik yuz berdi", + "Online status" : "Onlayn holat", + "Status message" : "Holat xabari", + "Set absence period" : "Aloqadan o`chirilgan muddatini belgilang", + "Set absence period and replacement" : "Aloqadan o`chirilgan muddatini va almashtirish belgilang", + "Your status was set automatically" : "Sizning holatingiz avtomatik ravishda o'rnatildi", + "Clear status message" : "Holat xabarini tozalash", + "Set status message" : "Holat xabarini o'rnatish", + "Don't clear" : "Aniq emas", + "Today" : "Bugun", + "This week" : "Shu hafta", + "Online" : "Online", + "Away" : "Uzoqda", + "Do not disturb" : "Bezovta qilmang", + "Invisible" : "Ko'rinmas", + "Offline" : "Offline", + "Set status" : "Holatni belgilash", + "There was an error saving the new status" : "Yangi holatni saqlashda xatolik yuz berdi", + "30 minutes" : "30 minut", + "1 hour" : "1 soat", + "4 hours" : "4 soat", + "Busy" : "Band", + "Mute all notifications" : "Barcha bildirishnomalarni o'chirish", + "Appear offline" : "Oflayn ko'rinishda" +},"pluralForm" :"nplurals=1; plural=0;" +}
\ No newline at end of file diff --git a/apps/user_status/l10n/vi.js b/apps/user_status/l10n/vi.js index e10bbaf0f93..0c2e8081a8e 100644 --- a/apps/user_status/l10n/vi.js +++ b/apps/user_status/l10n/vi.js @@ -1,24 +1,47 @@ OC.L10N.register( "user_status", { + "Recent statuses" : "Trạng thái gần đây", + "No recent status changes" : "Không có thay đổi trạng thái gần đây", + "In a meeting" : "Trong một cuộc họp", "Commuting" : "Đang di chuyển", - "Clear status message after" : "Xoá thông báo trạng thái sau", + "Out sick" : "Bị ốm", + "Vacationing" : "Đi nghỉ", + "Out of office" : "Không ở văn phòng", + "Working remotely" : "Làm việc từ xa", + "User status" : "Trạng thái người dùng", + "Clear status after" : "Xóa trạng thái sau", + "Emoji for your status message" : "Biểu tượng cảm xúc cho thông báo trạng thái của bạn", "What is your status?" : "Trạng thái của bạn là gì?", - "Set status" : "Đặt trạng thái", + "Predefined statuses" : "Trạng thái được xác định trước", + "Previously set" : "Đã đặt trước đó", + "Reset status" : "Thiết lập trạng thái", + "Reset status to \"{icon} {message}\"" : "Đặt lại trạng thái thành \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Đặt lại trạng thái thành \"{message}\"", + "Reset status to \"{icon}\"" : "Đặt lại trạng thái thành \"{icon}\"", + "There was an error saving the status" : "Đã xảy ra lỗi khi lưu trạng thái", + "There was an error clearing the status" : "Đã xảy ra lỗi khi xóa trạng thái", + "There was an error reverting the status" : "Đã xảy ra lỗi khi hoàn nguyên trạng thái", "Online status" : "Trạng thái trực tuyến", "Status message" : "Thông báo trạng thái", + "Your status was set automatically" : "Trạng thái của bạn đã được đặt tự động", "Clear status message" : "Xoá thông báo trạng thái", "Set status message" : "Đặt thông báo trạng thái", - "Away" : "Tạm vắng", - "Do not disturb" : "Đừng làm phiền", "Don't clear" : "Không xoá", "Today" : "Hôm nay", "This week" : "Tuần này", "Online" : "Trực tuyến", + "Away" : "Tạm vắng", + "Do not disturb" : "Đừng làm phiền", "Invisible" : "Vô hình", + "Offline" : "Ngoại tuyến", + "Set status" : "Đặt trạng thái", + "There was an error saving the new status" : "Đã xảy ra lỗi khi lưu trạng thái mới", "30 minutes" : "30 phút", "1 hour" : "1 tiếng", "4 hours" : "4 tiếng", - "What's your status?" : "Trạng thái của bạn là gì?" + "Busy" : "Bận", + "Mute all notifications" : "Tắt tiếng tất cả thông báo", + "Appear offline" : "Đang offline" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/vi.json b/apps/user_status/l10n/vi.json index eaef648d350..daf7d940656 100644 --- a/apps/user_status/l10n/vi.json +++ b/apps/user_status/l10n/vi.json @@ -1,22 +1,45 @@ { "translations": { + "Recent statuses" : "Trạng thái gần đây", + "No recent status changes" : "Không có thay đổi trạng thái gần đây", + "In a meeting" : "Trong một cuộc họp", "Commuting" : "Đang di chuyển", - "Clear status message after" : "Xoá thông báo trạng thái sau", + "Out sick" : "Bị ốm", + "Vacationing" : "Đi nghỉ", + "Out of office" : "Không ở văn phòng", + "Working remotely" : "Làm việc từ xa", + "User status" : "Trạng thái người dùng", + "Clear status after" : "Xóa trạng thái sau", + "Emoji for your status message" : "Biểu tượng cảm xúc cho thông báo trạng thái của bạn", "What is your status?" : "Trạng thái của bạn là gì?", - "Set status" : "Đặt trạng thái", + "Predefined statuses" : "Trạng thái được xác định trước", + "Previously set" : "Đã đặt trước đó", + "Reset status" : "Thiết lập trạng thái", + "Reset status to \"{icon} {message}\"" : "Đặt lại trạng thái thành \"{icon} {message}\"", + "Reset status to \"{message}\"" : "Đặt lại trạng thái thành \"{message}\"", + "Reset status to \"{icon}\"" : "Đặt lại trạng thái thành \"{icon}\"", + "There was an error saving the status" : "Đã xảy ra lỗi khi lưu trạng thái", + "There was an error clearing the status" : "Đã xảy ra lỗi khi xóa trạng thái", + "There was an error reverting the status" : "Đã xảy ra lỗi khi hoàn nguyên trạng thái", "Online status" : "Trạng thái trực tuyến", "Status message" : "Thông báo trạng thái", + "Your status was set automatically" : "Trạng thái của bạn đã được đặt tự động", "Clear status message" : "Xoá thông báo trạng thái", "Set status message" : "Đặt thông báo trạng thái", - "Away" : "Tạm vắng", - "Do not disturb" : "Đừng làm phiền", "Don't clear" : "Không xoá", "Today" : "Hôm nay", "This week" : "Tuần này", "Online" : "Trực tuyến", + "Away" : "Tạm vắng", + "Do not disturb" : "Đừng làm phiền", "Invisible" : "Vô hình", + "Offline" : "Ngoại tuyến", + "Set status" : "Đặt trạng thái", + "There was an error saving the new status" : "Đã xảy ra lỗi khi lưu trạng thái mới", "30 minutes" : "30 phút", "1 hour" : "1 tiếng", "4 hours" : "4 tiếng", - "What's your status?" : "Trạng thái của bạn là gì?" + "Busy" : "Bận", + "Mute all notifications" : "Tắt tiếng tất cả thông báo", + "Appear offline" : "Đang offline" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/zh_CN.js b/apps/user_status/l10n/zh_CN.js index d37d0687b89..c36ad38c713 100644 --- a/apps/user_status/l10n/zh_CN.js +++ b/apps/user_status/l10n/zh_CN.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "最近状态", + "No recent status changes" : "最近状态没有改变", "In a meeting" : "开会中", "Commuting" : "通勤中", "Out sick" : "生病了", "Vacationing" : "度假中", + "Out of office" : "不在办公室", "Working remotely" : "远程办公中", "In a call" : "通话中", + "Be right back" : "马上回来", "User status" : "用户状态", - "View profile" : "查看个人资料", - "Clear status message after" : "清除状态信息", - "What is your status?" : "你什么状态?", - "Set status" : "设定状态", - "Online status" : "在线状态", - "Status message" : "状态信息", - "Clear status message" : "清除状态信息", - "Set status message" : "设定状态信息", + "Clear status after" : "清除状态于", + "Emoji for your status message" : "状态消息的表情符号", + "What is your status?" : "您的状态如何?", + "Predefined statuses" : "预定义状态", + "Previously set" : "先前设置", + "Reset status" : "重置状态", + "Reset status to \"{icon} {message}\"" : "将状态重置为“{icon} {message}”", + "Reset status to \"{message}\"" : "将状态重置为“{message}”", + "Reset status to \"{icon}\"" : "将状态重置为“{icon}”", "There was an error saving the status" : "保存状态时出错", "There was an error clearing the status" : "清除状态时出错", - "No recent status changes" : "最近状态没有改变", - "Away" : "离开", - "Do not disturb" : "请勿打扰", - "{status}, {timestamp}" : "{status}, {timestamp}", + "There was an error reverting the status" : "恢复状态时出错", + "Online status" : "在线状态", + "Status message" : "状态消息", + "Set absence period" : "设置缺勤时段", + "Set absence period and replacement" : "设置缺勤时段和接替者", + "Your status was set automatically" : "您的状态已自动设置", + "Clear status message" : "清除状态消息", + "Set status message" : "设置状态消息", "Don't clear" : "不要清除", "Today" : "今天", "This week" : "本周", "Online" : "在线", - "Invisible" : "不可见", + "Away" : "离开", + "Do not disturb" : "勿扰", + "Invisible" : "隐身", "Offline" : "离线", + "Set status" : "设置状态", "There was an error saving the new status" : "保存新状态时出错", "30 minutes" : "30 分钟", "1 hour" : "1 小时", "4 hours" : "4 小时", + "Busy" : "忙碌", "Mute all notifications" : "静音所有通知", - "Appear offline" : "显示为离线", - "What's your status?" : "您现在是什么状态?" + "Appear offline" : "显示为离线" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/zh_CN.json b/apps/user_status/l10n/zh_CN.json index 1eb70482ecc..8546482d238 100644 --- a/apps/user_status/l10n/zh_CN.json +++ b/apps/user_status/l10n/zh_CN.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "最近状态", + "No recent status changes" : "最近状态没有改变", "In a meeting" : "开会中", "Commuting" : "通勤中", "Out sick" : "生病了", "Vacationing" : "度假中", + "Out of office" : "不在办公室", "Working remotely" : "远程办公中", "In a call" : "通话中", + "Be right back" : "马上回来", "User status" : "用户状态", - "View profile" : "查看个人资料", - "Clear status message after" : "清除状态信息", - "What is your status?" : "你什么状态?", - "Set status" : "设定状态", - "Online status" : "在线状态", - "Status message" : "状态信息", - "Clear status message" : "清除状态信息", - "Set status message" : "设定状态信息", + "Clear status after" : "清除状态于", + "Emoji for your status message" : "状态消息的表情符号", + "What is your status?" : "您的状态如何?", + "Predefined statuses" : "预定义状态", + "Previously set" : "先前设置", + "Reset status" : "重置状态", + "Reset status to \"{icon} {message}\"" : "将状态重置为“{icon} {message}”", + "Reset status to \"{message}\"" : "将状态重置为“{message}”", + "Reset status to \"{icon}\"" : "将状态重置为“{icon}”", "There was an error saving the status" : "保存状态时出错", "There was an error clearing the status" : "清除状态时出错", - "No recent status changes" : "最近状态没有改变", - "Away" : "离开", - "Do not disturb" : "请勿打扰", - "{status}, {timestamp}" : "{status}, {timestamp}", + "There was an error reverting the status" : "恢复状态时出错", + "Online status" : "在线状态", + "Status message" : "状态消息", + "Set absence period" : "设置缺勤时段", + "Set absence period and replacement" : "设置缺勤时段和接替者", + "Your status was set automatically" : "您的状态已自动设置", + "Clear status message" : "清除状态消息", + "Set status message" : "设置状态消息", "Don't clear" : "不要清除", "Today" : "今天", "This week" : "本周", "Online" : "在线", - "Invisible" : "不可见", + "Away" : "离开", + "Do not disturb" : "勿扰", + "Invisible" : "隐身", "Offline" : "离线", + "Set status" : "设置状态", "There was an error saving the new status" : "保存新状态时出错", "30 minutes" : "30 分钟", "1 hour" : "1 小时", "4 hours" : "4 小时", + "Busy" : "忙碌", "Mute all notifications" : "静音所有通知", - "Appear offline" : "显示为离线", - "What's your status?" : "您现在是什么状态?" + "Appear offline" : "显示为离线" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/zh_HK.js b/apps/user_status/l10n/zh_HK.js index c6c385c93d3..66fcd087abe 100644 --- a/apps/user_status/l10n/zh_HK.js +++ b/apps/user_status/l10n/zh_HK.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "最近的狀態", + "No recent status changes" : "最近沒有狀態變更", "In a meeting" : "會議中", "Commuting" : "通勤中", "Out sick" : "生病了 ", "Vacationing" : "休假中", + "Out of office" : "不在辦公室", "Working remotely" : "遠程工作中", "In a call" : "通話中", + "Be right back" : "馬上回來", "User status" : "用戶狀態", - "View profile" : "查看個人資料", - "Clear status message after" : "繼此之後清空狀態訊息", + "Clear status after" : "繼此之後清空狀態", + "Emoji for your status message" : "狀態訊息的表情符號", "What is your status?" : "您目前的狀態是什麼呢?", - "Set status" : "設定狀態", + "Predefined statuses" : "預先定義的狀態", + "Previously set" : "先前設定", + "Reset status" : "重設狀態", + "Reset status to \"{icon} {message}\"" : "將狀態重置為 “{icon} {message}”", + "Reset status to \"{message}\"" : "將狀態重置為“{message}”", + "Reset status to \"{icon}\"" : "將狀態重置為“{icon}”", + "There was an error saving the status" : "儲存狀態時發生錯誤", + "There was an error clearing the status" : "變更狀態時發生錯誤", + "There was an error reverting the status" : "恢復狀態時出錯", "Online status" : "線上狀態", "Status message" : "狀態訊息", + "Set absence period" : "設定缺席時間", + "Set absence period and replacement" : "設定缺席時間與職務代理人", + "Your status was set automatically" : "您的狀態是自動設置的", "Clear status message" : "清空狀態訊息", "Set status message" : "設定狀態訊息", - "There was an error saving the status" : "儲存狀態時發生錯誤", - "There was an error clearing the status" : "變更狀態時發生錯誤", - "No recent status changes" : "最近沒有狀態變更", - "Away" : "離開", - "Do not disturb" : "請勿打擾", - "{status}, {timestamp}" : "{status},{timestamp}", "Don't clear" : "不要清空", "Today" : "今日", "This week" : "本星期", "Online" : "在線", + "Away" : "離開", + "Do not disturb" : "請勿打擾", "Invisible" : "隱藏", "Offline" : "離線", + "Set status" : "設定狀態", "There was an error saving the new status" : "儲存新狀態時發生錯誤", "30 minutes" : "30分鐘", "1 hour" : "1 小時", "4 hours" : "4 小時", + "Busy" : "忙碌", "Mute all notifications" : "靜音所有通知", - "Appear offline" : "顯示為離線", - "What's your status?" : "你目前的狀態?" + "Appear offline" : "顯示為離線" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/zh_HK.json b/apps/user_status/l10n/zh_HK.json index f9aaaa1f6ea..a95da1fa45c 100644 --- a/apps/user_status/l10n/zh_HK.json +++ b/apps/user_status/l10n/zh_HK.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "最近的狀態", + "No recent status changes" : "最近沒有狀態變更", "In a meeting" : "會議中", "Commuting" : "通勤中", "Out sick" : "生病了 ", "Vacationing" : "休假中", + "Out of office" : "不在辦公室", "Working remotely" : "遠程工作中", "In a call" : "通話中", + "Be right back" : "馬上回來", "User status" : "用戶狀態", - "View profile" : "查看個人資料", - "Clear status message after" : "繼此之後清空狀態訊息", + "Clear status after" : "繼此之後清空狀態", + "Emoji for your status message" : "狀態訊息的表情符號", "What is your status?" : "您目前的狀態是什麼呢?", - "Set status" : "設定狀態", + "Predefined statuses" : "預先定義的狀態", + "Previously set" : "先前設定", + "Reset status" : "重設狀態", + "Reset status to \"{icon} {message}\"" : "將狀態重置為 “{icon} {message}”", + "Reset status to \"{message}\"" : "將狀態重置為“{message}”", + "Reset status to \"{icon}\"" : "將狀態重置為“{icon}”", + "There was an error saving the status" : "儲存狀態時發生錯誤", + "There was an error clearing the status" : "變更狀態時發生錯誤", + "There was an error reverting the status" : "恢復狀態時出錯", "Online status" : "線上狀態", "Status message" : "狀態訊息", + "Set absence period" : "設定缺席時間", + "Set absence period and replacement" : "設定缺席時間與職務代理人", + "Your status was set automatically" : "您的狀態是自動設置的", "Clear status message" : "清空狀態訊息", "Set status message" : "設定狀態訊息", - "There was an error saving the status" : "儲存狀態時發生錯誤", - "There was an error clearing the status" : "變更狀態時發生錯誤", - "No recent status changes" : "最近沒有狀態變更", - "Away" : "離開", - "Do not disturb" : "請勿打擾", - "{status}, {timestamp}" : "{status},{timestamp}", "Don't clear" : "不要清空", "Today" : "今日", "This week" : "本星期", "Online" : "在線", + "Away" : "離開", + "Do not disturb" : "請勿打擾", "Invisible" : "隱藏", "Offline" : "離線", + "Set status" : "設定狀態", "There was an error saving the new status" : "儲存新狀態時發生錯誤", "30 minutes" : "30分鐘", "1 hour" : "1 小時", "4 hours" : "4 小時", + "Busy" : "忙碌", "Mute all notifications" : "靜音所有通知", - "Appear offline" : "顯示為離線", - "What's your status?" : "你目前的狀態?" + "Appear offline" : "顯示為離線" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/l10n/zh_TW.js b/apps/user_status/l10n/zh_TW.js index 2b8bb4b6c15..c4cd18345a5 100644 --- a/apps/user_status/l10n/zh_TW.js +++ b/apps/user_status/l10n/zh_TW.js @@ -2,39 +2,50 @@ OC.L10N.register( "user_status", { "Recent statuses" : "最近的狀態", + "No recent status changes" : "最近沒有狀態變更", "In a meeting" : "會議中", "Commuting" : "通勤中", - "Out sick" : "生病", - "Vacationing" : "休假", - "Working remotely" : "遠地工作", + "Out sick" : "病假", + "Vacationing" : "休假中", + "Out of office" : "不在辦公室", + "Working remotely" : "遠端工作", "In a call" : "通話中", + "Be right back" : "馬上回來", "User status" : "使用者狀態", - "View profile" : "檢視個人檔案", - "Clear status message after" : "清空狀態訊息於……之後", + "Clear status after" : "多久後清除狀態", + "Emoji for your status message" : "狀態訊息的表情符號", "What is your status?" : "您目前的狀態是什麼呢?", - "Set status" : "設定狀態", + "Predefined statuses" : "預先定義的狀態", + "Previously set" : "先前設定", + "Reset status" : "重設狀態", + "Reset status to \"{icon} {message}\"" : "重設狀態為「{icon} {message}」", + "Reset status to \"{message}\"" : "重設狀態為「{message}」", + "Reset status to \"{icon}\"" : "重設狀態為「{icon}」", + "There was an error saving the status" : "儲存狀態時發生錯誤", + "There was an error clearing the status" : "變更狀態時發生錯誤", + "There was an error reverting the status" : "還原狀態時發生錯誤", "Online status" : "線上狀態", "Status message" : "狀態訊息", - "Clear status message" : "清空狀態訊息", + "Set absence period" : "設定缺席時間", + "Set absence period and replacement" : "設定缺席時間與職務代理人", + "Your status was set automatically" : "您的狀態為自動設定", + "Clear status message" : "清除狀態訊息", "Set status message" : "設定狀態訊息", - "There was an error saving the status" : "儲存狀態時發生錯誤", - "There was an error clearing the status" : "變更狀態時發生錯誤", - "No recent status changes" : "最近沒有狀態變更", - "Away" : "外出", - "Do not disturb" : "請勿打擾", - "{status}, {timestamp}" : "{status},{timestamp}", - "Don't clear" : "不要清空", + "Don't clear" : "不要清除", "Today" : "今天", "This week" : "本週", "Online" : "上線", + "Away" : "離開", + "Do not disturb" : "請勿打擾", "Invisible" : "隱藏", "Offline" : "離線", + "Set status" : "設定狀態", "There was an error saving the new status" : "儲存新狀態時發生錯誤", - "30 minutes" : "30分鐘", - "1 hour" : "1小時", - "4 hours" : "4小時", - "Mute all notifications" : "所有通知靜音", - "Appear offline" : "顯示為離線", - "What's your status?" : "您現在的狀態?" + "30 minutes" : "30 分鐘", + "1 hour" : "1 小時", + "4 hours" : "4 小時", + "Busy" : "忙碌", + "Mute all notifications" : "靜音所有通知", + "Appear offline" : "顯示為離線" }, "nplurals=1; plural=0;"); diff --git a/apps/user_status/l10n/zh_TW.json b/apps/user_status/l10n/zh_TW.json index 7990e9b54e3..9e99204b682 100644 --- a/apps/user_status/l10n/zh_TW.json +++ b/apps/user_status/l10n/zh_TW.json @@ -1,38 +1,49 @@ { "translations": { "Recent statuses" : "最近的狀態", + "No recent status changes" : "最近沒有狀態變更", "In a meeting" : "會議中", "Commuting" : "通勤中", - "Out sick" : "生病", - "Vacationing" : "休假", - "Working remotely" : "遠地工作", + "Out sick" : "病假", + "Vacationing" : "休假中", + "Out of office" : "不在辦公室", + "Working remotely" : "遠端工作", "In a call" : "通話中", + "Be right back" : "馬上回來", "User status" : "使用者狀態", - "View profile" : "檢視個人檔案", - "Clear status message after" : "清空狀態訊息於……之後", + "Clear status after" : "多久後清除狀態", + "Emoji for your status message" : "狀態訊息的表情符號", "What is your status?" : "您目前的狀態是什麼呢?", - "Set status" : "設定狀態", + "Predefined statuses" : "預先定義的狀態", + "Previously set" : "先前設定", + "Reset status" : "重設狀態", + "Reset status to \"{icon} {message}\"" : "重設狀態為「{icon} {message}」", + "Reset status to \"{message}\"" : "重設狀態為「{message}」", + "Reset status to \"{icon}\"" : "重設狀態為「{icon}」", + "There was an error saving the status" : "儲存狀態時發生錯誤", + "There was an error clearing the status" : "變更狀態時發生錯誤", + "There was an error reverting the status" : "還原狀態時發生錯誤", "Online status" : "線上狀態", "Status message" : "狀態訊息", - "Clear status message" : "清空狀態訊息", + "Set absence period" : "設定缺席時間", + "Set absence period and replacement" : "設定缺席時間與職務代理人", + "Your status was set automatically" : "您的狀態為自動設定", + "Clear status message" : "清除狀態訊息", "Set status message" : "設定狀態訊息", - "There was an error saving the status" : "儲存狀態時發生錯誤", - "There was an error clearing the status" : "變更狀態時發生錯誤", - "No recent status changes" : "最近沒有狀態變更", - "Away" : "外出", - "Do not disturb" : "請勿打擾", - "{status}, {timestamp}" : "{status},{timestamp}", - "Don't clear" : "不要清空", + "Don't clear" : "不要清除", "Today" : "今天", "This week" : "本週", "Online" : "上線", + "Away" : "離開", + "Do not disturb" : "請勿打擾", "Invisible" : "隱藏", "Offline" : "離線", + "Set status" : "設定狀態", "There was an error saving the new status" : "儲存新狀態時發生錯誤", - "30 minutes" : "30分鐘", - "1 hour" : "1小時", - "4 hours" : "4小時", - "Mute all notifications" : "所有通知靜音", - "Appear offline" : "顯示為離線", - "What's your status?" : "您現在的狀態?" + "30 minutes" : "30 分鐘", + "1 hour" : "1 小時", + "4 hours" : "4 小時", + "Busy" : "忙碌", + "Mute all notifications" : "靜音所有通知", + "Appear offline" : "顯示為離線" },"pluralForm" :"nplurals=1; plural=0;" }
\ No newline at end of file diff --git a/apps/user_status/lib/AppInfo/Application.php b/apps/user_status/lib/AppInfo/Application.php index 7a47fc45c95..5199c3fdbf0 100644 --- a/apps/user_status/lib/AppInfo/Application.php +++ b/apps/user_status/lib/AppInfo/Application.php @@ -3,40 +3,29 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\AppInfo; use OCA\UserStatus\Capabilities; use OCA\UserStatus\Connector\UserStatusProvider; +use OCA\UserStatus\Dashboard\UserStatusWidget; use OCA\UserStatus\Listener\BeforeTemplateRenderedListener; +use OCA\UserStatus\Listener\OutOfOfficeStatusListener; use OCA\UserStatus\Listener\UserDeletedListener; use OCA\UserStatus\Listener\UserLiveStatusListener; -use OCA\UserStatus\Dashboard\UserStatusWidget; use OCP\AppFramework\App; use OCP\AppFramework\Bootstrap\IBootContext; use OCP\AppFramework\Bootstrap\IBootstrap; use OCP\AppFramework\Bootstrap\IRegistrationContext; use OCP\AppFramework\Http\Events\BeforeTemplateRenderedEvent; use OCP\IConfig; +use OCP\User\Events\OutOfOfficeChangedEvent; +use OCP\User\Events\OutOfOfficeClearedEvent; +use OCP\User\Events\OutOfOfficeEndedEvent; +use OCP\User\Events\OutOfOfficeScheduledEvent; +use OCP\User\Events\OutOfOfficeStartedEvent; use OCP\User\Events\UserDeletedEvent; use OCP\User\Events\UserLiveStatusEvent; use OCP\UserStatus\IManager; @@ -71,6 +60,11 @@ class Application extends App implements IBootstrap { $context->registerEventListener(UserDeletedEvent::class, UserDeletedListener::class); $context->registerEventListener(UserLiveStatusEvent::class, UserLiveStatusListener::class); $context->registerEventListener(BeforeTemplateRenderedEvent::class, BeforeTemplateRenderedListener::class); + $context->registerEventListener(OutOfOfficeChangedEvent::class, OutOfOfficeStatusListener::class); + $context->registerEventListener(OutOfOfficeScheduledEvent::class, OutOfOfficeStatusListener::class); + $context->registerEventListener(OutOfOfficeClearedEvent::class, OutOfOfficeStatusListener::class); + $context->registerEventListener(OutOfOfficeStartedEvent::class, OutOfOfficeStatusListener::class); + $context->registerEventListener(OutOfOfficeEndedEvent::class, OutOfOfficeStatusListener::class); $config = $this->getContainer()->query(IConfig::class); $shareeEnumeration = $config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; diff --git a/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php b/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php index 0d8f5ac431b..51a9c623a03 100644 --- a/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php +++ b/apps/user_status/lib/BackgroundJob/ClearOldStatusesBackgroundJob.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\BackgroundJob; @@ -37,21 +20,18 @@ use OCP\BackgroundJob\TimedJob; */ class ClearOldStatusesBackgroundJob extends TimedJob { - /** @var UserStatusMapper */ - private $mapper; - /** * ClearOldStatusesBackgroundJob constructor. * * @param ITimeFactory $time * @param UserStatusMapper $mapper */ - public function __construct(ITimeFactory $time, - UserStatusMapper $mapper) { + public function __construct( + ITimeFactory $time, + private UserStatusMapper $mapper, + ) { parent::__construct($time); - $this->mapper = $mapper; - // Run every time the cron is run $this->setInterval(60); } @@ -61,7 +41,7 @@ class ClearOldStatusesBackgroundJob extends TimedJob { protected function run($argument) { $now = $this->time->getTime(); - $this->mapper->clearMessagesOlderThan($now); + $this->mapper->clearOlderThanClearAt($now); $this->mapper->clearStatusesOlderThan($now - StatusService::INVALIDATE_STATUS_THRESHOLD, $now); } } diff --git a/apps/user_status/lib/Capabilities.php b/apps/user_status/lib/Capabilities.php index f5b35896a56..c3edbc032d6 100644 --- a/apps/user_status/lib/Capabilities.php +++ b/apps/user_status/lib/Capabilities.php @@ -3,30 +3,13 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus; -use OCA\UserStatus\Service\EmojiService; use OCP\Capabilities\ICapability; +use OCP\IEmojiHelper; /** * Class Capabilities @@ -34,27 +17,21 @@ use OCP\Capabilities\ICapability; * @package OCA\UserStatus */ class Capabilities implements ICapability { - - /** @var EmojiService */ - private $emojiService; - - /** - * Capabilities constructor. - * - * @param EmojiService $emojiService - */ - public function __construct(EmojiService $emojiService) { - $this->emojiService = $emojiService; + public function __construct( + private IEmojiHelper $emojiHelper, + ) { } /** - * @inheritDoc + * @return array{user_status: array{enabled: bool, restore: bool, supports_emoji: bool, supports_busy: bool}} */ public function getCapabilities() { return [ 'user_status' => [ 'enabled' => true, - 'supports_emoji' => $this->emojiService->doesPlatformSupportEmoji(), + 'restore' => true, + 'supports_emoji' => $this->emojiHelper->doesPlatformSupportEmoji(), + 'supports_busy' => true, ], ]; } diff --git a/apps/user_status/lib/Connector/UserStatus.php b/apps/user_status/lib/Connector/UserStatus.php index ff05ded9e2b..04467a99e5e 100644 --- a/apps/user_status/lib/Connector/UserStatus.php +++ b/apps/user_status/lib/Connector/UserStatus.php @@ -3,31 +3,14 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Connector; use DateTimeImmutable; -use OCP\UserStatus\IUserStatus; use OCA\UserStatus\Db; +use OCP\UserStatus\IUserStatus; class UserStatus implements IUserStatus { @@ -46,21 +29,19 @@ class UserStatus implements IUserStatus { /** @var DateTimeImmutable|null */ private $clearAt; - /** @var Db\UserStatus */ - private $internalStatus; - - public function __construct(Db\UserStatus $status) { - $this->internalStatus = $status; - $this->userId = $status->getUserId(); - $this->status = $status->getStatus(); - $this->message = $status->getCustomMessage(); - $this->icon = $status->getCustomIcon(); + public function __construct( + private Db\UserStatus $internalStatus, + ) { + $this->userId = $this->internalStatus->getUserId(); + $this->status = $this->internalStatus->getStatus(); + $this->message = $this->internalStatus->getCustomMessage(); + $this->icon = $this->internalStatus->getCustomIcon(); - if ($status->getStatus() === IUserStatus::INVISIBLE) { + if ($this->internalStatus->getStatus() === IUserStatus::INVISIBLE) { $this->status = IUserStatus::OFFLINE; } - if ($status->getClearAt() !== null) { - $this->clearAt = DateTimeImmutable::createFromFormat('U', (string)$status->getClearAt()); + if ($this->internalStatus->getClearAt() !== null) { + $this->clearAt = DateTimeImmutable::createFromFormat('U', (string)$this->internalStatus->getClearAt()); } } diff --git a/apps/user_status/lib/Connector/UserStatusProvider.php b/apps/user_status/lib/Connector/UserStatusProvider.php index 46b89739f7c..e84d69d1eb2 100644 --- a/apps/user_status/lib/Connector/UserStatusProvider.php +++ b/apps/user_status/lib/Connector/UserStatusProvider.php @@ -3,44 +3,25 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Connector; +use OC\UserStatus\ISettableProvider; use OCA\UserStatus\Service\StatusService; use OCP\UserStatus\IProvider; -use OC\UserStatus\ISettableProvider; class UserStatusProvider implements IProvider, ISettableProvider { - /** @var StatusService */ - private $service; - /** * UserStatusProvider constructor. * * @param StatusService $service */ - public function __construct(StatusService $service) { - $this->service = $service; + public function __construct( + private StatusService $service, + ) { } /** @@ -57,15 +38,15 @@ class UserStatusProvider implements IProvider, ISettableProvider { return $userStatuses; } - public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup): void { - $this->service->setUserStatus($userId, $status, $messageId, $createBackup); + public function setUserStatus(string $userId, string $messageId, string $status, bool $createBackup, ?string $customMessage = null): void { + $this->service->setUserStatus($userId, $status, $messageId, $createBackup, $customMessage); } public function revertUserStatus(string $userId, string $messageId, string $status): void { - $this->service->revertUserStatus($userId, $messageId, $status); + $this->service->revertUserStatus($userId, $messageId); } public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void { - $this->service->revertMultipleUserStatus($userIds, $messageId, $status); + $this->service->revertMultipleUserStatus($userIds, $messageId); } } diff --git a/apps/user_status/lib/ContactsMenu/StatusProvider.php b/apps/user_status/lib/ContactsMenu/StatusProvider.php new file mode 100644 index 00000000000..6a6949b46ba --- /dev/null +++ b/apps/user_status/lib/ContactsMenu/StatusProvider.php @@ -0,0 +1,53 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\UserStatus\ContactsMenu; + +use OCA\UserStatus\Db\UserStatus; +use OCA\UserStatus\Service\StatusService; +use OCP\Contacts\ContactsMenu\IBulkProvider; +use OCP\Contacts\ContactsMenu\IEntry; +use function array_combine; +use function array_filter; +use function array_map; + +class StatusProvider implements IBulkProvider { + + public function __construct( + private StatusService $statusService, + ) { + } + + public function process(array $entries): void { + $uids = array_filter( + array_map(fn (IEntry $entry): ?string => $entry->getProperty('UID'), $entries) + ); + + $statuses = $this->statusService->findByUserIds($uids); + /** @var array<string, UserStatus> $indexed */ + $indexed = array_combine( + array_map(fn (UserStatus $status) => $status->getUserId(), $statuses), + $statuses + ); + + foreach ($entries as $entry) { + $uid = $entry->getProperty('UID'); + if ($uid !== null && isset($indexed[$uid])) { + $status = $indexed[$uid]; + $entry->setStatus( + $status->getStatus(), + $status->getCustomMessage(), + $status->getStatusMessageTimestamp(), + $status->getCustomIcon(), + ); + } + } + } + +} diff --git a/apps/user_status/lib/Controller/HeartbeatController.php b/apps/user_status/lib/Controller/HeartbeatController.php index c11a63b4420..30f4af6572a 100644 --- a/apps/user_status/lib/Controller/HeartbeatController.php +++ b/apps/user_status/lib/Controller/HeartbeatController.php @@ -3,34 +3,19 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Controller; use OCA\UserStatus\Db\UserStatus; +use OCA\UserStatus\ResponseDefinitions; use OCA\UserStatus\Service\StatusService; -use OCP\AppFramework\Controller; -use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Http; -use OCP\AppFramework\Http\JSONResponse; +use OCP\AppFramework\Http\Attribute\ApiRoute; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; +use OCP\AppFramework\Http\DataResponse; +use OCP\AppFramework\OCSController; use OCP\AppFramework\Utility\ITimeFactory; use OCP\EventDispatcher\IEventDispatcher; use OCP\IRequest; @@ -38,47 +23,43 @@ use OCP\IUserSession; use OCP\User\Events\UserLiveStatusEvent; use OCP\UserStatus\IUserStatus; -class HeartbeatController extends Controller { - - /** @var IEventDispatcher */ - private $eventDispatcher; - - /** @var IUserSession */ - private $userSession; - - /** @var ITimeFactory */ - private $timeFactory; - - /** @var StatusService */ - private $service; - - public function __construct(string $appName, - IRequest $request, - IEventDispatcher $eventDispatcher, - IUserSession $userSession, - ITimeFactory $timeFactory, - StatusService $service) { +/** + * @psalm-import-type UserStatusPrivate from ResponseDefinitions + */ +class HeartbeatController extends OCSController { + + public function __construct( + string $appName, + IRequest $request, + private IEventDispatcher $eventDispatcher, + private IUserSession $userSession, + private ITimeFactory $timeFactory, + private StatusService $service, + ) { parent::__construct($appName, $request); - $this->eventDispatcher = $eventDispatcher; - $this->userSession = $userSession; - $this->timeFactory = $timeFactory; - $this->service = $service; } /** - * @NoAdminRequired + * Keep the status alive + * + * @param string $status Only online, away + * + * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}>|DataResponse<Http::STATUS_BAD_REQUEST|Http::STATUS_INTERNAL_SERVER_ERROR|Http::STATUS_NO_CONTENT, list<empty>, array{}> * - * @param string $status - * @return JSONResponse + * 200: Status successfully updated + * 204: User has no status to keep alive + * 400: Invalid status to update */ - public function heartbeat(string $status): JSONResponse { + #[NoAdminRequired] + #[ApiRoute(verb: 'PUT', url: '/api/v1/heartbeat')] + public function heartbeat(string $status): DataResponse { if (!\in_array($status, [IUserStatus::ONLINE, IUserStatus::AWAY], true)) { - return new JSONResponse([], Http::STATUS_BAD_REQUEST); + return new DataResponse([], Http::STATUS_BAD_REQUEST); } $user = $this->userSession->getUser(); if ($user === null) { - return new JSONResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); + return new DataResponse([], Http::STATUS_INTERNAL_SERVER_ERROR); } $event = new UserLiveStatusEvent( @@ -91,11 +72,11 @@ class HeartbeatController extends Controller { $userStatus = $event->getUserStatus(); if (!$userStatus) { - return new JSONResponse([], Http::STATUS_NO_CONTENT); + return new DataResponse([], Http::STATUS_NO_CONTENT); } /** @psalm-suppress UndefinedInterfaceMethod */ - return new JSONResponse($this->formatStatus($userStatus->getInternal())); + return new DataResponse($this->formatStatus($userStatus->getInternal())); } private function formatStatus(UserStatus $status): array { diff --git a/apps/user_status/lib/Controller/PredefinedStatusController.php b/apps/user_status/lib/Controller/PredefinedStatusController.php index ea1ff5209b8..70262d1108a 100644 --- a/apps/user_status/lib/Controller/PredefinedStatusController.php +++ b/apps/user_status/lib/Controller/PredefinedStatusController.php @@ -3,43 +3,27 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Controller; +use OCA\UserStatus\ResponseDefinitions; use OCA\UserStatus\Service\PredefinedStatusService; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCSController; use OCP\IRequest; /** - * Class DefaultStatusController - * * @package OCA\UserStatus\Controller + * + * @psalm-import-type UserStatusPredefined from ResponseDefinitions */ class PredefinedStatusController extends OCSController { - /** @var PredefinedStatusService */ - private $predefinedStatusService; - /** * AStatusController constructor. * @@ -47,22 +31,27 @@ class PredefinedStatusController extends OCSController { * @param IRequest $request * @param PredefinedStatusService $predefinedStatusService */ - public function __construct(string $appName, - IRequest $request, - PredefinedStatusService $predefinedStatusService) { + public function __construct( + string $appName, + IRequest $request, + private PredefinedStatusService $predefinedStatusService, + ) { parent::__construct($appName, $request); - $this->predefinedStatusService = $predefinedStatusService; } /** - * @NoAdminRequired + * Get all predefined messages + * + * @return DataResponse<Http::STATUS_OK, list<UserStatusPredefined>, array{}> * - * @return DataResponse + * 200: Predefined statuses returned */ + #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/v1/predefined_statuses/')] public function findAll():DataResponse { // Filtering out the invisible one, that should only be set by API - return new DataResponse(array_filter($this->predefinedStatusService->getDefaultStatuses(), function (array $status) { + return new DataResponse(array_values(array_filter($this->predefinedStatusService->getDefaultStatuses(), function (array $status) { return !array_key_exists('visible', $status) || $status['visible'] === true; - })); + }))); } } diff --git a/apps/user_status/lib/Controller/StatusesController.php b/apps/user_status/lib/Controller/StatusesController.php index d30389e1716..44688c39023 100644 --- a/apps/user_status/lib/Controller/StatusesController.php +++ b/apps/user_status/lib/Controller/StatusesController.php @@ -3,43 +3,30 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Controller; use OCA\UserStatus\Db\UserStatus; +use OCA\UserStatus\ResponseDefinitions; use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\AppFramework\OCSController; use OCP\IRequest; use OCP\UserStatus\IUserStatus; +/** + * @psalm-import-type UserStatusType from ResponseDefinitions + * @psalm-import-type UserStatusPublic from ResponseDefinitions + */ class StatusesController extends OCSController { - /** @var StatusService */ - private $service; - /** * StatusesController constructor. * @@ -47,35 +34,44 @@ class StatusesController extends OCSController { * @param IRequest $request * @param StatusService $service */ - public function __construct(string $appName, - IRequest $request, - StatusService $service) { + public function __construct( + string $appName, + IRequest $request, + private StatusService $service, + ) { parent::__construct($appName, $request); - $this->service = $service; } /** - * @NoAdminRequired + * Find statuses of users * - * @param int|null $limit - * @param int|null $offset - * @return DataResponse + * @param int|null $limit Maximum number of statuses to find + * @param non-negative-int|null $offset Offset for finding statuses + * @return DataResponse<Http::STATUS_OK, list<UserStatusPublic>, array{}> + * + * 200: Statuses returned */ + #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/v1/statuses')] public function findAll(?int $limit = null, ?int $offset = null): DataResponse { $allStatuses = $this->service->findAll($limit, $offset); - return new DataResponse(array_map(function ($userStatus) { + return new DataResponse(array_values(array_map(function ($userStatus) { return $this->formatStatus($userStatus); - }, $allStatuses)); + }, $allStatuses))); } /** - * @NoAdminRequired + * Find the status of a user + * + * @param string $userId ID of the user + * @return DataResponse<Http::STATUS_OK, UserStatusPublic, array{}> + * @throws OCSNotFoundException The user was not found * - * @param string $userId - * @return DataResponse - * @throws OCSNotFoundException + * 200: Status returned */ + #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/v1/statuses/{userId}')] public function find(string $userId): DataResponse { try { $userStatus = $this->service->findByUserId($userId); @@ -88,9 +84,10 @@ class StatusesController extends OCSController { /** * @param UserStatus $status - * @return array{userId: string, message: string, icon: string, clearAt: int, status: string} + * @return UserStatusPublic */ private function formatStatus(UserStatus $status): array { + /** @var UserStatusType $visibleStatus */ $visibleStatus = $status->getStatus(); if ($visibleStatus === IUserStatus::INVISIBLE) { $visibleStatus = IUserStatus::OFFLINE; diff --git a/apps/user_status/lib/Controller/UserStatusController.php b/apps/user_status/lib/Controller/UserStatusController.php index 8708a7c2aac..9b3807ce86e 100644 --- a/apps/user_status/lib/Controller/UserStatusController.php +++ b/apps/user_status/lib/Controller/UserStatusController.php @@ -3,84 +3,60 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * @author Simon Spannagel <simonspa@kth.se> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Controller; +use OCA\DAV\CalDAV\Status\StatusService as CalendarStatusService; use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Exception\InvalidClearAtException; use OCA\UserStatus\Exception\InvalidMessageIdException; use OCA\UserStatus\Exception\InvalidStatusIconException; use OCA\UserStatus\Exception\InvalidStatusTypeException; use OCA\UserStatus\Exception\StatusMessageTooLongException; +use OCA\UserStatus\ResponseDefinitions; use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; +use OCP\AppFramework\Http; +use OCP\AppFramework\Http\Attribute\ApiRoute; +use OCP\AppFramework\Http\Attribute\NoAdminRequired; use OCP\AppFramework\Http\DataResponse; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\AppFramework\OCSController; -use OCP\ILogger; use OCP\IRequest; +use Psr\Log\LoggerInterface; +/** + * @psalm-import-type UserStatusType from ResponseDefinitions + * @psalm-import-type UserStatusPrivate from ResponseDefinitions + */ class UserStatusController extends OCSController { - - /** @var string */ - private $userId; - - /** @var ILogger */ - private $logger; - - /** @var StatusService */ - private $service; - - /** - * StatusesController constructor. - * - * @param string $appName - * @param IRequest $request - * @param string $userId - * @param ILogger $logger; - * @param StatusService $service - */ - public function __construct(string $appName, - IRequest $request, - string $userId, - ILogger $logger, - StatusService $service) { + public function __construct( + string $appName, + IRequest $request, + private ?string $userId, + private LoggerInterface $logger, + private StatusService $service, + private CalendarStatusService $calendarStatusService, + ) { parent::__construct($appName, $request); - $this->userId = $userId; - $this->logger = $logger; - $this->service = $service; } /** - * @NoAdminRequired + * Get the status of the current user * - * @return DataResponse - * @throws OCSNotFoundException + * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}> + * @throws OCSNotFoundException The user was not found + * + * 200: The status was found successfully */ + #[NoAdminRequired] + #[ApiRoute(verb: 'GET', url: '/api/v1/user_status')] public function getStatus(): DataResponse { try { + $this->calendarStatusService->processCalendarStatus($this->userId); $userStatus = $this->service->findByUserId($this->userId); } catch (DoesNotExistException $ex) { throw new OCSNotFoundException('No status for the current user'); @@ -90,12 +66,16 @@ class UserStatusController extends OCSController { } /** - * @NoAdminRequired + * Update the status type of the current user + * + * @param string $statusType The new status type + * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}> + * @throws OCSBadRequestException The status type is invalid * - * @param string $statusType - * @return DataResponse - * @throws OCSBadRequestException + * 200: The status was updated successfully */ + #[NoAdminRequired] + #[ApiRoute(verb: 'PUT', url: '/api/v1/user_status/status')] public function setStatus(string $statusType): DataResponse { try { $status = $this->service->setStatus($this->userId, $statusType, null, true); @@ -109,15 +89,19 @@ class UserStatusController extends OCSController { } /** - * @NoAdminRequired + * Set the message to a predefined message for the current user + * + * @param string $messageId ID of the predefined message + * @param int|null $clearAt When the message should be cleared + * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}> + * @throws OCSBadRequestException The clearAt or message-id is invalid * - * @param string $messageId - * @param int|null $clearAt - * @return DataResponse - * @throws OCSBadRequestException + * 200: The message was updated successfully */ + #[NoAdminRequired] + #[ApiRoute(verb: 'PUT', url: '/api/v1/user_status/message/predefined')] public function setPredefinedMessage(string $messageId, - ?int $clearAt): DataResponse { + ?int $clearAt): DataResponse { try { $status = $this->service->setPredefinedMessage($this->userId, $messageId, $clearAt); $this->service->removeBackupUserStatus($this->userId); @@ -132,19 +116,24 @@ class UserStatusController extends OCSController { } /** - * @NoAdminRequired + * Set the message to a custom message for the current user * - * @param string|null $statusIcon - * @param string $message - * @param int|null $clearAt - * @return DataResponse - * @throws OCSBadRequestException + * @param string|null $statusIcon Icon of the status + * @param string|null $message Message of the status + * @param int|null $clearAt When the message should be cleared + * @return DataResponse<Http::STATUS_OK, UserStatusPrivate, array{}> + * @throws OCSBadRequestException The clearAt or icon is invalid or the message is too long + * @throws OCSNotFoundException No status for the current user + * + * 200: The message was updated successfully */ + #[NoAdminRequired] + #[ApiRoute(verb: 'PUT', url: '/api/v1/user_status/message/custom')] public function setCustomMessage(?string $statusIcon, - ?string $message, - ?int $clearAt): DataResponse { + ?string $message, + ?int $clearAt): DataResponse { try { - if ($message !== null && $message !== '') { + if (($statusIcon !== null && $statusIcon !== '') || ($message !== null && $message !== '') || ($clearAt !== null && $clearAt !== 0)) { $status = $this->service->setCustomMessage($this->userId, $statusIcon, $message, $clearAt); } else { $this->service->clearMessage($this->userId); @@ -161,34 +150,51 @@ class UserStatusController extends OCSController { } catch (StatusMessageTooLongException $ex) { $this->logger->debug('New user-status for "' . $this->userId . '" was rejected due to a too long status message.'); throw new OCSBadRequestException($ex->getMessage(), $ex); + } catch (DoesNotExistException $ex) { + throw new OCSNotFoundException('No status for the current user'); } } /** - * @NoAdminRequired + * Clear the message of the current user * - * @return DataResponse + * @return DataResponse<Http::STATUS_OK, list<empty>, array{}> + * + * 200: Message cleared successfully */ - public function clearStatus(): DataResponse { - $this->service->clearStatus($this->userId); + #[NoAdminRequired] + #[ApiRoute(verb: 'DELETE', url: '/api/v1/user_status/message')] + public function clearMessage(): DataResponse { + $this->service->clearMessage($this->userId); return new DataResponse([]); } /** - * @NoAdminRequired + * Revert the status to the previous status * - * @return DataResponse + * @param string $messageId ID of the message to delete + * + * @return DataResponse<Http::STATUS_OK, UserStatusPrivate|list<empty>, array{}> + * + * 200: Status reverted */ - public function clearMessage(): DataResponse { - $this->service->clearMessage($this->userId); + #[NoAdminRequired] + #[ApiRoute(verb: 'DELETE', url: '/api/v1/user_status/revert/{messageId}')] + public function revertStatus(string $messageId): DataResponse { + $backupStatus = $this->service->revertUserStatus($this->userId, $messageId, true); + if ($backupStatus) { + return new DataResponse($this->formatStatus($backupStatus)); + } return new DataResponse([]); } /** * @param UserStatus $status - * @return array + * @return UserStatusPrivate */ private function formatStatus(UserStatus $status): array { + /** @var UserStatusType $visibleStatus */ + $visibleStatus = $status->getStatus(); return [ 'userId' => $status->getUserId(), 'message' => $status->getCustomMessage(), @@ -196,7 +202,7 @@ class UserStatusController extends OCSController { 'messageIsPredefined' => $status->getMessageId() !== null, 'icon' => $status->getCustomIcon(), 'clearAt' => $status->getClearAt(), - 'status' => $status->getStatus(), + 'status' => $visibleStatus, 'statusIsUserDefined' => $status->getIsUserDefined(), ]; } diff --git a/apps/user_status/lib/Dashboard/UserStatusWidget.php b/apps/user_status/lib/Dashboard/UserStatusWidget.php index 10411dc7f9d..2870a2c1907 100644 --- a/apps/user_status/lib/Dashboard/UserStatusWidget.php +++ b/apps/user_status/lib/Dashboard/UserStatusWidget.php @@ -3,34 +3,25 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Dashboard; use OCA\UserStatus\AppInfo\Application; use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Service\StatusService; -use OCP\Dashboard\IWidget; -use OCP\IInitialStateService; +use OCP\AppFramework\Services\IInitialState; +use OCP\Dashboard\IAPIWidget; +use OCP\Dashboard\IAPIWidgetV2; +use OCP\Dashboard\IIconWidget; +use OCP\Dashboard\IOptionWidget; +use OCP\Dashboard\Model\WidgetItem; +use OCP\Dashboard\Model\WidgetItems; +use OCP\Dashboard\Model\WidgetOptions; +use OCP\IDateTimeFormatter; use OCP\IL10N; +use OCP\IURLGenerator; use OCP\IUserManager; use OCP\IUserSession; use OCP\UserStatus\IUserStatus; @@ -40,42 +31,27 @@ use OCP\UserStatus\IUserStatus; * * @package OCA\UserStatus */ -class UserStatusWidget implements IWidget { - - /** @var IL10N */ - private $l10n; - - /** @var IInitialStateService */ - private $initialStateService; - - /** @var IUserManager */ - private $userManager; - - /** @var IUserSession */ - private $userSession; - - /** @var StatusService */ - private $service; - +class UserStatusWidget implements IAPIWidget, IAPIWidgetV2, IIconWidget, IOptionWidget { /** * UserStatusWidget constructor * * @param IL10N $l10n - * @param IInitialStateService $initialStateService + * @param IDateTimeFormatter $dateTimeFormatter + * @param IURLGenerator $urlGenerator + * @param IInitialState $initialStateService * @param IUserManager $userManager * @param IUserSession $userSession * @param StatusService $service */ - public function __construct(IL10N $l10n, - IInitialStateService $initialStateService, - IUserManager $userManager, - IUserSession $userSession, - StatusService $service) { - $this->l10n = $l10n; - $this->initialStateService = $initialStateService; - $this->userManager = $userManager; - $this->userSession = $userSession; - $this->service = $service; + public function __construct( + private IL10N $l10n, + private IDateTimeFormatter $dateTimeFormatter, + private IURLGenerator $urlGenerator, + private IInitialState $initialStateService, + private IUserManager $userManager, + private IUserSession $userSession, + private StatusService $service, + ) { } /** @@ -103,7 +79,16 @@ class UserStatusWidget implements IWidget { * @inheritDoc */ public function getIconClass(): string { - return 'icon-user-status'; + return 'icon-user-status-dark'; + } + + /** + * @inheritDoc + */ + public function getIconUrl(): string { + return $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->imagePath(Application::APP_ID, 'app-dark.svg') + ); } /** @@ -117,28 +102,22 @@ class UserStatusWidget implements IWidget { * @inheritDoc */ public function load(): void { - \OCP\Util::addScript(Application::APP_ID, 'dashboard'); - - $currentUser = $this->userSession->getUser(); - if ($currentUser === null) { - $this->initialStateService->provideInitialState(Application::APP_ID, 'dashboard_data', []); - return; - } - $currentUserId = $currentUser->getUID(); + } + private function getWidgetData(string $userId, ?string $since = null, int $limit = 7): array { // Fetch status updates and filter current user $recentStatusUpdates = array_slice( array_filter( - $this->service->findAllRecentStatusChanges(8, 0), - static function (UserStatus $status) use ($currentUserId): bool { - return $status->getUserId() !== $currentUserId; + $this->service->findAllRecentStatusChanges($limit + 1, 0), + static function (UserStatus $status) use ($userId, $since): bool { + return $status->getUserId() !== $userId + && ($since === null || $status->getStatusTimestamp() > (int)$since); } ), 0, - 7 + $limit ); - - $this->initialStateService->provideInitialState(Application::APP_ID, 'dashboard_data', array_map(function (UserStatus $status): array { + return array_map(function (UserStatus $status): array { $user = $this->userManager->get($status->getUserId()); $displayName = $status->getUserId(); if ($user !== null) { @@ -153,8 +132,46 @@ class UserStatusWidget implements IWidget { : $status->getStatus(), 'icon' => $status->getCustomIcon(), 'message' => $status->getCustomMessage(), - 'timestamp' => $status->getStatusTimestamp(), + 'timestamp' => $status->getStatusMessageTimestamp(), ]; - }, $recentStatusUpdates)); + }, $recentStatusUpdates); + } + + /** + * @inheritDoc + */ + public function getItems(string $userId, ?string $since = null, int $limit = 7): array { + $widgetItemsData = $this->getWidgetData($userId, $since, $limit); + + return array_values(array_map(function (array $widgetData) { + $formattedDate = $this->dateTimeFormatter->formatTimeSpan($widgetData['timestamp']); + return new WidgetItem( + $widgetData['displayName'], + $widgetData['icon'] . ($widgetData['icon'] ? ' ' : '') . $widgetData['message'] . ', ' . $formattedDate, + // https://nextcloud.local/index.php/u/julien + $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->linkToRoute('profile.ProfilePage.index', ['targetUserId' => $widgetData['userId']]) + ), + $this->urlGenerator->getAbsoluteURL( + $this->urlGenerator->linkToRoute('core.avatar.getAvatar', ['userId' => $widgetData['userId'], 'size' => 44]) + ), + (string)$widgetData['timestamp'] + ); + }, $widgetItemsData)); + } + + /** + * @inheritDoc + */ + public function getItemsV2(string $userId, ?string $since = null, int $limit = 7): WidgetItems { + $items = $this->getItems($userId, $since, $limit); + return new WidgetItems( + $items, + count($items) === 0 ? $this->l10n->t('No recent status changes') : '', + ); + } + + public function getWidgetOptions(): WidgetOptions { + return new WidgetOptions(true); } } diff --git a/apps/user_status/lib/Db/UserStatus.php b/apps/user_status/lib/Db/UserStatus.php index 8907c4a2c1b..b2da4a9e07a 100644 --- a/apps/user_status/lib/Db/UserStatus.php +++ b/apps/user_status/lib/Db/UserStatus.php @@ -3,29 +3,13 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Db; use OCP\AppFramework\Db\Entity; +use OCP\DB\Types; /** * Class UserStatus @@ -42,16 +26,18 @@ use OCP\AppFramework\Db\Entity; * @method void setStatusTimestamp(int $statusTimestamp) * @method bool getIsUserDefined() * @method void setIsUserDefined(bool $isUserDefined) - * @method string getMessageId() + * @method string|null getMessageId() * @method void setMessageId(string|null $messageId) - * @method string getCustomIcon() + * @method string|null getCustomIcon() * @method void setCustomIcon(string|null $customIcon) - * @method string getCustomMessage() + * @method string|null getCustomMessage() * @method void setCustomMessage(string|null $customMessage) - * @method int getClearAt() + * @method int|null getClearAt() * @method void setClearAt(int|null $clearAt) - * @method setIsBackup(bool $true): void + * @method setIsBackup(bool $isBackup): void * @method getIsBackup(): bool + * @method int getStatusMessageTimestamp() + * @method void setStatusMessageTimestamp(int $statusTimestamp) */ class UserStatus extends Entity { @@ -82,15 +68,19 @@ class UserStatus extends Entity { /** @var bool $isBackup */ public $isBackup; + /** @var int */ + protected $statusMessageTimestamp = 0; + public function __construct() { $this->addType('userId', 'string'); $this->addType('status', 'string'); - $this->addType('statusTimestamp', 'int'); + $this->addType('statusTimestamp', Types::INTEGER); $this->addType('isUserDefined', 'boolean'); $this->addType('messageId', 'string'); $this->addType('customIcon', 'string'); $this->addType('customMessage', 'string'); - $this->addType('clearAt', 'int'); + $this->addType('clearAt', Types::INTEGER); $this->addType('isBackup', 'boolean'); + $this->addType('statusMessageTimestamp', Types::INTEGER); } } diff --git a/apps/user_status/lib/Db/UserStatusMapper.php b/apps/user_status/lib/Db/UserStatusMapper.php index f67cfcd472d..15982d44fd8 100644 --- a/apps/user_status/lib/Db/UserStatusMapper.php +++ b/apps/user_status/lib/Db/UserStatusMapper.php @@ -3,29 +3,13 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Db; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\QBMapper; use OCP\DB\QueryBuilder\IQueryBuilder; use OCP\IDBConnection; @@ -75,11 +59,17 @@ class UserStatusMapper extends QBMapper { $qb ->select('*') ->from($this->tableName) - ->orderBy('status_timestamp', 'DESC') - ->where($qb->expr()->notIn('status', $qb->createNamedParameter([IUserStatus::ONLINE, IUserStatus::AWAY, IUserStatus::OFFLINE], IQueryBuilder::PARAM_STR_ARRAY))) - ->orWhere($qb->expr()->isNotNull('message_id')) - ->orWhere($qb->expr()->isNotNull('custom_icon')) - ->orWhere($qb->expr()->isNotNull('custom_message')); + ->orderBy('status_message_timestamp', 'DESC') + ->where($qb->expr()->andX( + $qb->expr()->neq('status_message_timestamp', $qb->createNamedParameter(0, IQueryBuilder::PARAM_INT), IQueryBuilder::PARAM_INT), + $qb->expr()->orX( + $qb->expr()->notIn('status', $qb->createNamedParameter([IUserStatus::ONLINE, IUserStatus::AWAY, IUserStatus::OFFLINE], IQueryBuilder::PARAM_STR_ARRAY)), + $qb->expr()->isNotNull('message_id'), + $qb->expr()->isNotNull('custom_icon'), + $qb->expr()->isNotNull('custom_message'), + ), + $qb->expr()->notLike('user_id', $qb->createNamedParameter($this->db->escapeLikeParameter('_') . '%')) + )); if ($limit !== null) { $qb->setMaxResults($limit); @@ -94,9 +84,9 @@ class UserStatusMapper extends QBMapper { /** * @param string $userId * @return UserStatus - * @throws \OCP\AppFramework\Db\DoesNotExistException + * @throws DoesNotExistException */ - public function findByUserId(string $userId, bool $isBackup = false):UserStatus { + public function findByUserId(string $userId, bool $isBackup = false): UserStatus { $qb = $this->db->getQueryBuilder(); $qb ->select('*') @@ -137,7 +127,7 @@ class UserStatusMapper extends QBMapper { $qb->expr()->eq('status', $qb->createNamedParameter(IUserStatus::ONLINE)) )); - $qb->execute(); + $qb->executeStatement(); } /** @@ -145,17 +135,13 @@ class UserStatusMapper extends QBMapper { * * @param int $timestamp */ - public function clearMessagesOlderThan(int $timestamp): void { + public function clearOlderThanClearAt(int $timestamp): void { $qb = $this->db->getQueryBuilder(); - $qb->update($this->tableName) - ->set('message_id', $qb->createNamedParameter(null)) - ->set('custom_icon', $qb->createNamedParameter(null)) - ->set('custom_message', $qb->createNamedParameter(null)) - ->set('clear_at', $qb->createNamedParameter(null)) + $qb->delete($this->tableName) ->where($qb->expr()->isNotNull('clear_at')) ->andWhere($qb->expr()->lte('clear_at', $qb->createNamedParameter($timestamp, IQueryBuilder::PARAM_INT))); - $qb->execute(); + $qb->executeStatement(); } @@ -164,15 +150,13 @@ class UserStatusMapper extends QBMapper { * * @param string $userId * @param string $messageId - * @param string $status * @return bool True if an entry was deleted */ - public function deleteCurrentStatusToRestoreBackup(string $userId, string $messageId, string $status): bool { + public function deleteCurrentStatusToRestoreBackup(string $userId, string $messageId): bool { $qb = $this->db->getQueryBuilder(); $qb->delete($this->tableName) ->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId))) ->andWhere($qb->expr()->eq('message_id', $qb->createNamedParameter($messageId))) - ->andWhere($qb->expr()->eq('status', $qb->createNamedParameter($status))) ->andWhere($qb->expr()->eq('is_backup', $qb->createNamedParameter(false, IQueryBuilder::PARAM_BOOL))); return $qb->executeStatement() > 0; } diff --git a/apps/user_status/lib/Exception/InvalidClearAtException.php b/apps/user_status/lib/Exception/InvalidClearAtException.php index a0ca08ade76..a3bd4dfa0d0 100644 --- a/apps/user_status/lib/Exception/InvalidClearAtException.php +++ b/apps/user_status/lib/Exception/InvalidClearAtException.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Exception; diff --git a/apps/user_status/lib/Exception/InvalidMessageIdException.php b/apps/user_status/lib/Exception/InvalidMessageIdException.php index dbf8d83d970..1feb36a916a 100644 --- a/apps/user_status/lib/Exception/InvalidMessageIdException.php +++ b/apps/user_status/lib/Exception/InvalidMessageIdException.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Exception; diff --git a/apps/user_status/lib/Exception/InvalidStatusIconException.php b/apps/user_status/lib/Exception/InvalidStatusIconException.php index 7a7c7947d5b..80dff2a7666 100644 --- a/apps/user_status/lib/Exception/InvalidStatusIconException.php +++ b/apps/user_status/lib/Exception/InvalidStatusIconException.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Exception; diff --git a/apps/user_status/lib/Exception/InvalidStatusTypeException.php b/apps/user_status/lib/Exception/InvalidStatusTypeException.php index 12115054b2c..a09284be40e 100644 --- a/apps/user_status/lib/Exception/InvalidStatusTypeException.php +++ b/apps/user_status/lib/Exception/InvalidStatusTypeException.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Exception; diff --git a/apps/user_status/lib/Exception/StatusMessageTooLongException.php b/apps/user_status/lib/Exception/StatusMessageTooLongException.php index c52f6079874..03d578abf46 100644 --- a/apps/user_status/lib/Exception/StatusMessageTooLongException.php +++ b/apps/user_status/lib/Exception/StatusMessageTooLongException.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Exception; diff --git a/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php b/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php index daf7265d988..ab3a1e62beb 100644 --- a/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php +++ b/apps/user_status/lib/Listener/BeforeTemplateRenderedListener.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Julius Härtl <jus@bitgrid.net> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Listener; @@ -36,21 +18,14 @@ use OCP\EventDispatcher\Event; use OCP\EventDispatcher\IEventListener; use OCP\IInitialStateService; use OCP\IUserSession; +use OCP\Util; +/** @template-implements IEventListener<BeforeTemplateRenderedEvent> */ class BeforeTemplateRenderedListener implements IEventListener { /** @var ProfileManager */ private $profileManager; - /** @var IUserSession */ - private $userSession; - - /** @var IInitialStateService */ - private $initialState; - - /** @var JSDataService */ - private $jsDataService; - /** * BeforeTemplateRenderedListener constructor. * @@ -61,14 +36,11 @@ class BeforeTemplateRenderedListener implements IEventListener { */ public function __construct( ProfileManager $profileManager, - IUserSession $userSession, - IInitialStateService $initialState, - JSDataService $jsDataService + private IUserSession $userSession, + private IInitialStateService $initialState, + private JSDataService $jsDataService, ) { $this->profileManager = $profileManager; - $this->userSession = $userSession; - $this->initialState = $initialState; - $this->jsDataService = $jsDataService; } /** @@ -97,7 +69,7 @@ class BeforeTemplateRenderedListener implements IEventListener { return ['profileEnabled' => $this->profileManager->isProfileEnabled($user)]; }); - \OCP\Util::addScript('user_status', 'menu'); - \OCP\Util::addStyle('user_status', 'user-status-menu'); + Util::addScript('user_status', 'menu'); + Util::addStyle('user_status', 'user-status-menu'); } } diff --git a/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php b/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php new file mode 100644 index 00000000000..6337d637896 --- /dev/null +++ b/apps/user_status/lib/Listener/OutOfOfficeStatusListener.php @@ -0,0 +1,57 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\UserStatus\Listener; + +use OCA\DAV\BackgroundJob\UserStatusAutomation; +use OCP\AppFramework\Utility\ITimeFactory; +use OCP\BackgroundJob\IJobList; +use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; +use OCP\User\Events\OutOfOfficeChangedEvent; +use OCP\User\Events\OutOfOfficeClearedEvent; +use OCP\User\Events\OutOfOfficeEndedEvent; +use OCP\User\Events\OutOfOfficeScheduledEvent; +use OCP\User\Events\OutOfOfficeStartedEvent; +use OCP\UserStatus\IManager; +use OCP\UserStatus\IUserStatus; + +/** + * Class UserDeletedListener + * + * @template-implements IEventListener<OutOfOfficeScheduledEvent|OutOfOfficeChangedEvent|OutOfOfficeClearedEvent|OutOfOfficeStartedEvent|OutOfOfficeEndedEvent> + * + */ +class OutOfOfficeStatusListener implements IEventListener { + public function __construct( + private IJobList $jobsList, + private ITimeFactory $time, + private IManager $manager, + ) { + } + + /** + * @inheritDoc + */ + public function handle(Event $event): void { + if ($event instanceof OutOfOfficeClearedEvent) { + $this->manager->revertUserStatus($event->getData()->getUser()->getUID(), IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::DND); + $this->jobsList->scheduleAfter(UserStatusAutomation::class, $this->time->getTime(), ['userId' => $event->getData()->getUser()->getUID()]); + return; + } + + if ($event instanceof OutOfOfficeScheduledEvent + || $event instanceof OutOfOfficeChangedEvent + || $event instanceof OutOfOfficeStartedEvent + || $event instanceof OutOfOfficeEndedEvent + ) { + // This might be overwritten by the office hours automation, but that is ok. This is just in case no office hours are set + $this->jobsList->scheduleAfter(UserStatusAutomation::class, $this->time->getTime(), ['userId' => $event->getData()->getUser()->getUID()]); + } + } +} diff --git a/apps/user_status/lib/Listener/UserDeletedListener.php b/apps/user_status/lib/Listener/UserDeletedListener.php index 0cacc89971a..bf021635156 100644 --- a/apps/user_status/lib/Listener/UserDeletedListener.php +++ b/apps/user_status/lib/Listener/UserDeletedListener.php @@ -3,50 +3,32 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Listener; use OCA\UserStatus\Service\StatusService; -use OCP\EventDispatcher\IEventListener; use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; use OCP\User\Events\UserDeletedEvent; /** * Class UserDeletedListener * * @package OCA\UserStatus\Listener + * @template-implements IEventListener<UserDeletedEvent> */ class UserDeletedListener implements IEventListener { - /** @var StatusService */ - private $service; - /** * UserDeletedListener constructor. * * @param StatusService $service */ - public function __construct(StatusService $service) { - $this->service = $service; + public function __construct( + private StatusService $service, + ) { } diff --git a/apps/user_status/lib/Listener/UserLiveStatusListener.php b/apps/user_status/lib/Listener/UserLiveStatusListener.php index c015e684142..2db999d3712 100644 --- a/apps/user_status/lib/Listener/UserLiveStatusListener.php +++ b/apps/user_status/lib/Listener/UserLiveStatusListener.php @@ -3,52 +3,39 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Listener; -use OCA\UserStatus\Db\UserStatus; +use OCA\DAV\CalDAV\Status\StatusService as CalendarStatusService; use OCA\UserStatus\Connector\UserStatus as ConnectorUserStatus; +use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Db\UserStatusMapper; use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; -use OCP\EventDispatcher\IEventListener; +use OCP\DB\Exception; use OCP\EventDispatcher\Event; +use OCP\EventDispatcher\IEventListener; use OCP\User\Events\UserLiveStatusEvent; use OCP\UserStatus\IUserStatus; +use Psr\Log\LoggerInterface; /** * Class UserDeletedListener * * @package OCA\UserStatus\Listener + * @template-implements IEventListener<UserLiveStatusEvent> */ class UserLiveStatusListener implements IEventListener { - private UserStatusMapper $mapper; - private ITimeFactory $timeFactory; - - public function __construct(UserStatusMapper $mapper, - ITimeFactory $timeFactory) { - $this->mapper = $mapper; - $this->timeFactory = $timeFactory; + public function __construct( + private UserStatusMapper $mapper, + private StatusService $statusService, + private ITimeFactory $timeFactory, + private CalendarStatusService $calendarStatusService, + private LoggerInterface $logger, + ) { } /** @@ -62,7 +49,8 @@ class UserLiveStatusListener implements IEventListener { $user = $event->getUser(); try { - $userStatus = $this->mapper->findByUserId($user->getUID()); + $this->calendarStatusService->processCalendarStatus($user->getUID()); + $userStatus = $this->statusService->findByUserId($user->getUID()); } catch (DoesNotExistException $ex) { $userStatus = new UserStatus(); $userStatus->setUserId($user->getUID()); @@ -71,10 +59,16 @@ class UserLiveStatusListener implements IEventListener { $userStatus->setIsUserDefined(false); } - // If the status is user-defined and one of the persistent statuses, we + // If the status is user-defined and one of the persistent status, we // will not override it. - if ($userStatus->getIsUserDefined() && - \in_array($userStatus->getStatus(), StatusService::PERSISTENT_STATUSES, true)) { + if ($userStatus->getIsUserDefined() + && \in_array($userStatus->getStatus(), StatusService::PERSISTENT_STATUSES, true)) { + return; + } + + // Don't overwrite the "away" calendar status if it's set + if ($userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY) { + $event->setUserStatus(new ConnectorUserStatus($userStatus)); return; } @@ -98,7 +92,19 @@ class UserLiveStatusListener implements IEventListener { $userStatus->setIsUserDefined(false); if ($userStatus->getId() === null) { - $this->mapper->insert($userStatus); + try { + $this->mapper->insert($userStatus); + } catch (Exception $e) { + if ($e->getReason() === Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + // A different process might have written another status + // update to the DB while we're processing our stuff. + // We can safely ignore it as we're only changing between AWAY and ONLINE + // and not doing anything with the message or icon. + $this->logger->debug('Unique constraint violation for live user status', ['exception' => $e]); + return; + } + throw $e; + } } else { $this->mapper->update($userStatus); } diff --git a/apps/user_status/lib/Migration/Version0001Date20200602134824.php b/apps/user_status/lib/Migration/Version0001Date20200602134824.php index 64490cc4207..678c2ec245a 100644 --- a/apps/user_status/lib/Migration/Version0001Date20200602134824.php +++ b/apps/user_status/lib/Migration/Version0001Date20200602134824.php @@ -3,32 +3,13 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Migration; -use OCP\DB\Types; use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; use OCP\Migration\IOutput; use OCP\Migration\SimpleMigrationStep; diff --git a/apps/user_status/lib/Migration/Version0002Date20200902144824.php b/apps/user_status/lib/Migration/Version0002Date20200902144824.php index 0c222eff8cd..199d2a4cc6b 100644 --- a/apps/user_status/lib/Migration/Version0002Date20200902144824.php +++ b/apps/user_status/lib/Migration/Version0002Date20200902144824.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Migration; diff --git a/apps/user_status/lib/Migration/Version1000Date20201111130204.php b/apps/user_status/lib/Migration/Version1000Date20201111130204.php index 8b20ed8306f..b0789684da0 100644 --- a/apps/user_status/lib/Migration/Version1000Date20201111130204.php +++ b/apps/user_status/lib/Migration/Version1000Date20201111130204.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020 Joas Schilling <coding@schilljs.com> - * - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Migration; diff --git a/apps/user_status/lib/Migration/Version1003Date20210809144824.php b/apps/user_status/lib/Migration/Version1003Date20210809144824.php new file mode 100644 index 00000000000..7c6cf76adbe --- /dev/null +++ b/apps/user_status/lib/Migration/Version1003Date20210809144824.php @@ -0,0 +1,43 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2021 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ +namespace OCA\UserStatus\Migration; + +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +/** + * @package OCA\UserStatus\Migration + */ +class Version1003Date20210809144824 extends SimpleMigrationStep { + + /** + * @param IOutput $output + * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` + * @param array $options + * @return null|ISchemaWrapper + * @since 23.0.0 + */ + public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $statusTable = $schema->getTable('user_status'); + + if (!$statusTable->hasColumn('is_backup')) { + $statusTable->addColumn('is_backup', Types::BOOLEAN, [ + 'notnull' => false, + 'default' => false, + ]); + } + + return $schema; + } +} diff --git a/apps/user_status/lib/Migration/Version1008Date20230921144701.php b/apps/user_status/lib/Migration/Version1008Date20230921144701.php new file mode 100644 index 00000000000..30ebbf37b0e --- /dev/null +++ b/apps/user_status/lib/Migration/Version1008Date20230921144701.php @@ -0,0 +1,54 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\UserStatus\Migration; + +use Closure; +use OCP\DB\ISchemaWrapper; +use OCP\DB\Types; +use OCP\IDBConnection; +use OCP\Migration\IOutput; +use OCP\Migration\SimpleMigrationStep; + +class Version1008Date20230921144701 extends SimpleMigrationStep { + + public function __construct( + private IDBConnection $connection, + ) { + } + + public function changeSchema(IOutput $output, Closure $schemaClosure, array $options): ?ISchemaWrapper { + /** @var ISchemaWrapper $schema */ + $schema = $schemaClosure(); + + $statusTable = $schema->getTable('user_status'); + if (!($statusTable->hasColumn('status_message_timestamp'))) { + $statusTable->addColumn('status_message_timestamp', Types::INTEGER, [ + 'notnull' => true, + 'length' => 11, + 'unsigned' => true, + 'default' => 0, + ]); + } + if (!$statusTable->hasIndex('user_status_mtstmp_ix')) { + $statusTable->addIndex(['status_message_timestamp'], 'user_status_mtstmp_ix'); + } + + return $schema; + } + + public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options): void { + $qb = $this->connection->getQueryBuilder(); + + $update = $qb->update('user_status') + ->set('status_message_timestamp', 'status_timestamp'); + + $update->executeStatement(); + } +} diff --git a/apps/user_status/lib/Migration/Version2301Date20210809144824.php b/apps/user_status/lib/Migration/Version2301Date20210809144824.php deleted file mode 100644 index 947378484c6..00000000000 --- a/apps/user_status/lib/Migration/Version2301Date20210809144824.php +++ /dev/null @@ -1,58 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright Copyright (c) 2021 Carl Schwan <carl@carlschwan.eu> - * - * @author Carl Schwan <carl@carlschwan.eu> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -namespace OCA\UserStatus\Migration; - -use OCP\DB\ISchemaWrapper; -use OCP\DB\Types; -use OCP\Migration\IOutput; -use OCP\Migration\SimpleMigrationStep; - -/** - * @package OCA\UserStatus\Migration - */ -class Version2301Date20210809144824 extends SimpleMigrationStep { - - /** - * @param IOutput $output - * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper` - * @param array $options - * @return null|ISchemaWrapper - * @since 23.0.0 - */ - public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) { - /** @var ISchemaWrapper $schema */ - $schema = $schemaClosure(); - - $statusTable = $schema->getTable('user_status'); - - $statusTable->addColumn('is_backup', Types::BOOLEAN, [ - 'notnull' => false, - 'default' => false, - ]); - - return $schema; - } -} diff --git a/apps/user_status/lib/ResponseDefinitions.php b/apps/user_status/lib/ResponseDefinitions.php new file mode 100644 index 00000000000..82f606dd301 --- /dev/null +++ b/apps/user_status/lib/ResponseDefinitions.php @@ -0,0 +1,44 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\UserStatus; + +/** + * @psalm-type UserStatusClearAtTimeType = "day"|"week" + * + * @psalm-type UserStatusClearAt = array{ + * type: "period"|"end-of", + * time: int|UserStatusClearAtTimeType, + * } + * + * @psalm-type UserStatusPredefined = array{ + * id: string, + * icon: string, + * message: string, + * clearAt: ?UserStatusClearAt, + * } + * + * @psalm-type UserStatusType = "online"|"away"|"dnd"|"busy"|"offline"|"invisible" + * + * @psalm-type UserStatusPublic = array{ + * userId: string, + * message: ?string, + * icon: ?string, + * clearAt: ?int, + * status: UserStatusType, + * } + * + * @psalm-type UserStatusPrivate = UserStatusPublic&array{ + * messageId: ?string, + * messageIsPredefined: bool, + * statusIsUserDefined: bool, + * } + */ +class ResponseDefinitions { +} diff --git a/apps/user_status/lib/Service/EmojiService.php b/apps/user_status/lib/Service/EmojiService.php deleted file mode 100644 index 0f197933872..00000000000 --- a/apps/user_status/lib/Service/EmojiService.php +++ /dev/null @@ -1,102 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -namespace OCA\UserStatus\Service; - -use OCP\IDBConnection; - -/** - * Class EmojiService - * - * @package OCA\UserStatus\Service - */ -class EmojiService { - - /** @var IDBConnection */ - private $db; - - /** - * EmojiService constructor. - * - * @param IDBConnection $db - */ - public function __construct(IDBConnection $db) { - $this->db = $db; - } - - /** - * @return bool - */ - public function doesPlatformSupportEmoji(): bool { - return $this->db->supports4ByteText() && - \class_exists(\IntlBreakIterator::class); - } - - /** - * @param string $emoji - * @return bool - */ - public function isValidEmoji(string $emoji): bool { - $intlBreakIterator = \IntlBreakIterator::createCharacterInstance(); - $intlBreakIterator->setText($emoji); - - $characterCount = 0; - while ($intlBreakIterator->next() !== \IntlBreakIterator::DONE) { - $characterCount++; - } - - if ($characterCount !== 1) { - return false; - } - - $codePointIterator = \IntlBreakIterator::createCodePointInstance(); - $codePointIterator->setText($emoji); - - foreach ($codePointIterator->getPartsIterator() as $codePoint) { - $codePointType = \IntlChar::charType($codePoint); - - // If the current code-point is an emoji or a modifier (like a skin-tone) - // just continue and check the next character - if ($codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_SYMBOL || - $codePointType === \IntlChar::CHAR_CATEGORY_MODIFIER_LETTER || - $codePointType === \IntlChar::CHAR_CATEGORY_OTHER_SYMBOL || - $codePointType === \IntlChar::CHAR_CATEGORY_GENERAL_OTHER_TYPES) { - continue; - } - - // If it's neither a modifier nor an emoji, we only allow - // a zero-width-joiner or a variation selector 16 - $codePointValue = \IntlChar::ord($codePoint); - if ($codePointValue === 8205 || $codePointValue === 65039) { - continue; - } - - return false; - } - - return true; - } -} diff --git a/apps/user_status/lib/Service/JSDataService.php b/apps/user_status/lib/Service/JSDataService.php index c08643ec64f..a777e97fe57 100644 --- a/apps/user_status/lib/Service/JSDataService.php +++ b/apps/user_status/lib/Service/JSDataService.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Service; @@ -31,22 +14,16 @@ use OCP\UserStatus\IUserStatus; class JSDataService implements \JsonSerializable { - /** @var IUserSession */ - private $userSession; - - /** @var StatusService */ - private $statusService; - /** * JSDataService constructor. * * @param IUserSession $userSession * @param StatusService $statusService */ - public function __construct(IUserSession $userSession, - StatusService $statusService) { - $this->userSession = $userSession; - $this->statusService = $statusService; + public function __construct( + private IUserSession $userSession, + private StatusService $statusService, + ) { } public function jsonSerialize(): array { diff --git a/apps/user_status/lib/Service/PredefinedStatusService.php b/apps/user_status/lib/Service/PredefinedStatusService.php index 354e0f16b32..599d5b8b52f 100644 --- a/apps/user_status/lib/Service/PredefinedStatusService.php +++ b/apps/user_status/lib/Service/PredefinedStatusService.php @@ -3,29 +3,13 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Service; use OCP\IL10N; +use OCP\UserStatus\IUserStatus; /** * Class DefaultStatusService @@ -36,23 +20,26 @@ use OCP\IL10N; * @package OCA\UserStatus\Service */ class PredefinedStatusService { + private const BE_RIGHT_BACK = 'be-right-back'; private const MEETING = 'meeting'; private const COMMUTING = 'commuting'; private const SICK_LEAVE = 'sick-leave'; private const VACATIONING = 'vacationing'; private const REMOTE_WORK = 'remote-work'; + /** + * @deprecated See \OCP\UserStatus\IUserStatus::MESSAGE_CALL + */ public const CALL = 'call'; - - /** @var IL10N */ - private $l10n; + public const OUT_OF_OFFICE = 'out-of-office'; /** * DefaultStatusService constructor. * * @param IL10N $l10n */ - public function __construct(IL10N $l10n) { - $this->l10n = $l10n; + public function __construct( + private IL10N $l10n, + ) { } /** @@ -79,6 +66,15 @@ class PredefinedStatusService { ], ], [ + 'id' => self::BE_RIGHT_BACK, + 'icon' => '⏳', + 'message' => $this->getTranslatedStatusForId(self::BE_RIGHT_BACK), + 'clearAt' => [ + 'type' => 'period', + 'time' => 900, + ], + ], + [ 'id' => self::REMOTE_WORK, 'icon' => '🏡', 'message' => $this->getTranslatedStatusForId(self::REMOTE_WORK), @@ -109,6 +105,13 @@ class PredefinedStatusService { 'clearAt' => null, 'visible' => false, ], + [ + 'id' => self::OUT_OF_OFFICE, + 'icon' => '🛑', + 'message' => $this->getTranslatedStatusForId(self::OUT_OF_OFFICE), + 'clearAt' => null, + 'visible' => false, + ], ]; } @@ -144,9 +147,15 @@ class PredefinedStatusService { case self::VACATIONING: return '🌴'; + case self::OUT_OF_OFFICE: + return '🛑'; + case self::REMOTE_WORK: return '🏡'; + case self::BE_RIGHT_BACK: + return '⏳'; + case self::CALL: return '💬'; @@ -174,12 +183,18 @@ class PredefinedStatusService { case self::VACATIONING: return $this->l10n->t('Vacationing'); + case self::OUT_OF_OFFICE: + return $this->l10n->t('Out of office'); + case self::REMOTE_WORK: return $this->l10n->t('Working remotely'); case self::CALL: return $this->l10n->t('In a call'); + case self::BE_RIGHT_BACK: + return $this->l10n->t('Be right back'); + default: return null; } @@ -195,8 +210,14 @@ class PredefinedStatusService { self::COMMUTING, self::SICK_LEAVE, self::VACATIONING, + self::OUT_OF_OFFICE, + self::BE_RIGHT_BACK, self::REMOTE_WORK, - self::CALL, + IUserStatus::MESSAGE_CALL, + IUserStatus::MESSAGE_AVAILABILITY, + IUserStatus::MESSAGE_VACATION, + IUserStatus::MESSAGE_CALENDAR_BUSY, + IUserStatus::MESSAGE_CALENDAR_BUSY_TENTATIVE, ], true); } } diff --git a/apps/user_status/lib/Service/StatusService.php b/apps/user_status/lib/Service/StatusService.php index 5dd70e4ea5e..188eb26d1d7 100644 --- a/apps/user_status/lib/Service/StatusService.php +++ b/apps/user_status/lib/Service/StatusService.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Service; @@ -37,8 +19,11 @@ use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\DB\Exception; use OCP\IConfig; -use OCP\IUser; +use OCP\IEmojiHelper; +use OCP\IUserManager; use OCP\UserStatus\IUserStatus; +use Psr\Log\LoggerInterface; +use function in_array; /** * Class StatusService @@ -46,27 +31,9 @@ use OCP\UserStatus\IUserStatus; * @package OCA\UserStatus\Service */ class StatusService { - - /** @var UserStatusMapper */ - private $mapper; - - /** @var ITimeFactory */ - private $timeFactory; - - /** @var PredefinedStatusService */ - private $predefinedStatusService; - - /** @var EmojiService */ - private $emojiService; - - /** @var bool */ - private $shareeEnumeration; - - /** @var bool */ - private $shareeEnumerationInGroupOnly; - - /** @var bool */ - private $shareeEnumerationPhone; + private bool $shareeEnumeration; + private bool $shareeEnumerationInGroupOnly; + private bool $shareeEnumerationPhone; /** * List of priorities ordered by their priority @@ -75,6 +42,7 @@ class StatusService { IUserStatus::ONLINE, IUserStatus::AWAY, IUserStatus::DND, + IUserStatus::BUSY, IUserStatus::INVISIBLE, IUserStatus::OFFLINE, ]; @@ -85,6 +53,7 @@ class StatusService { */ public const PERSISTENT_STATUSES = [ IUserStatus::AWAY, + IUserStatus::BUSY, IUserStatus::DND, IUserStatus::INVISIBLE, ]; @@ -95,27 +64,18 @@ class StatusService { /** @var int */ public const MAXIMUM_MESSAGE_LENGTH = 80; - /** - * StatusService constructor. - * - * @param UserStatusMapper $mapper - * @param ITimeFactory $timeFactory - * @param PredefinedStatusService $defaultStatusService - * @param EmojiService $emojiService - * @param IConfig $config - */ - public function __construct(UserStatusMapper $mapper, - ITimeFactory $timeFactory, - PredefinedStatusService $defaultStatusService, - EmojiService $emojiService, - IConfig $config) { - $this->mapper = $mapper; - $this->timeFactory = $timeFactory; - $this->predefinedStatusService = $defaultStatusService; - $this->emojiService = $emojiService; - $this->shareeEnumeration = $config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; - $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; - $this->shareeEnumerationPhone = $this->shareeEnumeration && $config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes'; + public function __construct( + private UserStatusMapper $mapper, + private ITimeFactory $timeFactory, + private PredefinedStatusService $predefinedStatusService, + private IEmojiHelper $emojiHelper, + private IConfig $config, + private IUserManager $userManager, + private LoggerInterface $logger, + ) { + $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes'; + $this->shareeEnumerationInGroupOnly = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_group', 'no') === 'yes'; + $this->shareeEnumerationPhone = $this->shareeEnumeration && $this->config->getAppValue('core', 'shareapi_restrict_user_enumeration_to_phone', 'no') === 'yes'; } /** @@ -159,7 +119,7 @@ class StatusService { * @return UserStatus * @throws DoesNotExistException */ - public function findByUserId(string $userId):UserStatus { + public function findByUserId(string $userId): UserStatus { return $this->processStatus($this->mapper->findByUserId($userId)); } @@ -182,9 +142,9 @@ class StatusService { * @throws InvalidStatusTypeException */ public function setStatus(string $userId, - string $status, - ?int $statusTimestamp, - bool $isUserDefined): UserStatus { + string $status, + ?int $statusTimestamp, + bool $isUserDefined): UserStatus { try { $userStatus = $this->mapper->findByUserId($userId); } catch (DoesNotExistException $ex) { @@ -193,9 +153,10 @@ class StatusService { } // Check if status-type is valid - if (!\in_array($status, self::PRIORITY_ORDERED_STATUSES, true)) { + if (!in_array($status, self::PRIORITY_ORDERED_STATUSES, true)) { throw new InvalidStatusTypeException('Status-type "' . $status . '" is not supported'); } + if ($statusTimestamp === null) { $statusTimestamp = $this->timeFactory->getTime(); } @@ -206,7 +167,7 @@ class StatusService { $userStatus->setIsBackup(false); if ($userStatus->getId() === null) { - return $this->mapper->insert($userStatus); + return $this->insertWithoutThrowingUniqueConstrain($userStatus); } return $this->mapper->update($userStatus); @@ -221,8 +182,8 @@ class StatusService { * @throws InvalidClearAtException */ public function setPredefinedMessage(string $userId, - string $messageId, - ?int $clearAt): UserStatus { + string $messageId, + ?int $clearAt): UserStatus { try { $userStatus = $this->mapper->findByUserId($userId); } catch (DoesNotExistException $ex) { @@ -247,9 +208,10 @@ class StatusService { $userStatus->setCustomIcon(null); $userStatus->setCustomMessage(null); $userStatus->setClearAt($clearAt); + $userStatus->setStatusMessageTimestamp($this->timeFactory->now()->getTimestamp()); if ($userStatus->getId() === null) { - return $this->mapper->insert($userStatus); + return $this->insertWithoutThrowingUniqueConstrain($userStatus); } return $this->mapper->update($userStatus); @@ -260,15 +222,17 @@ class StatusService { * @param string $status * @param string $messageId * @param bool $createBackup + * @param string|null $customMessage * @throws InvalidStatusTypeException * @throws InvalidMessageIdException */ public function setUserStatus(string $userId, - string $status, - string $messageId, - bool $createBackup): void { + string $status, + string $messageId, + bool $createBackup, + ?string $customMessage = null): ?UserStatus { // Check if status-type is valid - if (!\in_array($status, self::PRIORITY_ORDERED_STATUSES, true)) { + if (!in_array($status, self::PRIORITY_ORDERED_STATUSES, true)) { throw new InvalidStatusTypeException('Status-type "' . $status . '" is not supported'); } @@ -276,21 +240,58 @@ class StatusService { throw new InvalidMessageIdException('Message-Id "' . $messageId . '" is not supported'); } + try { + $userStatus = $this->mapper->findByUserId($userId); + } catch (DoesNotExistException $e) { + // We don't need to do anything + $userStatus = new UserStatus(); + $userStatus->setUserId($userId); + } + + $updateStatus = false; + if ($messageId === IUserStatus::MESSAGE_OUT_OF_OFFICE) { + // OUT_OF_OFFICE trumps AVAILABILITY, CALL and CALENDAR status + $updateStatus = $userStatus->getMessageId() === IUserStatus::MESSAGE_AVAILABILITY || $userStatus->getMessageId() === IUserStatus::MESSAGE_CALL || $userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY; + } elseif ($messageId === IUserStatus::MESSAGE_AVAILABILITY) { + // AVAILABILITY trumps CALL and CALENDAR status + $updateStatus = $userStatus->getMessageId() === IUserStatus::MESSAGE_CALL || $userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY; + } elseif ($messageId === IUserStatus::MESSAGE_CALL) { + // CALL trumps CALENDAR status + $updateStatus = $userStatus->getMessageId() === IUserStatus::MESSAGE_CALENDAR_BUSY; + } + + if ($messageId === IUserStatus::MESSAGE_OUT_OF_OFFICE || $messageId === IUserStatus::MESSAGE_AVAILABILITY || $messageId === IUserStatus::MESSAGE_CALL || $messageId === IUserStatus::MESSAGE_CALENDAR_BUSY) { + if ($updateStatus) { + $this->logger->debug('User ' . $userId . ' is currently NOT available, overwriting status [status: ' . $userStatus->getStatus() . ', messageId: ' . json_encode($userStatus->getMessageId()) . ']', ['app' => 'dav']); + } else { + $this->logger->debug('User ' . $userId . ' is currently NOT available, but we are NOT overwriting status [status: ' . $userStatus->getStatus() . ', messageId: ' . json_encode($userStatus->getMessageId()) . ']', ['app' => 'dav']); + } + } + + // There should be a backup already or none is needed. So we take a shortcut. + if ($updateStatus) { + $userStatus->setStatus($status); + $userStatus->setStatusTimestamp($this->timeFactory->getTime()); + $userStatus->setIsUserDefined(true); + $userStatus->setIsBackup(false); + $userStatus->setMessageId($messageId); + $userStatus->setCustomIcon(null); + $userStatus->setCustomMessage($customMessage); + $userStatus->setClearAt(null); + $userStatus->setStatusMessageTimestamp($this->timeFactory->now()->getTimestamp()); + return $this->mapper->update($userStatus); + } + if ($createBackup) { if ($this->backupCurrentStatus($userId) === false) { - return; // Already a status set automatically => abort. + return null; // Already a status set automatically => abort. } // If we just created the backup + // we need to create a new status to insert + // Unfortunately there's no way to unset the DB ID on an Entity $userStatus = new UserStatus(); $userStatus->setUserId($userId); - } else { - try { - $userStatus = $this->mapper->findByUserId($userId); - } catch (DoesNotExistException $ex) { - $userStatus = new UserStatus(); - $userStatus->setUserId($userId); - } } $userStatus->setStatus($status); @@ -299,20 +300,26 @@ class StatusService { $userStatus->setIsBackup(false); $userStatus->setMessageId($messageId); $userStatus->setCustomIcon(null); - $userStatus->setCustomMessage(null); + $userStatus->setCustomMessage($customMessage); $userStatus->setClearAt(null); + if ($this->predefinedStatusService->getTranslatedStatusForId($messageId) !== null + || ($customMessage !== null && $customMessage !== '')) { + // Only track status message ID if there is one + $userStatus->setStatusMessageTimestamp($this->timeFactory->now()->getTimestamp()); + } else { + $userStatus->setStatusMessageTimestamp(0); + } if ($userStatus->getId() !== null) { - $this->mapper->update($userStatus); - return; + return $this->mapper->update($userStatus); } - $this->mapper->insert($userStatus); + return $this->insertWithoutThrowingUniqueConstrain($userStatus); } /** * @param string $userId * @param string|null $statusIcon - * @param string $message + * @param string|null $message * @param int|null $clearAt * @return UserStatus * @throws InvalidClearAtException @@ -320,9 +327,9 @@ class StatusService { * @throws StatusMessageTooLongException */ public function setCustomMessage(string $userId, - ?string $statusIcon, - string $message, - ?int $clearAt): UserStatus { + ?string $statusIcon, + ?string $message, + ?int $clearAt): UserStatus { try { $userStatus = $this->mapper->findByUserId($userId); } catch (DoesNotExistException $ex) { @@ -334,11 +341,11 @@ class StatusService { } // Check if statusIcon contains only one character - if ($statusIcon !== null && !$this->emojiService->isValidEmoji($statusIcon)) { + if ($statusIcon !== null && !$this->emojiHelper->isValidSingleEmoji($statusIcon)) { throw new InvalidStatusIconException('Status-Icon is longer than one character'); } // Check for maximum length of custom message - if (\mb_strlen($message) > self::MAXIMUM_MESSAGE_LENGTH) { + if ($message !== null && \mb_strlen($message) > self::MAXIMUM_MESSAGE_LENGTH) { throw new StatusMessageTooLongException('Message is longer than supported length of ' . self::MAXIMUM_MESSAGE_LENGTH . ' characters'); } // Check that clearAt is in the future @@ -350,9 +357,10 @@ class StatusService { $userStatus->setCustomIcon($statusIcon); $userStatus->setCustomMessage($message); $userStatus->setClearAt($clearAt); + $userStatus->setStatusMessageTimestamp($this->timeFactory->now()->getTimestamp()); if ($userStatus->getId() === null) { - return $this->mapper->insert($userStatus); + return $this->insertWithoutThrowingUniqueConstrain($userStatus); } return $this->mapper->update($userStatus); @@ -394,6 +402,7 @@ class StatusService { $userStatus->setCustomMessage(null); $userStatus->setCustomIcon(null); $userStatus->setClearAt(null); + $userStatus->setStatusMessageTimestamp(0); $this->mapper->update($userStatus); return true; @@ -442,6 +451,7 @@ class StatusService { $this->cleanStatus($status); } if ($clearAt !== null && $clearAt < $this->timeFactory->getTime()) { + $this->cleanStatus($status); $this->cleanStatusMessage($status); } if ($status->getMessageId() !== null) { @@ -474,6 +484,7 @@ class StatusService { $status->setCustomIcon(null); $status->setCustomMessage(null); $status->setClearAt(null); + $status->setStatusMessageTimestamp(0); $this->mapper->update($status); } @@ -484,8 +495,14 @@ class StatusService { private function addDefaultMessage(UserStatus $status): void { // If the message is predefined, insert the translated message and icon $predefinedMessage = $this->predefinedStatusService->getDefaultStatusById($status->getMessageId()); - if ($predefinedMessage !== null) { + if ($predefinedMessage === null) { + return; + } + // If there is a custom message, don't overwrite it + if (empty($status->getCustomMessage())) { $status->setCustomMessage($predefinedMessage['message']); + } + if (empty($status->getCustomIcon())) { $status->setCustomIcon($predefinedMessage['icon']); } } @@ -505,28 +522,38 @@ class StatusService { } } - public function revertUserStatus(string $userId, string $messageId, string $status): void { + public function revertUserStatus(string $userId, string $messageId, bool $revertedManually = false): ?UserStatus { try { /** @var UserStatus $userStatus */ $backupUserStatus = $this->mapper->findByUserId($userId, true); } catch (DoesNotExistException $ex) { // No user status to revert, do nothing - return; + return null; } - $deleted = $this->mapper->deleteCurrentStatusToRestoreBackup($userId, $messageId, $status); + $deleted = $this->mapper->deleteCurrentStatusToRestoreBackup($userId, $messageId); if (!$deleted) { // Another status is set automatically or no status, do nothing - return; + return null; + } + + if ($revertedManually) { + if ($backupUserStatus->getStatus() === IUserStatus::OFFLINE) { + // When the user reverts the status manually they are online + $backupUserStatus->setStatus(IUserStatus::ONLINE); + } + $backupUserStatus->setStatusTimestamp($this->timeFactory->getTime()); } $backupUserStatus->setIsBackup(false); // Remove the underscore prefix added when creating the backup $backupUserStatus->setUserId(substr($backupUserStatus->getUserId(), 1)); $this->mapper->update($backupUserStatus); + + return $backupUserStatus; } - public function revertMultipleUserStatus(array $userIds, string $messageId, string $status): void { + public function revertMultipleUserStatus(array $userIds, string $messageId): void { // Get all user statuses and the backups $findById = $userIds; foreach ($userIds as $userId) { @@ -537,10 +564,9 @@ class StatusService { $backups = $restoreIds = $statuesToDelete = []; foreach ($userStatuses as $userStatus) { if (!$userStatus->getIsBackup() - && $userStatus->getMessageId() === $messageId - && $userStatus->getStatus() === $status) { + && $userStatus->getMessageId() === $messageId) { $statuesToDelete[$userStatus->getUserId()] = $userStatus->getId(); - } else if ($userStatus->getIsBackup()) { + } elseif ($userStatus->getIsBackup()) { $backups[$userStatus->getUserId()] = $userStatus->getId(); } } @@ -558,4 +584,16 @@ class StatusService { // For users that matched restore the previous status $this->mapper->restoreBackupStatuses($restoreIds); } + + protected function insertWithoutThrowingUniqueConstrain(UserStatus $userStatus): UserStatus { + try { + return $this->mapper->insert($userStatus); + } catch (Exception $e) { + // Ignore if a parallel request already set the status + if ($e->getReason() !== Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION) { + throw $e; + } + } + return $userStatus; + } } diff --git a/apps/user_status/openapi.json b/apps/user_status/openapi.json new file mode 100644 index 00000000000..e48d4970b96 --- /dev/null +++ b/apps/user_status/openapi.json @@ -0,0 +1,1195 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "user_status", + "version": "0.0.1", + "description": "User status", + "license": { + "name": "agpl" + } + }, + "components": { + "securitySchemes": { + "basic_auth": { + "type": "http", + "scheme": "basic" + }, + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "Capabilities": { + "type": "object", + "required": [ + "user_status" + ], + "properties": { + "user_status": { + "type": "object", + "required": [ + "enabled", + "restore", + "supports_emoji", + "supports_busy" + ], + "properties": { + "enabled": { + "type": "boolean" + }, + "restore": { + "type": "boolean" + }, + "supports_emoji": { + "type": "boolean" + }, + "supports_busy": { + "type": "boolean" + } + } + } + } + }, + "ClearAt": { + "type": "object", + "required": [ + "type", + "time" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "period", + "end-of" + ] + }, + "time": { + "anyOf": [ + { + "type": "integer", + "format": "int64" + }, + { + "$ref": "#/components/schemas/ClearAtTimeType" + } + ] + } + } + }, + "ClearAtTimeType": { + "type": "string", + "enum": [ + "day", + "week" + ] + }, + "OCSMeta": { + "type": "object", + "required": [ + "status", + "statuscode" + ], + "properties": { + "status": { + "type": "string" + }, + "statuscode": { + "type": "integer" + }, + "message": { + "type": "string" + }, + "totalitems": { + "type": "string" + }, + "itemsperpage": { + "type": "string" + } + } + }, + "Predefined": { + "type": "object", + "required": [ + "id", + "icon", + "message", + "clearAt" + ], + "properties": { + "id": { + "type": "string" + }, + "icon": { + "type": "string" + }, + "message": { + "type": "string" + }, + "clearAt": { + "nullable": true, + "allOf": [ + { + "$ref": "#/components/schemas/ClearAt" + } + ] + } + } + }, + "Private": { + "allOf": [ + { + "$ref": "#/components/schemas/Public" + }, + { + "type": "object", + "required": [ + "messageId", + "messageIsPredefined", + "statusIsUserDefined" + ], + "properties": { + "messageId": { + "type": "string", + "nullable": true + }, + "messageIsPredefined": { + "type": "boolean" + }, + "statusIsUserDefined": { + "type": "boolean" + } + } + } + ] + }, + "Public": { + "type": "object", + "required": [ + "userId", + "message", + "icon", + "clearAt", + "status" + ], + "properties": { + "userId": { + "type": "string" + }, + "message": { + "type": "string", + "nullable": true + }, + "icon": { + "type": "string", + "nullable": true + }, + "clearAt": { + "type": "integer", + "format": "int64", + "nullable": true + }, + "status": { + "$ref": "#/components/schemas/Type" + } + } + }, + "Type": { + "type": "string", + "enum": [ + "online", + "away", + "dnd", + "busy", + "offline", + "invisible" + ] + } + } + }, + "paths": { + "/ocs/v2.php/apps/user_status/api/v1/heartbeat": { + "put": { + "operationId": "heartbeat-heartbeat", + "summary": "Keep the status alive", + "tags": [ + "heartbeat" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "status" + ], + "properties": { + "status": { + "type": "string", + "description": "Only online, away" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Status successfully updated", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Private" + } + } + } + } + } + } + } + }, + "400": { + "description": "Invalid status to update", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "500": { + "description": "", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "204": { + "description": "User has no status to keep alive" + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/predefined_statuses": { + "get": { + "operationId": "predefined_status-find-all", + "summary": "Get all predefined messages", + "tags": [ + "predefined_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Predefined statuses returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Predefined" + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/statuses": { + "get": { + "operationId": "statuses-find-all", + "summary": "Find statuses of users", + "tags": [ + "statuses" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "limit", + "in": "query", + "description": "Maximum number of statuses to find", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null + } + }, + { + "name": "offset", + "in": "query", + "description": "Offset for finding statuses", + "schema": { + "type": "integer", + "format": "int64", + "nullable": true, + "default": null, + "minimum": 0 + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Statuses returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/Public" + } + } + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/statuses/{userId}": { + "get": { + "operationId": "statuses-find", + "summary": "Find the status of a user", + "tags": [ + "statuses" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "userId", + "in": "path", + "description": "ID of the user", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Status returned", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Public" + } + } + } + } + } + } + } + }, + "404": { + "description": "The user was not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/user_status": { + "get": { + "operationId": "user_status-get-status", + "summary": "Get the status of the current user", + "tags": [ + "user_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "The status was found successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Private" + } + } + } + } + } + } + } + }, + "404": { + "description": "The user was not found", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/user_status/status": { + "put": { + "operationId": "user_status-set-status", + "summary": "Update the status type of the current user", + "tags": [ + "user_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "statusType" + ], + "properties": { + "statusType": { + "type": "string", + "description": "The new status type" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "The status was updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Private" + } + } + } + } + } + } + } + }, + "400": { + "description": "The status type is invalid", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/user_status/message/predefined": { + "put": { + "operationId": "user_status-set-predefined-message", + "summary": "Set the message to a predefined message for the current user", + "tags": [ + "user_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "messageId" + ], + "properties": { + "messageId": { + "type": "string", + "description": "ID of the predefined message" + }, + "clearAt": { + "type": "integer", + "format": "int64", + "nullable": true, + "description": "When the message should be cleared" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "The message was updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Private" + } + } + } + } + } + } + } + }, + "400": { + "description": "The clearAt or message-id is invalid", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/user_status/message/custom": { + "put": { + "operationId": "user_status-set-custom-message", + "summary": "Set the message to a custom message for the current user", + "tags": [ + "user_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "statusIcon": { + "type": "string", + "nullable": true, + "description": "Icon of the status" + }, + "message": { + "type": "string", + "nullable": true, + "description": "Message of the status" + }, + "clearAt": { + "type": "integer", + "format": "int64", + "nullable": true, + "description": "When the message should be cleared" + } + } + } + } + } + }, + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "The message was updated successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "$ref": "#/components/schemas/Private" + } + } + } + } + } + } + } + }, + "400": { + "description": "The clearAt or icon is invalid or the message is too long", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + }, + "404": { + "description": "No status for the current user", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/user_status/message": { + "delete": { + "operationId": "user_status-clear-message", + "summary": "Clear the message of the current user", + "tags": [ + "user_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Message cleared successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": {} + } + } + } + } + } + } + } + } + } + }, + "/ocs/v2.php/apps/user_status/api/v1/user_status/revert/{messageId}": { + "delete": { + "operationId": "user_status-revert-status", + "summary": "Revert the status to the previous status", + "tags": [ + "user_status" + ], + "security": [ + { + "bearer_auth": [] + }, + { + "basic_auth": [] + } + ], + "parameters": [ + { + "name": "messageId", + "in": "path", + "description": "ID of the message to delete", + "required": true, + "schema": { + "type": "string" + } + }, + { + "name": "OCS-APIRequest", + "in": "header", + "description": "Required to be true for the API request to pass", + "required": true, + "schema": { + "type": "boolean", + "default": true + } + } + ], + "responses": { + "200": { + "description": "Status reverted", + "content": { + "application/json": { + "schema": { + "type": "object", + "required": [ + "ocs" + ], + "properties": { + "ocs": { + "type": "object", + "required": [ + "meta", + "data" + ], + "properties": { + "meta": { + "$ref": "#/components/schemas/OCSMeta" + }, + "data": { + "anyOf": [ + { + "$ref": "#/components/schemas/Private" + }, + { + "type": "array", + "maxItems": 0 + } + ] + } + } + } + } + } + } + } + } + } + } + } + }, + "tags": [] +} diff --git a/apps/user_status/openapi.json.license b/apps/user_status/openapi.json.license new file mode 100644 index 00000000000..83559daa9dc --- /dev/null +++ b/apps/user_status/openapi.json.license @@ -0,0 +1,2 @@ +SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors +SPDX-License-Identifier: AGPL-3.0-or-later
\ No newline at end of file diff --git a/apps/user_status/src/UserStatus.vue b/apps/user_status/src/UserStatus.vue index 8baf31de1b7..07d81aad95c 100644 --- a/apps/user_status/src/UserStatus.vue +++ b/apps/user_status/src/UserStatus.vue @@ -1,80 +1,70 @@ <!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> - <li> - <div class="user-status-menu-item"> - <!-- Username display --> - <a v-if="!inline" - class="user-status-menu-item__header" - :href="profilePageLink" - @click="loadProfilePage"> - <div class="user-status-menu-item__header-content"> - <div class="user-status-menu-item__header-content-displayname">{{ displayName }}</div> - <div v-if="!loadingProfilePage" class="user-status-menu-item__header-content-placeholder" /> - <div v-else class="icon-loading-small" /> - </div> - <div v-if="profileEnabled"> - {{ t('user_status', 'View profile') }} - </div> - </a> - - <!-- Status modal toggle --> - <toggle :is="inline ? 'button' : 'a'" - :class="{'user-status-menu-item__toggle--inline': inline}" - class="user-status-menu-item__toggle" - href="#" - @click.prevent.stop="openModal"> - <span :class="statusIcon" class="user-status-menu-item__toggle-icon" /> + <Fragment> + <NcListItem v-if="!inline" + class="user-status-menu-item" + compact + :name="visibleMessage" + @click.stop="openModal"> + <template #icon> + <NcUserStatusIcon class="user-status-icon" + :status="statusType" + aria-hidden="true" /> + </template> + </NcListItem> + + <div v-else> + <!-- Dashboard Status --> + <NcButton @click.stop="openModal"> + <template #icon> + <NcUserStatusIcon class="user-status-icon" + :status="statusType" + aria-hidden="true" /> + </template> {{ visibleMessage }} - </toggle> + </NcButton> </div> - <!-- Status management modal --> <SetStatusModal v-if="isModalOpen" + :inline="inline" @close="closeModal" /> - </li> + </Fragment> </template> <script> -import { generateUrl } from '@nextcloud/router' import { getCurrentUser } from '@nextcloud/auth' -import { loadState } from '@nextcloud/initial-state' import { subscribe, unsubscribe } from '@nextcloud/event-bus' +import { Fragment } from 'vue-frag' +import NcButton from '@nextcloud/vue/components/NcButton' +import NcListItem from '@nextcloud/vue/components/NcListItem' +import NcUserStatusIcon from '@nextcloud/vue/components/NcUserStatusIcon' import debounce from 'debounce' -import { sendHeartbeat } from './services/heartbeatService' -import OnlineStatusMixin from './mixins/OnlineStatusMixin' - -const { profileEnabled } = loadState('user_status', 'profileEnabled', false) +import { sendHeartbeat } from './services/heartbeatService.js' +import OnlineStatusMixin from './mixins/OnlineStatusMixin.js' export default { name: 'UserStatus', components: { - SetStatusModal: () => import(/* webpackChunkName: 'user-status-modal' */'./components/SetStatusModal'), + Fragment, + NcButton, + NcListItem, + NcUserStatusIcon, + SetStatusModal: () => import(/* webpackChunkName: 'user-status-modal' */'./components/SetStatusModal.vue'), }, mixins: [OnlineStatusMixin], props: { + /** + * Whether the component should be rendered as a Dashboard Status or a User Menu Entries + * true = Dashboard Status + * false = User Menu Entries + */ inline: { type: Boolean, default: false, @@ -83,41 +73,19 @@ export default { data() { return { - displayName: getCurrentUser().displayName, heartbeatInterval: null, isAway: false, isModalOpen: false, - loadingProfilePage: false, mouseMoveListener: null, - profileEnabled, setAwayTimeout: null, } }, - computed: { - /** - * The profile page link - * - * @return {string | null} - */ - profilePageLink() { - if (this.profileEnabled) { - return generateUrl('/u/{userId}', { userId: getCurrentUser().uid }) - } - // Since an anchor element is used rather than a button, - // this hack removes href if the profile is disabled so that disabling pointer-events is not needed to prevent a click from opening a page - // and to allow the hover event for styling - return null - }, - }, /** * Loads the current user's status from initial state * and stores it in Vuex */ mounted() { - subscribe('settings:display-name:updated', this.handleDisplayNameUpdate) - subscribe('settings:profile-enabled:updated', this.handleProfileEnabledUpdate) - this.$store.dispatch('loadStatusFromInitialState') if (OC.config.session_keepalive) { @@ -154,28 +122,12 @@ export default { * Some housekeeping before destroying the component */ beforeDestroy() { - unsubscribe('settings:display-name:updated', this.handleDisplayNameUpdate) - unsubscribe('settings:profile-enabled:updated', this.handleProfileEnabledUpdate) window.removeEventListener('mouseMove', this.mouseMoveListener) clearInterval(this.heartbeatInterval) unsubscribe('user_status:status.updated', this.handleUserStatusUpdated) }, methods: { - handleDisplayNameUpdate(displayName) { - this.displayName = displayName - }, - - handleProfileEnabledUpdate(profileEnabled) { - this.profileEnabled = profileEnabled - }, - - loadProfilePage() { - if (this.profileEnabled) { - this.loadingProfilePage = true - } - }, - /** * Opens the modal to set a custom status */ @@ -208,7 +160,7 @@ export default { } }, handleUserStatusUpdated(state) { - if (OC.getCurrentUser().uid === state.userId) { + if (getCurrentUser()?.uid === state.userId) { this.$store.dispatch('setStatusFromObject', { status: state.status, icon: state.icon, @@ -221,91 +173,12 @@ export default { </script> <style lang="scss" scoped> -.user-status-menu-item { - &__header { - display: flex !important; - flex-direction: column !important; - width: auto !important; - height: 44px * 1.5 !important; - padding: 10px 12px 5px 12px !important; - align-items: flex-start !important; - color: var(--color-main-text) !important; - - &:not([href]) { - height: var(--header-menu-item-height) !important; - color: var(--color-text-maxcontrast) !important; - cursor: default !important; - - & * { - cursor: default !important; - } - - &:hover { - background-color: transparent !important; - } - } - - &-content { - display: inline-flex !important; - font-weight: bold !important; - gap: 0 10px !important; - width: auto; - - &-displayname { - width: auto; - } - - &-placeholder { - width: 16px !important; - height: 24px !important; - margin-right: 10px !important; - visibility: hidden !important; - } - } - - span { - color: var(--color-text-maxcontrast) !important; - } - } - - &__toggle { - &-icon { - width: 16px; - height: 16px; - margin-right: 10px; - opacity: 1 !important; - background-size: 16px; - } - - // In dashboard - &--inline { - width: auto; - min-width: 44px; - height: 44px; - margin: 0; - border: 0; - border-radius: var(--border-radius-pill); - background-color: var(--color-background-translucent); - font-size: inherit; - font-weight: normal; - - -webkit-backdrop-filter: var(--background-blur); - backdrop-filter: var(--background-blur); - - &:active, - &:hover, - &:focus { - background-color: var(--color-background-hover); - } - &:focus { - border: 2px solid var(--color-main-text)!important; - } - } - } +.user-status-icon { + width: 20px; + height: 20px; + margin: calc((var(--default-clickable-area) - 20px) / 2); // 20px icon size + opacity: 1 !important; + background-size: 20px; + vertical-align: middle !important; } - -li { - list-style-type: none; -} - </style> diff --git a/apps/user_status/src/components/ClearAtSelect.vue b/apps/user_status/src/components/ClearAtSelect.vue index 09e0068f87f..91b816dc04a 100644 --- a/apps/user_status/src/components/ClearAtSelect.vue +++ b/apps/user_status/src/components/ClearAtSelect.vue @@ -1,46 +1,33 @@ <!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> <div class="clear-at-select"> - <span class="clear-at-select__label"> - {{ $t('user_status', 'Clear status message after') }} - </span> - <Multiselect label="label" - :value="option" + <label class="clear-at-select__label" for="clearStatus"> + {{ $t('user_status', 'Clear status after') }} + </label> + <NcSelect input-id="clearStatus" + class="clear-at-select__select" :options="options" - open-direction="top" - @select="select" /> + :value="option" + :clearable="false" + placement="top" + label-outside + @option:selected="select" /> </div> </template> <script> -import Multiselect from '@nextcloud/vue/dist/Components/Multiselect' -import { getAllClearAtOptions } from '../services/clearAtOptionsService' -import { clearAtFilter } from '../filters/clearAtFilter' +import NcSelect from '@nextcloud/vue/components/NcSelect' +import { getAllClearAtOptions } from '../services/clearAtOptionsService.js' +import { clearAtFilter } from '../filters/clearAtFilter.js' export default { name: 'ClearAtSelect', components: { - Multiselect, + NcSelect, }, props: { clearAt: { @@ -86,16 +73,13 @@ export default { <style lang="scss" scoped> .clear-at-select { display: flex; - margin-bottom: 10px; + gap: calc(2 * var(--default-grid-baseline)); align-items: center; + margin-block: 0 calc(2 * var(--default-grid-baseline)); - &__label { - margin-right: 10px; - } - - .multiselect { + &__select { flex-grow: 1; - min-width: 130px; + min-width: 215px; } } </style> diff --git a/apps/user_status/src/components/CustomMessageInput.vue b/apps/user_status/src/components/CustomMessageInput.vue index 88956e6871b..fb129281430 100644 --- a/apps/user_status/src/components/CustomMessageInput.vue +++ b/apps/user_status/src/components/CustomMessageInput.vue @@ -1,43 +1,49 @@ <!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> - <form class="custom-input__form" - @submit.prevent> - <input ref="input" - maxlength="80" - :disabled="disabled" - :placeholder="$t('user_status', 'What is your status?')" - type="text" - :value="message" - @change="change" - @keyup="change" - @paste="change" - @keyup.enter="submit"> - </form> + <div class="custom-input" role="group"> + <NcEmojiPicker container=".custom-input" @select="setIcon"> + <NcButton type="tertiary" + :aria-label="t('user_status', 'Emoji for your status message')"> + <template #icon> + {{ visibleIcon }} + </template> + </NcButton> + </NcEmojiPicker> + <div class="custom-input__container"> + <NcTextField ref="input" + maxlength="80" + :disabled="disabled" + :placeholder="t('user_status', 'What is your status?')" + :value="message" + type="text" + :label="t('user_status', 'What is your status?')" + @input="onChange" /> + </div> + </div> </template> <script> +import NcButton from '@nextcloud/vue/components/NcButton' +import NcEmojiPicker from '@nextcloud/vue/components/NcEmojiPicker' +import NcTextField from '@nextcloud/vue/components/NcTextField' + export default { name: 'CustomMessageInput', + + components: { + NcTextField, + NcButton, + NcEmojiPicker, + }, + props: { + icon: { + type: String, + default: '😀', + }, message: { type: String, required: true, @@ -48,6 +54,23 @@ export default { default: false, }, }, + + emits: [ + 'change', + 'select-icon', + ], + + computed: { + /** + * Returns the user-set icon or a smiley in case no icon is set + * + * @return {string} + */ + visibleIcon() { + return this.icon || '😀' + }, + }, + methods: { focus() { this.$refs.input.focus() @@ -58,24 +81,26 @@ export default { * * @param {Event} event The Change Event */ - change(event) { + onChange(event) { this.$emit('change', event.target.value) }, - submit(event) { - this.$emit('submit', event.target.value) + setIcon(icon) { + this.$emit('select-icon', icon) }, }, } </script> <style lang="scss" scoped> -.custom-input__form { - flex-grow: 1; +.custom-input { + display: flex; + align-items: flex-end; + gap: var(--default-grid-baseline); + width: 100%; - input { + &__container { width: 100%; - border-radius: 0 var(--border-radius) var(--border-radius) 0; } } </style> diff --git a/apps/user_status/src/components/OnlineStatusSelect.vue b/apps/user_status/src/components/OnlineStatusSelect.vue index d9ce249ad13..0abcc8d68e6 100644 --- a/apps/user_status/src/components/OnlineStatusSelect.vue +++ b/apps/user_status/src/components/OnlineStatusSelect.vue @@ -1,33 +1,19 @@ <!-- - - @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com> - - - - @author John Molakvoæ <skjnldsv@protonmail.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> <div class="user-status-online-select"> <input :id="id" :checked="checked" - class="user-status-online-select__input" + class="hidden-visually user-status-online-select__input" type="radio" name="user-status-online" @change="onChange"> - <label :for="id" :class="icon" class="user-status-online-select__label"> + <label :for="id" class="user-status-online-select__label"> + <NcUserStatusIcon :status="type" + class="user-status-online-select__icon" + aria-hidden="true" /> {{ label }} <em class="user-status-online-select__subline">{{ subline }}</em> </label> @@ -35,18 +21,20 @@ </template> <script> +import NcUserStatusIcon from '@nextcloud/vue/components/NcUserStatusIcon' + export default { name: 'OnlineStatusSelect', + components: { + NcUserStatusIcon, + }, + props: { checked: { type: Boolean, default: false, }, - icon: { - type: String, - required: true, - }, type: { type: String, required: true, @@ -76,41 +64,42 @@ export default { </script> <style lang="scss" scoped> -$icon-size: 24px; -$label-padding: 8px; - .user-status-online-select { - // Inputs are here for keyboard navigation, they are not visually visible - &__input { - position: absolute; - top: auto; - left: -10000px; - overflow: hidden; - width: 1px; - height: 1px; - } - &__label { - display: block; - margin: $label-padding; - padding: $label-padding; - padding-left: $icon-size + $label-padding * 2; - border: 2px solid var(--color-main-background); + box-sizing: inherit; + display: grid; + grid-template-columns: var(--default-clickable-area) 1fr 2fr; + align-items: center; + gap: var(--default-grid-baseline); + min-height: var(--default-clickable-area); + padding: var(--default-grid-baseline); border-radius: var(--border-radius-large); background-color: var(--color-background-hover); - background-position: $label-padding center; - background-size: $icon-size; - span, - & { + &, & * { cursor: pointer; } + + &:hover { + background-color: var(--color-background-dark); + } + } + + &__icon { + flex-shrink: 0; + max-width: 34px; + max-height: 100%; + } + + &__input:checked + &__label { + outline: 2px solid var(--color-main-text); + background-color: var(--color-background-dark); + box-shadow: 0 0 0 4px var(--color-main-background); } - &__input:checked + &__label, - &__input:focus + &__label, - &__label:hover { - border-color: var(--color-primary); + &__input:focus-visible + &__label { + outline: 2px solid var(--color-primary-element) !important; + background-color: var(--color-background-dark); } &__subline { @@ -118,5 +107,4 @@ $label-padding: 8px; color: var(--color-text-lighter); } } - </style> diff --git a/apps/user_status/src/components/PredefinedStatus.vue b/apps/user_status/src/components/PredefinedStatus.vue index f8d5fe26be4..b12892d4add 100644 --- a/apps/user_status/src/components/PredefinedStatus.vue +++ b/apps/user_status/src/components/PredefinedStatus.vue @@ -1,43 +1,31 @@ <!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> - <div class="predefined-status" - tabindex="0" - @keyup.enter="select" - @keyup.space="select" - @click="select"> - <span class="predefined-status__icon"> - {{ icon }} - </span> - <span class="predefined-status__message"> - {{ message }} - </span> - <span class="predefined-status__clear-at"> - {{ clearAt | clearAtFilter }} - </span> - </div> + <li class="predefined-status"> + <input :id="id" + class="hidden-visually predefined-status__input" + type="radio" + name="predefined-status" + :checked="selected" + @change="select"> + <label class="predefined-status__label" :for="id"> + <span aria-hidden="true" class="predefined-status__label--icon"> + {{ icon }} + </span> + <span class="predefined-status__label--message"> + {{ message }} + </span> + <span class="predefined-status__label--clear-at"> + {{ clearAt | clearAtFilter }} + </span> + </label> + </li> </template> <script> -import { clearAtFilter } from '../filters/clearAtFilter' +import { clearAtFilter } from '../filters/clearAtFilter.js' export default { name: 'PredefinedStatus', @@ -62,6 +50,16 @@ export default { required: false, default: null, }, + selected: { + type: Boolean, + required: false, + default: false, + }, + }, + computed: { + id() { + return `user-status-predefined-status-${this.messageId}` + }, }, methods: { /** @@ -76,35 +74,55 @@ export default { <style lang="scss" scoped> .predefined-status { - display: flex; - flex-wrap: nowrap; - justify-content: flex-start; - flex-basis: 100%; - border-radius: var(--border-radius); - align-items: center; - min-height: 44px; + &__label { + display: flex; + flex-wrap: nowrap; + justify-content: flex-start; + flex-basis: 100%; + border-radius: var(--border-radius); + align-items: center; + min-height: var(--default-clickable-area); + padding-inline: var(--default-grid-baseline); - &:hover, - &:focus { - background-color: var(--color-background-hover); - } + &, & * { + cursor: pointer; + } - &__icon { - flex-basis: 40px; - text-align: center; - } + &:hover { + background-color: var(--color-background-dark); + } - &__message { - font-weight: bold; - padding: 0 6px; - } + &--icon { + flex-basis: var(--default-clickable-area); + text-align: center; + } + + &--message { + font-weight: bold; + padding: 0 6px; + } - &__clear-at { - opacity: .7; + &--clear-at { + color: var(--color-text-maxcontrast); - &::before { - content: ' - '; + &::before { + content: ' – '; + } } } + + &__input:checked + &__label, + &__label:active { + outline: 2px solid var(--color-main-text); + box-shadow: 0 0 0 4px var(--color-main-background); + background-color: var(--color-background-dark); + border-radius: var(--border-radius-large); + } + + &__input:focus-visible + &__label { + outline: 2px solid var(--color-primary-element) !important; + background-color: var(--color-background-dark); + border-radius: var(--border-radius-large); + } } </style> diff --git a/apps/user_status/src/components/PredefinedStatusesList.vue b/apps/user_status/src/components/PredefinedStatusesList.vue index cff03289715..cdf359dce76 100644 --- a/apps/user_status/src/components/PredefinedStatusesList.vue +++ b/apps/user_status/src/components/PredefinedStatusesList.vue @@ -1,35 +1,21 @@ <!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> - <div v-if="hasLoaded" - class="predefined-statuses-list"> + <ul v-if="statusesHaveLoaded" + class="predefined-statuses-list" + :aria-label="t('user_status', 'Predefined statuses')"> <PredefinedStatus v-for="status in predefinedStatuses" :key="status.id" :message-id="status.id" :icon="status.icon" :message="status.message" :clear-at="status.clearAt" + :selected="lastSelected === status.id" @select="selectStatus(status)" /> - </div> + </ul> <div v-else class="predefined-statuses-list"> <div class="icon icon-loading-small" /> @@ -37,32 +23,41 @@ </template> <script> -import PredefinedStatus from './PredefinedStatus' -import { mapState } from 'vuex' +import PredefinedStatus from './PredefinedStatus.vue' +import { mapGetters, mapState } from 'vuex' export default { name: 'PredefinedStatusesList', components: { PredefinedStatus, }, + data() { + return { + lastSelected: null, + } + }, computed: { ...mapState({ predefinedStatuses: state => state.predefinedStatuses.predefinedStatuses, + messageId: state => state.userStatus.messageId, }), - /** - * Indicator whether the predefined statuses have already been loaded - * - * @return {boolean} - */ - hasLoaded() { - return this.predefinedStatuses.length > 0 - }, + ...mapGetters(['statusesHaveLoaded']), }, + + watch: { + messageId: { + immediate: true, + handler() { + this.lastSelected = this.messageId + }, + }, + }, + /** * Loads all predefined statuses from the server * when this component is mounted */ - mounted() { + created() { this.$store.dispatch('loadAllPredefinedStatuses') }, methods: { @@ -72,6 +67,7 @@ export default { * @param {object} status The selected status */ selectStatus(status) { + this.lastSelected = status.id this.$emit('select-status', status) }, }, @@ -82,6 +78,7 @@ export default { .predefined-statuses-list { display: flex; flex-direction: column; - margin-bottom: 10px; + gap: var(--default-grid-baseline); + margin-block: 0 calc(2 * var(--default-grid-baseline)); } </style> diff --git a/apps/user_status/src/components/PreviousStatus.vue b/apps/user_status/src/components/PreviousStatus.vue new file mode 100644 index 00000000000..58d6ebd294b --- /dev/null +++ b/apps/user_status/src/components/PreviousStatus.vue @@ -0,0 +1,106 @@ +<!-- + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> +<template> + <div class="predefined-status backup-status" + tabindex="0" + @keyup.enter="select" + @keyup.space="select" + @click="select"> + <span class="predefined-status__icon"> + {{ icon }} + </span> + <span class="predefined-status__message"> + {{ message }} + </span> + <span class="predefined-status__clear-at"> + {{ $t('user_status', 'Previously set') }} + </span> + + <div class="backup-status__reset-button"> + <NcButton @click="select"> + {{ $t('user_status', 'Reset status') }} + </NcButton> + </div> + </div> +</template> + +<script> +import NcButton from '@nextcloud/vue/components/NcButton' + +export default { + name: 'PreviousStatus', + + components: { + NcButton, + }, + + props: { + icon: { + type: [String, null], + required: true, + }, + message: { + type: String, + required: true, + }, + }, + methods: { + /** + * Emits an event when the user clicks the row + */ + select() { + this.$emit('select') + }, + }, +} +</script> + +<style lang="scss" scoped> +.predefined-status { + display: flex; + flex-wrap: nowrap; + justify-content: flex-start; + flex-basis: 100%; + border-radius: var(--border-radius); + align-items: center; + min-height: var(--default-clickable-area); + padding-inline: var(--default-grid-baseline); + + &:hover, + &:focus { + background-color: var(--color-background-hover); + } + + &:active{ + background-color: var(--color-background-dark); + } + + &__icon { + flex-basis: var(--default-clickable-area); + text-align: center; + } + + &__message { + font-weight: bold; + padding: 0 6px; + } + + &__clear-at { + color: var(--color-text-maxcontrast); + + &::before { + content: ' – '; + } + } +} + +.backup-status { + &__reset-button { + justify-content: flex-end; + display: flex; + flex-grow: 1; + } +} +</style> diff --git a/apps/user_status/src/components/SetStatusModal.vue b/apps/user_status/src/components/SetStatusModal.vue index df6858ca6ff..8624ed19e94 100644 --- a/apps/user_status/src/components/SetStatusModal.vue +++ b/apps/user_status/src/components/SetStatusModal.vue @@ -1,34 +1,22 @@ <!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> + - SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + - SPDX-License-Identifier: AGPL-3.0-or-later +--> <template> - <Modal size="normal" - :title="$t('user_status', 'Set status')" + <NcModal size="normal" + label-id="user_status-set-dialog" + dark + :set-return-focus="setReturnFocus" @close="closeModal"> <div class="set-status-modal"> <!-- Status selector --> - <div class="set-status-modal__header"> - <h3>{{ $t('user_status', 'Online status') }}</h3> - </div> - <div class="set-status-modal__online-status"> + <h2 id="user_status-set-dialog" class="set-status-modal__header"> + {{ $t('user_status', 'Online status') }} + </h2> + <div class="set-status-modal__online-status" + role="radiogroup" + :aria-label="$t('user_status', 'Online status')"> <OnlineStatusSelect v-for="status in statuses" :key="status.type" v-bind="status" @@ -36,55 +24,69 @@ @select="changeStatus" /> </div> - <!-- Status message --> - <div class="set-status-modal__header"> - <h3>{{ $t('user_status', 'Status message') }}</h3> - </div> - <div class="set-status-modal__custom-input"> - <EmojiPicker @select="setIcon"> - <button class="custom-input__emoji-button"> - {{ visibleIcon }} - </button> - </EmojiPicker> - <CustomMessageInput ref="customMessageInput" - :message="message" - @change="setMessage" - @submit="saveStatus" /> - </div> - <PredefinedStatusesList @select-status="selectPredefinedMessage" /> - <ClearAtSelect :clear-at="clearAt" - @select-clear-at="setClearAt" /> - <div class="status-buttons"> - <ButtonVue wide="true" - type="tertiary" - :text="$t('user_status', 'Clear status message')" - :disabled="isSavingStatus" - @click="clearStatus"> - {{ $t('user_status', 'Clear status message') }} - </ButtonVue> - <ButtonVue wide="true" - type="primary" - :text="$t('user_status', 'Set status message')" - :disabled="isSavingStatus" - @click="saveStatus"> - {{ $t('user_status', 'Set status message') }} - </ButtonVue> - </div> + <!-- Status message form --> + <form @submit.prevent="saveStatus" @reset="clearStatus"> + <h3 class="set-status-modal__header"> + {{ $t('user_status', 'Status message') }} + </h3> + <div class="set-status-modal__custom-input"> + <CustomMessageInput ref="customMessageInput" + :icon="icon" + :message="editedMessage" + @change="setMessage" + @select-icon="setIcon" /> + <NcButton v-if="messageId === 'vacationing'" + :href="absencePageUrl" + target="_blank" + type="secondary" + :aria-label="$t('user_status', 'Set absence period')"> + {{ $t('user_status', 'Set absence period and replacement') + ' ↗' }} + </NcButton> + </div> + <div v-if="hasBackupStatus" + class="set-status-modal__automation-hint"> + {{ $t('user_status', 'Your status was set automatically') }} + </div> + <PreviousStatus v-if="hasBackupStatus" + :icon="backupIcon" + :message="backupMessage" + @select="revertBackupFromServer" /> + <PredefinedStatusesList @select-status="selectPredefinedMessage" /> + <ClearAtSelect :clear-at="clearAt" + @select-clear-at="setClearAt" /> + <div class="status-buttons"> + <NcButton :wide="true" + type="tertiary" + native-type="reset" + :aria-label="$t('user_status', 'Clear status message')" + :disabled="isSavingStatus"> + {{ $t('user_status', 'Clear status message') }} + </NcButton> + <NcButton :wide="true" + type="primary" + native-type="submit" + :aria-label="$t('user_status', 'Set status message')" + :disabled="isSavingStatus"> + {{ $t('user_status', 'Set status message') }} + </NcButton> + </div> + </form> </div> - </Modal> + </NcModal> </template> <script> import { showError } from '@nextcloud/dialogs' -import EmojiPicker from '@nextcloud/vue/dist/Components/EmojiPicker' -import Modal from '@nextcloud/vue/dist/Components/Modal' -import ButtonVue from '@nextcloud/vue/dist/Components/Button' -import { getAllStatusOptions } from '../services/statusOptionsService' -import OnlineStatusMixin from '../mixins/OnlineStatusMixin' -import PredefinedStatusesList from './PredefinedStatusesList' -import CustomMessageInput from './CustomMessageInput' -import ClearAtSelect from './ClearAtSelect' -import OnlineStatusSelect from './OnlineStatusSelect' +import { generateUrl } from '@nextcloud/router' +import NcModal from '@nextcloud/vue/components/NcModal' +import NcButton from '@nextcloud/vue/components/NcButton' +import { getAllStatusOptions } from '../services/statusOptionsService.js' +import OnlineStatusMixin from '../mixins/OnlineStatusMixin.js' +import PredefinedStatusesList from './PredefinedStatusesList.vue' +import PreviousStatus from './PreviousStatus.vue' +import CustomMessageInput from './CustomMessageInput.vue' +import ClearAtSelect from './ClearAtSelect.vue' +import OnlineStatusSelect from './OnlineStatusSelect.vue' export default { name: 'SetStatusModal', @@ -92,32 +94,93 @@ export default { components: { ClearAtSelect, CustomMessageInput, - EmojiPicker, - Modal, + NcModal, OnlineStatusSelect, PredefinedStatusesList, - ButtonVue, + PreviousStatus, + NcButton, }, mixins: [OnlineStatusMixin], + props: { + /** + * Whether the component should be rendered as a Dashboard Status or a User Menu Entries + * true = Dashboard Status + * false = User Menu Entries + */ + inline: { + type: Boolean, + default: false, + }, + }, + data() { return { clearAt: null, - icon: null, - message: '', - messageId: '', + editedMessage: '', + predefinedMessageId: null, isSavingStatus: false, statuses: getAllStatusOptions(), } }, + computed: { - /** - * Returns the user-set icon or a smiley in case no icon is set - * - * @return {string} - */ - visibleIcon() { - return this.icon || '😀' + messageId() { + return this.$store.state.userStatus.messageId + }, + icon() { + return this.$store.state.userStatus.icon + }, + message() { + return this.$store.state.userStatus.message || '' + }, + hasBackupStatus() { + return this.messageId && (this.backupIcon || this.backupMessage) + }, + backupIcon() { + return this.$store.state.userBackupStatus.icon || '' + }, + backupMessage() { + return this.$store.state.userBackupStatus.message || '' + }, + + absencePageUrl() { + return generateUrl('settings/user/availability#absence') + }, + + resetButtonText() { + if (this.backupIcon && this.backupMessage) { + return this.$t('user_status', 'Reset status to "{icon} {message}"', { + icon: this.backupIcon, + message: this.backupMessage, + }) + } else if (this.backupMessage) { + return this.$t('user_status', 'Reset status to "{message}"', { + message: this.backupMessage, + }) + } else if (this.backupIcon) { + return this.$t('user_status', 'Reset status to "{icon}"', { + icon: this.backupIcon, + }) + } + + return this.$t('user_status', 'Reset status') + }, + + setReturnFocus() { + if (this.inline) { + return undefined + } + return document.querySelector('[aria-controls="header-menu-user-menu"]') ?? undefined + }, + }, + + watch: { + message: { + immediate: true, + handler(newValue) { + this.editedMessage = newValue + }, }, }, @@ -125,10 +188,9 @@ export default { * Loads the current status when a user opens dialog */ mounted() { - this.messageId = this.$store.state.userStatus.messageId - this.icon = this.$store.state.userStatus.icon - this.message = this.$store.state.userStatus.message || '' + this.$store.dispatch('fetchBackupFromServer') + this.predefinedMessageId = this.$store.state.userStatus.messageId if (this.$store.state.userStatus.clearAt !== null) { this.clearAt = { type: '_time', @@ -149,8 +211,12 @@ export default { * @param {string} icon The new icon */ setIcon(icon) { - this.messageId = null - this.icon = icon + this.predefinedMessageId = null + this.$store.dispatch('setCustomMessage', { + message: this.message, + icon, + clearAt: this.clearAt, + }) this.$nextTick(() => { this.$refs.customMessageInput.focus() }) @@ -161,8 +227,8 @@ export default { * @param {string} message The new message */ setMessage(message) { - this.messageId = null - this.message = message + this.predefinedMessageId = null + this.editedMessage = message }, /** * Sets a new clearAt value @@ -178,10 +244,12 @@ export default { * @param {object} status The predefined status object */ selectPredefinedMessage(status) { - this.messageId = status.id + this.predefinedMessageId = status.id this.clearAt = status.clearAt - this.icon = status.icon - this.message = status.message + this.$store.dispatch('setPredefinedMessage', { + messageId: status.id, + clearAt: status.clearAt, + }) }, /** * Saves the status and closes the @@ -196,15 +264,15 @@ export default { try { this.isSavingStatus = true - if (this.messageId !== undefined && this.messageId !== null) { - await this.$store.dispatch('setPredefinedMessage', { - messageId: this.messageId, + if (this.predefinedMessageId === null) { + await this.$store.dispatch('setCustomMessage', { + message: this.editedMessage, + icon: this.icon, clearAt: this.clearAt, }) } else { - await this.$store.dispatch('setCustomMessage', { - message: this.message, - icon: this.icon, + this.$store.dispatch('setPredefinedMessage', { + messageId: this.predefinedMessageId, clearAt: this.clearAt, }) } @@ -235,8 +303,30 @@ export default { } this.isSavingStatus = false + this.predefinedMessageId = null this.closeModal() }, + /** + * + * @return {Promise<void>} + */ + async revertBackupFromServer() { + try { + this.isSavingStatus = true + + await this.$store.dispatch('revertBackupFromServer', { + messageId: this.messageId, + }) + } catch (err) { + showError(this.$t('user_status', 'There was an error reverting the status')) + console.debug(err) + this.isSavingStatus = false + return + } + + this.isSavingStatus = false + this.predefinedMessageId = this.$store.state.userStatus?.messageId + }, }, } </script> @@ -246,38 +336,48 @@ export default { .set-status-modal { padding: 8px 20px 20px 20px; + &, & * { + box-sizing: border-box; + } + &__header { + font-size: 21px; text-align: center; - font-weight: bold; + height: fit-content; + min-height: var(--default-clickable-area); + line-height: var(--default-clickable-area); + overflow-wrap: break-word; + margin-block: 0 calc(2 * var(--default-grid-baseline)); } &__online-status { - display: grid; - // Space between the two sections - margin-bottom: 40px; - grid-template-columns: 1fr 1fr; + display: flex; + flex-direction: column; + gap: calc(2 * var(--default-grid-baseline)); + margin-block: 0 calc(2 * var(--default-grid-baseline)); } &__custom-input { display: flex; + flex-direction: column; + align-items: center; + gap: var(--default-grid-baseline); width: 100%; - margin-bottom: 10px; - - .custom-input__emoji-button { - flex-basis: 40px; - flex-grow: 0; - width: 40px; - height: 34px; - margin-right: 0; - border-right: none; - border-radius: var(--border-radius) 0 0 var(--border-radius); - } + padding-inline-start: var(--default-grid-baseline); + margin-block: 0 calc(2 * var(--default-grid-baseline)); + } + + &__automation-hint { + display: flex; + width: 100%; + margin-block: 0 calc(2 * var(--default-grid-baseline)); + color: var(--color-text-maxcontrast); } .status-buttons { display: flex; padding: 3px; - padding-left:0; + padding-inline-start:0; gap: 3px; } } diff --git a/apps/user_status/src/dashboard.js b/apps/user_status/src/dashboard.js deleted file mode 100644 index 9c3d94151d0..00000000000 --- a/apps/user_status/src/dashboard.js +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ - -import Vue from 'vue' -import { getRequestToken } from '@nextcloud/auth' -import { translate, translatePlural } from '@nextcloud/l10n' -import Dashboard from './views/Dashboard' - -// eslint-disable-next-line camelcase -__webpack_nonce__ = btoa(getRequestToken()) - -Vue.prototype.t = translate -Vue.prototype.n = translatePlural -Vue.prototype.OC = OC -Vue.prototype.OCA = OCA - -document.addEventListener('DOMContentLoaded', function() { - OCA.Dashboard.register('user_status', (el) => { - const View = Vue.extend(Dashboard) - new View({ - propsData: {}, - }).$mount(el) - }) - -}) diff --git a/apps/user_status/src/filters/clearAtFilter.js b/apps/user_status/src/filters/clearAtFilter.js index 9a99b9ec69f..5f62385a978 100644 --- a/apps/user_status/src/filters/clearAtFilter.js +++ b/apps/user_status/src/filters/clearAtFilter.js @@ -1,28 +1,11 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import { translate as t } from '@nextcloud/l10n' import moment from '@nextcloud/moment' -import { dateFactory } from '../services/dateService' +import { dateFactory } from '../services/dateService.js' /** * Formats a clearAt object to be human readable diff --git a/apps/user_status/src/menu.js b/apps/user_status/src/menu.js index c8d007d98a0..34e5e6eabb1 100644 --- a/apps/user_status/src/menu.js +++ b/apps/user_status/src/menu.js @@ -1,66 +1,38 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author John Molakvoæ <skjnldsv@protonmail.com> - * @author Julius Härtl <jus@bitgrid.net> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ +import { getCSPNonce } from '@nextcloud/auth' +import { subscribe } from '@nextcloud/event-bus' import Vue from 'vue' -import { getRequestToken } from '@nextcloud/auth' -import UserStatus from './UserStatus' -import store from './store' -import Avatar from '@nextcloud/vue/dist/Components/Avatar' -import { loadState } from '@nextcloud/initial-state' + +import UserStatus from './UserStatus.vue' +import store from './store/index.js' // eslint-disable-next-line camelcase -__webpack_nonce__ = btoa(getRequestToken()) +__webpack_nonce__ = getCSPNonce() Vue.prototype.t = t Vue.prototype.$t = t -const avatarDiv = document.getElementById('avatardiv-menu') -const userStatusData = loadState('user_status', 'status') -const propsData = { - preloadedUserStatus: { - message: userStatusData.message, - icon: userStatusData.icon, - status: userStatusData.status - }, - user: avatarDiv.dataset.user, - displayName: avatarDiv.dataset.displayname, - url: avatarDiv.dataset.avatar, - disableMenu: true, - disableTooltip: true, -} +const mountPoint = document.getElementById('user_status-menu-entry') -const AvatarInMenu = Vue.extend(Avatar) -new AvatarInMenu({ propsData }).$mount('#avatardiv-menu') +const mountMenuEntry = () => { + const mountPoint = document.getElementById('user_status-menu-entry') + // eslint-disable-next-line no-new + new Vue({ + el: mountPoint, + render: h => h(UserStatus), + store, + }) +} -// Register settings menu entry -export default new Vue({ - el: 'li[data-id="user_status-menuitem"]', - // eslint-disable-next-line vue/match-component-file-name - name: 'UserStatusRoot', - render: h => h(UserStatus), - store, -}) +if (mountPoint) { + mountMenuEntry() +} else { + subscribe('core:user-menu:mounted', mountMenuEntry) +} // Register dashboard status document.addEventListener('DOMContentLoaded', function() { diff --git a/apps/user_status/src/mixins/OnlineStatusMixin.js b/apps/user_status/src/mixins/OnlineStatusMixin.js index d1e3a9111fa..5670eb4dc06 100644 --- a/apps/user_status/src/mixins/OnlineStatusMixin.js +++ b/apps/user_status/src/mixins/OnlineStatusMixin.js @@ -1,23 +1,6 @@ /** - * @copyright Copyright (c) 2020 John Molakvoæ <skjnldsv@protonmail.com> - * - * @author John Molakvoæ <skjnldsv@protonmail.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import { mapState } from 'vuex' @@ -52,6 +35,7 @@ export default { return this.$t('user_status', 'Online') case 'away': + case 'busy': return this.$t('user_status', 'Away') case 'dnd': @@ -67,30 +51,6 @@ export default { return this.$t('user_status', 'Set status') }, - - /** - * The status indicator icon - * - * @return {string | null} - */ - statusIcon() { - switch (this.statusType) { - case 'online': - return 'icon-user-status-online' - - case 'away': - return 'icon-user-status-away' - - case 'dnd': - return 'icon-user-status-dnd' - - case 'invisible': - case 'offline': - return 'icon-user-status-invisible' - } - - return '' - }, }, methods: { diff --git a/apps/user_status/src/services/clearAtOptionsService.js b/apps/user_status/src/services/clearAtOptionsService.js index 2849e6170f2..af0059bfb7f 100644 --- a/apps/user_status/src/services/clearAtOptionsService.js +++ b/apps/user_status/src/services/clearAtOptionsService.js @@ -1,23 +1,6 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import { translate as t } from '@nextcloud/l10n' diff --git a/apps/user_status/src/services/clearAtService.js b/apps/user_status/src/services/clearAtService.js index a02905b90c9..f23d267ad02 100644 --- a/apps/user_status/src/services/clearAtService.js +++ b/apps/user_status/src/services/clearAtService.js @@ -1,28 +1,11 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import { dateFactory, -} from './dateService' +} from './dateService.js' import moment from '@nextcloud/moment' /** diff --git a/apps/user_status/src/services/dateService.js b/apps/user_status/src/services/dateService.js index 2d110db5998..26a61d4a3e2 100644 --- a/apps/user_status/src/services/dateService.js +++ b/apps/user_status/src/services/dateService.js @@ -1,23 +1,6 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ const dateFactory = () => { diff --git a/apps/user_status/src/services/heartbeatService.js b/apps/user_status/src/services/heartbeatService.js index 2065cb6836a..fda1a1ffc9f 100644 --- a/apps/user_status/src/services/heartbeatService.js +++ b/apps/user_status/src/services/heartbeatService.js @@ -1,27 +1,10 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import HttpClient from '@nextcloud/axios' -import { generateUrl } from '@nextcloud/router' +import { generateOcsUrl } from '@nextcloud/router' /** * Sends a heartbeat @@ -30,11 +13,11 @@ import { generateUrl } from '@nextcloud/router' * @return {Promise<void>} */ const sendHeartbeat = async (isAway) => { - const url = generateUrl('/apps/user_status/heartbeat') + const url = generateOcsUrl('apps/user_status/api/v1/heartbeat?format=json') const response = await HttpClient.put(url, { status: isAway ? 'away' : 'online', }) - return response.data + return response.data.ocs.data } export { diff --git a/apps/user_status/src/services/predefinedStatusService.js b/apps/user_status/src/services/predefinedStatusService.js index 0a4cb55b573..b423c6e0cc4 100644 --- a/apps/user_status/src/services/predefinedStatusService.js +++ b/apps/user_status/src/services/predefinedStatusService.js @@ -1,23 +1,6 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import HttpClient from '@nextcloud/axios' diff --git a/apps/user_status/src/services/statusOptionsService.js b/apps/user_status/src/services/statusOptionsService.js index 7bd50bf7aff..6c23645e5be 100644 --- a/apps/user_status/src/services/statusOptionsService.js +++ b/apps/user_status/src/services/statusOptionsService.js @@ -1,24 +1,6 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Jan C. Borchardt <hey@jancborchardt.net> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import { translate as t } from '@nextcloud/l10n' @@ -32,22 +14,20 @@ const getAllStatusOptions = () => { return [{ type: 'online', label: t('user_status', 'Online'), - icon: 'icon-user-status-online', }, { type: 'away', label: t('user_status', 'Away'), - icon: 'icon-user-status-away', + }, { + type: 'busy', + label: t('user_status', 'Busy'), }, { type: 'dnd', label: t('user_status', 'Do not disturb'), subline: t('user_status', 'Mute all notifications'), - icon: 'icon-user-status-dnd', - }, { type: 'invisible', label: t('user_status', 'Invisible'), subline: t('user_status', 'Appear offline'), - icon: 'icon-user-status-invisible', }] } diff --git a/apps/user_status/src/services/statusService.js b/apps/user_status/src/services/statusService.js index f4bda930303..6504411c996 100644 --- a/apps/user_status/src/services/statusService.js +++ b/apps/user_status/src/services/statusService.js @@ -1,23 +1,6 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import HttpClient from '@nextcloud/axios' @@ -36,6 +19,19 @@ const fetchCurrentStatus = async () => { } /** + * Fetches the current user-status + * + * @param {string} userId Id of the user to fetch the status + * @return {Promise<object>} + */ +const fetchBackupStatus = async (userId) => { + const url = generateOcsUrl('apps/user_status/api/v1/statuses/{userId}', { userId: '_' + userId }) + const response = await HttpClient.get(url) + + return response.data.ocs.data +} + +/** * Sets the status * * @param {string} statusType The status (online / away / dnd / invisible) @@ -90,10 +86,25 @@ const clearMessage = async () => { await HttpClient.delete(url) } +/** + * Revert the automated status + * + * @param {string} messageId ID of the message to revert + * @return {Promise<object>} + */ +const revertToBackupStatus = async (messageId) => { + const url = generateOcsUrl('apps/user_status/api/v1/user_status/revert/{messageId}', { messageId }) + const response = await HttpClient.delete(url) + + return response.data.ocs.data +} + export { fetchCurrentStatus, + fetchBackupStatus, setStatus, setCustomMessage, setPredefinedMessage, clearMessage, + revertToBackupStatus, } diff --git a/apps/user_status/src/store/index.js b/apps/user_status/src/store/index.js index c2c270d14d8..d9cfe674165 100644 --- a/apps/user_status/src/store/index.js +++ b/apps/user_status/src/store/index.js @@ -1,29 +1,13 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import Vue from 'vue' import Vuex, { Store } from 'vuex' -import predefinedStatuses from './predefinedStatuses' -import userStatus from './userStatus' +import predefinedStatuses from './predefinedStatuses.js' +import userStatus from './userStatus.js' +import userBackupStatus from './userBackupStatus.js' Vue.use(Vuex) @@ -31,6 +15,7 @@ export default new Store({ modules: { predefinedStatuses, userStatus, + userBackupStatus, }, strict: true, }) diff --git a/apps/user_status/src/store/predefinedStatuses.js b/apps/user_status/src/store/predefinedStatuses.js index e41ba24f7dd..6d592ca627e 100644 --- a/apps/user_status/src/store/predefinedStatuses.js +++ b/apps/user_status/src/store/predefinedStatuses.js @@ -1,26 +1,9 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ -import { fetchAllPredefinedStatuses } from '../services/predefinedStatusService' +import { fetchAllPredefinedStatuses } from '../services/predefinedStatusService.js' const state = { predefinedStatuses: [], @@ -35,11 +18,15 @@ const mutations = { * @param {object} status The status to add */ addPredefinedStatus(state, status) { - state.predefinedStatuses.push(status) + state.predefinedStatuses = [...state.predefinedStatuses, status] }, } -const getters = {} +const getters = { + statusesHaveLoaded(state) { + return state.predefinedStatuses.length > 0 + }, +} const actions = { diff --git a/apps/user_status/src/store/userBackupStatus.js b/apps/user_status/src/store/userBackupStatus.js new file mode 100644 index 00000000000..78e5318de9d --- /dev/null +++ b/apps/user_status/src/store/userBackupStatus.js @@ -0,0 +1,102 @@ +/** + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +import { + fetchBackupStatus, + revertToBackupStatus, +} from '../services/statusService.js' +import { getCurrentUser } from '@nextcloud/auth' +import { emit } from '@nextcloud/event-bus' + +const state = { + // Status (online / away / dnd / invisible / offline) + status: null, + // Whether the status is user-defined + statusIsUserDefined: null, + // A custom message set by the user + message: null, + // The icon selected by the user + icon: null, + // When to automatically clean the status + clearAt: null, + // Whether the message is predefined + // (and can automatically be translated by Nextcloud) + messageIsPredefined: null, + // The id of the message in case it's predefined + messageId: null, +} + +const mutations = { + /** + * Loads the status from initial state + * + * @param {object} state The Vuex state + * @param {object} data The destructuring object + * @param {string} data.status The status type + * @param {boolean} data.statusIsUserDefined Whether or not this status is user-defined + * @param {string} data.message The message + * @param {string} data.icon The icon + * @param {number} data.clearAt When to automatically clear the status + * @param {boolean} data.messageIsPredefined Whether or not the message is predefined + * @param {string} data.messageId The id of the predefined message + */ + loadBackupStatusFromServer(state, { status, statusIsUserDefined, message, icon, clearAt, messageIsPredefined, messageId }) { + state.status = status + state.message = message + state.icon = icon + + // Don't overwrite certain values if the refreshing comes in via short updates + // E.g. from talk participant list which only has the status, message and icon + if (typeof statusIsUserDefined !== 'undefined') { + state.statusIsUserDefined = statusIsUserDefined + } + if (typeof clearAt !== 'undefined') { + state.clearAt = clearAt + } + if (typeof messageIsPredefined !== 'undefined') { + state.messageIsPredefined = messageIsPredefined + } + if (typeof messageId !== 'undefined') { + state.messageId = messageId + } + }, +} + +const getters = {} + +const actions = { + /** + * Re-fetches the status from the server + * + * @param {object} vuex The Vuex destructuring object + * @param {Function} vuex.commit The Vuex commit function + * @return {Promise<void>} + */ + async fetchBackupFromServer({ commit }) { + try { + const status = await fetchBackupStatus(getCurrentUser()?.uid) + commit('loadBackupStatusFromServer', status) + } catch (e) { + // Ignore missing user backup status + } + }, + + async revertBackupFromServer({ commit }, { messageId }) { + const status = await revertToBackupStatus(messageId) + if (status) { + commit('loadBackupStatusFromServer', {}) + commit('loadStatusFromServer', status) + emit('user_status:status.updated', { + status: status.status, + message: status.message, + icon: status.icon, + clearAt: status.clearAt, + userId: getCurrentUser()?.uid, + }) + } + }, +} + +export default { state, mutations, getters, actions } diff --git a/apps/user_status/src/store/userStatus.js b/apps/user_status/src/store/userStatus.js index c54fbe5040b..9bc86ab5062 100644 --- a/apps/user_status/src/store/userStatus.js +++ b/apps/user_status/src/store/userStatus.js @@ -1,23 +1,6 @@ /** - * @copyright Copyright (c) 2020 Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license AGPL-3.0-or-later - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ import { @@ -26,16 +9,16 @@ import { setPredefinedMessage, setCustomMessage, clearMessage, -} from '../services/statusService' +} from '../services/statusService.js' import { loadState } from '@nextcloud/initial-state' import { getCurrentUser } from '@nextcloud/auth' -import { getTimestampForClearAt } from '../services/clearAtService' +import { getTimestampForClearAt } from '../services/clearAtService.js' import { emit } from '@nextcloud/event-bus' const state = { // Status (online / away / dnd / invisible / offline) status: null, - // Whether or not the status is user-defined + // Whether the status is user-defined statusIsUserDefined: null, // A custom message set by the user message: null, @@ -43,7 +26,7 @@ const state = { icon: null, // When to automatically clean the status clearAt: null, - // Whether or not the message is predefined + // Whether the message is predefined // (and can automatically be translated by Nextcloud) messageIsPredefined: null, // The id of the message in case it's predefined @@ -130,12 +113,23 @@ const mutations = { */ loadStatusFromServer(state, { status, statusIsUserDefined, message, icon, clearAt, messageIsPredefined, messageId }) { state.status = status - state.statusIsUserDefined = statusIsUserDefined state.message = message state.icon = icon - state.clearAt = clearAt - state.messageIsPredefined = messageIsPredefined - state.messageId = messageId + + // Don't overwrite certain values if the refreshing comes in via short updates + // E.g. from talk participant list which only has the status, message and icon + if (typeof statusIsUserDefined !== 'undefined') { + state.statusIsUserDefined = statusIsUserDefined + } + if (typeof clearAt !== 'undefined') { + state.clearAt = clearAt + } + if (typeof messageIsPredefined !== 'undefined') { + state.messageIsPredefined = messageIsPredefined + } + if (typeof messageId !== 'undefined') { + state.messageId = messageId + } }, } diff --git a/apps/user_status/src/views/Dashboard.vue b/apps/user_status/src/views/Dashboard.vue deleted file mode 100644 index 629a28abeb5..00000000000 --- a/apps/user_status/src/views/Dashboard.vue +++ /dev/null @@ -1,122 +0,0 @@ -<!-- - - @copyright Copyright (c) 2020 Georg Ehrke <oc.list@georgehrke.com> - - @author Georg Ehrke <oc.list@georgehrke.com> - - - - @license GNU AGPL version 3 or any later version - - - - This program is free software: you can redistribute it and/or modify - - it under the terms of the GNU Affero General Public License as - - published by the Free Software Foundation, either version 3 of the - - License, or (at your option) any later version. - - - - 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 - - along with this program. If not, see <http://www.gnu.org/licenses/>. - - - --> - -<template> - <DashboardWidget id="user-status_panel" - :items="items" - :loading="loading"> - <template #default="{ item }"> - <DashboardWidgetItem :main-text="item.mainText" - :sub-text="item.subText"> - <template #avatar> - <Avatar class="item-avatar" - :size="44" - :user="item.avatarUsername" - :display-name="item.mainText" - :show-user-status="false" - :show-user-status-compact="false" /> - </template> - </DashboardWidgetItem> - </template> - <template #empty-content> - <EmptyContent id="user_status-widget-empty-content" - icon="icon-user-status"> - {{ t('user_status', 'No recent status changes') }} - </EmptyContent> - </template> - </DashboardWidget> -</template> - -<script> -import { DashboardWidget, DashboardWidgetItem } from '@nextcloud/vue-dashboard' -import Avatar from '@nextcloud/vue/dist/Components/Avatar' -import EmptyContent from '@nextcloud/vue/dist/Components/EmptyContent' -import { loadState } from '@nextcloud/initial-state' -import moment from '@nextcloud/moment' - -export default { - name: 'Dashboard', - components: { - Avatar, - DashboardWidget, - DashboardWidgetItem, - EmptyContent, - }, - data() { - return { - statuses: [], - loading: true, - } - }, - computed: { - items() { - return this.statuses.map((item) => { - const icon = item.icon || '' - let message = item.message || '' - if (message === '') { - if (item.status === 'away') { - message = t('user_status', 'Away') - } - if (item.status === 'dnd') { - message = t('user_status', 'Do not disturb') - } - } - const status = item.icon !== '' ? `${icon} ${message}` : message - - let subText - if (item.icon === null && message === '' && item.timestamp === null) { - subText = '' - } else if (item.icon === null && message === '' && item.timestamp !== null) { - subText = moment(item.timestamp, 'X').fromNow() - } else if (item.timestamp !== null) { - subText = this.t('user_status', '{status}, {timestamp}', { - status, - timestamp: moment(item.timestamp, 'X').fromNow(), - }, null, { escape: false, sanitize: false }) - } else { - subText = status - } - - return { - mainText: item.displayName, - subText, - avatarUsername: item.userId, - } - }) - }, - }, - mounted() { - try { - this.statuses = loadState('user_status', 'dashboard_data') - this.loading = false - } catch (e) { - console.error(e) - } - }, -} -</script> - -<style lang="scss"> -#user_status-widget-empty-content { - text-align: center; - margin-top: 5vh; -} -</style> diff --git a/apps/user_status/tests/Integration/Service/StatusServiceIntegrationTest.php b/apps/user_status/tests/Integration/Service/StatusServiceIntegrationTest.php new file mode 100644 index 00000000000..8a21052b09f --- /dev/null +++ b/apps/user_status/tests/Integration/Service/StatusServiceIntegrationTest.php @@ -0,0 +1,196 @@ +<?php + +declare(strict_types=1); + +/** + * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +namespace OCA\UserStatus\Tests\Integration\Service; + +use OCA\UserStatus\Service\StatusService; +use OCP\AppFramework\Db\DoesNotExistException; +use OCP\IDBConnection; +use OCP\Server; +use OCP\UserStatus\IUserStatus; +use Test\TestCase; +use function sleep; +use function time; + +/** + * @group DB + */ +class StatusServiceIntegrationTest extends TestCase { + + private StatusService $service; + + protected function setUp(): void { + parent::setUp(); + + $this->service = Server::get(StatusService::class); + + $db = Server::get(IDBConnection::class); + $qb = $db->getQueryBuilder(); + $qb->delete('user_status')->executeStatement(); + } + + public function testNoStatusYet(): void { + $this->expectException(DoesNotExistException::class); + + $this->service->findByUserId('test123'); + } + + public function testCustomStatusMessageTimestamp(): void { + $before = time(); + $this->service->setCustomMessage( + 'test123', + '🍕', + 'Lunch', + null, + ); + $after = time(); + + $status = $this->service->findByUserId('test123'); + + self::assertSame('Lunch', $status->getCustomMessage()); + self::assertGreaterThanOrEqual($before, $status->getStatusMessageTimestamp()); + self::assertLessThanOrEqual($after, $status->getStatusMessageTimestamp()); + } + + public function testOnlineStatusKeepsMessageTimestamp(): void { + $this->service->setStatus( + 'test123', + IUserStatus::OFFLINE, + time() + 1000, + false, + ); + $this->service->setCustomMessage( + 'test123', + '🍕', + 'Lunch', + null, + ); + $timeAfterInsert = time(); + sleep(1); + $this->service->setStatus( + 'test123', + IUserStatus::ONLINE, + time() + 2000, + false, + ); + $status = $this->service->findByUserId('test123'); + + self::assertSame('Lunch', $status->getCustomMessage()); + self::assertLessThanOrEqual($timeAfterInsert, $status->getStatusMessageTimestamp()); + } + + public function testCreateRestoreBackupAutomatically(): void { + $this->service->setStatus( + 'test123', + IUserStatus::ONLINE, + null, + false, + ); + $this->service->setUserStatus( + 'test123', + IUserStatus::DND, + 'meeting', + true, + ); + + self::assertSame( + 'meeting', + $this->service->findByUserId('test123')->getMessageId(), + ); + self::assertSame( + IUserStatus::ONLINE, + $this->service->findByUserId('_test123')->getStatus(), + ); + + $revertedStatus = $this->service->revertUserStatus( + 'test123', + 'meeting', + ); + + self::assertNotNull($revertedStatus, 'Status should have been reverted'); + + try { + $this->service->findByUserId('_test123'); + $this->fail('Expected DoesNotExistException() to be thrown when finding backup status after reverting'); + } catch (DoesNotExistException) { + } + + self::assertSame( + IUserStatus::ONLINE, + $this->service->findByUserId('test123')->getStatus(), + ); + } + + public function testCallOverwritesMeetingStatus(): void { + $this->service->setStatus( + 'test123', + IUserStatus::ONLINE, + null, + false, + ); + $this->service->setUserStatus( + 'test123', + IUserStatus::BUSY, + IUserStatus::MESSAGE_CALENDAR_BUSY, + true, + ); + self::assertSame( + 'meeting', + $this->service->findByUserId('test123')->getMessageId(), + ); + + $this->service->setUserStatus( + 'test123', + IUserStatus::BUSY, + IUserStatus::MESSAGE_CALL, + true, + ); + self::assertSame( + IUserStatus::BUSY, + $this->service->findByUserId('test123')->getStatus(), + ); + + self::assertSame( + IUserStatus::MESSAGE_CALL, + $this->service->findByUserId('test123')->getMessageId(), + ); + } + + public function testOtherAutomationsDoNotOverwriteEachOther(): void { + $this->service->setStatus( + 'test123', + IUserStatus::ONLINE, + null, + false, + ); + $this->service->setUserStatus( + 'test123', + IUserStatus::DND, + IUserStatus::MESSAGE_AVAILABILITY, + true, + ); + self::assertSame( + 'availability', + $this->service->findByUserId('test123')->getMessageId(), + ); + + $nostatus = $this->service->setUserStatus( + 'test123', + IUserStatus::BUSY, + IUserStatus::MESSAGE_CALENDAR_BUSY, + true, + ); + + self::assertNull($nostatus); + self::assertSame( + IUserStatus::MESSAGE_AVAILABILITY, + $this->service->findByUserId('test123')->getMessageId(), + ); + } +} diff --git a/apps/user_status/tests/Unit/BackgroundJob/ClearOldStatusesBackgroundJobTest.php b/apps/user_status/tests/Unit/BackgroundJob/ClearOldStatusesBackgroundJobTest.php index 2cf9b7d1bd4..66142082343 100644 --- a/apps/user_status/tests/Unit/BackgroundJob/ClearOldStatusesBackgroundJobTest.php +++ b/apps/user_status/tests/Unit/BackgroundJob/ClearOldStatusesBackgroundJobTest.php @@ -3,44 +3,21 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\BackgroundJob; use OCA\UserStatus\BackgroundJob\ClearOldStatusesBackgroundJob; use OCA\UserStatus\Db\UserStatusMapper; use OCP\AppFramework\Utility\ITimeFactory; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class ClearOldStatusesBackgroundJobTest extends TestCase { - - /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ - private $time; - - /** @var UserStatusMapper|\PHPUnit\Framework\MockObject\MockObject */ - private $mapper; - - /** @var ClearOldStatusesBackgroundJob */ - private $job; + private ITimeFactory&MockObject $time; + private UserStatusMapper&MockObject $mapper; + private ClearOldStatusesBackgroundJob $job; protected function setUp(): void { parent::setUp(); @@ -51,9 +28,9 @@ class ClearOldStatusesBackgroundJobTest extends TestCase { $this->job = new ClearOldStatusesBackgroundJob($this->time, $this->mapper); } - public function testRun() { + public function testRun(): void { $this->mapper->expects($this->once()) - ->method('clearMessagesOlderThan') + ->method('clearOlderThanClearAt') ->with(1337); $this->mapper->expects($this->once()) ->method('clearStatusesOlderThan') diff --git a/apps/user_status/tests/Unit/CapabilitiesTest.php b/apps/user_status/tests/Unit/CapabilitiesTest.php index af36900d3bc..601fb207df4 100644 --- a/apps/user_status/tests/Unit/CapabilitiesTest.php +++ b/apps/user_status/tests/Unit/CapabilitiesTest.php @@ -3,66 +3,44 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests; use OCA\UserStatus\Capabilities; -use OCA\UserStatus\Service\EmojiService; +use OCP\IEmojiHelper; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class CapabilitiesTest extends TestCase { - - /** @var EmojiService|\PHPUnit\Framework\MockObject\MockObject */ - private $emojiService; - - /** @var Capabilities */ - private $capabilities; + private IEmojiHelper&MockObject $emojiHelper; + private Capabilities $capabilities; protected function setUp(): void { parent::setUp(); - $this->emojiService = $this->createMock(EmojiService::class); - $this->capabilities = new Capabilities($this->emojiService); + $this->emojiHelper = $this->createMock(IEmojiHelper::class); + $this->capabilities = new Capabilities($this->emojiHelper); } - /** - * @param bool $supportsEmojis - * - * @dataProvider getCapabilitiesDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('getCapabilitiesDataProvider')] public function testGetCapabilities(bool $supportsEmojis): void { - $this->emojiService->expects($this->once()) + $this->emojiHelper->expects($this->once()) ->method('doesPlatformSupportEmoji') ->willReturn($supportsEmojis); $this->assertEquals([ 'user_status' => [ 'enabled' => true, + 'restore' => true, 'supports_emoji' => $supportsEmojis, + 'supports_busy' => true, ] ], $this->capabilities->getCapabilities()); } - public function getCapabilitiesDataProvider(): array { + public static function getCapabilitiesDataProvider(): array { return [ [true], [false], diff --git a/apps/user_status/tests/Unit/Connector/UserStatusProviderTest.php b/apps/user_status/tests/Unit/Connector/UserStatusProviderTest.php index 2b126a7a5ea..df6c55488d5 100644 --- a/apps/user_status/tests/Unit/Connector/UserStatusProviderTest.php +++ b/apps/user_status/tests/Unit/Connector/UserStatusProviderTest.php @@ -3,40 +3,20 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Connector; use OCA\UserStatus\Connector\UserStatusProvider; use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Service\StatusService; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class UserStatusProviderTest extends TestCase { - - /** @var \PHPUnit\Framework\MockObject\MockObject */ - private $service; - - /** @var UserStatusProvider */ - private $provider; + private StatusService&MockObject $service; + private UserStatusProvider $provider; protected function setUp(): void { parent::setUp(); diff --git a/apps/user_status/tests/Unit/Connector/UserStatusTest.php b/apps/user_status/tests/Unit/Connector/UserStatusTest.php index 61b5d326287..fee9b4e4b89 100644 --- a/apps/user_status/tests/Unit/Connector/UserStatusTest.php +++ b/apps/user_status/tests/Unit/Connector/UserStatusTest.php @@ -3,34 +3,17 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Connector; use OCA\UserStatus\Connector\UserStatus; -use Test\TestCase; use OCA\UserStatus\Db; +use Test\TestCase; class UserStatusTest extends TestCase { - public function testUserStatus() { + public function testUserStatus(): void { $status = new Db\UserStatus(); $status->setUserId('user2'); $status->setStatus('away'); @@ -51,7 +34,7 @@ class UserStatusTest extends TestCase { $this->assertEquals('60000', $dateTime->format('U')); } - public function testUserStatusInvisible() { + public function testUserStatusInvisible(): void { $status = new Db\UserStatus(); $status->setUserId('user2'); $status->setStatus('invisible'); diff --git a/apps/user_status/tests/Unit/Controller/PredefinedStatusControllerTest.php b/apps/user_status/tests/Unit/Controller/PredefinedStatusControllerTest.php index 81ad3b8e390..0f96f41a524 100644 --- a/apps/user_status/tests/Unit/Controller/PredefinedStatusControllerTest.php +++ b/apps/user_status/tests/Unit/Controller/PredefinedStatusControllerTest.php @@ -3,40 +3,20 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Controller; use OCA\UserStatus\Controller\PredefinedStatusController; use OCA\UserStatus\Service\PredefinedStatusService; use OCP\IRequest; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class PredefinedStatusControllerTest extends TestCase { - - /** @var PredefinedStatusService|\PHPUnit\Framework\MockObject\MockObject */ - private $service; - - /** @var PredefinedStatusController */ - private $controller; + private PredefinedStatusService&MockObject $service; + private PredefinedStatusController $controller; protected function setUp(): void { parent::setUp(); @@ -44,11 +24,10 @@ class PredefinedStatusControllerTest extends TestCase { $request = $this->createMock(IRequest::class); $this->service = $this->createMock(PredefinedStatusService::class); - $this->controller = new PredefinedStatusController('user_status', $request, - $this->service); + $this->controller = new PredefinedStatusController('user_status', $request, $this->service); } - public function testFindAll() { + public function testFindAll(): void { $this->service->expects($this->once()) ->method('getDefaultStatuses') ->with() diff --git a/apps/user_status/tests/Unit/Controller/StatusesControllerTest.php b/apps/user_status/tests/Unit/Controller/StatusesControllerTest.php index 19c4bee076e..76d337879c3 100644 --- a/apps/user_status/tests/Unit/Controller/StatusesControllerTest.php +++ b/apps/user_status/tests/Unit/Controller/StatusesControllerTest.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Controller; @@ -31,15 +14,12 @@ use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\OCS\OCSNotFoundException; use OCP\IRequest; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class StatusesControllerTest extends TestCase { - - /** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */ - private $service; - - /** @var StatusesController */ - private $controller; + private StatusService&MockObject $service; + private StatusesController $controller; protected function setUp(): void { parent::setUp(); diff --git a/apps/user_status/tests/Unit/Controller/UserStatusControllerTest.php b/apps/user_status/tests/Unit/Controller/UserStatusControllerTest.php index 916f5447ea4..e99290319ed 100644 --- a/apps/user_status/tests/Unit/Controller/UserStatusControllerTest.php +++ b/apps/user_status/tests/Unit/Controller/UserStatusControllerTest.php @@ -3,29 +3,12 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Controller; +use OCA\DAV\CalDAV\Status\StatusService as CalendarStatusService; use OCA\UserStatus\Controller\UserStatusController; use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Exception\InvalidClearAtException; @@ -37,37 +20,41 @@ use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\OCS\OCSBadRequestException; use OCP\AppFramework\OCS\OCSNotFoundException; -use OCP\ILogger; use OCP\IRequest; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; use Throwable; class UserStatusControllerTest extends TestCase { - - /** @var ILogger|\PHPUnit\Framework\MockObject\MockObject */ - private $logger; - - /** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */ - private $service; - - /** @var UserStatusController */ - private $controller; + private LoggerInterface&MockObject $logger; + private StatusService&MockObject $statusService; + private CalendarStatusService&MockObject $calendarStatusService; + private UserStatusController $controller; protected function setUp(): void { parent::setUp(); $request = $this->createMock(IRequest::class); $userId = 'john.doe'; - $this->logger = $this->createMock(ILogger::class); - $this->service = $this->createMock(StatusService::class); - - $this->controller = new UserStatusController('user_status', $request, $userId, $this->logger, $this->service); + $this->logger = $this->createMock(LoggerInterface::class); + $this->statusService = $this->createMock(StatusService::class); + $this->calendarStatusService = $this->createMock(CalendarStatusService::class); + + $this->controller = new UserStatusController( + 'user_status', + $request, + $userId, + $this->logger, + $this->statusService, + $this->calendarStatusService, + ); } public function testGetStatus(): void { $userStatus = $this->getUserStatus(); - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('findByUserId') ->with('john.doe') ->willReturn($userStatus); @@ -86,7 +73,10 @@ class UserStatusControllerTest extends TestCase { } public function testGetStatusDoesNotExist(): void { - $this->service->expects($this->once()) + $this->calendarStatusService->expects(self::once()) + ->method('processCalendarStatus') + ->with('john.doe'); + $this->statusService->expects($this->once()) ->method('findByUserId') ->with('john.doe') ->willThrowException(new DoesNotExistException('')); @@ -97,37 +87,27 @@ class UserStatusControllerTest extends TestCase { $this->controller->getStatus(); } - /** - * @param string $statusType - * @param string|null $statusIcon - * @param string|null $message - * @param int|null $clearAt - * @param bool $expectSuccess - * @param bool $expectException - * @param Throwable|null $exception - * @param bool $expectLogger - * @param string|null $expectedLogMessage - * - * @dataProvider setStatusDataProvider - */ - public function testSetStatus(string $statusType, - ?string $statusIcon, - ?string $message, - ?int $clearAt, - bool $expectSuccess, - bool $expectException, - ?Throwable $exception, - bool $expectLogger, - ?string $expectedLogMessage): void { + #[\PHPUnit\Framework\Attributes\DataProvider('setStatusDataProvider')] + public function testSetStatus( + string $statusType, + ?string $statusIcon, + ?string $message, + ?int $clearAt, + bool $expectSuccess, + bool $expectException, + ?Throwable $exception, + bool $expectLogger, + ?string $expectedLogMessage, + ): void { $userStatus = $this->getUserStatus(); if ($expectException) { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('setStatus') ->with('john.doe', $statusType, null, true) ->willThrowException($exception); } else { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('setStatus') ->with('john.doe', $statusType, null, true) ->willReturn($userStatus); @@ -159,7 +139,7 @@ class UserStatusControllerTest extends TestCase { } } - public function setStatusDataProvider(): array { + public static function setStatusDataProvider(): array { return [ ['busy', '👨🏽💻', 'Busy developing the status feature', 500, true, false, null, false, null], ['busy', '👨🏽💻', 'Busy developing the status feature', 500, false, true, new InvalidStatusTypeException('Original exception message'), true, @@ -167,33 +147,25 @@ class UserStatusControllerTest extends TestCase { ]; } - /** - * @param string $messageId - * @param int|null $clearAt - * @param bool $expectSuccess - * @param bool $expectException - * @param Throwable|null $exception - * @param bool $expectLogger - * @param string|null $expectedLogMessage - * - * @dataProvider setPredefinedMessageDataProvider - */ - public function testSetPredefinedMessage(string $messageId, - ?int $clearAt, - bool $expectSuccess, - bool $expectException, - ?Throwable $exception, - bool $expectLogger, - ?string $expectedLogMessage): void { + #[\PHPUnit\Framework\Attributes\DataProvider('setPredefinedMessageDataProvider')] + public function testSetPredefinedMessage( + string $messageId, + ?int $clearAt, + bool $expectSuccess, + bool $expectException, + ?Throwable $exception, + bool $expectLogger, + ?string $expectedLogMessage, + ): void { $userStatus = $this->getUserStatus(); if ($expectException) { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('setPredefinedMessage') ->with('john.doe', $messageId, $clearAt) ->willThrowException($exception); } else { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('setPredefinedMessage') ->with('john.doe', $messageId, $clearAt) ->willReturn($userStatus); @@ -225,7 +197,7 @@ class UserStatusControllerTest extends TestCase { } } - public function setPredefinedMessageDataProvider(): array { + public static function setPredefinedMessageDataProvider(): array { return [ ['messageId-42', 500, true, false, null, false, null], ['messageId-42', 500, false, true, new InvalidClearAtException('Original exception message'), true, @@ -235,53 +207,43 @@ class UserStatusControllerTest extends TestCase { ]; } - /** - * @param string|null $statusIcon - * @param string $message - * @param int|null $clearAt - * @param bool $expectSuccess - * @param bool $expectException - * @param Throwable|null $exception - * @param bool $expectLogger - * @param string|null $expectedLogMessage - * @param bool $expectSuccessAsReset - * - * @dataProvider setCustomMessageDataProvider - */ - public function testSetCustomMessage(?string $statusIcon, - string $message, - ?int $clearAt, - bool $expectSuccess, - bool $expectException, - ?Throwable $exception, - bool $expectLogger, - ?string $expectedLogMessage, - bool $expectSuccessAsReset = false): void { + #[\PHPUnit\Framework\Attributes\DataProvider('setCustomMessageDataProvider')] + public function testSetCustomMessage( + ?string $statusIcon, + string $message, + ?int $clearAt, + bool $expectSuccess, + bool $expectException, + ?Throwable $exception, + bool $expectLogger, + ?string $expectedLogMessage, + bool $expectSuccessAsReset = false, + ): void { $userStatus = $this->getUserStatus(); if ($expectException) { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('setCustomMessage') ->with('john.doe', $statusIcon, $message, $clearAt) ->willThrowException($exception); } else { if ($expectSuccessAsReset) { - $this->service->expects($this->never()) + $this->statusService->expects($this->never()) ->method('setCustomMessage'); - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('clearMessage') ->with('john.doe'); - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('findByUserId') ->with('john.doe') ->willReturn($userStatus); } else { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('setCustomMessage') ->with('john.doe', $statusIcon, $message, $clearAt) ->willReturn($userStatus); - $this->service->expects($this->never()) + $this->statusService->expects($this->never()) ->method('clearMessage'); } } @@ -312,10 +274,11 @@ class UserStatusControllerTest extends TestCase { } } - public function setCustomMessageDataProvider(): array { + public static function setCustomMessageDataProvider(): array { return [ ['👨🏽💻', 'Busy developing the status feature', 500, true, false, null, false, null], - ['👨🏽💻', '', 500, true, false, null, false, null, true], + ['👨🏽💻', '', 500, true, false, null, false, null, false], + ['👨🏽💻', '', 0, true, false, null, false, null, false], ['👨🏽💻', 'Busy developing the status feature', 500, false, true, new InvalidClearAtException('Original exception message'), true, 'New user-status for "john.doe" was rejected due to an invalid clearAt value "500"'], ['👨🏽💻', 'Busy developing the status feature', 500, false, true, new InvalidStatusIconException('Original exception message'), true, @@ -325,17 +288,8 @@ class UserStatusControllerTest extends TestCase { ]; } - public function testClearStatus(): void { - $this->service->expects($this->once()) - ->method('clearStatus') - ->with('john.doe'); - - $response = $this->controller->clearStatus(); - $this->assertEquals([], $response->getData()); - } - public function testClearMessage(): void { - $this->service->expects($this->once()) + $this->statusService->expects($this->once()) ->method('clearMessage') ->with('john.doe'); diff --git a/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php b/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php index d23b2bc02ff..8773b04c95f 100644 --- a/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php +++ b/apps/user_status/tests/Unit/Dashboard/UserStatusWidgetTest.php @@ -3,69 +3,44 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Dashboard; use OCA\UserStatus\Dashboard\UserStatusWidget; -use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Service\StatusService; -use OCP\IInitialStateService; +use OCP\AppFramework\Services\IInitialState; +use OCP\IDateTimeFormatter; use OCP\IL10N; -use OCP\IUser; +use OCP\IURLGenerator; use OCP\IUserManager; use OCP\IUserSession; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class UserStatusWidgetTest extends TestCase { - - /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ - private $l10n; - - /** @var IInitialStateService|\PHPUnit\Framework\MockObject\MockObject */ - private $initialState; - - /** @var IUserManager|\PHPUnit\Framework\MockObject\MockObject */ - private $userManager; - - /** @var IUserSession|\PHPUnit\Framework\MockObject\MockObject */ - private $userSession; - - /** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */ - private $service; - - /** @var UserStatusWidget */ - private $widget; + private IL10N&MockObject $l10n; + private IDateTimeFormatter&MockObject $dateTimeFormatter; + private IURLGenerator&MockObject $urlGenerator; + private IInitialState&MockObject $initialState; + private IUserManager&MockObject $userManager; + private IUserSession&MockObject $userSession; + private StatusService&MockObject $service; + private UserStatusWidget $widget; protected function setUp(): void { parent::setUp(); $this->l10n = $this->createMock(IL10N::class); - $this->initialState = $this->createMock(IInitialStateService::class); + $this->dateTimeFormatter = $this->createMock(IDateTimeFormatter::class); + $this->urlGenerator = $this->createMock(IURLGenerator::class); + $this->initialState = $this->createMock(IInitialState::class); $this->userManager = $this->createMock(IUserManager::class); $this->userSession = $this->createMock(IUserSession::class); $this->service = $this->createMock(StatusService::class); - $this->widget = new UserStatusWidget($this->l10n, $this->initialState, $this->userManager, $this->userSession, $this->service); + $this->widget = new UserStatusWidget($this->l10n, $this->dateTimeFormatter, $this->urlGenerator, $this->initialState, $this->userManager, $this->userSession, $this->service); } public function testGetId(): void { @@ -85,178 +60,10 @@ class UserStatusWidgetTest extends TestCase { } public function testGetIconClass(): void { - $this->assertEquals('icon-user-status', $this->widget->getIconClass()); + $this->assertEquals('icon-user-status-dark', $this->widget->getIconClass()); } public function testGetUrl(): void { $this->assertNull($this->widget->getUrl()); } - - public function testLoadNoUserSession(): void { - $this->userSession->expects($this->once()) - ->method('getUser') - ->willReturn(null); - - $this->initialState->expects($this->once()) - ->method('provideInitialState') - ->with('user_status', 'dashboard_data', []); - - $this->service->expects($this->never()) - ->method('findAllRecentStatusChanges'); - - $this->widget->load(); - } - - public function testLoadWithCurrentUser(): void { - $user = $this->createMock(IUser::class); - $user->method('getUid')->willReturn('john.doe'); - $this->userSession->expects($this->once()) - ->method('getUser') - ->willReturn($user); - - $user1 = $this->createMock(IUser::class); - $user1->method('getDisplayName')->willReturn('User No. 1'); - - $this->userManager - ->method('get') - ->willReturnMap([ - ['user_1', $user1], - ['user_2', null], - ['user_3', null], - ['user_4', null], - ['user_5', null], - ['user_6', null], - ['user_7', null], - ]); - - $userStatuses = [ - UserStatus::fromParams([ - 'userId' => 'user_1', - 'status' => 'online', - 'customIcon' => '💻', - 'customMessage' => 'Working', - 'statusTimestamp' => 5000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_2', - 'status' => 'away', - 'customIcon' => '☕️', - 'customMessage' => 'Office Hangout', - 'statusTimestamp' => 6000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_3', - 'status' => 'dnd', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'john.doe', - 'status' => 'away', - 'customIcon' => '☕️', - 'customMessage' => 'Office Hangout', - 'statusTimestamp' => 90000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_4', - 'status' => 'dnd', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_5', - 'status' => 'invisible', - 'customIcon' => '🏝', - 'customMessage' => 'On vacation', - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_6', - 'status' => 'offline', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - UserStatus::fromParams([ - 'userId' => 'user_7', - 'status' => 'invisible', - 'customIcon' => null, - 'customMessage' => null, - 'statusTimestamp' => 7000, - ]), - ]; - - $this->service->expects($this->once()) - ->method('findAllRecentStatusChanges') - ->with(8, 0) - ->willReturn($userStatuses); - - $this->initialState->expects($this->once()) - ->method('provideInitialState') - ->with('user_status', 'dashboard_data', $this->callback(function ($data): bool { - $this->assertEquals([ - [ - 'userId' => 'user_1', - 'displayName' => 'User No. 1', - 'status' => 'online', - 'icon' => '💻', - 'message' => 'Working', - 'timestamp' => 5000, - ], - [ - 'userId' => 'user_2', - 'displayName' => 'user_2', - 'status' => 'away', - 'icon' => '☕️', - 'message' => 'Office Hangout', - 'timestamp' => 6000, - ], - [ - 'userId' => 'user_3', - 'displayName' => 'user_3', - 'status' => 'dnd', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_4', - 'displayName' => 'user_4', - 'status' => 'dnd', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_5', - 'displayName' => 'user_5', - 'status' => 'offline', - 'icon' => '🏝', - 'message' => 'On vacation', - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_6', - 'displayName' => 'user_6', - 'status' => 'offline', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - [ - 'userId' => 'user_7', - 'displayName' => 'user_7', - 'status' => 'offline', - 'icon' => null, - 'message' => null, - 'timestamp' => 7000, - ], - ], $data); - return true; - })); - - $this->widget->load(); - } } diff --git a/apps/user_status/tests/Unit/Db/UserStatusMapperTest.php b/apps/user_status/tests/Unit/Db/UserStatusMapperTest.php index 0d9f1c1f718..ea4480489c7 100644 --- a/apps/user_status/tests/Unit/Db/UserStatusMapperTest.php +++ b/apps/user_status/tests/Unit/Db/UserStatusMapperTest.php @@ -3,38 +3,19 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Christoph Wurst <christoph@winzerhof-wurst.at> - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Db; use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Db\UserStatusMapper; +use OCP\AppFramework\Db\DoesNotExistException; use OCP\DB\Exception; use Test\TestCase; class UserStatusMapperTest extends TestCase { - - /** @var UserStatusMapper */ - private $mapper; + private UserStatusMapper $mapper; protected function setUp(): void { parent::setUp(); @@ -153,14 +134,7 @@ class UserStatusMapperTest extends TestCase { $this->mapper->insert($userStatus2); } - /** - * @param string $status - * @param bool $isUserDefined - * @param int $timestamp - * @param bool $expectsClean - * - * @dataProvider clearStatusesOlderThanDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('clearStatusesOlderThanDataProvider')] public function testClearStatusesOlderThan(string $status, bool $isUserDefined, int $timestamp, bool $expectsClean): void { $oldStatus = UserStatus::fromParams([ 'userId' => 'john.doe', @@ -186,7 +160,7 @@ class UserStatusMapperTest extends TestCase { } } - public function clearStatusesOlderThanDataProvider(): array { + public static function clearStatusesOlderThanDataProvider(): array { return [ ['offline', false, 6000, false], ['online', true, 6000, false], @@ -204,22 +178,16 @@ class UserStatusMapperTest extends TestCase { ]; } - public function testClearMessagesOlderThan(): void { + public function testClearOlderThanClearAt(): void { $this->insertSampleStatuses(); - $this->mapper->clearMessagesOlderThan(55000); + $this->mapper->clearOlderThanClearAt(55000); $allStatuses = $this->mapper->findAll(); - $this->assertCount(3, $allStatuses); + $this->assertCount(2, $allStatuses); - $user1Status = $this->mapper->findByUserId('user1'); - $this->assertEquals('user1', $user1Status->getUserId()); - $this->assertEquals('dnd', $user1Status->getStatus()); - $this->assertEquals(5000, $user1Status->getStatusTimestamp()); - $this->assertEquals(true, $user1Status->getIsUserDefined()); - $this->assertEquals(null, $user1Status->getCustomIcon()); - $this->assertEquals(null, $user1Status->getCustomMessage()); - $this->assertEquals(null, $user1Status->getClearAt()); + $this->expectException(DoesNotExistException::class); + $this->mapper->findByUserId('user1'); } private function insertSampleStatuses(): void { @@ -233,6 +201,7 @@ class UserStatusMapperTest extends TestCase { $userStatus2->setUserId('user1'); $userStatus2->setStatus('dnd'); $userStatus2->setStatusTimestamp(5000); + $userStatus2->setStatusMessageTimestamp(5000); $userStatus2->setIsUserDefined(true); $userStatus2->setCustomIcon('💩'); $userStatus2->setCustomMessage('Do not disturb'); @@ -242,6 +211,7 @@ class UserStatusMapperTest extends TestCase { $userStatus3->setUserId('user2'); $userStatus3->setStatus('away'); $userStatus3->setStatusTimestamp(6000); + $userStatus3->setStatusMessageTimestamp(6000); $userStatus3->setIsUserDefined(false); $userStatus3->setCustomIcon('🏝'); $userStatus3->setCustomMessage('On vacation'); @@ -252,7 +222,7 @@ class UserStatusMapperTest extends TestCase { $this->mapper->insert($userStatus3); } - public function dataCreateBackupStatus(): array { + public static function dataCreateBackupStatus(): array { return [ [false, false, false], [true, false, true], @@ -261,12 +231,7 @@ class UserStatusMapperTest extends TestCase { ]; } - /** - * @dataProvider dataCreateBackupStatus - * @param bool $hasStatus - * @param bool $hasBackup - * @param bool $backupCreated - */ + #[\PHPUnit\Framework\Attributes\DataProvider('dataCreateBackupStatus')] public function testCreateBackupStatus(bool $hasStatus, bool $hasBackup, bool $backupCreated): void { if ($hasStatus) { $userStatus1 = new UserStatus(); @@ -305,7 +270,7 @@ class UserStatusMapperTest extends TestCase { $this->assertEquals('_user1', $user1Status->getUserId()); $this->assertEquals(true, $user1Status->getIsBackup()); $this->assertEquals('Current', $user1Status->getCustomMessage()); - } else if ($hasBackup) { + } elseif ($hasBackup) { $user1Status = $this->mapper->findByUserId('user1', true); $this->assertEquals('_user1', $user1Status->getUserId()); $this->assertEquals(true, $user1Status->getIsBackup()); diff --git a/apps/user_status/tests/Unit/Listener/UserDeletedListenerTest.php b/apps/user_status/tests/Unit/Listener/UserDeletedListenerTest.php index 883a06059f7..fbcea23338d 100644 --- a/apps/user_status/tests/Unit/Listener/UserDeletedListenerTest.php +++ b/apps/user_status/tests/Unit/Listener/UserDeletedListenerTest.php @@ -3,25 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Listener; @@ -30,15 +13,12 @@ use OCA\UserStatus\Service\StatusService; use OCP\EventDispatcher\GenericEvent; use OCP\IUser; use OCP\User\Events\UserDeletedEvent; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class UserDeletedListenerTest extends TestCase { - - /** @var StatusService|\PHPUnit\Framework\MockObject\MockObject */ - private $service; - - /** @var UserDeletedListener */ - private $listener; + private StatusService&MockObject $service; + private UserDeletedListener $listener; protected function setUp(): void { parent::setUp(); diff --git a/apps/user_status/tests/Unit/Listener/UserLiveStatusListenerTest.php b/apps/user_status/tests/Unit/Listener/UserLiveStatusListenerTest.php index 2e815073b5a..c03eed0089e 100644 --- a/apps/user_status/tests/Unit/Listener/UserLiveStatusListenerTest.php +++ b/apps/user_status/tests/Unit/Listener/UserLiveStatusListenerTest.php @@ -3,79 +3,63 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Listener; +use OCA\DAV\CalDAV\Status\StatusService as CalendarStatusService; use OCA\UserStatus\Db\UserStatus; use OCA\UserStatus\Db\UserStatusMapper; -use OCA\UserStatus\Listener\UserDeletedListener; use OCA\UserStatus\Listener\UserLiveStatusListener; +use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\EventDispatcher\GenericEvent; use OCP\IUser; use OCP\User\Events\UserLiveStatusEvent; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; class UserLiveStatusListenerTest extends TestCase { + private UserStatusMapper&MockObject $mapper; + private StatusService&MockObject $statusService; + private ITimeFactory&MockObject $timeFactory; + private CalendarStatusService&MockObject $calendarStatusService; - /** @var UserStatusMapper|\PHPUnit\Framework\MockObject\MockObject */ - private $mapper; - - /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ - private $timeFactory; - - /** @var UserDeletedListener */ - private $listener; + private LoggerInterface&MockObject $logger; + private UserLiveStatusListener $listener; protected function setUp(): void { parent::setUp(); $this->mapper = $this->createMock(UserStatusMapper::class); + $this->statusService = $this->createMock(StatusService::class); $this->timeFactory = $this->createMock(ITimeFactory::class); - $this->listener = new UserLiveStatusListener($this->mapper, $this->timeFactory); + $this->calendarStatusService = $this->createMock(CalendarStatusService::class); + $this->logger = $this->createMock(LoggerInterface::class); + + $this->listener = new UserLiveStatusListener( + $this->mapper, + $this->statusService, + $this->timeFactory, + $this->calendarStatusService, + $this->logger, + ); } - /** - * @param string $userId - * @param string $previousStatus - * @param int $previousTimestamp - * @param bool $previousIsUserDefined - * @param string $eventStatus - * @param int $eventTimestamp - * @param bool $expectExisting - * @param bool $expectUpdate - * - * @dataProvider handleEventWithCorrectEventDataProvider - */ - public function testHandleWithCorrectEvent(string $userId, - string $previousStatus, - int $previousTimestamp, - bool $previousIsUserDefined, - string $eventStatus, - int $eventTimestamp, - bool $expectExisting, - bool $expectUpdate): void { + #[\PHPUnit\Framework\Attributes\DataProvider('handleEventWithCorrectEventDataProvider')] + public function testHandleWithCorrectEvent( + string $userId, + string $previousStatus, + int $previousTimestamp, + bool $previousIsUserDefined, + string $eventStatus, + int $eventTimestamp, + bool $expectExisting, + bool $expectUpdate, + ): void { $userStatus = new UserStatus(); if ($expectExisting) { @@ -85,12 +69,12 @@ class UserLiveStatusListenerTest extends TestCase { $userStatus->setStatusTimestamp($previousTimestamp); $userStatus->setIsUserDefined($previousIsUserDefined); - $this->mapper->expects($this->once()) + $this->statusService->expects($this->once()) ->method('findByUserId') ->with($userId) ->willReturn($userStatus); } else { - $this->mapper->expects($this->once()) + $this->statusService->expects($this->once()) ->method('findByUserId') ->with($userId) ->willThrowException(new DoesNotExistException('')); @@ -142,7 +126,7 @@ class UserLiveStatusListenerTest extends TestCase { } } - public function handleEventWithCorrectEventDataProvider(): array { + public static function handleEventWithCorrectEventDataProvider(): array { return [ ['john.doe', 'offline', 0, false, 'online', 5000, true, true], ['john.doe', 'offline', 0, false, 'online', 5000, false, true], diff --git a/apps/user_status/tests/Unit/Service/EmojiServiceTest.php b/apps/user_status/tests/Unit/Service/EmojiServiceTest.php deleted file mode 100644 index 454f1d75a0d..00000000000 --- a/apps/user_status/tests/Unit/Service/EmojiServiceTest.php +++ /dev/null @@ -1,100 +0,0 @@ -<?php - -declare(strict_types=1); - -/** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * - */ -namespace OCA\UserStatus\Tests\Service; - -use OCA\UserStatus\Service\EmojiService; -use OCP\IDBConnection; -use Test\TestCase; - -class EmojiServiceTest extends TestCase { - - /** @var IDBConnection|\PHPUnit\Framework\MockObject\MockObject */ - private $db; - - /** @var EmojiService */ - private $service; - - protected function setUp(): void { - parent::setUp(); - - $this->db = $this->createMock(IDBConnection::class); - $this->service = new EmojiService($this->db); - } - - /** - * @param bool $supports4ByteText - * @param bool $expected - * - * @dataProvider doesPlatformSupportEmojiDataProvider - */ - public function testDoesPlatformSupportEmoji(bool $supports4ByteText, bool $expected): void { - $this->db->expects($this->once()) - ->method('supports4ByteText') - ->willReturn($supports4ByteText); - - $this->assertEquals($expected, $this->service->doesPlatformSupportEmoji()); - } - - /** - * @return array - */ - public function doesPlatformSupportEmojiDataProvider(): array { - return [ - [true, true], - [false, false], - ]; - } - - /** - * @param string $emoji - * @param bool $expected - * - * @dataProvider isValidEmojiDataProvider - */ - public function testIsValidEmoji(string $emoji, bool $expected): void { - $actual = $this->service->isValidEmoji($emoji); - - $this->assertEquals($expected, $actual); - } - - public function isValidEmojiDataProvider(): array { - return [ - ['🏝', true], - ['📱', true], - ['🏢', true], - ['📱📠', false], - ['a', false], - ['0', false], - ['$', false], - // Test some more complex emojis with modifiers and zero-width-joiner - ['👩🏿💻', true], - ['🤷🏼♀️', true], - ['🏳️🌈', true], - ['👨👨👦👦', true], - ['👩❤️👩', true] - ]; - } -} diff --git a/apps/user_status/tests/Unit/Service/PredefinedStatusServiceTest.php b/apps/user_status/tests/Unit/Service/PredefinedStatusServiceTest.php index 0a65256bfac..78e4a18d9f1 100644 --- a/apps/user_status/tests/Unit/Service/PredefinedStatusServiceTest.php +++ b/apps/user_status/tests/Unit/Service/PredefinedStatusServiceTest.php @@ -3,40 +3,19 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Daniel Kesselberg <mail@danielkesselberg.de> - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Service; use OCA\UserStatus\Service\PredefinedStatusService; use OCP\IL10N; +use PHPUnit\Framework\MockObject\MockObject; use Test\TestCase; class PredefinedStatusServiceTest extends TestCase { - - /** @var IL10N|\PHPUnit\Framework\MockObject\MockObject */ - protected $l10n; - - /** @var PredefinedStatusService */ - protected $service; + protected IL10N&MockObject $l10n; + protected PredefinedStatusService $service; protected function setUp(): void { parent::setUp(); @@ -47,17 +26,11 @@ class PredefinedStatusServiceTest extends TestCase { } public function testGetDefaultStatuses(): void { - $this->l10n->expects($this->exactly(6)) + $this->l10n->expects($this->exactly(8)) ->method('t') - ->withConsecutive( - ['In a meeting'], - ['Commuting'], - ['Working remotely'], - ['Out sick'], - ['Vacationing'], - ['In a call'], - ) - ->willReturnArgument(0); + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); $actual = $this->service->getDefaultStatuses(); $this->assertEquals([ @@ -80,6 +53,15 @@ class PredefinedStatusServiceTest extends TestCase { ], ], [ + 'id' => 'be-right-back', + 'icon' => '⏳', + 'message' => 'Be right back', + 'clearAt' => [ + 'type' => 'period', + 'time' => 900, + ], + ], + [ 'id' => 'remote-work', 'icon' => '🏡', 'message' => 'Working remotely', @@ -110,41 +92,36 @@ class PredefinedStatusServiceTest extends TestCase { 'clearAt' => null, 'visible' => false, ], + [ + 'id' => 'out-of-office', + 'icon' => '🛑', + 'message' => 'Out of office', + 'clearAt' => null, + 'visible' => false, + ], ], $actual); } - /** - * @param string $id - * @param string|null $expectedIcon - * - * @dataProvider getIconForIdDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('getIconForIdDataProvider')] public function testGetIconForId(string $id, ?string $expectedIcon): void { $actual = $this->service->getIconForId($id); $this->assertEquals($expectedIcon, $actual); } - /** - * @return array - */ - public function getIconForIdDataProvider(): array { + public static function getIconForIdDataProvider(): array { return [ ['meeting', '📅'], ['commuting', '🚌'], ['sick-leave', '🤒'], ['vacationing', '🌴'], ['remote-work', '🏡'], + ['be-right-back', '⏳'], ['call', '💬'], ['unknown-id', null], ]; } - /** - * @param string $id - * @param string|null $expected - * - * @dataProvider getTranslatedStatusForIdDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('getTranslatedStatusForIdDataProvider')] public function testGetTranslatedStatusForId(string $id, ?string $expected): void { $this->l10n->method('t') ->willReturnArgument(0); @@ -153,59 +130,44 @@ class PredefinedStatusServiceTest extends TestCase { $this->assertEquals($expected, $actual); } - /** - * @return array - */ - public function getTranslatedStatusForIdDataProvider(): array { + public static function getTranslatedStatusForIdDataProvider(): array { return [ ['meeting', 'In a meeting'], ['commuting', 'Commuting'], ['sick-leave', 'Out sick'], ['vacationing', 'Vacationing'], ['remote-work', 'Working remotely'], + ['be-right-back', 'Be right back'], ['call', 'In a call'], ['unknown-id', null], ]; } - /** - * @param string $id - * @param bool $expected - * - * @dataProvider isValidIdDataProvider - */ + #[\PHPUnit\Framework\Attributes\DataProvider('isValidIdDataProvider')] public function testIsValidId(string $id, bool $expected): void { $actual = $this->service->isValidId($id); $this->assertEquals($expected, $actual); } - /** - * @return array - */ - public function isValidIdDataProvider(): array { + public static function isValidIdDataProvider(): array { return [ ['meeting', true], ['commuting', true], ['sick-leave', true], ['vacationing', true], ['remote-work', true], + ['be-right-back', true], ['call', true], ['unknown-id', false], ]; } public function testGetDefaultStatusById(): void { - $this->l10n->expects($this->exactly(6)) + $this->l10n->expects($this->exactly(8)) ->method('t') - ->withConsecutive( - ['In a meeting'], - ['Commuting'], - ['Working remotely'], - ['Out sick'], - ['Vacationing'], - ['In a call'], - ) - ->willReturnArgument(0); + ->willReturnCallback(function ($text, $parameters = []) { + return vsprintf($text, $parameters); + }); $this->assertEquals([ 'id' => 'call', diff --git a/apps/user_status/tests/Unit/Service/StatusServiceTest.php b/apps/user_status/tests/Unit/Service/StatusServiceTest.php index 3dd397e1d36..7dfa5b0d064 100644 --- a/apps/user_status/tests/Unit/Service/StatusServiceTest.php +++ b/apps/user_status/tests/Unit/Service/StatusServiceTest.php @@ -3,26 +3,8 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * @author Joas Schilling <coding@schilljs.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ namespace OCA\UserStatus\Tests\Service; @@ -35,35 +17,29 @@ use OCA\UserStatus\Exception\InvalidMessageIdException; use OCA\UserStatus\Exception\InvalidStatusIconException; use OCA\UserStatus\Exception\InvalidStatusTypeException; use OCA\UserStatus\Exception\StatusMessageTooLongException; -use OCA\UserStatus\Service\EmojiService; use OCA\UserStatus\Service\PredefinedStatusService; use OCA\UserStatus\Service\StatusService; use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Utility\ITimeFactory; use OCP\DB\Exception; use OCP\IConfig; +use OCP\IEmojiHelper; +use OCP\IUserManager; use OCP\UserStatus\IUserStatus; +use PHPUnit\Framework\MockObject\MockObject; +use Psr\Log\LoggerInterface; use Test\TestCase; class StatusServiceTest extends TestCase { + private UserStatusMapper&MockObject $mapper; + private ITimeFactory&MockObject $timeFactory; + private PredefinedStatusService&MockObject $predefinedStatusService; + private IEmojiHelper&MockObject $emojiHelper; + private IConfig&MockObject $config; + private IUserManager&MockObject $userManager; + private LoggerInterface&MockObject $logger; - /** @var UserStatusMapper|\PHPUnit\Framework\MockObject\MockObject */ - private $mapper; - - /** @var ITimeFactory|\PHPUnit\Framework\MockObject\MockObject */ - private $timeFactory; - - /** @var PredefinedStatusService|\PHPUnit\Framework\MockObject\MockObject */ - private $predefinedStatusService; - - /** @var EmojiService|\PHPUnit\Framework\MockObject\MockObject */ - private $emojiService; - - /** @var IConfig|\PHPUnit\Framework\MockObject\MockObject */ - private $config; - - /** @var StatusService */ - private $service; + private StatusService $service; protected function setUp(): void { parent::setUp(); @@ -71,9 +47,10 @@ class StatusServiceTest extends TestCase { $this->mapper = $this->createMock(UserStatusMapper::class); $this->timeFactory = $this->createMock(ITimeFactory::class); $this->predefinedStatusService = $this->createMock(PredefinedStatusService::class); - $this->emojiService = $this->createMock(EmojiService::class); - + $this->emojiHelper = $this->createMock(IEmojiHelper::class); + $this->userManager = $this->createMock(IUserManager::class); $this->config = $this->createMock(IConfig::class); + $this->logger = $this->createMock(LoggerInterface::class); $this->config->method('getAppValue') ->willReturnMap([ @@ -84,8 +61,11 @@ class StatusServiceTest extends TestCase { $this->service = new StatusService($this->mapper, $this->timeFactory, $this->predefinedStatusService, - $this->emojiService, - $this->config); + $this->emojiHelper, + $this->config, + $this->userManager, + $this->logger, + ); } public function testFindAll(): void { @@ -138,8 +118,11 @@ class StatusServiceTest extends TestCase { $this->service = new StatusService($this->mapper, $this->timeFactory, $this->predefinedStatusService, - $this->emojiService, - $this->config); + $this->emojiHelper, + $this->config, + $this->userManager, + $this->logger, + ); $this->assertEquals([], $this->service->findAllRecentStatusChanges(20, 50)); @@ -155,22 +138,15 @@ class StatusServiceTest extends TestCase { $this->service = new StatusService($this->mapper, $this->timeFactory, $this->predefinedStatusService, - $this->emojiService, - $this->config); + $this->emojiHelper, + $this->config, + $this->userManager, + $this->logger, + ); $this->assertEquals([], $this->service->findAllRecentStatusChanges(20, 50)); } - public function testFindByUserId(): void { - $status = $this->createMock(UserStatus::class); - $this->mapper->expects($this->once()) - ->method('findByUserId') - ->with('john.doe') - ->willReturn($status); - - $this->assertEquals($status, $this->service->findByUserId('john.doe')); - } - public function testFindByUserIdDoesNotExist(): void { $this->mapper->expects($this->once()) ->method('findByUserId') @@ -245,30 +221,19 @@ class StatusServiceTest extends TestCase { $this->assertNull($status->getMessageId()); } - /** - * @param string $userId - * @param string $status - * @param int|null $statusTimestamp - * @param bool $isUserDefined - * @param bool $expectExisting - * @param bool $expectSuccess - * @param bool $expectTimeFactory - * @param bool $expectException - * @param string|null $expectedExceptionClass - * @param string|null $expectedExceptionMessage - * - * @dataProvider setStatusDataProvider - */ - public function testSetStatus(string $userId, - string $status, - ?int $statusTimestamp, - bool $isUserDefined, - bool $expectExisting, - bool $expectSuccess, - bool $expectTimeFactory, - bool $expectException, - ?string $expectedExceptionClass, - ?string $expectedExceptionMessage): void { + #[\PHPUnit\Framework\Attributes\DataProvider('setStatusDataProvider')] + public function testSetStatus( + string $userId, + string $status, + ?int $statusTimestamp, + bool $isUserDefined, + bool $expectExisting, + bool $expectSuccess, + bool $expectTimeFactory, + bool $expectException, + ?string $expectedExceptionClass, + ?string $expectedExceptionMessage, + ): void { $userStatus = new UserStatus(); if ($expectExisting) { @@ -319,7 +284,7 @@ class StatusServiceTest extends TestCase { } } - public function setStatusDataProvider(): array { + public static function setStatusDataProvider(): array { return [ ['john.doe', 'online', 50, true, true, true, false, false, null, null], ['john.doe', 'online', 50, true, false, true, false, false, null, null], @@ -377,28 +342,18 @@ class StatusServiceTest extends TestCase { ]; } - /** - * @param string $userId - * @param string $messageId - * @param bool $isValidMessageId - * @param int|null $clearAt - * @param bool $expectExisting - * @param bool $expectSuccess - * @param bool $expectException - * @param string|null $expectedExceptionClass - * @param string|null $expectedExceptionMessage - * - * @dataProvider setPredefinedMessageDataProvider - */ - public function testSetPredefinedMessage(string $userId, - string $messageId, - bool $isValidMessageId, - ?int $clearAt, - bool $expectExisting, - bool $expectSuccess, - bool $expectException, - ?string $expectedExceptionClass, - ?string $expectedExceptionMessage): void { + #[\PHPUnit\Framework\Attributes\DataProvider('setPredefinedMessageDataProvider')] + public function testSetPredefinedMessage( + string $userId, + string $messageId, + bool $isValidMessageId, + ?int $clearAt, + bool $expectExisting, + bool $expectSuccess, + bool $expectException, + ?string $expectedExceptionClass, + ?string $expectedExceptionMessage, + ): void { $userStatus = new UserStatus(); if ($expectExisting) { @@ -461,7 +416,7 @@ class StatusServiceTest extends TestCase { } } - public function setPredefinedMessageDataProvider(): array { + public static function setPredefinedMessageDataProvider(): array { return [ ['john.doe', 'sick-leave', true, null, true, true, false, null, null], ['john.doe', 'sick-leave', true, null, false, true, false, null, null], @@ -474,30 +429,19 @@ class StatusServiceTest extends TestCase { ]; } - /** - * @param string $userId - * @param string|null $statusIcon - * @param bool $supportsEmoji - * @param string $message - * @param int|null $clearAt - * @param bool $expectExisting - * @param bool $expectSuccess - * @param bool $expectException - * @param string|null $expectedExceptionClass - * @param string|null $expectedExceptionMessage - * - * @dataProvider setCustomMessageDataProvider - */ - public function testSetCustomMessage(string $userId, - ?string $statusIcon, - bool $supportsEmoji, - string $message, - ?int $clearAt, - bool $expectExisting, - bool $expectSuccess, - bool $expectException, - ?string $expectedExceptionClass, - ?string $expectedExceptionMessage): void { + #[\PHPUnit\Framework\Attributes\DataProvider('setCustomMessageDataProvider')] + public function testSetCustomMessage( + string $userId, + ?string $statusIcon, + bool $supportsEmoji, + string $message, + ?int $clearAt, + bool $expectExisting, + bool $expectSuccess, + bool $expectException, + ?string $expectedExceptionClass, + ?string $expectedExceptionMessage, + ): void { $userStatus = new UserStatus(); if ($expectExisting) { @@ -519,7 +463,7 @@ class StatusServiceTest extends TestCase { ->willThrowException(new DoesNotExistException('')); } - $this->emojiService->method('isValidEmoji') + $this->emojiHelper->method('isValidSingleEmoji') ->with($statusIcon) ->willReturn($supportsEmoji); @@ -558,7 +502,7 @@ class StatusServiceTest extends TestCase { } } - public function setCustomMessageDataProvider(): array { + public static function setCustomMessageDataProvider(): array { return [ ['john.doe', '😁', true, 'Custom message', null, true, true, false, null, null], ['john.doe', '😁', true, 'Custom message', null, false, true, false, null, null], @@ -749,7 +693,6 @@ class StatusServiceTest extends TestCase { } public function testBackup(): void { - $e = new Exception('', Exception::REASON_UNIQUE_CONSTRAINT_VIOLATION); $this->mapper->expects($this->once()) ->method('createBackupStatus') ->with('john') @@ -795,24 +738,91 @@ class StatusServiceTest extends TestCase { $backupOnly->setUserId('_backuponly'); $backupOnly->setIsBackup(true); + $noBackupDND = new UserStatus(); + $noBackupDND->setId(5); + $noBackupDND->setStatus(IUserStatus::DND); + $noBackupDND->setStatusTimestamp(1337); + $noBackupDND->setIsUserDefined(false); + $noBackupDND->setMessageId('call'); + $noBackupDND->setUserId('nobackupanddnd'); + $noBackupDND->setIsBackup(false); + $this->mapper->expects($this->once()) ->method('findByUserIds') - ->with(['john', 'nobackup', 'backuponly', '_john', '_nobackup', '_backuponly']) + ->with(['john', 'nobackup', 'backuponly', 'nobackupanddnd', '_john', '_nobackup', '_backuponly', '_nobackupanddnd']) ->willReturn([ $john, $johnBackup, $noBackup, $backupOnly, + $noBackupDND, ]); $this->mapper->expects($this->once()) ->method('deleteByIds') - ->with([1, 3]); + ->with([1, 3, 5]); $this->mapper->expects($this->once()) ->method('restoreBackupStatuses') ->with([2]); - $this->service->revertMultipleUserStatus(['john', 'nobackup', 'backuponly'], 'call', IUserStatus::AWAY); + $this->service->revertMultipleUserStatus(['john', 'nobackup', 'backuponly', 'nobackupanddnd'], 'call'); + } + + public static function dataSetUserStatus(): array { + return [ + [IUserStatus::MESSAGE_CALENDAR_BUSY, '', false], + + // Call > Meeting + [IUserStatus::MESSAGE_CALENDAR_BUSY, IUserStatus::MESSAGE_CALL, false], + [IUserStatus::MESSAGE_CALL, IUserStatus::MESSAGE_CALENDAR_BUSY, true], + + // Availability > Call&Meeting + [IUserStatus::MESSAGE_CALENDAR_BUSY, IUserStatus::MESSAGE_AVAILABILITY, false], + [IUserStatus::MESSAGE_CALL, IUserStatus::MESSAGE_AVAILABILITY, false], + [IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::MESSAGE_CALENDAR_BUSY, true], + [IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::MESSAGE_CALL, true], + + // Out-of-office > Availability&Call&Meeting + [IUserStatus::MESSAGE_AVAILABILITY, IUserStatus::MESSAGE_OUT_OF_OFFICE, false], + [IUserStatus::MESSAGE_CALENDAR_BUSY, IUserStatus::MESSAGE_OUT_OF_OFFICE, false], + [IUserStatus::MESSAGE_CALL, IUserStatus::MESSAGE_OUT_OF_OFFICE, false], + [IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::MESSAGE_AVAILABILITY, true], + [IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::MESSAGE_CALENDAR_BUSY, true], + [IUserStatus::MESSAGE_OUT_OF_OFFICE, IUserStatus::MESSAGE_CALL, true], + ]; + } + + #[\PHPUnit\Framework\Attributes\DataProvider('dataSetUserStatus')] + public function testSetUserStatus(string $messageId, string $oldMessageId, bool $expectedUpdateShortcut): void { + $previous = new UserStatus(); + $previous->setId(1); + $previous->setStatus(IUserStatus::AWAY); + $previous->setStatusTimestamp(1337); + $previous->setIsUserDefined(false); + $previous->setMessageId($oldMessageId); + $previous->setUserId('john'); + $previous->setIsBackup(false); + + $this->mapper->expects($this->once()) + ->method('findByUserId') + ->with('john') + ->willReturn($previous); + + $e = DbalException::wrap($this->createMock(UniqueConstraintViolationException::class)); + $this->mapper->expects($expectedUpdateShortcut ? $this->never() : $this->once()) + ->method('createBackupStatus') + ->willThrowException($e); + + $this->mapper->expects($this->any()) + ->method('update') + ->willReturnArgument(0); + + $this->predefinedStatusService->expects($this->once()) + ->method('isValidId') + ->with($messageId) + ->willReturn(true); + + $this->service->setUserStatus('john', IUserStatus::DND, $messageId, true); } } diff --git a/apps/user_status/tests/bootstrap.php b/apps/user_status/tests/bootstrap.php index b6d8fc06417..c98daca1dfc 100644 --- a/apps/user_status/tests/bootstrap.php +++ b/apps/user_status/tests/bootstrap.php @@ -3,34 +3,18 @@ declare(strict_types=1); /** - * @copyright Copyright (c) 2020, Georg Ehrke - * - * @author Georg Ehrke <oc.list@georgehrke.com> - * - * @license GNU AGPL version 3 or any later version - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * 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 - * along with this program. If not, see <http://www.gnu.org/licenses/>. - * + * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors + * SPDX-License-Identifier: AGPL-3.0-or-later */ + +use OCP\App\IAppManager; +use OCP\Server; + if (!defined('PHPUNIT_RUN')) { define('PHPUNIT_RUN', 1); } -require_once __DIR__.'/../../../lib/base.php'; - -\OC::$composerAutoloader->addPsr4('Test\\', OC::$SERVERROOT . '/tests/lib/', true); - -\OC_App::loadApp('user_status'); +require_once __DIR__ . '/../../../lib/base.php'; +require_once __DIR__ . '/../../../tests/autoload.php'; -OC_Hook::clear(); +Server::get(IAppManager::class)->loadApp('user_status'); |